CSAPP - 保持好奇,反汇编 initialize_bomb()

CSAPP - 保持好奇,反汇编 initialize_bomb()

相比于直接看 bomblab phase_1 的答案,我更想搞懂答案之外涉及的每个函数的反汇编 - 反正是一个实验,代码能复杂到哪里去? 而搞懂这些函数, 无疑对于实际工程中的各种 debug 问题, 能补全基本的 gdb 调试技能。这一篇是分析 initialize_bomb() 函数.

好奇 - Ctrl-C 被接管了?

查看 bomb.c 可以看到,除了读取文件、打印提示信息,在 phase_1() 之前还做了一件事:初始化 bomb:

int main()
{.../* Do all sorts of secret stuff that makes the bomb harder to defuse. */initialize_bomb(); // 好奇这里read_line();phase_1();...
}

如果是第一次运行 bomb, 输入字符串后希望临时退出, 会发现 Ctrl+C 并不能立即退出。原因是 initialize_bomb() 里使用了信号量,捕获了 Ctrl+C。 当然,这是一个猜测,需要从汇编代码验证。 和上一篇的方式一样,先获取汇编代码, 再逐句翻译, 随后整理和简化C代码。

反汇编 initialize_bomb() - 翻译出来了,但是很懵

(gdb) disassemble initialize_bomb
Dump of assembler code for function initialize_bomb:         // void initialize_bomb() {0x00000000004013a2 <+0>:     sub    rsp,0x8               //0x00000000004013a6 <+4>:     mov    esi,0x4012a0          // void* p2 = 0x4012a0;0x00000000004013ab <+9>:     mov    edi,0x2               // int p1 = 2;0x00000000004013b0 <+14>:    call   0x400b90 <signal@plt> // signal(p1, p2);0x00000000004013b5 <+19>:    add    rsp,0x8               //0x00000000004013b9 <+23>:    ret                          // }
End of assembler dump.

于是踉踉跄跄的写出 C 代码:

void initialize_bomb()
{void* p2 = 0x4012a0;signal(2, p2);
}

其中 void* p2 = 0x4012a0 让人费解, 需要结合 signal 的函数原型分析:

man signalNAMEsignal - ANSI C signal handlingSYNOPSIS#include <signal.h>typedef void (*sighandler_t)(int);sighandler_t signal(int signum, sighandler_t handler);

可以发现, signal() 第二个参数是一个函数指针, 对应到 initialize_bomb() 函数中, 0x4012a0 是这个函数指针的值, 查看其汇编代码:

神奇的 0x4012a0 - 来反汇编吧!

(gdb) disassemble 0x4012a0
Dump of assembler code for function sig_handler:                    // sig_handler() {0x00000000004012a0 <+0>:     sub    rsp,0x8                      //0x00000000004012a4 <+4>:     mov    edi,0x4024c0                 // const char* p1 = (char*)0x4024c0; , 用 x /s 查看知道是 "So you think you can stop the bomb with ctrl-c, do you?"0x00000000004012a9 <+9>:     call   0x400b10 <puts@plt>          // puts(p1);0x00000000004012ae <+14>:    mov    edi,0x3                      // int p2 = 3;0x00000000004012b3 <+19>:    call   0x400c50 <sleep@plt>         // sleep(p2);0x00000000004012b8 <+24>:    mov    esi,0x402582                 // int p3 = 0x402582;    0x402582 值为 "Well..."0x00000000004012bd <+29>:    mov    edi,0x1                      // int p4 = 1;0x00000000004012c2 <+34>:    mov    eax,0x0                      // int ret = 0;0x00000000004012c7 <+39>:    call   0x400c00 <__printf_chk@plt>  // __printf_chk(p4, p3);  __printf_chk 是 printf 的安全版本,会检查格式字符串有效性0x00000000004012cc <+44>:    mov    rdi,QWORD PTR [rip+0x20246d]        # 0x603740 <stdout@@GLIBC_2.2.5>0x00000000004012d3 <+51>:    call   0x400be0 <fflush@plt>        // fflush(stdou);0x00000000004012d8 <+56>:    mov    edi,0x1                      // int p5 = 1;0x00000000004012dd <+61>:    call   0x400c50 <sleep@plt>         // sleep(p5);0x00000000004012e2 <+66>:    mov    edi,0x40258a                 // const char* p6 = (char*)0x40258a; "OK. :-)"0x00000000004012e7 <+71>:    call   0x400b10 <puts@plt>          // puts(p6);0x00000000004012ec <+76>:    mov    edi,0x10                     // int p7 = 16;0x00000000004012f1 <+81>:    call   0x400c20 <exit@plt>          // exit(p7);   // 返回16
End of assembler dump.

