Instream prints the flat-line instruction stream of an executing program, the sequence of instructions that actually gets executed. Like single-stepping through it with a debugger (you can achieve something similar with GDB scripting). This implementation uses the hardware single-stepping feature (a.k.a. MSR tracing) of modern processors to do its job efficiently.


$ tar xf instream-0.1.tar.gz
$ cd instream-0.1
$ make
$ ./instream ./hello | less
[7174] Done attaching onto 7176
Target received signal 19
Target received signal 19
Entry point: 400410
          400410 (02) 31ed                     XOR EBP, EBP
          400412 (03) 4989d1                   MOV R9, RDX
          400415 (01) 5e                       POP RSI
          400416 (03) 4889e2                   MOV RDX, RSP
          400419 (04) 4883e4f0                 AND RSP, -0x10
          40041d (01) 50                       PUSH RAX
          40041e (01) 54                       PUSH RSP
          40041f (07) 49c7c090054000           MOV R8, 0x400590
          400426 (07) 48c7c120054000           MOV RCX, 0x400520
          40042d (07) 48c7c7fd044000           MOV RDI, 0x4004fd
          400434 (05) e8b7ffffff               CALL 0x4003f0

It should be possible to build Instream with just a C compiler, all dependencies are bundled with the source.


The mechanism Instream uses is to take control of the target through ptrace, open the ELF file to find its entry point, and inject code at the entry point. This code enables the hardware tracing features. It would be straightforward to instead turn on tracing once the target reaches a given address, or to trace at the per-branch level instead (and disassemble more code). Distorm3 is used for code disassembly (it is included in the source archive below).


Page generated on Tue Jul 27 05:38:57 2021