Pintr is an execution tracer based on Intel Pin for reverse-engineering.
This is a rough and experimental tool developed for CTF and malware analysis. A common tracer is very slow because it saves all executed instructions in the log and makes huge log files, and is not easy to use for reverse-engineering. To solve this problem, this excludes uninteresting logs such as the instructions within API and records only essential information for analysis.
- OS: Windows 10, Windows 8.1, Windows 7, Linux (Ubuntu 20.04)
- Arch: x64
- Intel Pin 3.21
- PE, ELF
- Download and expand Intel Pin.
- Set the path.
$ export PATH="$PATH;[PATH_TO_PIN_ROOT]"$ export PIN_ROOT="[PATH_TO_PIN_ROOT]"
- Run make.
$ cd pintr$ make
- Output
obj-intel64/pintr.so.
- Install Visual Studio and Cygwin.
- Download and expand Intel Pin.
- Launch the Visual Studio Developer Command Prompt.
- Set the path.
$ SET PATH=%PATH%;[PATH_TO_CYGWIN_BIN]- e.g.
$ SET PATH=%PATH%;C:\cygwin64\bin
- e.g.
$ SET PATH=%PATH%;[PATH_TO_PIN_ROOT]$ SET PIN_ROOT=[PATH_TO_PIN_ROOT]- e.g.
SET PIN_ROOT=C:/pin-3.31(Note: not backslash but slash)
- e.g.
- Run make.
$ cd pintr$ make
- Output
obj-intel64\pintr.dll.
- Run program.
pin -t pintr.so [OPTIONS]... -- [TARGET_APP]
- Attach to running program.
pin -pid [PID] -t pintr.so [OPTIONS]...
- Run program.
pin -t pintr.dll [OPTIONS]... -- [TARGET_APP]
- Attach to running program.
pin -pid [PID] -t pintr.dll [OPTIONS]...
- -Ss
- select log count column
- -St
- select time of execution column
- -Sh
- select hex of instruction binary column
- -Sb
- select branch mark column
- -Si
- select image name column
- -Sr
- select routine name column (e.g. API)
- -Sf
- select all eflags registers column
- -Sg
- select all general-purpose registers column
- -Sx
- select all xmm registers column
- -Sy
- select all ymm registers column
- -Sall
- select all column
-
-Ki IMAGE
- Image name to skip
- This option can be used multiple times.
-
-Kr ROUTINE
- Routine name to skip
- This option can be used multiple times.
-
-Ka ADDRESS-ADDRESS
- Address range to skip (e.g. 400000-408000)
- This option can be used multiple times.
-
-Hi IMAGE
- Image name to hook
- This option can be used multiple times.
-
-Hr ROUTINE
- Routine name to hook
- This option can be used multiple times.
-
-Ha ADDRESS-ADDRESS
- Address range to hook (e.g. 400000-408000)
- This option can be used multiple times.
-
-Fi IMAGE
- Image name to filter
- This option can be used multiple times.
-
-Fr ROUTINE
- Routine name to filter
- This option can be used multiple times.
-
-Fa ADDRESS-ADDRESS
- Address range to filter (e.g. 400000-408000)
- This option can be used multiple times.
-
-Fe
- Filter before entry point (Start from entry point)
-
-Fm
- Filter before main image (Start from main image)
-
-Fs
- Filter before defined address (Start from defined address)
-
-Fd
- Filter after defined address (End in defined address)
-
-Fx
- Filter all instructions (Log only API call)
-
-Ti IMAGE
- Image name to trace
- This option can be used multiple times.
-
-Tr ROUTINE
- Routine name to trace
- This option can be used multiple times.
-
-Ta ADDRESS-ADDRESS
- Address range to trace (e.g. 400000-408000)
- This option can be used multiple times.
-
-Td
- Trace inside routine
-
-a
- Trace all instruction
-
-Ei COUNT
- Instructions count limit
-
-Et MILLISECOND
- Time limit
-
-Dc
- Detect crypt magic numbers
-
-Da
- Detect crypt APIs (for Windows)
-
-Dr ROUTINE
- Detect defined routine
- This option can be used multiple times.
-
-Dm MAGIC
- Detect defined magic number
- This option can be used multiple times.
-
-Dall
- -Dc and -Da
-
-Om INS_ADDRESS:MEM_ADDRESS:SIZE
- Dump memory (e.g. 401000:7F000000:100)
- This option can be used multiple times.
-
-Or INS_ADDRESS
- Dump registers (e.g. 401000)
- This option can be used multiple times.
-
-q
- Quiet
-
-v
- Verbose
-
-vv
- Debug
-
-mt
- Trace only main thread
-
-o FILENAME
- Trace log filename
The -Td option enables to output all logs including inside APIs.
$ pin -t pintr.so -Td -- ls
You can also use -a. The difference is that it makes all filtering rules clear.
$ pin -t pintr.so -a -- ls
[+] Image info
Name: /usr/bin/ls
Address: 555555554000-555555574b4f (22b40)
Entry: 55555555a7d0
[+] Image info
Name: /lib64/ld-linux-x86-64.so.2
Address: 7ffff7fcf000-7ffff7ffaccb (2ebf0)
Entry: 7ffff7fd0100
[+] Image info
Name: [vdso]
Address: 7ffff7fcd000-7ffff7fcdfde (2000)
Entry: 7ffff7fcd6d0
[+] Tracing started ...
[+] Settings
[Columns]
Default
[Trigger]
Start -
End -
[Rules]
Skip -
Hook -
Filter -
Trace -
[Mode]
Log file (base) trace-44352
Verbose level 1
Only API No
Only main thread No
Detect crypt magic No
Detect crypt API No
[Dump]
Memory Dump -
Registry Dump -
[Others]
Time Limit -
Ins Limit -
[+] Image info
Name: /lib/x86_64-linux-gnu/libselinux.so.1
Address: 7fffe32ae000-7fffe32d8a07 (27d80)
Entry: 7fffe32b5040
[+] Image info
Name: /lib/x86_64-linux-gnu/libc.so.6
Address: 7fffe2fe8000-7fffe31d94d7 (1ef6a8)
Entry: 7fffe300f1f0
[+] Image info
Name: /lib/x86_64-linux-gnu/libpcre2-8.so.0
Address: 7fffe2f0d000-7fffe2f9c327 (8eac8)
Entry: 7fffe2f0f2e0
[+] Image info
Name: /lib/x86_64-linux-gnu/libdl.so.2
Address: 7fffe2f06000-7fffe2f0b10f (4980)
Entry: 7fffe2f07220
[+] Image info
Name: /lib/x86_64-linux-gnu/libpthread.so.0
Address: 7fffe2eb4000-7fffe2ed6477 (26628)
Entry: 7fffe2ebc190
The log is saved in the following format.
(snip)
|55555555a7d4|xor ebp, ebp|{ebp_0}<={ebp_0,ebp_0}
|55555555a7d6|mov r9, rdx|{r9_7ffff7fe0d50}<={rdx_7ffff7fe0d50}
|55555555a7d9|pop rsi|{rsi_1,rsp_7fffffffdc98}<={rsp_7fffffffdc90,7fffffffdc90_8_1}
|55555555a7da|mov rdx, rsp|{rdx_7fffffffdc98}<={rsp_7fffffffdc98}
|55555555a7dd|and rsp, 0xfffffffffffffff0|{rsp_7fffffffdc90}<={rsp_7fffffffdc98}
|55555555a7e1|push rax|{rsp_7fffffffdc88,7fffffffdc88_8_1c}<={rax_1c,rsp_7fffffffdc90}
(snip)
The value read/written by registers/memory is described in the following formats.
{written value}<={read value}
The value includes that
reg_val: Read or writtenvalby registerreg.addr_size_val: Read or writtenvalof sizesizeby memory addressaddr.
For example, push rbp is logged as follows.
{rsp_7fffffffd790,7fffffffd790_8_7fffe2dab298}<={rbp_7fffe2dab298,rsp_7fffffffd798}
$ pin -t pintr.so -Td -Si -Sr -Sb -- ls
(snip)
|ls|.text|55555555a7d4|xor ebp, ebp|{ebp_0}<={ebp_0,ebp_0}
|ls|.text|55555555a7d6|mov r9, rdx|{r9_7ffff7fe0d50}<={rdx_7ffff7fe0d50}
|ls|.text|55555555a7d9|pop rsi|{rsi_1,rsp_7fffffffdc98}<={rsp_7fffffffdc90,7fffffffdc90_8_1}
|ls|.text|55555555a7da|mov rdx, rsp|{rdx_7fffffffdc98}<={rsp_7fffffffdc98}
|ls|.text|55555555a7dd|and rsp, 0xfffffffffffffff0|{rsp_7fffffffdc90}<={rsp_7fffffffdc98}
|ls|.text|55555555a7e1|push rax|{rsp_7fffffffdc88,7fffffffdc88_8_1c}<={rax_1c,rsp_7fffffffdc90}
|ls|.text|55555555a7e2|push rsp|{rsp_7fffffffdc80,7fffffffdc80_8_7fffffffdc88}<={rsp_7fffffffdc88,rsp_7fffffffdc88}
(snip)
Tracing starts from the initial loader program and outputs long unnecessary logs before the main program starts. There are some techniques to filter uninteresting parts using options.
Using -Fe enables to filter initial logs until the entry point.
$ pin -t pintr.so -Fe -- ls
Similarly, you can use -Fm. This is used for filtering initial logs until reaching the main image.
$ pin -t pintr.so -Fm -- ls
Using -Fi enables to exclude logs of the specified image. This is usually used with -Td option.
$ pin -t pintr.so -Td -Fi libc.so.6 -Ti ld-linux-x86-64.so.2 -- ls
-Ki enables to skip hooking all instructions of the specified image. This is similar but the difference from Fi is if hook or not. Filtering is slower than skipping.
$ pin -t pintr.so -Td -Ki libc.so.6 -Ki ld-linux-x86-64.so.2 -- ls
Using -Ti enables to specify the image to trace.
$ pin -t pintr.so -Td -Ti ls -- ls
MIT License
- Copyright 2022, Hiroki Hada
- All rights reserved.