这段代码,相比于 phase_1 本身的代码,有意思的多。

首先我们验证, 当启动 bomb 程序后,输入 Ctrl+C, 并等待5秒左右,是否会退出,返回值是什么:

zz@Legion-R7000P% ./bomb
Welcome to my fiendish little bomb. You have 6 phases with
which to blow yourself up. Have a nice day!
^CSo you think you can stop the bomb with ctrl-c, do you?
Well...OK. :-)
zz@Legion-R7000P% echo $?
16

返回值的确是16,和直接从汇编代码看到的一致。

对应的C代码,整理一下:

void sig_handler(int )
{puts("So you think you can stop the bomb with ctrl-c, do you?");sleep(3);printf("Well...");fflush(stdout);sleep(1);puts("OK. :-)");exit(16);
}void initialize_bomb()
{signal(2, sig_handler);
}

验证 - 捕获 Ctrl-C, 是这么玩的吗?

首先拿出这几次反汇编中,人工写出的C代码:

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <unistd.h>
#include <signal.h>int string_length(const char* str)
{for (const char* p = str; ; p++){int ret = p - str;if (*p == 0){return ret;}}
}int strings_not_equal(const char* s1, const char* s2)
{const char* p1 = s1;const 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++;}
}void sig_handler(int)
{puts("So you think you can stop the bomb with ctrl-c, do you?");sleep(3);printf("Well...");fflush(stdout);sleep(1);puts("OK. :-)");exit(16);
}void initialize_bomb()
{signal(2, sig_handler);
}

然后添加一小段调用代码, 也就是 main() 函数: 每隔1秒打印一个 hello world N, N 是递增的数字。 而在打印 hello world N 的过程中, 如果按下了 Ctrl+C, 就会捕获到信号,打印出和 bomblab 一样的输出,并最终结束:

int main()
{initialize_bomb();int i = 0;while (true){printf("hello world, %d\n", i);i += 1;sleep(1);}return 0;
}

运行一下, 的确如此, 就是这么玩的:

zz@Legion-R7000P% gcc test.c
zz@Legion-R7000P% ./a.out
hello world, 0
hello world, 1
hello world, 2
^CSo you think you can stop the bomb with ctrl-c, do you?
Well...OK. :-)

总结

  1. 保持好奇, 保持一定可以搞清楚的信念, 汇编之下, 了无秘密。
  2. x /s 0x4024c0 命令再次被使用,使用了好几次, gdb 命令得到了强化
  3. 看到往 rsi 寄存器(函数第二个参数)存入莫名奇妙的数字,不要慌,它就是一个函数的地址, 照常去 disas 它,没有难度, sig_handler() 很简单
  4. printf 和 __printf_chk, 这里确实是可以忽略和猜测的函数
  5. 整理好每一个反汇编出来的函数, 然后按自己想法,添加 main 函数去验证, bomb lab 的神秘性一点一点被拨开。

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

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

相关文章

每日一题——LeetCode1160.拼写单词

