吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 3483|回复: 3
收起左侧

[调试逆向] hutrace工具系列第4篇之衍生工具hzytrace

[复制链接]
QS+HUD 发表于 2022-6-7 18:44

图片1.png

    hutrace的功能已经实现的比较全面了,dynamroio与pin虽然在对程序的分析处理上各有一定的优势,但是实际中测试下来dynamorio在Linux下的兼容性要比pin稍微差一点,存在一些无法用hutrace记录但pin可以追踪的情况,而且pin提供的接口功能也更丰富,故基于pin完成了大部分hutrace的功能,也即是下面要介绍的hzytrace工具。hzytrace目前仅支持linux平台,windows平台上基于dynamrio的hutrace在效率、兼容性上均优于pin,暂时就还没完善window下的hzytrace。

1. 简介

hzytrace本身基于pin+codapintracer开发,原codapintracer仅支持Windows平台的API记录(类似drltrace),代码基于Window做了特别多的处理(所以hzytrace移植到win上比较简单...),功能也很多,导致移植到linux多了很多坑,而且在linux下pin的对程序的处理接口也存在一些问题,最终魔改完的代码快没法看了。。不过整体来说hzytrace的功能性还可以,可作为hutrace在处理一些Linux程序上的补充,本篇先介绍下hzytrace的基本功能,最后将结合一些实例进行演示。

2. 基本功能

hzytrace支持的基本功能参数如下:

-bbllog     [default true]      打印所有执行基本块的汇编指令
-forklog    [default true]      默认追踪fork的子进程
-syscall    [default true]      默认追踪进程的syscall调用
-inslog     [default false]     打印所有执行指令的运行状态信息
-logstart   [default false]     指定记录的指令开始地址
-logend     [default false]     指定记录的指令结束地址
-target     [default -]         指定需要记录的模块名
-allimage   [default false]     记录所有模块的运行

默认情况下,hzytrace会记录程序的API调用、Syscall调用以及所有的基本块转移记录,下面结合一些实例的记录信息进行介绍。

2.1 基本块汇编指令打印

在hzytrace目录中执行下述指令:

# huhu @ huhu in ~/Desktop/pin-3.5 [3:12:07] 
$ ./pin -t hzytrace.so -bbllog  -- ls -al 
[INFO] Configuring Pintool
[INFO] Starting instrumented program

Load Image:/bin/ls Base:400000-41da63
setMainIMGAddress:400000 41da63
Load Image:/lib64/ld-linux-x86-64.so.2 Base:7f8438bd4000-7f8438bf93af
Load Image:[vdso] Base:7ffdde88b000-7ffdde88c02a
[INFO] Opening file
./Results/2022_05_21_03_07_08//TRACER/hzytrace.ls.11596.0.1653120428.out
Load Image:/lib/x86_64-linux-gnu/libselinux.so.1 Base:7f84252b9000-7f84254da6df
Load Image:/lib/x86_64-linux-gnu/libc.so.6 Base:7f8424ec2000-7f842528b99f
Load Image:/lib/x86_64-linux-gnu/libpcre.so.3 Base:7f8424c4b000-7f8424eba107
Load Image:/lib/x86_64-linux-gnu/libdl.so.2 Base:7f8424a2f000-7f8424c320ef
Load Image:/lib/x86_64-linux-gnu/libpthread.so.0 Base:7f8424811000-7f8424a2d427
Load Image:/lib/x86_64-linux-gnu/libnss_compat.so.2 Base:7f8423474000-7f842367c45f
Load Image:/lib/x86_64-linux-gnu/libnsl.so.1 Base:7f8423256000-7f842346ea57
Load Image:/lib/x86_64-linux-gnu/libnss_nis.so.2 Base:7f8422f82000-7f842318d587
Load Image:/lib/x86_64-linux-gnu/libnss_files.so.2 Base:7f8422d6b000-7f8422f7c717

//以上为hzytrace打印的调试信息

total 6228
drwxr-x---  4 huhu huhu    4096 May 21 03:07 .
drwxr-x--- 48 huhu huhu    4096 May 21 02:50 ..
//省略部分ls结果显示

查看Results目录下记录的trace日志内容:

C0x4049c4|0x402640                      

//C0x4049c4对应下面ida中ls程序反汇编结果
//.text:00000000004049AF mov     r8, offset fini ; fini
//.text:00000000004049B6 mov     rcx, offset init ; init
//.text:00000000004049BD mov     rdi, offset main ; main
//.text:00000000004049C4 call    ___libc_start_main

B0x402640|0x402640
        D0x402640|jmp qword ptr [rip+0x21bb7a]
B0x402646|0x40264b
        D0x402646|push 0x35
        D0x40264b|jmp 0x4022e0
B0x4022e0|0x4022e6
        D0x4022e0|push qword ptr [rip+0x21bd22]
        D0x4022e6|jmp qword ptr [rip+0x21bd24]
J0x4022e6|0x7f15489d0f10

//hzytrace_linux.config未配置的函数默认打印四个参数
~~16451~~ libc.so.6!__libc_start_main N:0x1
        arg 0: 0x402a00
        arg 1: 0x2
        arg 2: 0x7ffda586d668
        arg 3: 0x413bb0

//ls的init
B0x413bb0|0x413bdc                  
        D0x413bb0|push r15
        D0x413bb2|push r14
        D0x413bb4|mov r15d, edi
        D0x413bb7|push r13
        D0x413bb9|push r12
        D0x413bbb|lea r12, ptr [rip+0x20a23e]
        D0x413bc2|push rbp
        D0x413bc3|lea rbp, ptr [rip+0x20a23e]
        D0x413bca|push rbx
        D0x413bcb|mov r14, rsi
        D0x413bce|mov r13, rdx
        D0x413bd1|sub rbp, r12
        D0x413bd4|sub rsp, 0x8
        D0x413bd8|sar rbp, 0x3
        D0x413bdc|call 0x4022b8
C0x413bdc|0x4022b8
......

//hzytrace_linux.config配置的函数根据设置的参数类型的打印参数信息
~~16451~~ libc.so.6!__lxstat N:0x25b
        arg 0: 0x1
        arg 1: 0x7ffda586ce00
        arg 2: 0x246d3e0
        arg 3: 0x2
~~16451~~ libc.so.6!__lxstat64 N:0x25c
         arg 0: 0x1 (type=int, size=0x4)
         arg 1: pintool.log (type=char*, size=0x0)
         arg 2:  (type=char*, size=0x0)
S|lstat:6
   executed libc.so.6!__lxstat returnIp:0x4080c9 =>
        retval: 0x0
   executed libc.so.6!__lxstat64 returnIp:0x4080c9 =>
         retval: 0x0 (type=int, size=0x4)
......

显示功能基本与hutrace保持一致,同时支持hex以及struct打印,除后面介绍的hook、dump功能上(不支持hutrace的简易patch、hide功能),hzytrace_linux.config与hutrace.config在API参数打印上的设置基本一致。

如果不需要打印基本块对应的汇编指令,可以设置bbllog参数的值为false:

$ ./pin -t hzytrace.so -bbllog  0 -- ls -al 

trace结果:

C0x4049c4|0x402640
J0x4022e6|0x7f93f9a77f10
~~16821~~ libc.so.6!__libc_start_main N:0x1
        arg 0: 0x402a00
        arg 1: 0x2
        arg 2: 0x7ffda07a5b88
        arg 3: 0x413bb0
C0x413bdc|0x4022b8
R0x4022d1|0x413be1
C0x413bf9|0x404a70
R0x404a49|0x413bfd
R0x413c14|0x7f93e5d6e7cf

注意开启bbllog的trace日志中会打印出所有ls主程序中执行的代码,而在上述不开启bbllog的trace日志结果中,并不会记录到跳转到main函数0x402A00地址的信息,因为并非是从ls主程序中执行的指令跳转进入的main函数。

  • 一个小bug:在ls等程序运行加载libc.so.6进行初始化时,pin无法获取到初始化代码的模块名称,而hzytrace记录时会默认记录不在任意模块内的代码,导致trace日志开头会存在一小部分libc.so代码的冗余,后面的trace日志中不会再出现该情况。

2.2 syscall记录

功能及使用方式与hutrace类似,默认情况下只打印执行的syscall的名称,在hzytrace_linux.config文件中设置参数信息后才会根据参数类型打印对应的参数:

int|syscall_read|LONG|__out hex^ARG2|int
int|syscall_write|LONG|char *
int|syscall_open|char *|LONG

trace记录样例(运行过程中所有syscall):

$ ./pin -t hzytrace.so -syscall -- ls -al 

分析trace的结果:

S|brk:12
S|access:21
S|access:21
S|open:2
SysEnter|syscall_open|0x7f5ec45d41d1|0x80000|
         arg 0: /etc/ld.so.cache (type=char*, size=0x0)
         arg 1: 0x80000 (type=long, size=0x8)
SysExit|open
S|fstat:5
S|mmap:9
S|close:3
S|access:21
S|open:2
SysEnter|syscall_open|0x7f5ec47dbd60|0x80000|
         arg 0: /lib/x86_64-linux-gnu/libselinux.so.1 (type=char*, size=0x0)
         arg 1: 0x80000 (type=long, size=0x8)
SysExit|open
S|read:0
SysEnter|syscall_read|0x3|0x7ffda586ce38|0x340|
         arg 0: 0x3 (type=long, size=0x8)
         arg 2: 0x340 (type=int, size=0x4)
SysExit|read
         arg 1: 0x7ffda586ce38
000000: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00  .ELF............
000010: 03 00 3e 00 01 00 00 00 b0 5a 00 00 00 00 00 00  ..>......Z......
000020: 40 00 00 00 00 00 00 00 30 f5 01 00 00 00 00 00  @.......0.......
000030: 00 00 00 00 40 00 38 00 08 00 40 00 1e 00 1d 00  ....@.8...@.....
000040: 01 00 00 00 05 00 00 00 00 00 00 00 00 00 00 00  ................
......

如果不需要记录syscall调用,同样设置syscall参数为0即可:

$ ./pin -t hzytrace.so -syscall  0 -- ls -al 

2.3 指令运行状态记录

功能类似hutrace,开启指令状态记录时则不需要再记录bbllog功能中的指令反汇编结果:

$ ./pin -t hzytrace.so -inslog -- ls -al

trace的部分日志结果:

B0x402a00|0x402a2c
        I0x402a00|push r15                                   | M:0x7fffffffd930 | D:0x0 | r15:0x0
        I0x402a02|push r14                                   | M:0x7fffffffd928 | D:0x0 | r14:0x0
        I0x402a04|push r13                                   | M:0x7fffffffd920 | D:0x7fffffffda10 | r13:0x7fffffffda10
        I0x402a06|push r12                                   | M:0x7fffffffd918 | D:0x4049a0 | r12:0x4049a0
        I0x402a08|push rbp                                   | M:0x7fffffffd910 | D:0x413bb0 | rbp:0x413bb0
        I0x402a09|push rbx                                   | M:0x7fffffffd908 | D:0x0 | rbx:0x0
        I0x402a0a|mov ebx, edi                               | rdi:0x2 | rbx:0x0 
        I0x402a0c|mov rbp, rsi                               | rsi:0x7fffffffda18 | rbp:0x413bb0 
        I0x402a0f|sub rsp, 0x388                             | rsp:0x7fffffffd908 
        I0x402a16|mov rdi, qword ptr [rsi]                   | M:0x7fffffffda18 | D:0x7fffffffddeb | rdi:0x2
        I0x402a19|mov rax, qword ptr fs:[0x28]               | M:0x7fffe39a3828 | D:0x8cde58e761386e00 | rax:0x402a00
        I0x402a22|mov qword ptr [rsp+0x378], rax             | M:0x7fffffffd8f8 | D:0x413bfd | rax:0x8cde58e761386e00
        I0x402a2a|xor eax, eax                               | rax:0x8cde58e761386e00 
C0x402a2c|0x40db00
        I0x402a2c|call 0x40db00                              | M:0x7fffffffd578 | D:0x7fffe46f84e8 

