GDB/CGDB入门与拆弹游戏
这是我的嵌入式笔记第七篇同时也是完结篇,原文写于2015年。本文除了介绍GDB/CGBD的基础使用方法以及嵌入式开发应用外,还会分享一个解密类经典游戏 Defusing a binary bomb with GDB
,非常有趣!
使用GDB
GDB
b [function name] *[address]
:設置斷點d [breakpoint num]
:刪除斷點c
:繼續執行,到下一個斷點處(或運行結束)n
:單步跟蹤程序,當遇到函數調用時,也不會進入函數內(針對src)s
:單步調試,如果有函數調用,則進入函數(針對src)si
:同s(針對asm)ni
:同n(針對asm)p /x $r0
:以16進制格式打印寄存器r0的值x/s [address]
:以字串方式打印出地址所指向的內容layout asm/src
:會顯示出當前正在執行的asm/src代碼段(這樣就不用看objdump -D啦)layout split
:同時顯示當前執行的原始碼和組語layout regs
:會以10進制和16進制方式顯示寄存器的值,包含r0-r12、sp、lr、pc、cpsr(這樣就可以不用p了)winheight name +/- count
:調整 TUI 窗口大小,例如 winheight src -5 代表 TUI 窗口減少 5 行代碼info stack/variables/files/...
- REF:
CGDB
- 安裝:
sudo apt-get install cgdb
- 官方手冊:CGDB Manual 0.6.6 (请查看手册最新版本:CGDB Manual 0.7.1)
- 相比 GDB 無需用 layout 調出 TUI,CGDB 會自動顯示出來,source window 和 GDB command window 切換方式和 VI 相同,使用 i 和 Esc。
- 新增及移除 break point 方法,直接在 source window 裏移動到想要新增/移除的位置,使用 space 鍵就可以了。
- 使用 cross compiler 方法:
cgdb -d arm-none-eabi-gdb -x "gdb.script"
- Source window 類似 VI 界面,常見的
:
設定、/
查詢等都可以使用,具體參考 CGDB configuration commands - 使用
o
可以選擇要顯示的檔案源碼,超潮der - 注意:
- 當前代碼行的行數會是粗體,不過不太明顯,用 space 敲敲看就知道在哪一行了
- 相比 GDB,記得在 CGDB 裏不要
layout
指令!會產生一堆亂碼死掉@@
可視化除錯工具
Using STM32 discovery kits with open source tools
- 原 PDF 链接已失效,原文请自行 Google
- Written by STLINK development team
Installing GNU toolchain
- 请自行 Google
Installing STLINK
- Dependencies
libusb-1.0
pkg-config
autotools
- Install stlink
1 | git clone https://github.com/texane/stlink stlink.git |
It includes:
- A communication library (stlink.git/libstlink.a).
- A GDB server (stlink.git/st-util).
- A flash manipulation tool (stlink.git/st-flash).
Using the GDB server
- A GDB server must be started to interact with the STM32. Depending on the discovery kit you are using, you must run one of the 2 commands:
st-util --stlinkv1
: STM32VL discoverykit (onboard ST−link)st-util
: STM32L or STM32F4 discoverykit (onboard ST−link /V2)
- Then, GDB can be used to interact with the kit:
arm-none-eabi-gdb XXX.elf
- From GDB, connect to the server using:
(gdb) target extended localhost: 4242
(gdb) load
(gdb) continue
Building and flashing a program
- If you want to simply flash binary files to arbitrary sections of memory, or read arbitary addresses of memory out to a binary file, use the st-flash tool, as shown below:
st-flash read v1 out.bin 0x8000000 4096
: stlink-v1 command to read 4096 from flash into out.binst-flash read out.bin 0x8000000 4096
: stlink-v2 commandst-flash write v1 in.bin 0x8000000
: stlink-v1 command to write the file in.bin into flashst-flash write in.bin 0x8000000
: stlink-v1 command
Notes
Disassembling THUMB code in GDB
By default, the disassemble command in GDB operates in ARM mode. The programs running on CORTEX-M3 are compiled in THUMB mode. To correctly disassemble them under GDB, uses an odd address. For instance, if you want to disassemble the code at 0x20000000, use(gdb) disassemble 0x20000001
每次都輸入一堆必備的指令很麻煩,可以寫入一個
gdb.script
檔案裏,例如:
1 | target remote:4242 |
然後使用 arm-none-eabi-gdb -x gdb.script
進入後,單步執行即可。
- 記得先打開
st-util
; - 個人習慣把
arm-none-eabi-gdb -x gdb.script
寫進Makefile
裏。
Defusing a binary bomb
Lab43: Runtime Behavior
預期目標
- 複習 ARM 處理器和指令集,並深入 stack 和執行時期的行為
- 熟悉 objdump、gdb 等工具,並利用上述工具分析執行檔
Phase 0, Phase 1: Comparison
使用
b phase_0
設好斷點後,一個c
來到phase0
函數,在源程式端輸入help
,則可見:可以看到程式是用
r0
和r1
作比較,r0
是我們輸入的值,r1
就是我們要猜的值,這裏已經告訴我們是help
了用
si
執行到 0x87ee ,可以看到r0
和r1
的值:x/s $r0
x/s $r1
直接可以印出r0
r1
的地址和指向的值:同理,
continue
到phase_1
,印出r1
Psalm 23:4
Yea, though I walk through the valley of the shadow of death, I will fear no evil; For You are with me; Your rod and Your staff, they comfort me.
Phase 2: For loop
先隨意輸入,看下寄存器
r1
的值0x8bc8: "%d %d %d %d"
,看起來是要輸入4個整數,重頭再來一次發現用
ni
跳過 function 會讀不到指令,還是用si
一步一步來吧到 0x885e,如果輸入的數的個數不是4個,就會 explode bomb,若是則跳到 0x8864
接下來的代碼中:
從 0x886a 到 0x887a 是一個迴圈,完整的
si
走了一邊,只是運行完後不能讀到r2
r3
的值所指向的地址裏的值類似的代碼爲:
1
2
3
4
5a=2;i=0;
do {
a+=1;
i++;
} while (i<=9);意外但肯定不是巧合地發現,之前輸入的四個數分別存在
r7+12
r7+16
r7+20
r7+24
裏(其實是用x/s $r7+n
試出來的)所以輸入的第二個數(上述代碼中的
a
)在迴圈後會增加10而函數最後對比的是
r7+16
和r7+20
,需要他們相等,故輸入時第三個數減第二個數要等於10測試果然過關~
Phase 3: If condition
第一步,設置斷點在
phase_3
後隨意輸入進入斷點,印出r1
的值,爲"%d %d %d"
,後面也有判斷輸入個數的代碼,和階段2同理:接着把斷點設在 0x88be,代碼如下:
r3
會先取出輸入的第一個數,和 40 做對比,這裏我輸入的 1,因此會繼續往下走接着把給輸入的第二個數、第三個數的值賦給
r2
r3
,然後r3=r3+r2
,再把r3
的值存回[r7,#16]
然後把
r2
的值設爲[r7,#16]
,再把r3
的值還原回初始的第三個數的值,對比他們相不相等- 即要使得
r3=r2+r3
,所以在第一個數不爲 40 的情況下,第二個數和第三個數都只能是 0 - 那如果第一個數等於 40,則
r2
r3
相等即可
- 即要使得
試驗一下
當第一個數不爲40時,正確
當第一個數爲40時,正確
Phase 4: Iteration
與階段2、3同理,得知輸入爲一個整數
接下來
phase_4
的函數就很短了把輸入的數,代入fun4後,return的值要等於1024。
fun4
的代碼如下:當
r3
不爲 0 時,會一直減 1 然後調用自身函數;當r3
終於減到 0 後,會在 0x88f2 賦值爲 1,然後跳到 8904,回傳上一層的fun
函數。然後r3=r0=1
,開始左移所以相當於輸入的數字 n,可以滿足 2 的 n 次方爲 1024,即是正確答案,真相如下: