逆向知识第八讲,if语句在汇编中表达的方式
一丶if else的最简单情况还原(无分支情况)
高级代码:
#include "stdafx.h"
int main(int argc, char* argv[])
{
unsigned int nNumber = 0;
scanf("%ud",&nNumber);
if(argc == 0)
{
nNumber = 0; //第一种情况下无分支
}
else
{
nNumber = -1;
}
return nNumber;
}
总共两种情况,我们看下Release中怎么优化的把(注意,优化方式选择O2,速度优先)
汇编代码:
可以看到我们熟悉的代码了.也就是昨天的三目运算.
总共三行汇编代码.
还原套路一样,还是 代入大于0 小于0 还有==0,看看最终结果是什么.
鉴于昨天还原过代码了,这里这届代入,还原出高级代码.
argc > 0的情况下
if(argc > 0) eax = -1
argc < 0的情况下
if(argc < 0) eax =-1
argc == 0的情况下
if(argc == 0) eax = 0
综合三种情况,可以得出具体的条件了. 其中 ><这样写是在高级语言中不能这样写的,
所以得出的还原代码为
if(argc == 0) eax =0
else eax == -1
二丶if else 的第二种情况(减少分支)
高级代码:
// MyCode.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
int main(int argc, char* argv[])
{
unsigned int nNumber = 0;
scanf("%ud",&nNumber);
if(argc == nNumber)
{
printf("%d",nNumber / 8);
}
else
{
printf("%d",nNumber / 5);
}
return nNumber;
}
对应汇编代码:
这个主要涉及找上下界问题
1.地址: 1018 101C 分别保存了局部变量的值
2.地址: 1023 比较了argc和局部变量Var4的值
3.地址: 1025 jnz跳转,因为1023地址的比较会影响标志位 由此判定, argc和var4比较,jnz(不相等)但因为汇编中是反条件,所以是相等的情况下
4.因为jnz是一个地址,所以这个地址是一个下界,那么jnz上面的比较代码则是上界,在其内部,我们还原为if语句块(先不用管里面具体干啥)
还原if语句块
if(argc == var4) printf("%d",var4 / 8);
还原else语句块
else printf("%d",var4 / 5);
在下方我们发现了相同的汇编代码,也就是把retn放到上面去了,这个主要是为了减少分支.
三丶if else 第第三种形式,代码外提的情况
代码外提的情况下,主要在优化方式的选择上,我们知道 o2(优化方式是速度优先) 现在我们改成o1(也就是体积优先了)
这个时候就会出现代码外提.
高级代码:
// MyCode.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
int main(int argc, char* argv[])
{
unsigned int nNumber = 0;
scanf("%ud",&nNumber);
if(argc == nNumber)
{
printf("Hello");
}
else
{
printf("World");
}
return nNumber;
}
切换为o1
protect -> setting即可.
对应汇编代码:
首先,找if else的时候,先确定上下界
地址: 101A位置 寻得了 if的上界
地址: 101E位置 寻得了 if的下界
注意: 中间划掉了两个指令,这两个指令是流水线优化,平栈的指令.所以没有帮助,划掉
地址: 1025位置,其指令跳转的地址是一个增量,那么则确定是else的下界
地址: 1027位置 寻得了else的上界
其实简单来说,第一个跳转位置,跳转到哪里的一块区域,是一个if的语句块而跳转的位置则是else语句块的上界,其上面固定一个jmp(注意其地址跳转是一个增量)那么跳转的地址是else的下界
重点代码外提:
我们可以看到 我们的if语句块中 push了一个 hello,我们的else语句块中,push了一个 word
那么除了if else 直接调用的printf,这样也是可以的.因为参数是一样的.平栈都是相等的.所以可以提到外面来打印输出.
四丶多分支if elseif .... else的还原
这个其实很简单了.如果是多分支,则寻找上界下界即可.
因为编译器做的东西很多了.
高级代码:
// Test.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
int main(int argc, char* argv[])
{
unsigned int nVar_4 = 5;
scanf("%d", &nVar_4);
// argc == 0 ? 0 : -1
if (argc == 0)
{
printf("argc == 0\r\n");
}
else if(argc == 1)
{
printf("argc == 1\r\n");
}
else if(argc == 2)
{
printf("argc == 2\r\n");
}
else if(argc == 3)
{
printf("argc == 3\r\n");
}
else
{
printf("else\r\n");
}
printf("haha\r\n");
printf("haha\r\n");
printf("haha\r\n");
printf("haha\r\n");
printf("haha\r\n");
return nVar_4;
}
对应汇编代码:
看到这种,直接判断为 if else if else if else这种语句,然后寻找上下界即可.