2.4 指定trace指令起始、结束地址

指定需要trace的指令范围,需要设置为基本块的开始或结束地址(为了便于展示,可以取消全局的syscall调用打印):

$ ./pin -t hzytrace.so -inslog -logstart 0x402a00 -logend 0x402c7c -syscall 0 -- ls -al

trace的结果信息中只会打印到0x402c7c的前一个基本块信息结束,并不会打印0x402c7c所在基本块的指令信息等。

2.5 指定需要trace的模块

利用target参数指定需要trace的模块:

$ ./pin -t hzytrace.so -inslog -target mytestso.so -syscall 0 -- ./test.out

trace得到的部分结果:

~~25933~~ libdl.so.2!dlsym N:0x7
         arg 0: 0x555555756030 (type=long, size=0x8)
         arg 1: my_main (type=char*, size=0x0)
   executed libdl.so.2!dlsym returnIp:0x5555555548cb =>
         retval: 0x7fffe36f460a (type=int, size=0x4)
//得到mytestso.so!my_main的函数地址

B0x5555555548cb|0x5555555548e2
        I0x5555555548cb|mov qword ptr [rbp-0x10], rax              | M:0x7fffffffd920 | D:0x0 | rax:0x7fffe36f460a
        I0x5555555548cf|mov rax, qword ptr [rbp-0x10]              | M:0x7fffffffd920 | D:0x7fffe36f460a | rax:0x7fffe36f460a
        I0x5555555548d3|mov edx, 0x3                               | rdx:0x1 
        I0x5555555548d8|mov esi, 0x2                               | rsi:0x7fffe471a0d8 
        I0x5555555548dd|mov edi, 0x1                               | rdi:0x7ffff7ffd948 
C0x5555555548e2|0x7fffe36f460a
        I0x5555555548e2|call rax                                   | M:0x7fffffffd918 | D:0x5555555548cb | rax:0x7fffe36f460a
~~25933~~ mytestso.so!my_main N:0x8
        arg 0: 0x1
        arg 1: 0x2
        arg 2: 0x3
        arg 3: 0x0
B0x7fffe36f460a|0x7fffe36f4622
        I0x7fffe36f460a|push rbp                                   | M:0x7fffffffd910 | D:0x7fffffffd930 | rbp:0x7fffffffd930
        I0x7fffe36f460b|mov rbp, rsp                               | rsp:0x7fffffffd910 | rbp:0x7fffffffd930 
        I0x7fffe36f460e|sub rsp, 0x10                              | rsp:0x7fffffffd910 
        I0x7fffe36f4612|mov dword ptr [rbp-0x4], edi               | M:0x7fffffffd90c | D:0xffffd93000000000 | rdi:0x1
        I0x7fffe36f4615|mov dword ptr [rbp-0x8], esi               | M:0x7fffffffd908 | D:0x100000000 | rsi:0x2
        I0x7fffe36f4618|mov dword ptr [rbp-0xc], edx               | M:0x7fffffffd904 | D:0x200005555 | rdx:0x3
        I0x7fffe36f461b|lea rdi, ptr [rip+0x1f]                    | rip:0x7fffe36f461b | rdi:0x1 

3. 其它功能

3.1 任意地址hook插件

这里继续使用hutrace的linux应用文章中的例子进行演示,将原本程序中打印函数的参数从1-8修改为11-18,首先在hzytrace_linux.config设置需要hook的地址:

hook|0x400706

在hzytrace中简化了插件的加载和调用方式,只需要设置需要hook的的地址即可,而且不支持hutrace提供的函数开始、结束同时hook,如果有类似需求,可以在返回地址处添加新的返回地址hook条目,hzytrace运行到0x400706地址处时会加载mypinplugin.so并调用导出函数名为f_hookpre_0x400706的导出函数。

