CSAPP - 流程化的人工反汇编 string_length, strings_not_equal

文章目录

    • 反汇编的流程
    • string_length 的反汇编,第二次尝试
    • strings_not_equal 反汇编,第二次尝试
    • 一些“定式”的整理
      • 定式1: cmp 和 je/jne
      • 定式2:test A,A 和 je/jne

反汇编的流程

依然是 CSAPP bomblab phase_1 的小白视角的理解。先前已经根据汇编代码,手工翻译到了C代码,但是步骤上显得很吃力。为什么呢?汇编代码比较短的时候(比如10行之内),能够记住每个寄存器的值; 汇编代码超过10行时,很容易忘记每个寄存器里的值。虽然可以用注释的方式,把变量和寄存器名字绑定起来,但是每翻译一小段汇编代码后,就需要更新对应的C代码,过于繁琐了。例如 strings_not_equal 大概分成了10小段汇编代码。而且这个划分未必是合理的,还容易漏掉内容。

本篇则是前面两篇的尝试手工反汇编的重构版本: 使用了标准的4个步骤,让反汇编变得容易:

  • 先获取汇编代码
  • 在汇编代码上,以注释的形式,逐句翻译为C代码,期间会多次写出goto,也就是 je,jne,jmp 这些的跳转
  • 抄写注释里写出的C代码,并增加用到了的 label,使得 goto 能正确跳转。此时也许直接用C编译器编译,能编译通过
  • 消除goto和label:可能有很多goto,可以分两次、三次消除
  • 简化代码: 在消除 goto 的时候, 对于 for 循环、while循环的原始C代码,一定会看到重复代码,可能上一步没消除干净,这一步处理掉

string_length 的反汇编,第二次尝试

第0步: 打开 gdb, 查看函数汇编代码:

gdb bomb
(gdb) disas string_length

第1步: 复制汇编代码到文本文件,在汇编代码右侧,逐句写出对应的C代码

Dump of assembler code for function string_length:                  // int string_length(char* str)0x000000000040131b <+0>:     cmp    BYTE PTR [rdi],0x0           // if (*str==0)0x000000000040131e <+3>:     je     0x401332 <string_length+23>  //    goto label230x0000000000401320 <+5>:     mov    rdx,rdi                      // char* p = str;0x0000000000401323 <+8>:     add    rdx,0x1                      // p += 1;0x0000000000401327 <+12>:    mov    eax,edx                      // int ret = p;0x0000000000401329 <+14>:    sub    eax,edi                      // ret = ret - str;0x000000000040132b <+16>:    cmp    BYTE PTR [rdx],0x0           // if (!(*p == 0))0x000000000040132e <+19>:    jne    0x401323 <string_length+8>   //      goto label80x0000000000401330 <+21>:    repz ret                            // return ret0x0000000000401332 <+23>:    mov    eax,0x0                      // ret = 00x0000000000401337 <+28>:    ret                                 // return ret

第2步:抄写C代码,并且添加用到的label,这些 label 是 goto 的目的位置

int string_length(char* str)
{if (*str == 0){goto label23;}char* p = str;
label8:p += 1;int ret = p - str;if (*p != 0){goto label8;}return ret;
label23:ret = 0;return ret;
}

第3步:消除 goto 和 label:

int string_length(char* str)
{if (*str == 0){return 0;}char* p = str;while (true){p += 1;int ret = p - str;if (*p == 0){return ret;}}
}

第4步: 消除冗余C代码

int string_length(char* str)
{if (*str == 0){return 0;}char* p = str;int ret = 1;while (true){p += 1;ret = p - str;if (*p == 0){break;}}return ret;
}

第5步: 消除冗余C代码

int string_length(char* str)
{for (char* p = str; ; p++){int ret = p - str;if (*p == 0){return ret;}}
}

strings_not_equal 反汇编,第二次尝试

第0步: gdb 加载可执行文件, 使用 disas 命令查看反汇编代码。

