# 修改被調試程序的二進制文件
## 例子
#include <stdio.h>
#include <stdlib.h>
void drawing (int n)
{
if (n != 0)
puts ("Try again?\nAll you need is a dollar, and a dream.");
else
puts ("You win $3000!");
}
int main (void)
{
int n;
srand (time (0));
n = rand () % 10;
printf ("Your number is %d\n", n);
drawing (n);
return 0;
}
## 技巧
gdb不僅可以用來調試程序,還可以修改程序的二進制代碼。
缺省情況下,gdb是以只讀方式加載程序的。可以通過命令行選項指定為可寫:
$ gcc -write ./a.out
(gdb) show write
Writing into executable and core files is on.
也可以在gdb中,使用命令設置并重新加載程序:
(gdb) set write on
(gdb) file ./a.out
接下來,查看反匯編:
(gdb) disassemble /mr drawing
Dump of assembler code for function drawing:
5 {
0x0000000000400642 <+0>: 55 push %rbp
0x0000000000400643 <+1>: 48 89 e5 mov %rsp,%rbp
0x0000000000400646 <+4>: 48 83 ec 10 sub $0x10,%rsp
0x000000000040064a <+8>: 89 7d fc mov %edi,-0x4(%rbp)
6 if (n != 0)
0x000000000040064d <+11>: 83 7d fc 00 cmpl $0x0,-0x4(%rbp)
0x0000000000400651 <+15>: 74 0c je 0x40065f <drawing+29>
7 puts ("Try again?\nAll you need is a dollar, and a dream.");
0x0000000000400653 <+17>: bf e0 07 40 00 mov $0x4007e0,%edi
0x0000000000400658 <+22>: e8 b3 fe ff ff callq 0x400510 <puts@plt>
0x000000000040065d <+27>: eb 0a jmp 0x400669 <drawing+39>
8 else
9 puts ("You win $3000!");
0x000000000040065f <+29>: bf 12 08 40 00 mov $0x400812,%edi
0x0000000000400664 <+34>: e8 a7 fe ff ff callq 0x400510 <puts@plt>
10 }
0x0000000000400669 <+39>: c9 leaveq
0x000000000040066a <+40>: c3 retq
End of assembler dump.
修改二進制代碼(注意大小端和指令長度):
(gdb) set variable *(short*)0x400651=0x0ceb
(gdb) disassemble /mr drawing
Dump of assembler code for function drawing:
5 {
0x0000000000400642 <+0>: 55 push %rbp
0x0000000000400643 <+1>: 48 89 e5 mov %rsp,%rbp
0x0000000000400646 <+4>: 48 83 ec 10 sub $0x10,%rsp
0x000000000040064a <+8>: 89 7d fc mov %edi,-0x4(%rbp)
6 if (n != 0)
0x000000000040064d <+11>: 83 7d fc 00 cmpl $0x0,-0x4(%rbp)
0x0000000000400651 <+15>: eb 0c jmp 0x40065f <drawing+29>
7 puts ("Try again?\nAll you need is a dollar, and a dream.");
0x0000000000400653 <+17>: bf e0 07 40 00 mov $0x4007e0,%edi
0x0000000000400658 <+22>: e8 b3 fe ff ff callq 0x400510 <puts@plt>
0x000000000040065d <+27>: eb 0a jmp 0x400669 <drawing+39>
8 else
9 puts ("You win $3000!");
0x000000000040065f <+29>: bf 12 08 40 00 mov $0x400812,%edi
0x0000000000400664 <+34>: e8 a7 fe ff ff callq 0x400510 <puts@plt>
10 }
0x0000000000400669 <+39>: c9 leaveq
0x000000000040066a <+40>: c3 retq
End of assembler dump.
可以看到,條件跳轉指令“je”已經被改為無條件跳轉“jmp”了。
退出,運行一下:
$ ./a.out
Your number is 2
You win $3000!
詳情參見[gdb手冊](https://sourceware.org/gdb/onlinedocs/gdb/Patching.html#Patching)
## 貢獻者
xmj
- 介紹
- 信息顯示
- 顯示gdb版本信息
- 顯示gdb版權相關信息
- 啟動時不顯示提示信息
- 退出時不顯示提示信息
- 輸出信息多時不會暫停輸出
- 函數
- 列出函數的名字
- 是否進入帶調試信息的函數
- 進入不帶調試信息的函數
- 退出正在調試的函數
- 直接執行函數
- 打印函數堆棧幀信息
- 打印尾調用堆棧幀信息
- 選擇函數堆棧幀
- 向上或向下切換函數堆棧幀
- 斷點
- 在匿名空間設置斷點
- 在程序地址上打斷點
- 在程序入口處打斷點
- 在文件行號上打斷點
- 保存已經設置的斷點
- 設置臨時斷點
- 設置條件斷點
- 忽略斷點
- 觀察點
- 設置觀察點
- 設置觀察點只針對特定線程生效
- 設置讀觀察點
- 設置讀寫觀察點
- Catchpoint
- 讓catchpoint只觸發一次
- 為fork調用設置catchpoint
- 為vfork調用設置catchpoint
- 為exec調用設置catchpoint
- 為系統調用設置catchpoint
- 通過為ptrace調用設置catchpoint破解anti-debugging的程序
- 打印
- 打印ASCII和寬字符字符串
- 打印STL容器中的內容
- 打印大數組中的內容
- 打印數組中任意連續元素值
- 打印數組的索引下標
- 打印函數局部變量的值
- 打印進程內存信息
- 打印靜態變量的值
- 打印變量的類型和所在文件
- 打印內存的值
- 打印源代碼行
- 每行打印一個結構體成員
- 按照派生類型打印對象
- 指定程序的輸入輸出設備
- 使用“$\”和“$\_”變量
- 打印程序動態分配內存的信息
- 打印調用棧幀中變量的值
- 多進程/線程
- 調試已經運行的進程
- 調試子進程
- 同時調試父進程和子進程
- 查看線程信息
- 在Solaris上使用maintenance命令查看線程信息
- 不顯示線程啟動和退出信息
- 只允許一個線程運行
- 使用“$_thread”變量
- 一個gdb會話中同時調試多個程序
- 打印程序進程空間信息
- 使用“$_exitcode”變量
- core dump文件
- 為調試進程產生core dump文件
- 加載可執行程序和core dump文件
- 匯編
- 設置匯編指令格式
- 在函數的第一條匯編指令打斷點
- 自動反匯編后面要執行的代碼
- 將源程序和匯編指令映射起來
- 顯示將要執行的匯編指令
- 打印寄存器的值
- 顯示程序原始機器碼
- 改變程序的執行
- 改變字符串的值
- 設置變量的值
- 修改PC寄存器的值
- 跳轉到指定位置執行
- 使用斷點命令改變程序的執行
- 修改被調試程序的二進制文件
- 信號
- 查看信號處理信息
- 信號發生時是否暫停程序
- 信號發生時是否打印信號信息
- 信號發生時是否把信號丟給程序處理
- 給程序發送信號
- 使用“$_siginfo”變量
- 共享庫
- 顯示共享鏈接庫信息
- 腳本
- 配置gdb init文件
- 按何種方式解析腳本文件
- 保存歷史命令
- 源文件
- 設置源文件查找路徑
- 替換查找源文件的目錄
- 圖形化界面
- 進入和退出圖形化調試界面
- 顯示匯編代碼窗口
- 顯示寄存器窗口
- 調整窗口大小
- 其它
- 命令行選項的格式
- 支持預處理器宏信息
- 使用命令的縮寫形式
- 在gdb中執行shell命令和make
- 在gdb中執行cd和pwd命令
- 設置命令提示符
- 設置被調試程序的參數
- 設置被調試程序的環境變量
- 得到命令的幫助信息
- 記錄執行gdb的過程