int  f_hookpre_0x400706(bluepill_tls *tdata,ADDRINT *r_RDI,ADDRINT *r_RSI,ADDRINT *r_RDX,ADDRINT *r_RCX,ADDRINT *r_R8,ADDRINT *r_R9,ADDRINT *r_RAX,ADDRINT *r_RBX,ADDRINT *r_RBP,ADDRINT *r_RSP,ADDRINT *r_R10,ADDRINT *r_R11,ADDRINT *r_R12,ADDRINT *r_R13,ADDRINT *r_R14,ADDRINT *r_R15)
{
        *r_RDI = 11;
        *r_RSI = 12;
        *r_RDX = 13;
        *r_RCX = 14;
        *r_R8 = 15;
        *r_R9 = 16;
        *(ADDRINT *)(*r_RSP + (7-6) * 8) = 17;
        *(ADDRINT *)(*r_RSP + (8-6) * 8) = 18;
        //写入到trace的log日志中
        (*tdata->file_write)(tdata->threadid, tdata->buffer, tdata->OutFile, "[hook]|test r_RDI:%p\n",*r_RDI);

        return 0;
}

mypinplugin.so编译时可以使用以下编译选项:

//x64
g++ -fPIC -shared -o mypinplugin.so mypinPlugin.cpp  -m64 -D X86_64 -Wl,--hash-style=sysv
//x32
g++ -fPIC -shared -o mypinplugin.so mypinPlugin.cpp  -m32 -D X86_32 -Wl,--hash-style=sysv

同时注意因为pin的限制,插件中无法引用其它系统的libc.so文件,故不建议在hook函数中引用api函数实现较为复杂的功能,如果确有此类需求,可以尝试编译成静态的so文件或者编译一个main函数为空、仅导出功能函数的pin插件加载,使用hutrace则不受此限制。

3.2 内存dump功能

根据hzytrace在运行时输出的调试信息中测试程序soTest加载后的代码范围0x400000-400b43,来演示下hzytrace的内存dump功能,在hzytrace_linux.config设置需要dump的时机以及需要dump的内存地址以及内存大小。

dump|0x400706|0x400000|0xb43

同样设置代码运行到0x400706时dump地址从0x400000开始大小为0xb43字节的内存数据,运行测试程序后,在Result目录中对应的日志记录文件夹中生成内存dump文件。

  • dump功能可以和hook功能指定同一个地址,即可执行到该地址后进行dump操作,又可以在当前地址处使用hook功能加载插件(hutrace则不支持)。

  • dump功能同样可以在不同运行地址状态指定相同地址范围的内存进行提取,dump的文件名结尾会进行累加,可以比对不同状态下内存状态信息改变情况。

4. 实例演示

图片2.png

4.1 hide

来看一个几年前qwb里ling博狗的例子“hide”,用了upx壳并且修改了一些upx标识,无法自动脱壳,程序本身使用了ptrace的PTRACE_TRACEME反调试(使用strace跟踪会退出),而且本身程序使用syscall完成读写、还使用了一处虚假的flag校验函数进行混淆,常规方式可以使用“catch syscall ptrace”逐步定位关键代码处,下面我们尝试使用hzytrace处理类似程序(hutrace虽然可以正常处理upx和PTRACE_TRACEME,但是这个程序无法正常trace,原因没有深入研究)。

# huhu @ huhu in ~/Desktop/pin-3.5 [7:30:39] 
$ ./pin -t hzytrace.so -bbllog -- ./hide
[INFO] Configuring Pintool
[INFO] Starting instrumented program

[INFO] Opening file
./Results/2022_05_26_07_31_43//TRACER/hzytrace.hide.37360.0.1653568303.out
Enter the flag:
1234567890
You are wrong

查看日志直接搜索输入的“1234567890”(trace的日志500m文件使用010edit秒搜):
图片3.png

因为hzytrace仅对运行的代码进行记录,下面把这段内存进行dump拖进ida里查看完整的代码逻辑,在hzytrace_linux.config中设置执行到0x4c8eeb代码处时自动dump地址为0x400000代码处的内存(可设置关闭aslr固定内存地址):

dump|0x4c8eeb|0x400000|0xca000

再次运行在对应的result日志目录生成内存dump文件,拖进ida,查看上述记录的日志中对应代码:
图片4.png

后面分析算法既可以ida静态,也可使用hzytrace的inslog参数追踪代码执行过程的寄存器及内存信息辅助分析算法,亦可使用gdb根据日志中的ptrace调用信息对其反调试进行绕过并继续调试,不再赘述。