gdb bomb
(gdb) disas strings_not_equal:

第1步: 在汇编代码右侧,逐句写出对应的C代码:

Dump of assembler code for function strings_not_equal:                  //  int strings_not_equal(const char* s1, const char* s2) {0x0000000000401338 <+0>:     push   r12                              //0x000000000040133a <+2>:     push   rbp                              //0x000000000040133b <+3>:     push   rbx                              //0x000000000040133c <+4>:     mov    rbx,rdi                          //  char* p1 = s1;    根据后面 BYTE PTR 能确定类型是 char*0x000000000040133f <+7>:     mov    rbp,rsi                          //  char* p2 = s2;0x0000000000401342 <+10>:    call   0x40131b <string_length>         //  int len1 = string_length(s1);0x0000000000401347 <+15>:    mov    r12d,eax                         //0x000000000040134a <+18>:    mov    rdi,rbp                          //  char* p = s2;0x000000000040134d <+21>:    call   0x40131b <string_length>         //  int len2 = string_length(p);0x0000000000401352 <+26>:    mov    edx,0x1                          //  int ret = 1;0x0000000000401357 <+31>:    cmp    r12d,eax                         //  if (len1 != len2)0x000000000040135a <+34>:    jne    0x40139b <strings_not_equal+99>  //      goto label990x000000000040135c <+36>:    movzx  eax,BYTE PTR [rbx]               //  char c1 = *p1;0x000000000040135f <+39>:    test   al,al                            //  if (c1 == '\0')0x0000000000401361 <+41>:    je     0x401388 <strings_not_equal+80>  //      goto label800x0000000000401363 <+43>:    cmp    al,BYTE PTR [rbp+0x0]            //  if (c1 == *p2)0x0000000000401366 <+46>:    je     0x401372 <strings_not_equal+58>  //      goto label580x0000000000401368 <+48>:    jmp    0x40138f <strings_not_equal+87>  //  goto label870x000000000040136a <+50>:    cmp    al,BYTE PTR [rbp+0x0]            //  if (c1 != *p2)0x000000000040136d <+53>:    nop    DWORD PTR [rax]                  //0x0000000000401370 <+56>:    jne    0x401396 <strings_not_equal+94>  //      goto label940x0000000000401372 <+58>:    add    rbx,0x1                          //  p1++;0x0000000000401376 <+62>:    add    rbp,0x1                          //  p2++;0x000000000040137a <+66>:    movzx  eax,BYTE PTR [rbx]               //  c1 = *p1;0x000000000040137d <+69>:    test   al,al                            //  if (c1 != '\0')0x000000000040137f <+71>:    jne    0x40136a <strings_not_equal+50>  //      goto label500x0000000000401381 <+73>:    mov    edx,0x0                          //  ret = 00x0000000000401386 <+78>:    jmp    0x40139b <strings_not_equal+99>  //  goto label990x0000000000401388 <+80>:    mov    edx,0x0                          //  ret = 00x000000000040138d <+85>:    jmp    0x40139b <strings_not_equal+99>  //  goto label990x000000000040138f <+87>:    mov    edx,0x1                          //  ret = 10x0000000000401394 <+92>:    jmp    0x40139b <strings_not_equal+99>  //  goto label990x0000000000401396 <+94>:    mov    edx,0x1                          //  ret = 10x000000000040139b <+99>:    mov    eax,edx                          //  return ret0x000000000040139d <+101>:   pop    rbx0x000000000040139e <+102>:   pop    rbp0x000000000040139f <+103>:   pop    r120x00000000004013a1 <+105>:   ret

第2步: 逐句抄写 C 代码, 并且添加对应的 label, 用于 goto:

