CSAPP bomblab 作弊方式通关: gdb set 命令的使用

这篇具有很好参考价值的文章主要介绍了CSAPP bomblab 作弊方式通关: gdb set 命令的使用。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

bomblab 的博客、视频挺多的,但是步骤都太“友善”了。既然每次都是 explode_bomb 函数爆炸的,那么不执行这个函数不就完事儿了吗?这的确是“作弊”,但是我的目的不在于得到每一个 phase 的正确答案, 而是希望每个 phase 随便输入,但是仍然能通关。

一种方式是修改二进制文件 bomb, 我暂时不会。

另一种方式,是在 gdb 运行期间, 使用 set 命令修改 call explode_bomb 汇编指令为 nop 指令,那么程序就能继续往下运行, 而不是由于 explode_bomb() 中的 call exit 导致结束。本篇讲使用set的具体做法。

1. 最小例子

直接修改 call explode_bomb() 的过程,过于庞大。先弄懂这个简化的例子,其他都能搞定:

test2.c:

#include <stdio.h>
#include <stdlib.h>

static void die()
{
    printf("You lose\n");
    exit(1);
}

static void congrat()
{
    printf("You win!\n");
    return;
}

int main()
{
    die();
    congrat();
    return 0;
}

正常执行 test.c, 会看到 “You lose”。我们希望在gdb里做手脚,使得gdb里能够看到 “You Win!” 的输出。

关键命令:

set {char[5]}0x00005555555551b1={0x90,0x90,0x90,0x90,0x90}

完整命令

(gdb) start
Temporary breakpoint 1 at 0x11ac
Starting program: /home/zz/work/zcnn/csapp/bomblab/a.out
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Temporary breakpoint 1, 0x00005555555551ac in main ()
(gdb) disassemble
Dump of assembler code for function main:
   0x00005555555551a4 <+0>:     endbr64
   0x00005555555551a8 <+4>:     push   rbp
   0x00005555555551a9 <+5>:     mov    rbp,rsp
=> 0x00005555555551ac <+8>:     mov    eax,0x0
   0x00005555555551b1 <+13>:    call   0x555555555169 <die>
   0x00005555555551b6 <+18>:    mov    eax,0x0
   0x00005555555551bb <+23>:    call   0x55555555518a <congrat>
   0x00005555555551c0 <+28>:    mov    eax,0x0
   0x00005555555551c5 <+33>:    pop    rbp
   0x00005555555551c6 <+34>:    ret
End of assembler dump.
(gdb) ni
0x00005555555551b1 in main ()
(gdb) disassemble
Dump of assembler code for function main:
   0x00005555555551a4 <+0>:     endbr64
   0x00005555555551a8 <+4>:     push   rbp
   0x00005555555551a9 <+5>:     mov    rbp,rsp
   0x00005555555551ac <+8>:     mov    eax,0x0
=> 0x00005555555551b1 <+13>:    call   0x555555555169 <die>
   0x00005555555551b6 <+18>:    mov    eax,0x0
   0x00005555555551bb <+23>:    call   0x55555555518a <congrat>
   0x00005555555551c0 <+28>:    mov    eax,0x0
   0x00005555555551c5 <+33>:    pop    rbp
   0x00005555555551c6 <+34>:    ret
End of assembler dump.
(gdb) set {char[5]}0x00005555555551b1={0x90,0x90,0x90,0x90,0x90}
(gdb) disassemble
Dump of assembler code for function main:
   0x00005555555551a4 <+0>:     endbr64
   0x00005555555551a8 <+4>:     push   rbp
   0x00005555555551a9 <+5>:     mov    rbp,rsp
   0x00005555555551ac <+8>:     mov    eax,0x0
=> 0x00005555555551b1 <+13>:    nop
   0x00005555555551b2 <+14>:    nop
   0x00005555555551b3 <+15>:    nop
   0x00005555555551b4 <+16>:    nop
   0x00005555555551b5 <+17>:    nop
   0x00005555555551b6 <+18>:    mov    eax,0x0
   0x00005555555551bb <+23>:    call   0x55555555518a <congrat>
   0x00005555555551c0 <+28>:    mov    eax,0x0
   0x00005555555551c5 <+33>:    pop    rbp
   0x00005555555551c6 <+34>:    ret
End of assembler dump.
(gdb) c
Continuing.
You win!
[Inferior 1 (process 91783) exited normally]

2. 在 bomb 可执行文件上实验的记录

2.1 把 call explode_bomb 改为 nop

我们在 bomblab phase_1 上做实验。预期的效果是,随便输入一个字符串,例如 “hello”, 都能看到第一关通关后的提示:

Phase 1 defused. How about the next one?

具体做法:先通过反汇编找到 call explode_bomb 指令的地址,设定断点;然后运行程序, 在到达断点之前或刚刚到断点的地方时, 用 set 指令修改断点处的5个byte的内存,全都改为nop。

设置断点

(gdb) disassemble phase_1
Dump of assembler code for function phase_1:
   0x0000000000400ee0 <+0>:     sub    rsp,0x8
   0x0000000000400ee4 <+4>:     mov    esi,0x402400
   0x0000000000400ee9 <+9>:     call   0x401338 <strings_not_equal>
   0x0000000000400eee <+14>:    test   eax,eax
   0x0000000000400ef0 <+16>:    je     0x400ef7 <phase_1+23>
   0x0000000000400ef2 <+18>:    call   0x40143a <explode_bomb>
   0x0000000000400ef7 <+23>:    add    rsp,0x8
   0x0000000000400efb <+27>:    ret
End of assembler dump.
(gdb) b *0x400ef2
Breakpoint 1 at 0x400ef2

运行程序

(gdb) r
hello  # 这是phase_1()中执行read_line()时,输入的字符串

别小看这一步,不执行的话,直接执行后续的 set 命令会被提示修改无效

用set命令修改内存

(gdb) set {char[5]}0x0000000000400ef2 = {0x90, 0x90, 0x90, 0x90, 0x90}

在执行这一命令后,原本的 call 0x40143a <explode_bomb> 被替换为 nop。也就是,原来是:

=> 0x0000000000400ef2 <+18>:    call   0x40143a <explode_bomb>
   0x0000000000400ef7 <+23>:    add    rsp,0x8
   0x0000000000400efb <+27>:    ret

现在再执行 disassemble, 看到的是:

=> 0x0000000000400ef2 <+18>:    nop
   0x0000000000400ef3 <+19>:    nop
   0x0000000000400ef4 <+20>:    nop
   0x0000000000400ef5 <+21>:    nop
   0x0000000000400ef6 <+22>:    nop
   0x0000000000400ef7 <+23>:    add    rsp,0x8
   0x0000000000400efb <+27>:    ret

继续执行

(gdb) c
Continuing.
Phase 1 defused. How about the next one?

没错,看到了预期的输出,意思是“祝贺你通过了第一关”。

为什么是5个nop

因为 x86 架构中, call 指令的长度是确定的,是5个字节:1 个字节的操作码,后面跟着 4 个字节的偏移量。

例如,一个 call 指令可能看起来像这样(在机器码中):

E8 xx xx xx xx

其中 E8 是 call 指令的操作码,后面的 xx xx xx xx 是目标地址与下一条指令地址之间的偏移量。

也可以在 gdb 中检查:

(gdb) x /5xb 0x0000000000400ef2
0x400ef2 <phase_1+18>:  0xe8    0x43    0x05    0x00    0x00

其中 /5xb 的解释:

在 GDB 的 x 命令中,/5xb 是一个参数字符串,它指定了如何显示内存内容。下面是它的分解和解释:

x:这是 GDB 中的 "examine" 命令的简写,用于检查内存中的内容。

/:这是一个分隔符,用于分隔命令和其参数。

5:这个数字指定了要检查的单位数量。在这个例子中,它告诉 GDB 显示 5 个单位。

x:这是一个格式说明符,它告诉 GDB 以十六进制格式显示内存内容。在 GDB 中,x 用于十六进制,d 用于十进制,u 用于无符号十进制,t 用于二进制,o 用于八进制,a 用于地址,c 用于字符,f 用于浮点数,等等。

b:这是一个单位大小说明符,它告诉 GDB 每个单位应该是多大。在这个例子中,b 表示字节(byte)。其他选项包括 h(半字,halfword,通常是 2 字节),w(字,word,通常是 4 字节),g(巨字,giant word,通常是 8 字节)。

综合起来,x /5xb 命令告诉 GDB 以十六进制格式显示从指定地址开始的 5 个字节。这是在调试程序时检查内存内容的常用方法。

完整的gdb命令执行记录

(gdb) file bomb
Reading symbols from bomb...
(gdb) disassemble phase_1
Dump of assembler code for function phase_1:
   0x0000000000400ee0 <+0>:     sub    rsp,0x8
   0x0000000000400ee4 <+4>:     mov    esi,0x402400
   0x0000000000400ee9 <+9>:     call   0x401338 <strings_not_equal>
   0x0000000000400eee <+14>:    test   eax,eax
   0x0000000000400ef0 <+16>:    je     0x400ef7 <phase_1+23>
   0x0000000000400ef2 <+18>:    call   0x40143a <explode_bomb>
   0x0000000000400ef7 <+23>:    add    rsp,0x8
   0x0000000000400efb <+27>:    ret