方法一 个人方法&#xff1a; 先统计chars里每个字符出现的次数&#xff0c;再对words里每个字符串统计每个字符出现的字符&#xff0c;当&#xff1a; 1、字符串里出现chars里没有的字符 2、字符串里某个字符出现的次数大于该字符在chars里出现的次数 以上两种情况则不符合…

基于微信小程序的音乐平台 开源项目

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块三、系统展示 四、核心代码4.1 查询单首音乐4.2 新增音乐4.3 新增音乐订单4.4 查询音乐订单4.5 新增音乐收藏 五、免责说明 一、摘要 1.1 项目介绍 基于微信小程序JAVAVueSpringBootMySQL的音乐平台&#xff0c;包含了音乐…

【MIT 6.S081】2020, 实验记录(3),Lab: page tables

目录 TaskTask 1: Print a page table Task Task 1: Print a page table 该实验需要增加一个 vmprint 函数&#xff0c;用于打印一个 page table&#xff0c;实现过程可以参考 vm.c 文件中的 freewalk() 函数。 在 defs.h 中增加 vmprint 的定义&#xff1a; void …

宝塔安装redis并且远程连接redis教程

第一步&#xff1a;搜索redis并安装 第二步&#xff1a;在防火墙添加端口6379 第三步&#xff1a;查看宝塔防火墙是否开启了6379端口 firewall-cmd --zonepublic --list-ports 很显然并没有开启 第四步&#xff1a;开启防火墙的6379端口 firewall-cmd --zonepublic --add-po…

Unity中URP下实现能量罩(性能优化 和 BRP适配)

文章目录 前言一、性能优化1、尽可能减少纹理采样次数2、 尽量把 max函数 换成 saturate函数,可以减少一次GPU指令3、尽可能的把计算移到顶点着色器4、变体优化5、变量放入 常量缓冲区二、BuideIn Render Pipeline适配1、C#脚本开启摄像机深度图2、CG语言适配三、最终效果和代…

【python】搭配Miniconda使用VSCode

现在的spyder总是运行出错&#xff0c;启动不了&#xff0c;尝试使用VSCode。 一、在VSCode中使用Miniconda管理的Python环境&#xff0c;可以按照以下步骤进行&#xff1a; a. 确保Miniconda环境已经安装并且正确配置。 b. 打开VSCode&#xff0c;安装Python扩展。 打开VS…

linux软件安装(yum命令)

1.Linux系统的应用商店 操作系统安装软件有许多种方式&#xff0c;一般分为&#xff1a; 下载安装包自行安装 如win系统使用exe文件、msi文件等如mac系统使用dmg文件、pkg文件等 系统的应用商店内安装 如win系统有Microsoft Store商店如mac系统有AppStore商店 Linux命令行…

qt学习:多界面跳转+信号+槽函数

目录 概念 分类 多界面编程思路 新建界面 注意 头文件 无数据传输跳转界面 有数据传输跳转界面 对象公有接口 界面之间数据传输 信号与槽函数进行数据传输跳转界面 信号: 槽: 概念 格式1 关联信号和发送信号 格式2 通信步骤 自定义信号和槽函数 总结 实…

精彩手绘全解:RAG技术,从入门到精通

本文整理自IVAN ILIN发布于Towards AI的博客[1]。感谢作者的精彩讲解。 深度学习自然语言处理 分享整理&#xff1a;Winnie 引言 检索增强生成&#xff08;Retrieval Augmented Generation&#xff0c;简称RAG&#xff09;为大型语言模型&#xff08;LLMs&#xff09;提供了从某…

绘图工具用的好,头发掉的少

程序员不管是在学习&#xff0c;还是工作过程中&#xff0c;很多时候都需要画图&#xff0c;如产品分析、架构设计、方案选型等&#xff0c;良好的绘图不仅可以让绘图者的思路清晰&#xff0c;也可以让聆听者更好的理解。用好画图&#xff0c;升职加薪少不了&#xff01;今天介…

C程序训练:与输入有关的错误

