2020-08-20汇编学习00
请注意,本文编写于 831 天前,最后修改于 204 天前,其中某些信息可能已经过时。

目录


一、switch语句

1、switch语句 是if语句的简写

switch(表达式)
{
     	case 常量表达式1:
		语句;
		break;
	case 常量表达式2:
		语句;
		break;
	case 常量表达式3:
		语句;
		break;
	case 常量表达式3:
		语句;
		break;
	default:
		语句;
		break;
}
if(表达式 == 常量1)
{
	//...代码
}
else if(表达式 == 常量2)
{
	//...代码
}
else if(表达式 == 常量3)
{
	//...代码
}
else
{
	//...代码
}

switch要求:

  1. case后面必须是常量表达式

  2. case后常量表达式的值不能一样

  3. switch后面表达式必须为整数

2、游戏中的switch语句

F1  F2  F3  F4  F5  F6  F7  F8
0   1   2   3   4   5   6   7
switch(表达式)
{
     	case 1:
		打坐....
		break;
	case 2:
		加红....
		break;
	case 3:
		加蓝....
		break;
	case 4:
		释放技能....
		break;
	default:
		语句;
		break;
}

3、break加与不加有什么特点?default语句可以省略吗?

如果不加break,那么程序会一直打印,直到碰到break为止,default 可以省略,但因为不排除用户输入,没有设定好的case,最好是带上default

4、添加case后面的值,一个一个增加,观察反汇编代码的变化(何时生成大表).

分支少于4的时候,用switch没有意义,因为编译器会生成类似if...else之类的反汇编。

5、将3中的常量值的顺序打乱,观察反汇编代码(观察顺序是否会影响生成大表).

case后边的常量,可以使无序的,并不影响大表的生成

6、将case后面的值改成从100开始到109,观察汇编变化(观察值较大时是否生成大表).

# include "stdafx.h"
# include "string.h"


void Fun(int x)
{

switch(x)
	{
	case 100:
		printf("100");
		break;
	case 101:
		printf("101");
		break;
	case 102:
		printf("102");
		break;
	case 103:
		printf("103");
		break;
	case 104:
		printf("104");
		break;
	case 105:
		printf("105");
		break;
	case 106:
		printf("106");
		break;
	case 107:
		printf("107");
		break;
	case 108:
		printf("108");
		break;
	case 109:
		printf("109");
		break;
	default:
		printf("error");
		break;
	}
}

会生成大表,减100

7、将连续的10项中抹去1项或者2项,观察反汇编有无变化(观察大表空缺位置的处理).

抹去其中的几个项的话,大表会将default的地址放入抹去的那一项的空缺,

抹去几个分支,大表中空出来的位置,将由default那个分支来填补

所以 ,如果将连续的项,抹去其中几个的话是,有一定的空间浪费的

如果抹去超过一定数量(根据编译器来定),那么就会精简大表,省略default,生成小表

8、在10项中连续抹去,不要抹去最大值和最小值(观察何时生成小表).

如果抹去超过一定数量5(根据编译器来定),那么就会精简大表,省略default,生成小表

9、将case后面常量表达式改成毫不连续的值,观察反汇编变化.

如果case表达式 毫不连续, 那么反汇编生成类似if...else的反汇编

所以如果要生成大表,一定得是 连续的值,相近的值才可以

小表最多存256个,

二、do..while反汇编

do
{


}while(表达式)

do..while反汇编

例子

dowhile

总结

  1. 根据条件跳转指令所跳转到的地址,可以得到循环语句块的起始地址。

  2. 根据条件跳转指令所在的地址,可以得到循环语句块的结束地址。

  3. 条件跳转的逻辑与源码相同。

三、while反汇编

while(表达式)
{

	//执行代码
}

while反汇编

例子

while反汇编

总结

  1. 根据条件跳转指令所跳转到的地址,可以得到循环语句块的结束地址;

  2. 根据jmp 指令所跳转到的地址,可以得到循环语句块的起始地址;

  3. 在还原while 比较时,条件跳转的逻辑与源码相反。

四、for循环反汇编

for(表达式1;表达式2;表达式3)
{
	//执行的代码
}

for循环的执行次序:

表达式1
表达式2
执行的代码(大括号里面的内容)
表达式3

表达式2 //如果表达式2成立
执行的代码(大括号里面的内容)
表达式3

表达式2 //如果表达式2成立
执行的代码(大括号里面的内容)
表达式3

表达式2 //如果不成立
跳出循环

例子

for循环反汇编

总结:

  1. 第一个jmp 指令之前为赋初值部分.

  2. 第一个jmp 指令所跳转的地址为循环条件判定部分起始.

  3. 判断条件后面的跳转指令条件成立时跳转的循环体外面

  4. 条件判断跳转指令所指向的地址上面有一个jmp ,jmp地址为表达式3的起始位置