int strings_not_equal(const char* s1, const char* s2)
{char* p1 = s1;char* p2 = s2;int len1 = string_length(s1);int len2 = string_length(s2);int ret = 1;if (len1 != len2){goto label99}char c1 = *p1;if (c1 =='\0'){goto label80;}if (c1 == *p2){goto label58;}else{goto label87;}
label50:if (c1 != *p2){goto label94;}
label58:p1++;p2++;c1 = *p1;if (c1 != '\0')goto label50ret = 0;goto label99;label80:ret = 0;goto label99;
label87:ret = 1;goto label99;
label94:ret = 1;goto label99;label99:return ret;
}

第3步: 消除用于返回返回值的 goto:

int strings_not_equal(const char* s1, const char* s2)
{char* p1 = s1;char* p2 = s2;int len1 = string_length(s1);int len2 = string_length(s2);if (len1 != len2){return 1;}char c1 = *p1;if (c1 =='\0'){return 0;}if (c1 == *p2){goto label58;}else{return 1;}
label50:if (c1 != *p2){return 1;}
label58:p1++;p2++;c1 = *p1;if (c1 != '\0')goto label50return 0;
}

第4步: 消除最后的 goto, 消除重复代码, 转为 while 循环:

int strings_not_equal(const char* s1, const char* s2)
{char* p1 = s1;char* p2 = s2;int len1 = string_length(s1);int len2 = string_length(s2);if (len1 != len2){return 1;}while (true){char c1 = *p1;if (c1 =='\0'){return 0;}if (c1 != *p2){return 1;}p1++;p2++;}
}

一些“定式”的整理

围棋里有定式。反汇编也有定式。

定式1: cmp 和 je/jne

cmp + je: if( A == B) goto C

   0x000000000040131b <+0>:     cmp    BYTE PTR [rdi],0x0           // if (*str==0)0x000000000040131e <+3>:     je     0x401332 <string_length+23>  //    goto label23

cmp + jne: if (A != B) goto C

   0x000000000040132b <+16>:    cmp    BYTE PTR [rdx],0x0           // if (!(*p == 0))0x000000000040132e <+19>:    jne    0x401323 <string_length+8>   //      goto label8

更多例子:

   0x0000000000401357 <+31>:    cmp    r12d,eax                         //  if (len1 != len2)0x000000000040135a <+34>:    jne    0x40139b <strings_not_equal+99>  //      goto label99
   0x0000000000401363 <+43>:    cmp    al,BYTE PTR [rbp+0x0]            //  if (c1 == *p2)0x0000000000401366 <+46>:    je     0x401372 <strings_not_equal+58>  //      goto label58
   0x0000000000401368 <+48>:    jmp    0x40138f <strings_not_equal+87>  //  goto label870x000000000040136a <+50>:    cmp    al,BYTE PTR [rbp+0x0]            //  if (c1 != *p2)
   0x000000000040136a <+50>:    cmp    al,BYTE PTR [rbp+0x0]            //  if (c1 != *p2)0x000000000040136d <+53>:    nop    DWORD PTR [rax]                  //0x0000000000401370 <+56>:    jne    0x401396 <strings_not_equal+94>  //      goto label94

定式2:test A,A 和 je/jne

test A,A + je: if (A == 0) goto B

   0x000000000040135f <+39>:    test   al,al                            //  if (c1 == '\0')0x0000000000401361 <+41>:    je     0x401388 <strings_not_equal+80>  //      goto label80

test A, A + jne: if (A != 0) goto B

   0x000000000040137d <+69>:    test   al,al                            //  if (c1 != '\0')0x000000000040137f <+71>:    jne    0x40136a <strings_not_equal+50>  //      goto label50

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

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

相关文章

c# ref和out参数修饰符

ref&#xff1a;把值类型变成引用类型传递&#xff0c;形参的值改变了实参的值也会改变 public static int findMax(ref int num1, ref int num2){num1 * 2;num2 * 2;return num1 num2;}private static void Main(string[] args){int a1 1; int a2 2;findMax(ref a1, ref a2…

什么是算法的空间复杂度?