End of assembler dump.
(gdb) b *0x0000000000400ef2
Breakpoint 1 at 0x400ef2
(gdb) c
The program is not being run.
(gdb) r
Starting program: /home/zz/work/zcnn/csapp/bomblab/bomb
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Welcome to my fiendish little bomb. You have 6 phases with
which to blow yourself up. Have a nice day!
hello

Breakpoint 1, 0x0000000000400ef2 in phase_1 ()
(gdb) disassemble
Dump of assembler code for function phase_1:
   0x0000000000400ee0 <+0>:     sub    rsp,0x8
   0x0000000000400ee4 <+4>:     mov    esi,0x402400
   0x0000000000400ee9 <+9>:     call   0x401338 <strings_not_equal>
   0x0000000000400eee <+14>:    test   eax,eax
   0x0000000000400ef0 <+16>:    je     0x400ef7 <phase_1+23>
=> 0x0000000000400ef2 <+18>:    call   0x40143a <explode_bomb>
   0x0000000000400ef7 <+23>:    add    rsp,0x8
   0x0000000000400efb <+27>:    ret
End of assembler dump.
(gdb) set {char[5]}0x0000000000400ef2 = {0x90, 0x90, 0x90, 0x90, 0x90}
(gdb) disassemble
Dump of assembler code for function phase_1:
   0x0000000000400ee0 <+0>:     sub    rsp,0x8
   0x0000000000400ee4 <+4>:     mov    esi,0x402400
   0x0000000000400ee9 <+9>:     call   0x401338 <strings_not_equal>
   0x0000000000400eee <+14>:    test   eax,eax
   0x0000000000400ef0 <+16>:    je     0x400ef7 <phase_1+23>
=> 0x0000000000400ef2 <+18>:    nop
   0x0000000000400ef3 <+19>:    nop
   0x0000000000400ef4 <+20>:    nop
   0x0000000000400ef5 <+21>:    nop
   0x0000000000400ef6 <+22>:    nop
   0x0000000000400ef7 <+23>:    add    rsp,0x8
   0x0000000000400efb <+27>:    ret
End of assembler dump.
(gdb) c
Continuing.
Phase 1 defused. How about the next one?

2.2 自动化上述打印断点+set修改call explode_bomb()为nop的过程

基本思路: 生成一个脚本 gdb_script.txt, gdb 启动时指定要执行这个脚本,gdb启动后先执行脚本中的内容,然后再按正常的程序一样去执行(此时用户可以交互式的输入、看到输出)。

关于 gdb_script.txt 的内容,是用 Python 脚本生成, 是在可执行程序 bomb 的反汇编代码中,找到所有的 call explode_bomb 语句,把这些语句所在的内存地址拿出来, 并对每个地址生成一句 set 指令来修改为5个 nop。此外,需要增加 start 指令, 使得 set 命令能够生效。

使用的 Python 脚本如下:

#!/usr/bin/env python3
import subprocess

# 替换为你的程序名和explode_bomb的确切名称
PROGRAM = "bomb"
EXPLODE_BOMB_FUNCTION = "explode_bomb"

# 使用 objdump 获取反汇编代码,并查找所有调用 explode_bomb 的行
cmd = f"objdump -d {PROGRAM} | grep 'call.*<{EXPLODE_BOMB_FUNCTION}>'"
result = subprocess.check_output(cmd, shell=True).decode('utf-8')

# 处理结果,移除地址后面的冒号,并添加 0x 前缀
gdb_commands = ["start"]  # Start the program and stop at the beginning of main
for line in result.strip().split('\n'):
    address = line.split()[0].rstrip(':')
    # Replace call instruction with 5 nops (assuming call instruction is 5 bytes)
    gdb_commands.append(f"set {{char[5]}}0x{address} = {{0x90, 0x90, 0x90, 0x90, 0x90}}")

# 将 GDB 命令写入 gdb_script.txt 文件
gdb_script = 'gdb_script.txt'
with open(gdb_script, 'w') as f:
    f.write('\n'.join(gdb_commands) + '\n')
    f.write('continue\n')  # Continue execution after setting breakpoints

print(f"GDB命令文件已生成:{gdb_script}")
print(f"在GDB中使用命令 'source {gdb_script}' 来设置断点并运行程序。")

生成的 gdb_script.txt:

start
set {char[5]}0x400ef2 = {0x90, 0x90, 0x90, 0x90, 0x90}
set {char[5]}0x400f10 = {0x90, 0x90, 0x90, 0x90, 0x90}
set {char[5]}0x400f20 = {0x90, 0x90, 0x90, 0x90, 0x90}
set {char[5]}0x400f65 = {0x90, 0x90, 0x90, 0x90, 0x90}
set {char[5]}0x400fad = {0x90, 0x90, 0x90, 0x90, 0x90}
set {char[5]}0x400fc4 = {0x90, 0x90, 0x90, 0x90, 0x90}
set {char[5]}0x401035 = {0x90, 0x90, 0x90, 0x90, 0x90}
set {char[5]}0x401058 = {0x90, 0x90, 0x90, 0x90, 0x90}
set {char[5]}0x401084 = {0x90, 0x90, 0x90, 0x90, 0x90}
set {char[5]}0x4010c6 = {0x90, 0x90, 0x90, 0x90, 0x90}
set {char[5]}0x401123 = {0x90, 0x90, 0x90, 0x90, 0x90}
set {char[5]}0x401140 = {0x90, 0x90, 0x90, 0x90, 0x90}
set {char[5]}0x4011e9 = {0x90, 0x90, 0x90, 0x90, 0x90}
set {char[5]}0x401267 = {0x90, 0x90, 0x90, 0x90, 0x90}
set {char[5]}0x40127d = {0x90, 0x90, 0x90, 0x90, 0x90}
set {char[5]}0x401494 = {0x90, 0x90, 0x90, 0x90, 0x90}
set {char[5]}0x401595 = {0x90, 0x90, 0x90, 0x90, 0x90}
continue

启动 gdb 程序的命令如下:

gdb -x gdb_script.txt ./bomb

程序执行结果: 前5关能顺序执行,第6关报告segment fault:

