0

I want to be able to see the output of my program in hex, as it runs, however if I pipe the output into xxd it will only print once the program has stopped running.

These are the things that that I've tried:

./a.out | while read LINE; do echo "$LINE" | xxd; done

./a.out | xxd

This is what my console looks like: (the arrows are my comments)

1 <-- input
2 <-- input
3 <-- input
4 <-- input
a <-- input (program ends after this input)
00000000: 6465 6667 0a                           defg.. <-- output
00000000: 6465 6667 0a                           defg.. <-- output
00000000: 6465 6667 0a                           defg.. <-- output
00000000: 6465 6667 0a                           defg.. <-- output

but this is what I want

1 <-- input
00000000: 6465 6667 0a                           defg.. <-- output
2 <-- input
00000000: 6465 6667 0a                           defg.. <-- output
3 <-- input
00000000: 6465 6667 0a                           defg.. <-- output
4 <-- input
00000000: 6465 6667 0a                           defg.. <-- output
a <-- input (program ends after this input)

(it's a simple test program in which it will print a set string if a number is inputted else it will exit)

a.c program

#include <stdio.h>

int main() {
    
    const char test[7] = {0x64,0x65,0x66,0x67,'\n',0x00};
    int testInteger;
    while(scanf("%d", &testInteger)){
        printf(test);
    }
}

Thanks in advance

user13392352
  • 164
  • 10
  • So the `1\n2\n3\n4\a\n` is input? Why are you showing the input interleaved with the text on the terminal? Just show the output. – William Pursell Jan 04 '21 at 16:14
  • nah so I have a loop in C like this ```while(scanf("%d", &testInt)){printf(test);}``` so it receives a line of input and prints a string as output. (It's just a test example as I've got another program which will output non-string characters and I want to print them in hex). The interleaved text is what I'd expect to see in my console as I'm running it. – user13392352 Jan 04 '21 at 16:18
  • `0d 0a` looks horribly like Windows-y CR+LF? You may want to delete the CR with `tr`. – Mark Setchell Jan 04 '21 at 16:28
  • I used a hex to ascii converter and just put that in, my string is made up of a hex array (ik that's really wierd). fixed that now – user13392352 Jan 04 '21 at 16:31
  • A [mre] would be a good addition. We don't have access to your `./a.out`, how are we supposed to test this? Is the behavior reproducible with other programs? `seq` for example. – oguz ismail Jan 04 '21 at 16:38
  • @oguzismail I've appended the C program now – user13392352 Jan 04 '21 at 16:40
  • If you don't have linefeeds in your data, the `read` in your `bash` or any `awk` isn't going to work too well. – Mark Setchell Jan 04 '21 at 16:41
  • 1
    Output to a pipe is buffered. Call `fflush(stdout);` after each `printf()` or turn off buffering with `setvbuf()`. – Barmar Jan 04 '21 at 16:43
  • @Barmar, This is mainly for a toy exploit, so I won't have the ability to change the binary to call fflush. Am I correct in thinking that the bash console prints this output as it receives it through stdout? Therefore isn't there a way to simply redirect this into my own program? – user13392352 Jan 04 '21 at 16:48
  • The bash console is irrelevant. Buffering means that the program doesn't write it. – Barmar Jan 04 '21 at 16:50
  • 1
    You can use the `unbuffer` tool that's included with Expect. – Barmar Jan 04 '21 at 16:50
  • But when I run the program on it's own without piping it works just as I expect, it waits for input then it prints a response – user13392352 Jan 04 '21 at 16:51
  • 1
    `stdout` is line-buffered when it's connected to a terminal, fully buffered in other cases. – Barmar Jan 04 '21 at 16:51
  • If you're an advanced enough programmer that you're designing exploits, this should be well known to you. – Barmar Jan 04 '21 at 16:52
  • Did you try `tee`? Something like this `./a.out | tee | xxd`? – accdias Jan 04 '21 at 16:54
  • 1
    @accdias That won't make a difference, `a.out` still buffers it output when writing to the pipe. – Barmar Jan 04 '21 at 16:54
  • See https://unix.stackexchange.com/questions/25372/turn-off-buffering-in-pipe – Danny Staple Jan 04 '21 at 16:58
  • The proper way to pipe a loop is with `while stuff; do ... done | xxd`; but of course, in this case, your `while` loop was just a really slow and buggy [useless `cat`.](https://stackoverflow.com/questions/11710552/useless-use-of-cat) – tripleee Jan 04 '21 at 17:04
  • @Barmar, I'm just learning about the basics of binary exploitation, not at the stage of developing full exploits for anything complicated, so I'm not incredibly experienced in the workings of linux. – user13392352 Jan 04 '21 at 17:27

1 Answers1

5

By default, stdout is fully buffered when writing to a pipe, so read doesn't receive anything until the output is flushed. This won't happen until the program has written 4K bytes (almost 700 lines) or exits.

You can use stdbuf to alter the buffering.

stdbuf -oL a.out | xxd

-oL switches to line buffering, so xxd (or any other program) will receive each line as it's printed.

Barmar
  • 741,623
  • 53
  • 500
  • 612
  • 1
    The problem is that the output buffer isn't flushed until `a.out` exits. So `while read` can't read anything until the program ends. He wants to see each line as it's printed. – Barmar Jan 04 '21 at 17:09