一、问题 常常⽤算法的空间复杂度来评价算法的性能&#xff0c;那么什么是算法的空间复杂度呢&#xff1f; 二、解答 算法的空间复杂度是指在算法的执⾏过程中&#xff0c;需要的辅助空间数量。 辅助空间数量指的不是程序指令、常数、指针等所需要的存储空间&#xff0c;也不是…

Pandas实战100例 | 案例 41: 字符串操作

案例 41: 字符串操作 知识点讲解 Pandas 提供了强大的字符串处理功能&#xff0c;这些功能类似于 Python 的标准字符串方法。你可以对 DataFrame 中的字符串数据执行各种操作&#xff0c;如分割、提取、计算长度等。 字符串分割: 使用 str.split() 分割字符串。提取字符串: …

【面试合集】1.说说你对微信小程序的理解?优缺点?

面试官&#xff1a;说说你对微信小程序的理解&#xff1f;优缺点&#xff1f; 一、是什么 2017年&#xff0c;微信正式推出了小程序&#xff0c;允许外部开发者在微信内部运行自己的代码&#xff0c;开展业务 截至目前&#xff0c;小程序已经成为国内前端的一个重要业务&…

NPM进阶知识与用法详解(二)

文章目录 一、NPM高级用法1. NPM模块发布与私有模块管理2. NPM钩子函数3. NPM包管理与优化 二、NPM与现代化前端工具链1. NPM与Yarn、PNPM的比较2. NPM在Webpack、Vite等构建工具中的应用3. NPM与Monorepo架构 三、总结与展望1. 前端包管理工具发展趋势2. 提高NPM使用效率的建议…

从传统到智能:机器视觉检测赋能PCB行业数字化转型!

PCB板在现代电子设备中是一个重要的组成部分&#xff0c;它是用来集成各种电子元器件的信息载体。在电子领域中&#xff0c;PCB板有着广泛的应用&#xff0c;而它的质量直接影响到产品的性能。随着电子科技技术和电子制造业的发展&#xff0c;贴片元器件的体积 变小&#xff0c…

AOSP 编译

AOSP清华镜像站 [2023-11-21 20:44:21] 内存太小导致编译失败&#xff0c;这里通过删除原来的 swap 然后创建更大的 swap 来解决 # 首先关闭并删除现存的 swap sudo swapoff /swapfile sudo rm /swapfile# 创建新 swap sudo dd if/dev/zero of/swapfile bs1G count32 sudo c…

亚马逊怎么防止店铺关联?

亚马逊&#xff08;Amazon&#xff09;为了确保公平竞争和防止不当行为&#xff0c;采取了一些措施来防止店铺关联&#xff0c;即通过不同的方式将多个店铺相关联&#xff0c;以获取不正当的竞争优势。以下是一些亚马逊防止店铺关联的主要措施&#xff1a; 同一经营者规定&…

在Anaconda(conda)(命令行/Linux )中新建环境安装python版本,删除环境等

1.在命令行终端新建conda环境 例如新建一个叫love的环境 在Windows的Anaconda Prompt 或 macOS/Linux的终端输入 conda create -n love python3.102.激活环境 conda activate love注&#xff1a;运行conda activate则直接激活anaconda的base环境 3.退出环境 conda deactiva…

VMware workstation搭建与安装AlmaLinux-9.2虚拟机

VMware workstation搭建与安装AlmaLinux-9.2虚拟机 适用于需要在VMware workstation平台安装AlmaLinux-9.2&#xff08;最小化安装、无图形化界面&#xff09;虚拟机。 1. 安装准备 1.1 安装平台 Windows 11 1.2. 软件信息 软件名称软件版本安装路径VMware-workstation 1…

openssl3.2 - 官方demo学习 - client-arg.c

