avatar

6.7日更新 (week 7)

小黄书更新

昨天应该到了if…else这里

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//C++源码说明,if...else..模拟条件表达式转换方式
if(argc == 0){
argc = 5;
}
else{
argc = 6;
}
printf("%d \r\n",argc); //防止argc被优化处理
//对应汇编
if(argc == 0){
00401098 cmp dword ptr [ebp+8],0
0040109c jne main+27h(004010a7)
argc = 5;
0040109E mov dword ptr [ebp+8],5
}
else{
004010A5 jmp main+2Eh(004010ae)
argc = 6;
004010A7 mov dword ptr [ebp+8],6
}
printf("%d \r\n",argc);
//略
004010AE ...

所以说汇编还是比较好看的,记住一下JNE即可

1
2
3
4
5
6
7
8
9
10
总结结构:
//产生修改标志位的指令
jxx else_begin
if begin:
//执行if中的内容
if end:
jmp else end
else begin:
//执行else的内容
else end

两处跳转可以准确的划分一下哪里是else哪里是if,在我们else begin之前会有一个 jmp的指令,那么那里之后就是我们lelse块的开始,从而分析if else

O2优化选项,反汇编代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
arg_0 = dword ptr 4
//取到的参数数据放在edx中
mov edx,[esp+argc_0]
//将eax清0
xor eax,eax
//对edx和edx进行想与的操作,结果不影响edx
test edx,edx
//检查ZF的标记位,edx不等于0的时候,我们的al = 1,等于0 我们的al = 0
setnz al
add eax,5 //这里可能是5/6,看al了,我们不等于0,那么就是6,我们等于0,那么就是5
push eax
push offset Format ; "%d \r\n"
call _printf
add esp,8
retn

所以分析一下可以知道我们的优化后的代码也可以做到这个分支结构的选项,主要用了setnz这个指令

用if构成的多分支流程

总体来说就是我们经常看到的 if … else if … else if … else …

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
//C++源码说明,多分支结构
void IfElseIf(int argc){
if (argc > 0){
printf("argc > 0");
}
else if (argc == 0){
printf("argc == 0");
}
else{
printf("argc <= 0");
}
}
//对应汇编
if(argc > 0)
00401108 cmp dword ptr [ebp+8],0
//相减 argc-0 之后使用小于等于跳转的条件,jle
0040110C jle IfElseIf+2Dh(0040111d) //到else位置,目测那边是一个cmp 一个jne{
printf("argc > 0");
//printf 略
0040110E push offset string "argc > 0"(00420f9c)
00401113 call printf(00401150)
00401118 add esp,4
}
else if ( argc == 0 )
0040111B jmp IfElseIf+4Fh(0040113f)
//if比较转换,和我上面目测的差不多一个cmp,一个jne
0040111D cmp dword ptr [ebp+8],0
00401121 jne IfElseIf+42h(00401132) //到下一个else的位置,直接就是执行了
{
printf("argc == 0");
//printf 略
00401123 push offset string "argc == 0"(0042003c)
00401128 call printf(00401150)
0040112D add esp,4
}
//跳转到多分支结构结束地址
00401130 jmp IfElseIf+4Fh(0040113f)
{
printf("argc < = 0");//上面都不满足,无条件执行
//printf略
00401132 push offset string "argc != 0" (00420030)
00401137 call printf (00401150)
0040113C add esp,4
}
0040113F pop edi

上面的大部分结构都是个 cmp jxx jmp cmp jxx jmp 这样类似

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
总结:
//影响标志位
jxx else if begin
if begin:
...
if end:
jmp end
else if begin:
//影响标志位
jxx else begin
...
else if end:
jmp end
else begin
...
end:
...

这个属于没有优化的版本,如果开了O2编译选项,,我们将会对永远不能达到的地方进行不执行,不参与编译处理

假设我们的argc = 0,我们看一下O2版本的

1
2
3
4
5
6
sub_401000 proc near
push offset Format; "argc == 0"
call _printf
pop ecx
retn
sub_401000 endp

我们把不可以达到的分支直接删除,从而只剩下我们的一个必达分支语句块

如果我们把单分支if结构,每个位置加上一个return语句,那么我们没有了else,减少了一次JMP跳转,使代码执行效率提高

1
2
3
4
5
6
7
8
9
10
11
12
void IfElseIf(int argc){
if (argc > 0){
printf("argc > 0");
return;
}
if (argc == 0){
printf("argc == 0");
return;
}
printf("argc <= 0");
return;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
.text:00401000 sub_401000	proc near ; CODE XREF: _main+5p
//arg_0为函数参数
.text:00401000 arg_0 = dword ptr 4
//取出参数数据,放入eax,进行第一次if比较
.text:00401000 mov eax,[esp+arg_0]
.text:00401004 test eax,eax
//比较后进行转移,目测jle
.text:00401006 jle short loc_401016
//执行
.text:00401008 push offset Format ; "argc > 0"
.text:0040100D call _printf
.text:00401012 add esp,4
//使用retn指令返回,结束函数调用
.text:00401015 retn

//代表此处代码被符号sub_401000地址加6的地方引用
.text:00401016 loc_401006: ;CODE XREF: sub_401000+6j
//这里目测因为有test的问题 直接jne就可以
.text:00401018 push offset aArgc0_0 ; "argc == 0"
.text:0040101D call _printf
.text:00401022 add esp,4
//返回
.text:00401025 retn

//前两次失败没返回直接执行此处
.text:00401026 loc_401026: ; CODE XREF: sub_401000:loc_401016j
.text:00401026 push offset aArgc0_1; "argc <= 0"
.text:0040102B call _printf
.text:00401030 pop ecx
.text:00401031 retn
.text:00401031 sub_401000 endp

可以看出来大大的节省了效率

switch的真相

1
2
3
4
5
6
//switch转换if else 代码
int nIndex = 1;
scanf("%d",&nIndex);
switch(nIndex){
case 1:printf("nIndex == 1"); break;
}

STOP!调整了一下自己的学习方式,以后博客大概记录自己今天学的一个大概,以及明天的安排,即查即用,让自己快速学习了,感觉这个学习方法有点影响效率,我去看书去!

近期的安排就是把C++反汇编揭秘都看完,加密与解密4,深入理解计算机系统,程序员的自我修养,xv6,以后博客大概只会记录一下CTF的wp了

Author: L0x1c
Link: https://l0x1c.github.io/2020/06/07/2020-6-07/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付寶
    支付寶