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 调试器,可以进行动态调试和静态分析,深入了解程序的结构和运行过程,但这章未对源程序进行修改,只是在调试器中改变了标志寄存器的值。

加载中...
此文章数据所有权由区块链加密技术和智能合约保障仅归创作者所有。