我想理解/解碼我的 aarch64 設備上的 ARM 指令。
我有以下用C語言撰寫的代碼:
void test_function(int a, int b, int c, int d) {
int flag;
char buffer[10];
flag = 31337;
buffer[0] = 'A';
}
int main() {
test_function(1, 2, 3, 4);
}
gcc -g stack_example.c并gdb -q ./a.out產生以下程式集:
(gdb) disass main
Dump of assembler code for function main:
0x00000000000016d4 < 0>: stp x29, x30, [sp, #-16]!
0x00000000000016d8 < 4>: mov x29, sp
0x00000000000016dc < 8>: mov w0, #0x1 // #1
0x00000000000016e0 < 12>: mov w1, #0x2 // #2
0x00000000000016e4 < 16>: mov w2, #0x3 // #3
0x00000000000016e8 < 20>: mov w3, #0x4 // #4
0x00000000000016ec < 24>: bl 0x16a8 <test_function>
0x00000000000016f0 < 28>: mov w0, wzr
0x00000000000016f4 < 32>: ldp x29, x30, [sp], #16
0x00000000000016f8 < 36>: ret
End of assembler dump.
(gdb) disass test_function
Dump of assembler code for function test_function:
0x00000000000016a8 < 0>: sub sp, sp, #0x20
0x00000000000016ac < 4>: str w0, [sp, #28]
0x00000000000016b0 < 8>: str w1, [sp, #24]
0x00000000000016b4 < 12>: str w2, [sp, #20]
0x00000000000016b8 < 16>: str w3, [sp, #16]
0x00000000000016bc < 20>: mov w8, #0x7a69 // #31337
0x00000000000016c0 < 24>: str w8, [sp, #12]
0x00000000000016c4 < 28>: mov w8, #0x41 // #65
0x00000000000016c8 < 32>: strb w8, [sp, #2]
0x00000000000016cc < 36>: add sp, sp, #0x20
0x00000000000016d0 < 40>: ret
End of assembler dump.
當我現在做的break 10,break test_function,run和disass main我得到
(gdb) disass main
Dump of assembler code for function main:
0x00000055907a86d4 < 0>: stp x29, x30, [sp, #-16]!
0x00000055907a86d8 < 4>: mov x29, sp
0x00000055907a86dc < 8>: mov w0, #0x1 // #1
0x00000055907a86e0 < 12>: mov w1, #0x2 // #2
0x00000055907a86e4 < 16>: mov w2, #0x3 // #3
0x00000055907a86e8 < 20>: mov w3, #0x4 // #4
=> 0x00000055907a86ec < 24>: bl 0x55907a86a8 <test_function>
0x00000055907a86f0 < 28>: mov w0, wzr
0x00000055907a86f4 < 32>: ldp x29, x30, [sp], #16
0x00000055907a86f8 < 36>: ret
End of assembler dump.
現在根據Arm 架構參考手冊 Armv8,對于 A-profile 架構,第 934 頁,BL 指令以 100101 開頭,后跟 26 位立即數。
用 yields 檢查程式計數器所在位置的記憶體
(gdb) x/16b 0x55907a86ec
0x55907a86ec <main 24>: 11101111 11111111 11111111 10010111 11100000 00000011 00011111 00101010
0x55907a86f4 <main 32>: 11111101 01111011 11000001 10101000 11000000 00000011 01011111 11010110
我認為,指令從第四個位元組開始,但我不確定。我試圖重建地址 0x55907a86a8,但無法重建。有人可以幫忙嗎?
uj5u.com熱心網友回復:
AArch64 指令是小端編碼的,因此如果您一次轉儲一個位元組的代碼,每個 4 位元組的字將具有相反順序的位元組。因此,從您擁有的輸出中,您必須取前 4 個位元組,顛倒它們的順序(但不要顛倒位元組中的位),并將它們連接起來。(你可以讓除錯器為你做x/tw 0x55907a86ec這件事。)這給出:
10010111111111111111111111101111
實際上,最高 6 位是操作碼100101。即時是11111111111111111111101111。這是二進制補碼中的負數(回想一下,立即數是符號擴展的),值為-17or -0x11。這個數字乘以 4(左移兩位),產生-0x44并添加到bl指令本身的地址以找到分支目標。事實上0x00000055907a86ec - 0x44 = 0x55907a86a8,這是除錯器向您顯示的地址,并且將是test_function.
請注意,在您開始運行程式時,ASLR已完成,這就是為什么反匯編在run. 如果你在disassemble test_function之后做了run,你應該看到它從0x55907a86a8. 盡管如此,如果您查看 ASLR 之前的反匯編,您會注意到bl test_function指令 ( 0x16ec) 的地址與其test_function自身地址( )之間的相對位移0x16a8是相同的-0x44。(實際上 ASLR 是以頁為單位完成的,因此它的低 12 位沒有改變。)
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/386837.html
上一篇:帶有argv的C用戶動態輸入
