banner
lca

lca

真正的不自由,是在自己的心中设下牢笼。

《从零开始学IDA逆向》学习笔记-10(IDA调试器)

image

选择 IDA 调试器#

ida 支持多个调试器。

image

ida 支持的调试器

选择 Local Windows debugger 调试器

打开菜单栏调试器 - 调试器选项,可以设置一些调试器的功能。

image

ida 调试器选项

调试器界面功能#

勾选进程入口点暂停,并选择事件条件,点击确定。

image

对之前的关键代码 jinx 重命名及改色

image

修改后如下,按 X 键查看哪里引用了这个函数:

image

对引用点进行着色。

image

在 0x00401243 处设置断点,鼠标放到这一行,右键 - 添加断点,添加断点后变成红色背景。

image

通过菜单栏调试器-启动进程(F9),开启调试。如果在本地调试可执行程序会弹出如下警告窗口。

image

注:

在加载器分析程序的时候,程序不会在本地执行,但是调试则不是。如果程序是一个病毒或者共他危险的恶意软件时,需要特别的当心。这时候需要使用远程调试器 (REMOTE DEBUGGER)在虛拟机种执行程序。

点击继续调试。

由于设置了让调试器在入口处暂停,如下图,ida 暂停在入口处(0x00401000)。

image

调整右上角的通用寄存器和标志寄存器窗口,以便查看。

image

上图中,可以看到这些寄存器的值。调整正常之后,打开菜单栏窗口-保存桌面并勾选default选项,保存为调试器默认的窗口设置。那么之后,运行调试器的时候,程序按照默认设置运行,如需修改也可以。

在通用寄存器下方可放置堆栈视图。

image

左侧和最下方是反汇编及 16 进制窗口。

image

在反汇编视图下方是当前的内存地址以及文件偏移(FILE OFFSET),这个偏移是指可执行文件偏移。

image

在 ida 中,默认 G 键是转向一个内存地址的快捷键,按 G 输入 0x401389,转向之前设置的断点。

image

所有静态分析、重命名等改变的内容都会保存。

image

打开菜单栏视图 - 打开子视图 - 段,发现加载器加载了 3 个区段。

image

加载了 0x401000 上的 code 字段,以及下方的 data 和.idata 字段,对这些区段的修改都会保存,除此之外的修改都不会保存,因为他们是调试器加载的区段,不会保存到 IDA 数据库中。

上图中的 L 标志,表示这个程序被加载器和调试器同时加载,既能实施静态分析,同时在动态调试时也不会丢失静态分析的信息。

下面介绍了一些小工具栏。

1、菜单栏 view(视图)-toolbars(工具类)-jump(跳转),再通过保存桌面功能将它设置为默认启用。

image

按返回键可以返回之前的程序入口处。

image

在菜单栏 debugger(调试器)-breakpoints(断点)-breakpoint list(断点列表)中,能够查看所有的程序断点。

image

点击任意一处就可以跳转到对应的断点处。

条件跳转指令与标志寄存器#

目前调试器执行到了程序入口,并且设置了两个断点,按 F9 继续运行。

image

此时运行了 crackme.exe 程序,打开目标程序 Help-register 菜单栏输入用户名和密码。

image

点击 ok

image

上图中,左边闪烁的红色箭头表示程序继续执行的路径,此时 eax 的值是 0x6c。

image

0x6c 转换为字符串就是 l。

image

image

上图中,al 寄存器与 0x41 进行比较,判断是否小于 0x41(A),下方的绿色代码块中 al 寄存器也和 0x5a 进行了比较。

asmconditionoperation
JAz=0 and c=0jump if above(如果大于则跳转)
JAEc=0jump if above or equal(如果大于或等于则跳转)
JBc=1jump if below (如果低于则跳转)
JBEz=1 or c=1jump if below or equal(如果小于等于则跳转)
JCc=1jump if carry(如果进位则跳转)
JECXZecx=0jump if ecx is 0 (如果 ecx 为 0,则跳转)
JEz=1jump if equal(如果相等就跳转)
JZz=1jump if zero (如果为零则跳转)
JNEz=0jump if not equal (如果不相等就跳转)
JNZz=0jump if not zero (如果非零则跳转)
JO超出范围jump if overflow
JP有偶数个 1 位(操作结果中二进制中 1 的个数,01110000)jump if parity
JPE偶数校验jump if parity even
JNP没有偶数个 1 位jump if not parity
JPO奇数校验jump if parity odd
JS符号位为 1jump if sign(如果有标志则跳转)
JNS符号位为 0jump if not sign(如果没有标志则跳转)
JL/JNGE符号位与溢出位相同jump if less or not greater/equal
JLE/JNGz=1 or 符号位与溢出位相同jump if less or equal/not greater
JG/JNLEz=0 and 符号位与溢出位相同jump is greater/not less or equal

条件跳转指令及跳转条件

下面转到 ida 标志寄存器视图,如下图所示。

image

根据表格可知,如果 CF=0,就不跳转,程序往绿色代码块执行,那么触发这个 C 标志的数学条件是什么呢?

C 标志代表无符号整数运算有错误这一信息,如果把 cmp 指令看作是不保存结果的减法算法,那么0x6c - 0x41 = 0x2b,结果是正数,如果 al 是 0x30,那么0x30 - 0x41 = -0x11

image

-0x11 是一个负数,程序只能继续使用它对应的 16 进制运行。

image

如上图所示,-0x11 的 16 进制是 0xffffffef,10 进制是 4294967279,这个值很大,而且0x30-0x41也不会是正数。

那么如何知道操作中有没有考虑正负号呢。这取决于使用的跳转类型,JB 是用于无符号数比较后的跳转指令,对应的有符号数的指令是 JL。

当使用 JB 指令时,通常是用它来检测无符号整数是否小于某个值。如果运算结果产生了借位,就表示第二个操作数(被比较数)比第一个操作数(比较数)大,此时 JB 标志位为 1,就可以进行跳转。否则,如果运算结果没有产生借位,则 JB 标志位为 0,即不满足条件,就不进行跳转。

示例:

mov al, 150    ;把150赋值给 al 
cmp al, 255    ;比较 al 255
jb  smaller    ;如果 al小于255,就跳转到smaller标签处
   ;执行其他操作
   smaller:
   ;如果 al小于等于255,就会跳转到这里

在这个示例中,如果 al 中的值小于 255,则 CF 标志位为 1,就会跳转到 smaller 标签处。否则,如果 al 中的值大于 255,则 CF 标志位为 0,不跳转,执行其他操作。(总而言之,如果al比255小,则跳转)

对于比较是否带符号需要通过它后面的条件跳转指令来确定。

无符号跳转

符号描述标志位
JE/JZJumps if equal or zerozf
JNE/JNZJumps if not equal or zerozf
JA/JNBEJumps if above or not below or equalzf,cf
JB/JNAEJumps if below or not above or equalcf
JBE/JNAJumps if below or equal or not abovecf,af

无符号跳转

上图中的指令都不考虑正负号,每一种跳转都有对应的有符号跳转。

符号描述标志位
JE/JZJumps if equal or zerozf
JNE/JNZJumps if not equal or zerozf
JG/JNLEJumps if greater or not less or equalzf,sf,of
JGE/JNLJumps if greater or not equal or lesssf,of
JL/JNGEJumps if less or not grater or equalsf,of
JLE/JNGJumps if less or equal or not greaterzf,sf,of

有符号跳转

上面两个图中,JE(是否相等)出现在两个图中,因为在这个特例中,符号并不重要,如果两个数相等,zf=1,意味着标志触发。
有符号跳转中JG = Jumps if greater,在无符号跳转中它对应的指令是JA,Jumps if above

继续调试程序发现,ida 会在每一个设置的断点上暂停,执行了一个循环,每个循环会读取在目标程序输入的用户名的一个字符并和 0x41 进行比较,如果任何一个字符小于 0x41,就会报错,由于输入的是 lca,每个值都比 0x41 大,所以不显示报错。

尝试输入数字看看。

image

此时,就跳转到红色区块,也就是 jb 跳转的地方,因为第一个比较的字符是 2(0x32),2 肯定比 0x41 小。

image

image

同时触发了 C 标志位,CF=1,因为 0x32 - 0x41 无符号数相减,结果是负数,这将触发 C 标志位。

image

在 C 标志位右键单击,选择 Zero Value 将 C 标志清 0。

image

image

按 F9 继续进程,程序读取 22lca 的第二个字符,左侧红色箭头又开始闪烁。继续将 CF 标志位设为 0,之后的字符 lca 都会大于 0x41,不会触发标志位,程序都走左侧红色箭头。

字符检测完成后,程序来到最后一个跳转。

image

上图的 cmp 指令比较 eax 和 ebx,jz 判断比较是否相等,无符号,程序走向红色区块,因为这两个寄存器不相等。

image

由于不相等,所以 zf 标志未被触发。

image

如果手动触发 zf 标志,改变跳转方向,程序会转向绿色区块,显示注册成功。

image

image

SET IP#

set ip 只有在调试器模式下才有。

有时候也可以不直接修改跳转,可以将鼠标移动至想要执行的那个代码块上,右键单击,选择 SET EIP。

在 0x40124c 处,set eip,程序会从 0x40124c 处开始运行。

image

注:在 7.7 中这样操作,执行多次后报错如下:

image

提示 “尝试执行非法指令”

image

image

报错信息提示内存不可写,也许读取内容超出了范围。

总结#

通过使用 IDA 调试器,可以进行动态调试和静态分析,深入了解程序的结构和运行过程,但这章未对源程序进行修改,只是在调试器中改变了标志寄存器的值。

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.