我計劃在不久的將來參加一些奪旗 (CTF) 挑戰。出于這個原因,我決定學習匯編。到目前為止,我專注于 CPU 暫存器的使用。根據我在互聯網上找到的一些示例,我嘗試除錯一個用 C 撰寫的非常簡單的“Hello World”程式,以查看 CPU 暫存器的使用方式。我的環境是 Linux 和 GCC 版本 11。我使用 -g 標志編譯了我的代碼,以便包含除錯符號。
以下是我非常簡單的 C 源代碼:
#include <iostream>
int main (int argc, char** argv)
{
char message_c_str[] = "Hello World from C!";
printf("%s\n", message_c_str);
return 0;
}
研究 main 函式的反匯編,我了解到包含訊息的字串在呼叫 printf 函式之前存盤在 RAX(和 RDX 暫存器?)中:
└─$ objdump -M intel -D main| grep -A20 main.:
0000000000001159 <main>:
1159: 55 push rbp
115a: 48 89 e5 mov rbp,rsp
115d: 48 83 ec 30 sub rsp,0x30
1161: 89 7d dc mov DWORD PTR [rbp-0x24],edi
1164: 48 89 75 d0 mov QWORD PTR [rbp-0x30],rsi
1168: 48 b8 48 65 6c 6c 6f movabs rax,0x6f57206f6c6c6548
116f: 20 57 6f
1172: 48 ba 72 6c 64 20 66 movabs rdx,0x6d6f726620646c72
1179: 72 6f 6d
117c: 48 89 45 e0 mov QWORD PTR [rbp-0x20],rax
1180: 48 89 55 e8 mov QWORD PTR [rbp-0x18],rdx
1184: c7 45 f0 20 43 21 00 mov DWORD PTR [rbp-0x10],0x214320
118b: 48 8d 45 e0 lea rax,[rbp-0x20]
118f: 48 89 c7 mov rdi,rax
1192: e8 b9 fe ff ff call 1050 <puts@plt>
1197: b8 00 00 00 00 mov eax,0x0
119c: c9 leave
119d: c3 ret
我想開始一個除錯會話并嘗試動態更改 RAX,只是為了看看在命令列上列印之前是否能夠更改字串內容。不幸的是,即使我似乎可以更改 RAX 值,程式仍然會列印硬編碼訊息。所以,我不確定為什么我不能改變它。更新 RAX 的值后,我是否缺少運行任何 gdb 命令?
以下是我與該問題的除錯會話:
┌──(alexis?kali)-[~/Desktop/Hacking/hello_world]
└─$ gdb -q main
Reading symbols from main...
(gdb) break main
Breakpoint 1 at 0x1168: file /home/alexis/Desktop/Hacking/hello_world/main.cpp, line 5.
(gdb) run
Starting program: /home/alexis/Desktop/Hacking/hello_world/main
Breakpoint 1, main (argc=1, argv=0x7fffffffdf58) at
/home/alexis/Desktop/Hacking/hello_world/main.cpp:5
5 char message_c_str[] = "Hello World from C!";
(gdb) info register rax
rax 0x555555555159 93824992235865
(gdb) next
6 printf("%s\n", message_c_str);
(gdb) info register rax
rax 0x6f57206f6c6c6548 8022916924116329800
(gdb) set $rax=0x6361636361
(gdb) info register rax
rax 0x6361636361 426835665761
(gdb) next
Hello World from C!
8 return 0;
(gdb)
您可以看到代碼仍然列印“Hello World from C!”,即使 RAX 暫存器發生了變化。為什么?
uj5u.com熱心網友回復:
該字串僅暫時位于rax
中rdx
。在以下幾行中,它被放置在堆疊中,并且地址轉到rdi
,由 使用puts
。
這里重要的是要理解一行源代碼被翻譯成多行匯編。當您更改rax
在線printf("%s\n", message_c_str);
時,字串已經被壓入堆疊并且rax
只保留舊值,因為它沒有被任何東西覆寫。它不再是正在列印的字串。
為了實作您的目標,您必須更改堆疊上的字串或在rax
將其推送到它之前將其更改(因此在您的next
命令之前)。
另請注意,next
前進一個源代碼行。如果您想移動一條匯編指令,請使用nexti
- 這樣您就可以更好地控制要執行的內容。
uj5u.com熱心網友回復:
您正在使用next
(對應于 C 源代碼行的整個 asm 塊),而不是nexti
or stepi
(又名ni
or si
)來逐步執行 asm 指令。
而且您進行了除錯構建,因此 GCC不會在 C 陳述句的暫存器中保留任何內容。 執行停止的點next
是編譯器生成的指令即將加載或 LEA 新 RAX 的點,因此其當前值已失效且無關緊要。
(而且它根本只使用 RAX,因為它是使用 GCC 進行的除錯構建;否則像 lea rax,[rbp-0x20]
/之類的東西mov rdi,rax
會 LEA 直接進入 RDI,而不是無用地使用 RAX 作為臨時。 當從非結束時寫入未使用的引數回傳值-void function 或者對于 mov-immediate 到記憶體,沒有 mov r/m64, imm64,只能注冊,所以這些移動到 RAX 和 RDX 確實有意義。)
如果你想讓它列印一些不同的東西,你可以si
直到 aftermovabs rax,0x6f57206f6c6c6548
但 before mov QWORD PTR [rbp-0x20],rax
,然后更改部分字串資料的初始化程式。(此時在 RAX 中。)例如引入一個0x00
位元組將終止 C 字串。
或者就在之前call puts
,你可能set $rdi = $rdi 5
會喜歡puts(message_c_str 5)
。
layout reg
或layout asm
(如果顯示損壞,使用layout next
/prev
修復顯示)有助于查看執行位置。請參閱https://stackoverflow.com/tags/x86/info底部的其他 GDB asm 提示
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/498469.html
下一篇:匯編中的“movl”指令