滴水逆向三期笔记与作业——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;
}

在这里插入图片描述

由汇编可见,少分支的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;
}

在这里插入图片描述
未发现大表寻址过程

  • 多分支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;
}

在这里插入图片描述
存在大表寻址过程,已优化

  • 总结
    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;
}
  • 反汇编
    在这里插入图片描述

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

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

在这里插入图片描述

被删除的部分并不会被填充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;
}
  • 反汇编
    在这里插入图片描述
    与if/else相同,下图为海哥教程图
    在这里插入图片描述

二、do/while反汇编

1、do/while的语法

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

2、do/while的反汇编

在这里插入图片描述

3、example

在这里插入图片描述

4、总结

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

三、while反汇编

1、while语句的语法

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

2、while语句反汇编

在这里插入图片描述

3、example

在这里插入图片描述

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

在这里插入图片描述

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;
}

在这里插入图片描述

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;
}

在这里插入图片描述

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;
}

在这里插入图片描述

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

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

在这里插入图片描述

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;
}

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/434608.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java笔记 --- 二、Stream流

二、Stream流 结合Lambda表达式&#xff0c;简化集合、数组的操作 获取Stream流对象 单列集合获取Stream流 双列集合获取Stream流 数组获取Stream流 一堆零散的数据获取Stream流 Stream流的静态方法of的形参是一个可变参数&#xff0c;可以传递零散数据&#xff0c;也可以传递…

记录一道ctf web题

0x00 前言 某同学发在群里一道不知道什么ctf的web题 0x01 bypass open_basedir 开始没想那么多&#xff0c;看到了可以执行phpinfo&#xff0c;直接先eval一个一句话上去看看什么情况&#xff1a; 接着发现了没有权限去读取/var/www/html以外的目录&#xff0c;那么我开始想的…

基于51单片机智能电子秤

实物显示效果&#xff1a; https://www.bilibili.com/video/BV1Wb4y1A7Aw/?vd_source6ff7cd03af95cd504b60511ef9373a1d 功能介绍&#xff1a; &#xff08;1&#xff09;用键盘设计单价&#xff1b; &#xff08;2&#xff09;称重后同时显示该物品的重量、单价和总额&…

sqlx的初体验

sqlx的介绍和优点 sqlx 是一个用于 Go 语言的数据库工具&#xff0c;它在标准库的 database/sql 包的基础上提供了一些额外的功能&#xff0c;使得数据库操作更加方便和灵活。 优点&#xff1a; 查询构建器&#xff1a; sqlx 提供了更强大的查询构建器&#xff0c;使得在 Go…

Ubuntu添加AppImage到桌面及应用程序菜单

将AppImage添加到桌面&#xff0c;以PicGo为例 效果&#xff1a; 在桌面创建PicGo.desktop文件&#xff0c;输入以下内容&#xff1a; [Desktop Entry] EncodingUTF-8 TypeApplication #应用名称 NamePicGo #图标路径 Icon/usr/local/AppImage/icons/PicGo.png #启动是否开启…

通俗易懂理解FCN全卷积网络模型

温故而知新&#xff0c;可以为师矣&#xff01; 一、参考资料 深度学习笔记&#xff08;二十三&#xff09;Semantic Segmentation(FCN/U-Net/PSPNet/SegNet/U-Net/ICNet/DFANet/Fast-SCNN) 二、FCN相关介绍 1. FCN简介 全卷积神经网络(Fully Convolutional Networks, 简称…

MySQL-删除重复数据

在实际应用中&#xff0c;遇到一个这样的问题&#xff0c;MySQL中存储的数据为资讯类数据&#xff0c;在页面展示时会出现多个平台的新闻报导相同的内容&#xff0c;导致页面会出现重复数据。因为数据是每天定期更新&#xff0c;所以最快捷有效的方式是在更新完数据后增加一个去…

$monitor和$strobe都看的是啥

注&#xff1a;本文来自硅芯思见 在编写测试平时&#xff0c;经常会用到$monitor和$strobe监测某些信号&#xff0c;并且使用格式上与$display比较类似&#xff0c;但是它们之间还是存在差异的&#xff0c;它们在当前仿真时间槽&#xff08;time-slot&#xff09;中被执行的区间…

【保姆级教程】Windows11安装go-zero代码生成工具goctl、protoc、go-zero

【保姆级教程】Windows11安装go-zero代码生成工具goctl、protoc、go-zero 大家好 我是寸铁&#x1f44a; 总结了一篇Windows11安装go-zero代码生成工具goctl的文章✨ 喜欢的小伙伴可以点点关注 &#x1f49d; goctl介绍 背景&#xff1a;goctl 的最早功能是为了解决 GRPC 内网…

leetcode:1768. 交替合并字符串(python3解法)

难度&#xff1a;简单 给你两个字符串 word1 和 word2 。请你从 word1 开始&#xff0c;通过交替添加字母来合并字符串。如果一个字符串比另一个字符串长&#xff0c;就将多出来的字母追加到合并后字符串的末尾。 返回 合并后的字符串 。 示例 1&#xff1a; 输入&#xff1a;w…

一些反序列化总结

1 反序列化漏洞原理 如果反序列化的内容就是那串字符串&#xff0c;是用户可以控制的&#xff08;即变量的值&#xff09;&#xff0c;且后台不正当的使用了PHP中的魔法函数&#xff0c;就会导致反序列化漏洞&#xff0c;可以执行任意命令。Java 序列化指 Java 对象转换为字节序…

迷人的数据结构:揭秘数组和链表的不同

数据结构中的数组和链表的区别 一、简介二、数组的特点和特性三、链表的特点和特性四、数组和链表的对比五、数组和链表的代码实现六、总结 一、简介 数据结构是组织和存储数据的方式&#xff0c;直接影响着程序性能、内存利用和资源管理等关键方面。 数据结构提供了各种方法来…