c++中if语句的反汇编及优化

C++ if语句反汇编

只有一个if的情况

首先我们通过观察debug选项下的汇编代码,对if语句有一个大致的了解。程序的源代码非常简单,如下:

cpp 复制代码
#include <stdio.h>

int main(int argc, char* argv[])
{
	if (argc == 0)
		printf("argc == 0");

	return 0;
}

我们先在if语句处下断点,直接在vs2022中进行调试

从图中我们可以看到,反汇编使用的判断与0相比较,并进行了jne不等于则跳转指令,跳转的地址正是整个if逻辑的结束地址。如果跳转条件不成立的话,则执行的是满足源代码中if语句块的代码。

接下来我们修改一下源代码,如下:

cpp 复制代码
#include <stdio.h>

int main(int argc, char* argv[])
{
	if (argc > 0)
		printf("argc > 0");

	return 0;
}

同样是在debug编译选项中,进行调试,同样在if语句处下断点

这里使用了jle小于等于则跳转指令,跳转的目的地是整个if语句的结束地址。如果跳转条件不成立的话,则执行的是满足源代码中if语句块的代码。

我们源代码中使用的是大于比较符,而汇编代码中使用的是小于等于跳转指令。似乎汇编中的判断条件总是和源代码中相反的,我们先不着急下结论,在多看几种情况。

if和else

我们修改一下先前的源代码,如下:

cpp 复制代码
#include <stdio.h>

int main(int argc, char* argv[])
{
	if (argc == 0)
		printf("argc == 0");
	else
		printf("argc != 0");

	return 0;
}

使用Debug编译选项。同样在if处下断点,反汇编代码如下:

同样的,if语句的反汇编代码中进行的是和源代码中相反的判断,跳转的地址是else语句块的起始地址。如果跳转条件不成立,则会执行if语句块中的代码,并且我们可以看到,为了跳过紧挨着if语句块反汇编代码末尾的else反汇编代码块,在if反汇编代码块的末尾处,使用了无条件跳转指令跳转到整个if else逻辑的结束地址处。

我们知道,if与else语句和条件表达式语句(三目运算符)的功能是相同的,我之前写过一篇博客,里面讨论了对条件表达式的反汇编和优化,既然两者的功能是相同的,那么它们在反汇编的优化上是否有相似之处呢?答案是有的。读者可以参考那篇文章,自己构造测试代码并反汇编,看看其中的优化方案。笔者实验后发现,if...else语句和条件表达式使用的是同一套优化策略。

if多分支语句

先给出我们的测试代码:

cpp 复制代码
#include <stdio.h>

int main(int argc, char* argv[])
{
	if (argc > 0) {
		printf("argc > 0");
	}
	else if (argc == 0) {
		printf("argc == 0");
	}
	else {
		printf("argc <= 0");
	}
	return 0;
}

在Release下编译并反汇编,得到的汇编代码如下所示:

在反汇编视图中我们可以看到,先是使用了test指令对argc进行按位与运算,判断argc是否为0,并设置了SF(为1时表示运算结果为负数),而jle指令执行的是小于等于则跳转,要执行jle指令会先检查SF标志位(其实还需要检查OF溢出标志位,但test指令并不影响该标志位,始终将其置0),当SF标志位为1时,执行jle指令。所以test和jle指令的结合,用于判断一个数是否小于等于0,这与源代码中的>0相对应。如果跳转不执行,说明符合>0的条件,接下来就执行第一个if语句块中的代码,并直接ret,而不是跳转到整个多分枝if的结束处。

有趣的是对于后两个语句块的优化,它们使用了条件运算符的优化方案(详情见该篇博客),把两个printf的参数都加载,然后使用条件传输指令选择正确的参数地址,避免了使用分支跳转代码,加快了流水线的执行。

总结

在逆向还原代码的时候,因为if语句和条件判断语句的相似之处,我们可以自行选择将其还原成对应的c代码。

相关推荐
Jet_582 天前
神庙逃亡(Temple Run)IL2CPP 逆向实战:从 APK 到 Frida 实现角色无敌
unity·il2cpp·逆向工程·frida·android逆向·hook技术·游戏逆向
Jet_585 天前
IDA Pro 远程调试指南:gdbserver / armlinux_server 全流程实战
安卓逆向·逆向工程·远程调试·gdbserver·ida pro·android 调试
幽络源小助理10 天前
逆向工程系统学习资源图谱(2026):从 Windows 内核、安卓安全到游戏协议分析的全栈教程清单
学习·安全·游戏·逆向工程
阿昭L14 天前
结构体和类的反汇编
逆向工程
深念Y18 天前
proxypin抓包工具获得nb实验室VIP(已失效)
游戏·网络安全·抓包·逆向工程·软件逆向·nb实验室·教育软件
Jet_5820 天前
[特殊字符] AndroidReverse101:100 天系统学习 Android 逆向工程(学习路线推荐)
安卓逆向·逆向工程·frida·android逆向·安全研究·apk逆向
智_永无止境20 天前
MyBatisMyBatis的隐形炸弹:selectByExampleWithBLOBs使用不当,让性能下降80%的隐形炸弹
逆向工程·mgb
Logic1011 个月前
深入理解C语言if语句的汇编实现原理:从条件判断到底层跳转
c语言·汇编语言·逆向工程·底层原理·条件跳转·编译器原理·x86汇编
Eloudy3 个月前
一个逆向工具 Ghidra 在 Linux 上的安装和基本使用
逆向工程