如何在二进制执行跟踪中记录所有内存访问(读取和写入),包括内存内容?

逆向工程 艾达 调试 奇木 追踪
2021-06-29 23:26:54

我想创建一个二进制文件的执行跟踪。准确地说,我想记录每条执行的汇编指令,以及可能的内存访问。我所说的内存访问是指从内存中读取或写入内存。对于这些访问,我想记录其中指令从读取(相应地,写入)和什么样的价值它读取(分别是什么值写入)。

如果可能,我更喜欢适用于 Windows 和 Linux 以及不同类型 CPU 的解决方案。

性能暂时无关紧要,即调试器脚本就可以了。

我尝试了几件事,但没有得到我想要的:

  • IDA:我找不到通过内容获取内存访问的直接方法(有一些晦涩的功能,例如idc.GetTevRegMem参见此处),但要实现我的目标,事情变得非常复杂。
  • Valgrind:valgrind --tool=lackey --trace-mem=yes给了我访问权限,但没有给我内容,请看这里的仆从
  • GDB:使用观察点不是一种选择,因为它们的数量受到限制

目前,PANDA似乎是最有希望的选择(请参阅此处 PANDA 作者的评论)。然而,我不了解 PANDA,因此无法确定创建一个合适的 PANDA 插件会有多复杂。

由于我的目标对我来说似乎不是很奇特,我认为一定已经存在某些东西或者必须有一种简单的方法。例如,调试器脚本代码的某些行、PIN 工具(但仅限于 Intel)或 qemu 参数等。可以?

1个回答

我知道这个问题是前一段时间被问到的,但这里有适用于 Windows 的解决方案。

注意: 请参阅本答案的最后一部分以获取适用于其他系统和架构的解决方案。

x86 32 位文件

OllyDbg2是可用于记录每条汇编指令以及内存读取和写入的工具。下面提供了如何记录它的简短指南:

  1. 运行 OllyDbg。
  2. 选择Options-> Options...(或使用Alt+o快捷方式)。将显示选项窗口。
  3. 搜索Run trace部分并选择下图中指定的选项: olly_options_run_trace

当然,如果您不希望 Olly 记录系统 DLL 中的所有字符串指令或代码,您可以只选择两个相关的框。此外,如果要将日志转储到文件,您可以选择较小的跟踪缓冲区大小。

  1. 现在,打开您的目标应用程序,但先不要启动它。
  2. 选择View-> Run trace
  3. 右键单击出现的窗口,然后选择要在跟踪中使用的内存和寄存器选项。Olly_run_trace_options
  4. 再次右键单击该窗口并选择Log to file...选项并选择要写入整个运行跟踪的文件。
  5. Ctrl+F11开始跟踪。
  6. 当您希望它停止时,单击暂停按钮(或F12)以暂停执行。
  7. 您将看到登录Run trace窗口的说明
  8. 右键单击Run trace窗口并选择Stop logging选项。这将关闭并保存跟踪文件。

而已!您现在可以打开并分析该文件(不过它可能会很大)。

下面给出了这样一个文件的一小段摘录(它只显示修改过的寄存器,不进入系统 DLL):

main  <ModuleEntryPoint>          JMP SHORT 00401012
main  00401012                    MOV EAX,[DWORD DS:4F61EF]               [004F61EF]=0                EAX=00000000
main  00401017                    SHL EAX,2
main  0040101A                    MOV [DWORD DS:4F61F3],EAX               [004F61F3]=0
main  0040101F                    PUSH EDX                                [0019FF80]=0                ESP=0019FF80
main  00401020                    PUSH 0                                  [0019FF7C]=0                ESP=0019FF7C
main  00401022                    CALL <JMP.&KERNEL32.GetModuleHandleA>                               EAX=00400000, ECX=DC5CD787, ESP=0019FF80
main  00401027                    MOV EDX,EAX                                                         EDX=00400000
main  00401029                    CALL 004E7210                                                       ESP=0019FF7C
main  004E7210                    MOV EAX,EDX
main  004E7212                    CMP [BYTE DS:4F61E0],0                  [004F61E0]=00
main  004E7219                    JNE SHORT 004E7240
main  004E721B                    CMP [BYTE DS:4F61E1],0                  [004F61E1]=00
main  004E7222                    JE SHORT 004E7238
main  004E7238                    MOV ECX,[DWORD DS:57D7D4]               [0057D7D4]=ollydbg.0061B108 ECX=0061B108
main  004E723E                    MOV [DWORD DS:ECX],EAX                  [0061B108]=0
main  004E7240                    MOV EAX,[DWORD DS:57D7D8]               [0057D7D8]=ollydbg.0061B131 EAX=0061B131
main  004E7245                    MOV [BYTE DS:EAX],1                     [0061B131]=00

DOS 可执行文件

当您分析 DOS 可执行文件时,DOSBox Debugger将记录您想要的所有内容。

  1. 例如这里下载
  2. 通过将可执行文件拖放到 DOSBox 调试器图标上来启动应用程序。
  3. 在您想要开始记录执行跟踪的那一刻Alt+ Pause- 应用程序将冻结。
  4. 切换到调试器窗口。你会看到这样的事情: DOSBox调试器
  5. 类型logl n,其中n是要记录的(十六进制)指令数;例如:logl ffff
  6. 日志文件已经创建,应该与 DOSBox 调试器位于同一目录中 - 它会有LOGCPU.txt名字。

下面给出了几行结果文件:

01A2:00004654  mov  ax,si                                              8B C6                 EAX:0000002A EBX:0000002A ECX:00000A00 EDX:00000000 ESI:00000004 EDI:00000004 EBP:0000FFE2 ESP:0000FFDE DS:26EF ES:A000 FS:0000 GS:0000 SS:26EF CF:1 ZF:0 SF:1 OF:0 AF:1 PF:1 IF:1 TF:0 VM:0 FLG:00007293 CR0:00000000
01A2:00004656  mov  dx,000E                                            BA 0E 00              EAX:00000004 EBX:0000002A ECX:00000A00 EDX:00000000 ESI:00000004 EDI:00000004 EBP:0000FFE2 ESP:0000FFDE DS:26EF ES:A000 FS:0000 GS:0000 SS:26EF CF:1 ZF:0 SF:1 OF:0 AF:1 PF:1 IF:1 TF:0 VM:0 FLG:00007293 CR0:00000000
01A2:00004659  imul dx                                                 F7 EA                 EAX:00000004 EBX:0000002A ECX:00000A00 EDX:0000000E ESI:00000004 EDI:00000004 EBP:0000FFE2 ESP:0000FFDE DS:26EF ES:A000 FS:0000 GS:0000 SS:26EF CF:1 ZF:0 SF:1 OF:0 AF:1 PF:1 IF:1 TF:0 VM:0 FLG:00007293 CR0:00000000
01A2:0000465B  mov  bx,ax                                              8B D8                 EAX:00000038 EBX:0000002A ECX:00000A00 EDX:00000000 ESI:00000004 EDI:00000004 EBP:0000FFE2 ESP:0000FFDE DS:26EF ES:A000 FS:0000 GS:0000 SS:26EF CF:0 ZF:0 SF:1 OF:0 AF:1 PF:1 IF:1 TF:0 VM:0 FLG:00007296 CR0:00000000
01A2:0000465D  cmp  word [bx+56F6],0001        ds:[572E]=0000          83 BF F6 56 01        EAX:00000038 EBX:00000038 ECX:00000A00 EDX:00000000 ESI:00000004 EDI:00000004 EBP:0000FFE2 ESP:0000FFDE DS:26EF ES:A000 FS:0000 GS:0000 SS:26EF CF:0 ZF:0 SF:1 OF:0 AF:1 PF:1 IF:1 TF:0 VM:0 FLG:00007296 CR0:00000000
01A2:00004662  jne  00004678 ($+14)            (down)                  75 14                 EAX:00000038 EBX:00000038 ECX:00000A00 EDX:00000000 ESI:00000004 EDI:00000004 EBP:0000FFE2 ESP:0000FFDE DS:26EF ES:A000 FS:0000 GS:0000 SS:26EF CF:1 ZF:0 SF:1 OF:0 AF:1 PF:1 IF:1 TF:0 VM:0 FLG:00007296 CR0:00000000
01A2:00004678  inc  si                                                 46                    EAX:00000038 EBX:00000038 ECX:00000A00 EDX:00000000 ESI:00000004 EDI:00000004 EBP:0000FFE2 ESP:0000FFDE DS:26EF ES:A000 FS:0000 GS:0000 SS:26EF CF:1 ZF:0 SF:1 OF:0 AF:1 PF:1 IF:1 TF:0 VM:0 FLG:00007296 CR0:00000000

每个或几乎每个架构和系统

radare2是可用于您的目的的工具,无论系统和架构如何(此处提供了它们的完整列表)。

  1. 运行r2 -c aei -d programToDebug
  2. 在要开始跟踪的地址处放置一个断点(db address_in_hex例如使用)。
  3. 运行dc以继续,直到遇到断点。
  4. 键入e dbg.trace=1并按回车键。
  5. 运行des N到步骤N说明(例如des 10)。
  6. 使用dtd > log1打印追溯到说明log1文件。
  7. 使用dte > log2打印所有存储器和寄存器访问log2文件。这些文件的示例内容如下:

说明: r2Trace 指令 以及一些相应的内存访问: r2TraceMemory

当然,以 OllyDbg 那样的方式列出这些输出会更好,但它只需要编写一个脚本将这两个文件链接在一起并以更方便的方式显示信息。像这样,例如: r2PrettyLog

此处提供用于从这些文件创建此类输出的 Python 脚本用法:

./prettyTraceLog.py file1 file2

, 其中log1log2是默认值。如果您发现任何错误,或者由于其他原因想要修改它,请随时进行。

感谢@pancake 告诉我如何在radare2.