【Day 15】从零开始的 Debug 生活 - Debugger 原理

环境

  • Windows 10 21H1
  • x64dbg Aug 2 2020, 13:56:14
  • IDA 7.5

前情提要

【Day 05】你逆 - 逆向工程工具介绍有提过逆向工程所需要的工具,其中包含我常用的 Debugger x64dbg。我们也逆过小算盘,认识基本的 Debugger 使用方法,这篇文章也会拿小算盘下手认识 Debugger。

这篇会介绍 Debugger 究竟是怎麽运作的,为什麽可以停在某个断点,让使用者可以慢慢的观察程序的运行流程。由於不同的 Debugger 在处理同个事件上可能会有不同的实作方式,这篇文会以 x64dbg 为例讲解 Debugger 的行为。

下面介绍与实际测试的部分都是在 64-bit 的环境,但是 32-bit 其实大同小异。

Debugger 机制

Debug Flag

介绍

这是 PEB 结构中的一个成员 BeingDebugged,顾名思义它就是用来判断目前这个 Process 是否正在被 Deubg。开发者在程序中可以利用这个 Flag 判断是否被 Debug,而做出不同的行为。

Windows API 有相对应的 IsDebuggerPresentCheckRemoteDebuggerPresent 函数检查这个 Flag 的值,回传为 TRUE 代表程序正在被 Debug。

实际测试

用 x64dbg 可以看到 PEB 的第三个 Byte 是 1,也就是正在 Debug。

Software Breakpoint

介绍

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

介绍

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

介绍

Hardware Breakpoint(硬体断点) 是透过 Debug Register DR0~DR7 来实作的。其中 DR0~DR3 四个暂存器存放下硬体断点的位址;DR4、DR5 保留;DR6 存放 Debug Status,用来判断是踩到哪个断点;DR7 是 Debug Control,用来设定断点,其中包含要在对 DR0~DR3 做什麽操作才会触发断点,例如读、写、执行。

实际测试

使用方法很简单,就在目标位址按右键 => Breakpoint => Hardware,设定断点。接着就可以在右边视窗中看到 Debug Register 的改变。

参考资料


<<:  Day 30 | ContentProvider

>>:  【Day 15】浅谈 Django model

[13th-铁人赛]Day 6:Modern CSS 超详细新手攻略 - Selector (二)

介绍完基础选择器,再来介绍一下复合选择器~ a b 选择a元素里的子元素 ab ab为同一元素但不同...

[第二十二只羊] 迷雾森林舞会XVI 策略模式 Strategy Pattern

天亮了 昨晚是平安夜 关於迷雾森林故事 甜水镇 洛神:10号玩家请继续发言 10号: 我跟5号的想法...

[C#] LeetCode 3. Longest Substring Without Repeating Characters

Given a string s, find the length of the longest s...

用React刻自己的投资Dashboard Day16 - react-router-dom让SPA也有路由

tags: 2021铁人赛 React 前一篇提到的导览列的各个按钮,点击之後会跳到不同的页面,每个...

【领域展开 03 式】 架站工具平台选择依据

厘清目标,选择合适的工具,事半功倍 当前两天决定使用从零建置个人网站 30 天领域展开最为题目的时候...