在录入程序时有时稍不注意就可能录入错误的字符导致程序运行结果出现错误&#xff0c;下面举例说明。 下面程序的运行结果是错的&#xff0c;但程序又没有错&#xff0c;到底问题出现在哪呢&#xff1f; #include <stdio.h> int main() {FILE *fp;int i, k, n;fpfopen(…

OceanBase 4.2特性解读:Show Trace全链路跟踪,助力快速问题定位与精准诊断

在分布式数据库环境下&#xff0c;慢 SQL 诊断是运维人员面临的一大挑战。在无法及时发现问题根本原因的情况下&#xff0c;可能会严重影响用户体验&#xff0c;甚至会导致业务服务不可用。相对于单机数据库&#xff0c;分布式数据库系统涉及多个节点、多组件的协同工作&#x…

Go语言认识

Go语言认识 1. Go语言的设计背景2. Go语言的历程3. Go语言对比分析4. Go语言未来的发展规划5. 要不要选择Go 关注 go博客 直接了解第一手资料。 go文档 了解go的全貌。 1. Go语言的设计背景 Go语言&#xff08;也称为Golang&#xff09;是由Google开发的一种编程语言。它的设计…

构建基于RHEL7(CentOS7)的OpenSSH9.5p1的RPM包和升级回退方案

本文适用&#xff1a;RHEL7系列&#xff0c;或同类系统(CentOS7等) 文档形成时期&#xff1a;2023年 因软件世界之复杂和个人能力之限&#xff0c;难免疏漏和错误&#xff0c;欢迎指正。 文章目录 环境准备安装依赖openssh-9.5p1-el7.spec内容构建RPM包下载安装前注意事项开启t…

SQL注入攻击

1.用java实现登录的检查 package jdbc1;import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.Statement; import java.util.Scanner;public class Login {public static void main(String args[]){try(Connection connec…

Redis管道操作

文章目录 1. 问题提出2. 解决方案3. 案例演示4. 总结 1. 问题提出 如何优化频繁命令往返造成的性能瓶颈&#xff1f; Redis是一种基于C/S一级请求响应协议的TCP服务&#xff0c;一个请求会遵循一下步骤&#xff1a; 客户端向服务端发送命令分四步&#xff08;发送命令-> …

教程视频二维码怎么做?扫码学习使用技巧

现在购买商品时经常会发现使用手册或者包装上会印有相关的二维码&#xff0c;扫码可以查看产品介绍或者使用说明的视频教学。将需要展示的内容放到二维码中&#xff0c;让用户能够通过扫码了解内容详情&#xff0c;有效的降低成本而且方便用户获取内容。 那么如果想要制作视频…

中科星图——Landsat9_C2_SR大气校正后的地表反射率数据

数据名称&#xff1a; Landsat9_C2_SR 数据来源&#xff1a; USGS 时空范围&#xff1a; 2022年1月-2023年3月 空间范围&#xff1a; 全国 数据简介&#xff1a; Landsat9_C2_SR数据集是经大气校正后的地表反射率数据&#xff0c;属于Collection2的二级数据产品&#…

linux |离线安装软件 | rpm命令

离线 安装包管理命令 rpm ##### #检查安装包是否认证成功 简单讲 来源是否可靠 rpm --checksig xxx.rpmrpm --checksig nmap-7.92-1.x86_64.rpm nmap-7.92-1.x86_64.rpm: sha1 md5 OK#### 安装前检验包的依赖库 rpm -qpR nmap-7.92-1.x86_64.rpm python > 2.4 rpmlib(Fil…

128基于matlab的粒子群优化算法寻找多元函数的最大值

基于matlab的粒子群优化算法寻找多元函数的最大值&#xff0c;可定义多元函数&#xff0c;变量区间范围&#xff0c;输出最大值条件下的变量值。程序已调通&#xff0c;可直接运行。 128matlab多元函数极值 (xiaohongshu.com)