作业

1、写一个switch语句,不生产大表也不生产小表,贴出对应的反汇编

00401030   push        ebp
00401031   mov         ebp,esp
00401033   sub         esp,44h
00401036   push        ebx
00401037   push        esi
00401038   push        edi
00401039   lea         edi,[ebp-44h]
0040103C   mov         ecx,11h
00401041   mov         eax,0CCCCCCCCh
00401046   rep stos    dword ptr [edi]
00401048   mov         eax,dword ptr [ebp+8]
0040104B   mov         dword ptr [ebp-4],eax
0040104E   cmp         dword ptr [ebp-4],1
00401052   je          Fun+32h (00401062)
00401054   cmp         dword ptr [ebp-4],2
00401058   je          Fun+41h (00401071)
0040105A   cmp         dword ptr [ebp-4],3
0040105E   je          Fun+50h (00401080)
00401060   jmp         Fun+5Fh (0040108f)
00401062   push        offset string "1" (0042902c)
00401067   call        printf (00401730)
0040106C   add         esp,4
0040106F   jmp         Fun+6Ch (0040109c)
00401071   push        offset string "2" (00429028)
00401076   call        printf (00401730)
0040107B   add         esp,4
0040107E   jmp         Fun+6Ch (0040109c)
00401080   push        offset string "3" (00429024)
00401085   call        printf (00401730)
0040108A   add         esp,4
0040108D   jmp         Fun+6Ch (0040109c)
0040108F   push        offset string "error" (0042901c)
00401094   call        printf (00401730)
00401099   add         esp,4
0040109C   pop         edi
0040109D   pop         esi
0040109E   pop         ebx
0040109F   add         esp,44h
004010A2   cmp         ebp,esp
004010A4   call        __chkesp (00401690)
004010A9   mov         esp,ebp
004010AB   pop         ebp
004010AC   ret

2、写一个switch语句,只生成大表,贴出对应的反汇编.

00401030   push        ebp
00401031   mov         ebp,esp
00401033   sub         esp,44h
00401036   push        ebx
00401037   push        esi
00401038   push        edi
00401039   lea         edi,[ebp-44h]
0040103C   mov         ecx,11h
00401041   mov         eax,0CCCCCCCCh
00401046   rep stos    dword ptr [edi]
00401048   mov         eax,dword ptr [ebp+8]        //eax = 3
0040104B   mov         dword ptr [ebp-4],eax
0040104E   mov         ecx,dword ptr [ebp-4]
00401051   sub         ecx,1                        //case 表达式 最小的那个值,也就是case 1 的1,ecx = 3-1 =2
00401054   mov         dword ptr [ebp-4],ecx        //ecx  = 2
00401057   cmp         dword ptr [ebp-4],6          // 2-6,显然是不成立的
0040105B   ja          $L860+0Fh (004010d0)         //所以 不会跳转到004010d0
0040105D   mov         edx,dword ptr [ebp-4]        //将ebp-4的值,也就是2 赋给edx
00401060   jmp         dword ptr [edx*4+4010EEh]    // 2*4 + 4010EEh  = 8+4010EEh,所以等于004010F6,找到这个地址上的值,图1所示
                                                    // 00401085
$L848:
00401067   push        offset string "1" (0042903c)
0040106C   call        printf (00401730)
00401071   add         esp,4
00401074   jmp         $L860+1Ch (004010dd)
$L850:
00401076   push        offset string "2" (00429038)
0040107B   call        printf (00401730)
00401080   add         esp,4
00401083   jmp         $L860+1Ch (004010dd)
$L852:
00401085   push        offset string "3" (00429034)      //打印3
0040108A   call        printf (00401730)
0040108F   add         esp,4
00401092   jmp         $L860+1Ch (004010dd)
$L854:
00401094   push        offset string "4" (00429030)
00401099   call        printf (00401730)
0040109E   add         esp,4
004010A1   jmp         $L860+1Ch (004010dd)
$L856:
004010A3   push        offset string "107" (0042902c)
004010A8   call        printf (00401730)
004010AD   add         esp,4
004010B0   jmp         $L860+1Ch (004010dd)
$L858:
004010B2   push        offset string "\xc4\xc9\xbf\xcb\xc8\xf8\xc2\xea\xcb\xb9" (00429028)
004010B7   call        printf (00401730)
004010BC   add         esp,4
004010BF   jmp         $L860+1Ch (004010dd)
$L860:
004010C1   push        offset string "109" (00429024)
004010C6   call        printf (00401730)
004010CB   add         esp,4
004010CE   jmp         $L860+1Ch (004010dd)
004010D0   push        offset string "\xbf\xad\xb6\xfb\xc8\xf8\xcb\xb9" (0042901c)
004010D5   call        printf (00401730)
004010DA   add         esp,4
004010DD   pop         edi
004010DE   pop         esi
004010DF   pop         ebx
004010E0   add         esp,44h
004010E3   cmp         ebp,esp
004010E5   call        __chkesp (00401690)
004010EA   mov         esp,ebp
004010EC   pop         ebp
004010ED   ret

图1:
图1

3、写一个switch语句,生成大表和小表,贴出对应的反汇编

00401020   push        ebp
00401021   mov         ebp,esp
00401023   sub         esp,44h
00401026   push        ebx
00401027   push        esi
00401028   push        edi
00401029   lea         edi,[ebp-44h]
0040102C   mov         ecx,11h
00401031   mov         eax,0CCCCCCCCh
00401036   rep stos    dword ptr [edi]
00401038   mov         eax,dword ptr [ebp+8]                //ebp+8内是 参数7,eax = 7
0040103B   mov         dword ptr [ebp-4],eax                //将eax的值7 赋给局部变量ebp-4
0040103E   mov         ecx,dword ptr [ebp-4]                //将ebp-4的值7赋给ecx,ecx = 7
00401041   sub         ecx,1                                //ecx = 7-1 = 6
00401044   mov         dword ptr [ebp-4],ecx
00401047   cmp         dword ptr [ebp-4],10h                //6-10 显然 ja是不成立的
0040104B   ja          $L860+0Fh (004010c8)
0040104D   mov         eax,dword ptr [ebp-4]                // eax = 6
00401050   xor         edx,edx                              // edx 变成0
00401052   mov         dl,byte ptr  (00401106)[eax]         // 将00401106+eax的值给dl,也就是 00401106拖到内存从0数到6,看图02
                                                            // dl = 07,也就是 edx = 0x00000007
00401058   jmp         dword ptr [edx*4+4010E6h]            //edx*4+4010E6h 等于 7*4+4010E6h等于1C+4010E6h = 401102h
                                                            //找到该地值,发现该地值上保存了004010C8,也就是default
$L848:
0040105F   push        offset string "1" (0042203c)
00401064   call        printf (004011a0)
00401069   add         esp,4
0040106C   jmp         $L860+1Ch (004010d5)
$L850:
0040106E   push        offset string "2" (00422038)
00401073   call        printf (004011a0)
00401078   add         esp,4
0040107B   jmp         $L860+1Ch (004010d5)
$L852:
0040107D   push        offset string "3" (00422034)
00401082   call        printf (004011a0)
00401087   add         esp,4
0040108A   jmp         $L860+1Ch (004010d5)
$L854:
0040108C   push        offset string "10" (00422030)
00401091   call        printf (004011a0)
00401096   add         esp,4
00401099   jmp         $L860+1Ch (004010d5)
$L856:
0040109B   push        offset string "11" (0042202c)
004010A0   call        printf (004011a0)
004010A5   add         esp,4
004010A8   jmp         $L860+1Ch (004010d5)
$L858:
004010AA   push        offset string "15" (00422028)
004010AF   call        printf (004011a0)
004010B4   add         esp,4
004010B7   jmp         $L860+1Ch (004010d5)
$L860:
004010B9   push        offset string "17" (00422024)
004010BE   call        printf (004011a0)
004010C3   add         esp,4
004010C6   jmp         $L860+1Ch (004010d5)
004010C8   push        offset string "error" (0042201c)
004010CD   call        printf (004011a0)
004010D2   add         esp,4
004010D5   pop         edi
004010D6   pop         esi
004010D7   pop         ebx
004010D8   add         esp,44h
004010DB   cmp         ebp,esp
004010DD   call        __chkesp (00401220)
004010E2   mov         esp,ebp
004010E4   pop         ebp
004010E5   ret

图2:
图2

图3:
图3

4、为do..while语句生成的反汇编填写注释.

# include "stdafx.h"

void Fun(int x,int y)
{

	do
	{
		printf("%d\n",x);
		x++;

	}while(x < y);


}

int main(int argc, char* argv[])
{

	Fun(1,8);
	return 0;
}

do...while反汇编注释

5、为while语句生成的反汇编填写注释.

# include "stdafx.h"

void Fun(int x,int y)
{
	while(x < y)
	{
		printf("%d\n",x);
		x++;
	}
}

int main(int argc, char* argv[])
{
	Fun(1,8);
	return 0;
}

while反汇编注释

6、为for语句生成的反汇编填写注释.

# include "stdafx.h"

void Fun(int x,int y)
{
	for(int i = x; i < y;i++)
	{
		printf("%d\n",i);
	}
}

int main(int argc, char* argv[])
{
	Fun(1,8);
	return 0;
}

for反汇编注释
笔记内容来自滴水三期

本文作者:Na1r

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!