文章目录 openssl3.2 - 官方demo学习 - client-arg.c笔记client-arg.cEND openssl3.2 - 官方demo学习 - client-arg.c 笔记 client-arg.c /*! \file client-argc. *//*! * \noteadd _CRT_SECURE_NO_WARNINGS to VS2019 option *//** Copyright 2013-2023 The OpenSSL Proj…

Pandas实战100例 | 案例 42: 数据过滤

案例 42: 数据过滤 知识点讲解 数据过滤是数据处理中的一个基本任务。在 Pandas 中&#xff0c;你可以使用布尔索引来过滤符合特定条件的数据行。 数据过滤: 通过结合条件表达式&#xff08;例如 df[A] > 2 和 df[B] < 5&#xff09;&#xff0c;可以创建一个布尔索引…

vue3 源码解析(4)— createApp 源码的实现

前言 本文是 vue3 源码分析系列的第四篇文章&#xff0c;在使用 vue3 时&#xff0c;我们需要使用 createApp 来创建一个应用实例&#xff0c;然后使用 mount 方法将应用挂载到某个DOM节点上。那么在调用 createApp 时&#xff0c;vue 再背后做了些什么事情呢&#xff1f;在这…

类和对象---C++

类和对象目录 类和对象1.封装1.1 封装的意义1.2 struct和class区别1.3 成员属性设置为私有1.3.1 联系---判断圆和点的位置关系 2.对象的初始化和清理2.1 构造函数和析构函数2.2 构造函数的分类及调用2.2.1无参构造函数调用2.2.2有参构造函数调用2.2.2.1括号法2.2.2.2显式法2.2.…

微信小程序快速入门02(含案例)

&#x1f3e1;浩泽学编程&#xff1a;个人主页 &#x1f525; 推荐专栏&#xff1a;《深入浅出SpringBoot》《java项目分享》 《RabbitMQ》《Spring》《SpringMVC》 &#x1f6f8;学无止境&#xff0c;不骄不躁&#xff0c;知行合一 文章目录 前言一、页面导航1.…

互联网资讯精选:科技爱好者周刊 | 开源日报 No.145

ruanyf/weekly Stars: 37.4k License: NOASSERTION 记录每周值得分享的科技内容&#xff0c;提供大量就业信息。欢迎投稿、推荐或自荐文章/软件/资源&#xff0c;并可通过多种方式进行搜索。 提供丰富的科技内容每周更新可以提交工作/实习岗位支持投稿和推荐功能 GyulyVGC/…

bootloader学习笔记及SD卡启动盘制作

Bootloader介绍 在操作系统运行之前运行的一小段代码&#xff0c;用于将软硬件环境初始化到一个合适的状态&#xff0c;为操作系统的加载和运行做准备&#xff08;其本身不是操作系统&#xff09; Bootloader基本功能 1、初始化软硬件环境 2、引导加载linux内核 3、给linux…

一个无敌的 Python 文件系统监控库

在软件开发和系统管理领域&#xff0c;经常需要监控文件和目录的变化&#xff0c;以便在文件被创建、修改或删除时触发相应的操作。Python Watchdog是一个强大的Python库&#xff0c;它提供了简单而灵活的方式来监控文件系统的变化。本文将详细介绍Python Watchdog的用法和功能…

旅游数据可视化大屏:一屏掌控,畅游数据之海

随着旅游业的蓬勃发展&#xff0c;如何有效地管理和分析旅游数据成为行业关注的焦点。旅游数据可视化大屏作为一种新兴的技术手段&#xff0c;为旅游业带来了前所未有的机遇和挑战。 旅游数据可视化大屏集成了丰富的数据资源&#xff0c;通过直观的图表、图像和交互界面&#x…

慢 SQL 的优化思路

分析慢 SQL 如何定位慢 SQL 呢&#xff1f; 可以通过 slow log 来查看慢SQL&#xff0c;默认的情况下&#xff0c;MySQL 数据库是不开启慢查询日志&#xff08;slow query log&#xff09;。所以我们需要手动把它打开。 查看下慢查询日志配置&#xff0c;我们可以使用 show …