在 【Day 05】你逆 - 逆向工程工具介绍有提过逆向工程所需要的工具,其中包含我常用的 Debugger x64dbg。我们也逆过小算盘,认识基本的 Debugger 使用方法,这篇文章也会拿小算盘下手认识 Debugger。
这篇会介绍 Debugger 究竟是怎麽运作的,为什麽可以停在某个断点,让使用者可以慢慢的观察程序的运行流程。由於不同的 Debugger 在处理同个事件上可能会有不同的实作方式,这篇文会以 x64dbg 为例讲解 Debugger 的行为。
下面介绍与实际测试的部分都是在 64-bit 的环境,但是 32-bit 其实大同小异。
这是 PEB 结构中的一个成员 BeingDebugged
,顾名思义它就是用来判断目前这个 Process 是否正在被 Deubg。开发者在程序中可以利用这个 Flag 判断是否被 Debug,而做出不同的行为。
Windows API 有相对应的 IsDebuggerPresent 和 CheckRemoteDebuggerPresent 函数检查这个 Flag 的值,回传为 TRUE 代表程序正在被 Debug。
用 x64dbg 可以看到 PEB 的第三个 Byte 是 1,也就是正在 Debug。
Software Breakpoint(软件断点)有三种实作方式,分别是 INT3、Long INT3、UD2,在 x64dbg 可以点选 Options => Preferences => Engine => Default Breakpoint Type 设定。
x64dbg 预设是使用 int3
,Opcode 为 cc
,执行後触发 EXCEPTION_BREAKPOINT,然後 Debugger 再去处理这个 Exception,达到断点的效果。
Debugger 会把下断点的位址的指令改成 int3
,所以当程序执行到这个位址时,就会触发上面所提到的 EXCEPTION_BREAKPOINT。执行完 int3
後,因为 Instruction Pointer(RIP/EIP)指向的位址是 int3
的下一个 Byte,所以 Debugger 在处理 Exception 时会把 Instruction Pointer 减 1,并且把原本要执行的指令填回去。
用 IDA 打开 calc.exe,可以看到最後有执行 ShellExecuteW。
这边我们针对 ShellExecuteW 下断点。因为 Debugger 不会把它做的改变显示在 Debugger,方便使用者使用,所以我使用了另一个工具观察。下图左边是 x64dbg 在 ShellExecuteW 函数的位址,并且下了断点;右边是开源的工具 HookHunter。
HookHunter 会自动比对档案与记忆体,看函数有没有被改动。下图可以发现,下了断点後,原本执行的是 push rbp
,机械码是 40 55
。但是因为下断点的关系,其中的 40
被改成 cc
。而原本的值 40
会被 Debugger 存起来等等用来复原。
在抵达断点後可以注意到 HookHunter 已经没有侦测到档案和记忆体的不同,因为这时 Debugger 已经把原本被改掉的机械码 40
填回去了。
之後在执行断点位址的下一个指令後,断点的位址又被设回去 int3
,机械码为 cc
。
Trap Flag(陷阱标志)是 CPU 中的其中一个 Flag,当 Flag 为 1(set) 时会触发 EXCEPTION_SINGLE_STEP,其他还有 OF(Overflow Flag)、DF(Direction Flag)、IF(Interrupt Flag)、SF(Sign Flag)、ZF(Zero Flag)、AF(Auxiliary Flag)、PF(Parity Flag)、CF(Carry Flag)。
这边只说明 Trap Flag 的运作原理。在上面介绍 Software Breakpoint 时,最後一个步骤有说明断点的位址会在执行完後再填回 int3
,让断点继续发挥作用。因此这边需要有个机制让 int3
再被填回去,Debugger 就是利用 Trap Flag。
由於 Trap Flag 为 1(set) 时会触发 EXCEPTION_SINGLE_STEP,Debugger 就可以透过处理这个 Exception 来达到把 int3
填回原本程序的效果。在触发 Exception 之後,Trap Flag 则会被 CPU 设为 0(unset)。
一样在 ShellExecuteW 下断点并停在这个位址後,可以观察到右边视窗有个 TF,代表着 Trap Flag,目前的值为 1(set)。
这时会触发 EXCEPTION_SINGLE_STEP,而 TF 会被重设为 0(reset)。
Hardware Breakpoint(硬体断点) 是透过 Debug Register DR0~DR7 来实作的。其中 DR0~DR3 四个暂存器存放下硬体断点的位址;DR4、DR5 保留;DR6 存放 Debug Status,用来判断是踩到哪个断点;DR7 是 Debug Control,用来设定断点,其中包含要在对 DR0~DR3 做什麽操作才会触发断点,例如读、写、执行。
使用方法很简单,就在目标位址按右键 => Breakpoint => Hardware,设定断点。接着就可以在右边视窗中看到 Debug Register 的改变。
介绍完基础选择器,再来介绍一下复合选择器~ a b 选择a元素里的子元素 ab ab为同一元素但不同...
天亮了 昨晚是平安夜 关於迷雾森林故事 甜水镇 洛神:10号玩家请继续发言 10号: 我跟5号的想法...
Given a string s, find the length of the longest s...
tags: 2021铁人赛 React 前一篇提到的导览列的各个按钮,点击之後会跳到不同的页面,每个...
厘清目标,选择合适的工具,事半功倍 当前两天决定使用从零建置个人网站 30 天领域展开最为题目的时候...