3.多条件 if 语句执行流程
文章摘要: 该文通过C语言函数与对应汇编代码的对比分析,展示了如何逆向解析多条件if-else if-else结构。函数根据输入数字num的大小返回不同结果,汇编表现为一系列cmp指令配合条件跳转。作者详细解读了每个条件分支的汇编实现,包括正负数处理,并总结出识别这类结构的逆向技巧:当看到同一变量被连续比较、各分支都跳向同一出口时,基本可判定为if-else if-else链。最后用表格完整呈现了
文章目录
一、先把原始代码和汇编摆在桌面上
原始 C 代码(不改)
int checkNumber(int num)
{
int result;
if (num > 1000)
result = 10000;
else if (num > 500)
result = 5000;
else if (num > 100)
result = 1000;
else if (num > 50)
result = 500;
else if (num > 0)
result = 100;
else if (num == 0)
result = 0;
else if (num > -50)
result = -100;
else if (num > -100)
result = -500;
else if (num > -500)
result = -1000;
else
result = -5000;
return result;
}
对应的关键汇编(不改,仅截取核心逻辑)
002F1576 cmp dword ptr [ebp+8],3E8h
002F157D jle 002F158B
002F157F mov dword ptr [ebp-4],2710h
002F1586 jmp 002F1610
002F158B cmp dword ptr [ebp+8],1F4h
002F1592 jle 002F159D
002F1594 mov dword ptr [ebp-4],1388h
002F159B jmp 002F1610
002F159D cmp dword ptr [ebp+8],64h
002F15A4 jle 002F15AF
002F15A6 mov dword ptr [ebp-4],3E8h
002F15AD jmp 002F1610
002F15AF cmp dword ptr [ebp+8],32h
002F15B6 jle 002F15C1
002F15B8 mov dword ptr [ebp-4],1F4h
002F15BF jmp 002F1610
002F15C1 cmp dword ptr [ebp+8],0
002F15C5 jle 002F15CF
002F15C7 mov dword ptr [ebp-4],64h
002F15CE jmp 002F1610
002F15CF cmp dword ptr [ebp+8],0
002F15D3 jne 002F15D9
002F15D5 mov dword ptr [ebp-4],0
002F15DC jmp 002F1610
002F15D9 cmp dword ptr [ebp+8],0FFFFFFCEh
002F15DD jle 002F15E8
002F15DF mov dword ptr [ebp-4],0FFFFFF9Ch
002F15E6 jmp 002F1610
002F15E8 cmp dword ptr [ebp+8],0FFFFFF9Ch
002F15EC jle 002F15F7
002F15EE mov dword ptr [ebp-4],0FFFFFE0Ch
002F15F5 jmp 002F1610
002F15F7 cmp dword ptr [ebp+8],0FFFFFE0Ch
002F15FB jle 002F1606
002F15FD mov dword ptr [ebp-4],0FFFFFC18h
002F1604 jmp 002F1610
002F1606 mov dword ptr [ebp-4],0FFFFEC78h
002F1610 mov eax,dword ptr [ebp-4]
二、第一眼扫过去:这不是 switch,是一条 if-else 链
我在 IDA 里第一眼看到这段的时候,并没有逐条翻译,而是先看结构:
-
[ebp+8]被反复cmp -
每次
cmp后面紧跟条件跳转 -
每个分支一旦命中,都会:
-
mov [ebp-4], 常量 -
jmp 002F1610
-
-
002F1610是所有路径都会汇合的统一出口
这在逆向里基本是一个信号:
这是“线性 if → else if → else”的经典编译形态。
三、从第一个 if 开始,对着汇编“反着读逻辑”
cmp dword ptr [ebp+8],3E8h
jle 002F158B
这里非常关键的一点是:
-
C 里写的是
if (num > 1000) -
汇编里判断的是 “不满足就跳走”
也就是说:
-
jle跳走 → 条件失败 → 去试下一个 else if -
不跳 → 条件成立 → 执行赋值
mov dword ptr [ebp-4],2710h ; result = 10000
jmp 002F1610
到这里,第一个 if 分支已经完全闭合。
四、else if 的本质:上一个条件失败后,立刻 cmp 下一个阈值
002F158B cmp dword ptr [ebp+8],1F4h
002F1592 jle 002F159D
我在这里通常会做一件事:
看上一个
jle的目标地址,是不是正好跳到这里。
一对上,结构就彻底清楚了:
-
失败 → 跳到下一个 cmp
-
成功 → 赋值 → 跳统一出口
mov dword ptr [ebp-4],1388h ; result = 5000
jmp 002F1610
这就是:
else if (num > 500)
后面的 num > 100 / 50 / 0 分支,全都是同一个套路,只是阈值和结果不同。
五、看到补码就要警觉:开始进入负数区间判断
cmp dword ptr [ebp+8],0FFFFFFCEh
jle 002F15E8
0xFFFFFFCE 是什么?
-
补码
-
转成有符号:-50
再看赋值:
mov dword ptr [ebp-4],0FFFFFF9Ch ; -100
这一步在逆向时非常“顺”:
结构没变,只是常量换成了负数。
说明 C 里的逻辑大概是:
else if (num > -50)
result = -100;
后面的 -100 / -500 分支,完全同理。
六、没有 cmp 的那一段:这就是 else
002F1606 mov dword ptr [ebp-4],0FFFFEC78h
这里有两个非常明显的信号:
-
前面没有任何比较
-
执行完就自然落到返回点
这说明:
这是所有条件都失败之后的兜底分支
也就是:
else
result = -5000;
七、把整个 if-else 链“反推”成一张逻辑表
这是我在逆向里经常做的最后一步,用来确认自己没有看漏条件:
| 条件 | result |
|---|---|
| num > 1000 | 10000 |
| num > 500 | 5000 |
| num > 100 | 1000 |
| num > 50 | 500 |
| num > 0 | 100 |
| num == 0 | 0 |
| num > -50 | -100 |
| num > -100 | -500 |
| num > -500 | -1000 |
| else | -5000 |
如果这张表能完整整理出来,说明这个函数已经被你完全逆向成功。
八、一句话总结这类结构的“逆向直觉”
只要在反汇编里看到:同一个变量被一串
cmp连续比较,每个分支内部“赋值 + jmp 同一个出口”,最后还有一个自然落地的分支,那它几乎一定是一个多条件 if-else if-else。
#include<iostream>
int checkNumber(int num) {
int result;
// 多条件 if-else if-else 语句
if (num > 1000) {
result = 10000;
}
else if (num > 500) {
result = 5000;
}
else if (num > 100) {
result = 1000;
}
else if (num > 50) {
result = 500;
}
else if (num > 0) {
result = 100;
}
else if (num == 0) {
result = 0;
}
else if (num > -50) { // 负数的判断,从靠近0的开始
result = -100;
}
else if (num > -100) {
result = -500;
}
else if (num > -500) {
result = -1000;
}
else {
result = -5000;
}
return result;
}
int main() {
// 测试不同的数字
int testNumbers[] = { 1500, 750, 200, 75, 25, 0, -25, -75, -150, -300, -1000 };
int size = sizeof(testNumbers) / sizeof(testNumbers[0]);
std::cout << "多条件判断测试结果:" << std::endl;
std::cout << "====================" << std::endl;
for (int i = 0; i < size; i++) {
int result = checkNumber(testNumbers[i]);
std::cout << "checkNumber(" << testNumbers[i] << ") = " << result << std::endl;
}
return 0;
}
更多推荐

所有评论(0)