滴水逆向三期笔记与作业——02C语言——10 Switch语句反汇编

滴水逆向三期笔记与作业——02C语言——10 Switch语句反汇编

  • 一、Switch语句
    • 1、switch语句 是if语句的简写
    • 2、break加与不加有什么特点?default语句可以省略吗?
    • 3、游戏中的switch语句(示例)
    • 4、添加case后面的值,一个一个增加,观察反汇编代码的变化(何时生成大表).
    • 5、将3中的常量值的顺序打乱,观察反汇编代码(观察顺序是否会影响生成大表).
    • 6、将case后面的值改成从100开始到109(连续),观察汇编变化(观察值较大时是否生成大表).
    • 7、将连续的10项中抹去1项或者2项,观察反汇编有无变化(观察大表空缺位置的处理).
    • 8、在10项中连续抹去,不要抹去最大值和最小值(观察何时生成小表).
    • 9、将case后面常量表达式改成毫不连续的值,观察反汇编变化.
    • 10、部分连续,部分差值非常大
  • 二、do/while反汇编
    • 1、do/while的语法
    • 2、do/while的反汇编
    • 3、example
    • 4、总结
  • 三、while反汇编
    • 1、while语句的语法
    • 2、while语句反汇编
    • 3、example
    • 4、总结
  • 四、for循环反汇编
    • 1、for语句的语法
    • 2、for循环的执行次序
    • 3、example
    • 4、总结
  • 五、作业
    • 1、写一个Switch语句,不生产大表也不生产小表,贴出对应反汇编
    • 2、写一个Switch语句,只生成大表,贴出对应反汇编
    • 3、写一个Switch语句,生成大表和小表,贴出对应反汇编
    • 4、为do/while语句生成的反汇编填写注释
    • 5、为while语句生成的反汇编填写注释
    • 6、为for语句生成的反汇编填写注释

一、Switch语句

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

  • if语句
if(表达式 == 常量1)
{
	//...代码
}
else if(表达式 == 常量2)
{
	//...代码
}
else if(表达式 == 常量3)
{
	//...代码
}
else
{
	//...代码
}

  • switch语句
switch(表达式)                
{                
    case 常量表达式1:
    	语句;
    	break;
	case 常量表达式2:
		语句;
		break;
	case 常量表达式3:
		语句;
		break;
	case 常量表达式3:
		语句;
		break;
	default:        
		语句;
		break;
}

switch要求:

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

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

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

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

不写break时,编译可以通过,但会将不写break的case全部执行一遍。
default语句可以省略,当所有条件都不满足的时候,会默认执行default中的代码,如果不存在default,但所有条件不满足,则不执行代码。

3、游戏中的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;
}

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

我的环境是64位的vscode,与海哥教程中存在较大差异。

  • 少分支Switch结构
void Function(int x){
switch (x){
case 1:
printf("1");
break;
case 2:
printf("2");
break;
case 3:
printf("3");
break;
default:
printf("4");
break;
}
}
 
int main(int argc, char* argv[]){
Function(2);
 
return 0;
}

滴水逆向三期笔记与作业——02C语言——10 Switch语句反汇编_第1张图片

由汇编可见,少分支的Switch与if相似,所以正向代码中,分支较少时建议不使用Switch

  • 多分支Switch结构
void Function(int x){
switch (x){
case 1:
printf("1");
break;
case 2:
printf("2");
break;
case 3:
printf("3");
break;
case 4:
printf("4");
break;
default:
printf("5");
break;
}
}
 
int main(int argc, char* argv[]){
Function(2);
 
return 0;
}

滴水逆向三期笔记与作业——02C语言——10 Switch语句反汇编_第2张图片
未发现大表寻址过程

  • 多分支Switch结构
void Function(int x){
switch (x){
case 1:
printf("1");
break;
case 2:
printf("2");
break;
case 3:
printf("3");
break;
case 4:
printf("4");
break;
case 5:
printf("5");
break;
case 6:
printf("6");
break;
default:
printf("7");
break;
}
}
int main(int argc, char* argv[]){
Function(3);
return 0;
}

滴水逆向三期笔记与作业——02C语言——10 Switch语句反汇编_第3张图片
存在大表寻址过程,已优化

  • 总结
    1、分支少于4的时候,使用Switch没有意义,因为编译器会生成类似if/else之类的反汇编;
    2、case后面的常量表达式可以是无序的,并不影响大表的生成

• 分支较少时,不生成大表,也不生成小表,会生成if…else语句
• 分支达到一定数量时,生成大表,且大表跟顺序无关
• 大表可以理解为一个存储了多个地址的连续表,通过Register*4可以来寻址。
• 分支达到一定数量,生成大表,但是中间缺少很多case时,还会生成一张小表。
• 小表的作用可以理解为把大表的空缺地址,移动到了小表,把空缺的case值所在的地方填为default的地址

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

并不影响大表生成

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

  • 代码
void Function(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;
default:
printf("109");
break;
}
}
int main(int argc, char* argv[]){
Function(103);
return 0;
}

  • 反汇编
    滴水逆向三期笔记与作业——02C语言——10 Switch语句反汇编_第4张图片

如果[参数-100]大于[max-min],说明传入参数小于case最小值或者大于case最大值,此时直接执行default即可;
反之说明参数在min到max之间,而此时eax中存储的是[参数-100]的数值,而编译器已经维护了一张表,根据eax的位置,像一维数组查数一样根据公式,eax=基址+eax代表的内存的数据,跳转到eax的执行地址即可(jmp rax)。

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