Temporary breakpoint 1, main (argc=1, argv=0x7fffffffd988) at bomb.c:37
37      {
Welcome to my fiendish little bomb. You have 6 phases with
which to blow yourself up. Have a nice day!
1
Phase 1 defused. How about the next one?
2
That's number 2.  Keep going!
3
Halfway there!
4
So you got that one.  Try this one.
5
Good work!  On to the next...
6

Program received signal SIGSEGV, Segmentation fault.
0x00000000004011c0 in phase_6 ()

其中每一关的输入,我只输入了一个数字。第6关失败是因为需要输入6个数字,我改为输入6个数字后就成功的“作弊”通关了:

Welcome to my fiendish little bomb. You have 6 phases with
which to blow yourself up. Have a nice day!
1
Phase 1 defused. How about the next one?
2
That's number 2.  Keep going!
3
Halfway there!
4
So you got that one.  Try this one.
5
Good work!  On to the next...
1 2 3 4 5 6
Congratulations! You've defused the bomb!
[Inferior 1 (process 84917) exited normally]

3. 总结

  1. 在调用某个函数的地方,设置断点

需要先根据汇编代码,找到 call explode_bomb 汇编指令对应的内存地址,例如地址是 0x400b10, 那么输入 break *0x400b10 来打断点。

而如果执行 break explode_bomb, 则是进入到了 explode_bomb 函数里的第一句,此时已经晚了,不能用 set 修改 call explode_bomb 为 nop 了

  1. 自动化执行 gdb 命令

gdb 可以被交互方式使用, 也可以把需要执行的命令, 提前准备好到一个文本中, 启动 gdb 时传入 -x xxx.txt 来启动:

gdb -x gdb_script.txt ./bomb
  1. gdb_script.txt 内容

set 命令是改内存, 需要先让程序启动, 最佳方式是先执行 start 命令, 会让程序加载进来,在main入口暂停

使用 Python 并结合 shell 命令, 相比于一水儿的 shell 命令, 代码虽然多了,但是更容易写出来。

  1. set 命令举例:把 call xxx 改为5个 nop:

set {char[5]}0x400ef2 = {0x90, 0x90, 0x90, 0x90, 0x90}文章来源地址https://www.toymoban.com/news/detail-803649.html

  1. 上述修改,是在 gdb 运行前、gdb 运行中修改的, 并不会修改可执行程序本身。

到了这里,关于CSAPP bomblab 作弊方式通关: gdb set 命令的使用的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【CSAPP】探究BombLab奥秘:Phase_6的解密与实战

    ​🌈个人主页: Sarapines Programmer 🔥 系列专栏: 《斯坦福大学之CSAPP》 ⏰诗赋清音:桃花灼灼春风暖,心随乐曲扬徐徐。 苦尽甘来梦未阑,岁月长河任舟游。 ​  🎉欢迎大家关注🔍点赞👍收藏⭐️留言📝   🔔 作者留言: 欢迎来到我的【CSAPP】炸弹实验室!这里是探索

    2024年02月03日
    浏览(29)
  • 【CSAPP】探究BombLab奥秘:Phase_3的解密与实战

    ​🌈个人主页: Sarapines Programmer 🔥 系列专栏: 《斯坦福大学之CSAPP》 ⏰诗赋清音:桃花灼灼春风暖,心随乐曲扬徐徐。 苦尽甘来梦未阑,岁月长河任舟游。 ​  🎉欢迎大家关注🔍点赞👍收藏⭐️留言📝   🔔 作者留言: 欢迎来到我的【CSAPP】炸弹实验室!这里是探索

    2024年02月04日
    浏览(31)
  • 3Dmigoto学习笔记(7) 两种挂载方式与联机游戏反作弊

    3dmigoto有两种挂载方式,第一种是基础笔记里提到的直接把一堆文件放到游戏进程的运行目录下,第二种是使用Loader的方式。 第一种方式简单快捷,一般用于单机游戏,第二种方式一般用于联机游戏,防止联机游戏在运行的过程中有时会扫描游戏目录下的文件,并判断是否多

    2024年02月11日
    浏览(45)
  • DVWA通关攻略之命令注入

    命令注入(Command Injection)漏洞也称为远程命令/代码执行漏洞(RCE,Remote Command/Code Exec),指应用程序的某些功能需要调用可以执行系统命令的函数,如果这些函数或者函数的参数能被用户控制,就可能通过命令连接符将恶意命令拼接到正常的函数中,从而随意执行系统命令,属

    2024年02月11日
    浏览(37)
  • iwebsec靶场 命令执行漏洞通关笔记

    iwebsec靶场的命令执行通关笔记,共有五个关卡,分别涉及到基础的命令执行漏洞、空格绕过、绕过、通配符绕过、base64绕过共五方面的渗透。 什么是命令执行漏洞?命令执行漏洞是服务器端没有对客户端用户输入的参数进行过滤,导致用户可以通过任意拼接系统命令

    2024年02月10日
    浏览(42)
  • UNIX常用命令(C站最全,一文通关)

    unix常见命令列举如下,除了看还要会用: 命令 描述 ls 列出目录下的文件 cd 切换目录 pwd 显示当前目录 mkdir 创建目录 rm 删除文件或目录 rmdir 删除空目录 cp 复制文件或目录 mv 移动文件或目录,或重命名 cat 显示文件内容 less 分页显示文件内容 head/tail 显示文件头部/尾部内容

    2024年02月03日
    浏览(40)
  • k8s基础:使用kubectl set image命令更新Deployment中容器的镜像

    在Kubernetes中,使用 kubectl 更新Deployment中容器的镜像,可以使用以下命令: 例如,如果你有一个名为 myapp 的 Deployment,其中包含一个名为 mycontainer 的容器,你想将镜像从 myregistry/myimage:v1 更新到 myregistry/myimage:v2 ,可以执行: 这条命令将会触发一个滚动更新,根据你的Deploy

    2024年04月26日
    浏览(41)
  • Linux系统gdb调试常用命令

    GDB(GNU调试器)是一款常用的调试工具,用于调试C、C++等编程语言的程序。以下是一些常用的GDB命令: 1. 启动程序:    - `gdb executable`:启动GDB调试器,并加载可执行文件。 2. 设置断点:    - `break line`:在指定行设置断点。    - `break function`:在指定函数的入口处设置断

    2024年02月10日
    浏览(38)
  • GDB 到 LLDB 命令对照表

    Below is a table of GDB commands with their LLDB counterparts. The built in GDB-compatibility aliases in LLDB are also listed. The full lldb command names are often long, but any unique short form can be used. Instead of “ breakpoint set ”, “ br se ” is also acceptable. Execution Commands Breakpoint Commands Watchpoint Commands Examining Variables Ev

    2024年02月12日
    浏览(41)
  • qemu-基础篇——GDB 常用调试命令(三)

    info source 查看当前程序信息 layout 分割窗口,一边查看代码,一边测试 layout asm layout src continue/c 程序继续运行,到下一断点处暂停 run/r 运行 step/c 单步运行 info reg 查看寄存器 break/b + 标号/行号 设置断点 info break/b 查看断点 print 表达式 简记为 p 其中 表达式 可以是任何当前正

    2024年02月03日
    浏览(34)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包