4.2 bytepacker

这个程序来自某次分享的ctf赛题,使用双进程方式进行反调试,但是没有使用特别复杂的debugblock方式,所以依旧可以使用hzytrace进行指令流的trace(bbllog功能),但是无法使用inslog功能,全指令插桩会影响其执行流程:

$ ./pin -t hzytrace.so -bbllog -- ./bytepacker
[INFO] Configuring Pintool
[INFO] Starting instrumented program

[INFO] Opening file
./Results/2022_05_29_08_46_16//TRACER/hzytrace.bytepacker.47505.0.1653831976.out
[INFO] Fork New Process
[INFO] Opening file
./Results/2022_05_29_08_46_16//TRACER/hzytrace.bytepacker.47509.0.1653831976.out
Show me the flag:
>> 1234567890
No, not this one.%                                                                          

同样可以在trace的日志中直接搜索到使用syscall方式读取输入的测试flag的代码位置:

B0x7fffe42f6359|0x7fffe42f635e
        D0x7fffe42f6359|mov eax, 0x0
        D0x7fffe42f635e|syscall 
S|read:0
SysEnter|syscall_read|0x0|0x7ffff7fff420|0x400|
         arg 0: <null> (type=long, size=0x8)
         arg 2: 0x400 (type=int, size=0x4)
SysExit|read
         arg 1: 0x7ffff7fff420
000000: 31 32 33 34 35 36 37 38 39 30 30 0a 00 00 00 00  12345678900.....
......//省略部分显示
 (type=__out hex^ARG2*, size=0x400)
B0x7fffe42f6360|0x7fffe42f6366
        D0x7fffe42f6360|cmp rax, 0xfffffffffffff001
        D0x7fffe42f6366|jnb 0x7fffe42f6399
......//省略部分显示
B0x7fffe42f63b0|0x7fffe42f63b7
        D0x7fffe42f63b0|cmp dword ptr [rip+0x2d2389], 0x0
        D0x7fffe42f63b7|jnz 0x7fffe42f63c9
B0x7fffe42f63b9|0x7fffe42f63be
        D0x7fffe42f63b9|mov eax, 0x1
        D0x7fffe42f63be|syscall 
S|write:1
SysEnter|syscall_write|0x1|0x7ffff7fff010|
         arg 0: 0x1 (type=long, size=0x8)
         arg 1: No, not this one.5;74mflag:
 (type=char*, size=0x0)
SysExit|write

在hzytrace_linux.config中设置dump内存(关闭aslr的情况下,查看0x7fffe42f6360代码所在内存范围,确保内存地址固定):

dump|0x7fffe42f6360|0x7fffe41f7000|0x1c0000

后续可以据此静态分析,同样也可以向上述hide一样对照trace日志中父进程对子进程的操作进行针对性的处理,只是不能支持inslog功能打印寄存器及引用的内存状态了,父进程的处理代码地址可简单定位如下:
图片5.png

实际上像一些更复杂的debugblock代码等使用hzytrace处理子进程时也会崩溃,有的情况下可以通过pin提供的接口对其进行绕过,但是代价略大点,同样后续有好的方案了会进行更新。

5. 总结

前面的文章中提到hzytrace一个主要目的是为了应对linux平台下一些程序无法使用hutrace处理的问题,当然不止是上面提到的一些小众的ctf赛题,pin的接口相对更为丰富,hzytrace也只是相对hutrace稍微简化了下,功能整体来说保持一致。

github地址:https://github.com/huhu0706/hzytrace

免费评分

参与人数 2吾爱币 +1 热心值 +1 收起 理由
maimiao + 1 热心回复!
dechong + 1 谢谢@Thanks!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

砂砾酱 发表于 2022-6-8 17:07
支持arm64吗?
 楼主| QS+HUD 发表于 2022-6-8 18:06

您好,目前dynamorio和pin还都不支持arm64,安卓平台可以使用frida+stakler~
jsncy 发表于 2022-8-9 08:42
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-12-22 00:21

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表