滴水逆向三期笔记与作业——02C语言——10 Switch语句反汇编_第5张图片

被删除的部分并不会被填充0,大表会把抹去的分支项原先所对应的地址全部给填充为default默认地址.

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

小表是将大表的地址移动到小表,空缺的地方填充为到default的偏移量。
海哥的教程中删除一定的case分支后,生成小表,但本地环境win64+VSCOde中,未生成小表,删除一定的分支后,直接转换成if/else形式(我也很疑惑……)。

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

类似于if/else的结构

10、部分连续,部分差值非常大

  • 代码
void Function(int x){
switch (x){
case 300:
printf("300");
break;
case 301:
printf("301");
break;
case 302:
printf("302");
break;
case 303:
printf("303");
break;
case 304:
printf("304");
break;
case 305:
printf("305");
break;
case 306:
printf("306");
break;
case 307:
printf("307");
break;
case 3:
printf("3");
break;
default:
printf("309");
break;
}
}
int main(int argc, char* argv[]){
Function(303);
return 0;
}

  • 反汇编
    滴水逆向三期笔记与作业——02C语言——10 Switch语句反汇编_第6张图片
    与if/else相同,下图为海哥教程图
    滴水逆向三期笔记与作业——02C语言——10 Switch语句反汇编_第7张图片

二、do/while反汇编

1、do/while的语法

do
{
	//执行代码
}while(表达式)
 

2、do/while的反汇编

滴水逆向三期笔记与作业——02C语言——10 Switch语句反汇编_第8张图片

3、example

滴水逆向三期笔记与作业——02C语言——10 Switch语句反汇编_第9张图片

4、总结

  1. 根据条件跳转指令所跳转到的地址,可以得到循环语句块的起始地址。
  2. 根据条件跳转指令所在的地址,可以得到循环语句块的结束地址。
  3. 条件跳转的逻辑与源码相同。

三、while反汇编

1、while语句的语法

while(表达式)        
{
	//执行代码
}

2、while语句反汇编

滴水逆向三期笔记与作业——02C语言——10 Switch语句反汇编_第10张图片

3、example

滴水逆向三期笔记与作业——02C语言——10 Switch语句反汇编_第11张图片

4、总结

  1. 根据条件跳转指令所跳转到的地址,可以得到循环语句块的结束地址;
  2. 根据jmp 指令所跳转到的地址,可以得到循环语句块的起始地址;
  3. 在还原while 比较时,条件跳转的逻辑与源码相反。

四、for循环反汇编

1、for语句的语法

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

2、for循环的执行次序

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

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

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

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

3、example

滴水逆向三期笔记与作业——02C语言——10 Switch语句反汇编_第12张图片

4、总结

  1. 第一个jmp 指令之前为赋初值部分
  2. 第一个jmp 指令所跳转的地址为循环条件判定部分起始
  3. 判断条件后面的跳转指令条件成立时跳转的循环体外面
  4. 条件判断跳转指令所指向的地址上面有一个jmp jmp地址为表达式3的起始位置

五、作业

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

void Function(int x)
{
switch(x)
{
case 1:
	printf("1");
	break;
case 2:
	printf("2");
	break;
case 3:
	printf("3");
	break;
default:
	printf("Error");
	break;
}
}
 
int main(int argc, char* argv[]){
	Function(2);
	return 0;
}

滴水逆向三期笔记与作业——02C语言——10 Switch语句反汇编_第13张图片

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

void Function(int x)
{
switch(x)
{
case 1:
	printf("1");
	break;
case 2:
	printf("2");
	break;
case 3:
	printf("3");
	break;
case 4:
	printf("4");
	break;
case 5:
	printf("5");
	break;
case 6:
	printf("6");
	break;
default:
	printf("Error");
	break;
}
}
 
int main(int argc, char* argv[]){
Function(5);
    return 0;
}

滴水逆向三期笔记与作业——02C语言——10 Switch语句反汇编_第14张图片

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

void Function(int x)
{
switch(x)
{
case 100:
	printf("100");
	break;
case 101:
	printf("101");
	break;
case 110:
	printf("110");
	break;
case 3:
	printf("3");
	break;
case 1:
	printf("1");
	break;
default:
	printf("Error");
	break;
}
}
int main(int argc, char* argv[]){
	Function(101);
    return 0;
}

我的是if/else结构,博客站中是大小表结构。

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

void Function(int i)
{
	do
	{
		printf("%d\n", i);
		i++;
	} while (i>3);
 
}
int main(int argc, char* argv[]){
	Function(0);
    return 0;
}

滴水逆向三期笔记与作业——02C语言——10 Switch语句反汇编_第15张图片

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

void Function(int i)
{
	while (i<3)
	{
		printf("%d\n", i);
		i++;
	}
 
}
int main(int argc, char* argv[]){
	Function(0);
    return 0;
}
 

滴水逆向三期笔记与作业——02C语言——10 Switch语句反汇编_第16张图片

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

void Function(int x)
{
	for (int i = 0; i < x; i++)
	{
		printf("%d\n", i);
	}
}
int main(int argc, char* argv[]){
	Function(5);
    return 0;
}
 

滴水逆向三期笔记与作业——02C语言——10 Switch语句反汇编_第17张图片

你可能感兴趣的:(滴水逆向学习笔记,笔记,滴水逆向)