簡體   English   中英

elf aarch64 使用 sys_write 打高爾夫球

[英]elf aarch64 golfed with sys_write

為了更好地理解ELF格式和 ARM aarch64 ,我嘗試創建沒有編譯器的 elf 二進制文件,只是用 bash 回顯字節。

可以在這里看到我的努力: http://www.github.com/glaudiston/elf

我已經成功地使用x64sys_writesys_exit系統調用實現了一個完全工作的精靈。

但是對於aarch64 ,它並沒有像我期望的那樣工作:

# cat make-elf.sh 
#!/bin/bash
#
# depends on:
# - elf_fn.sh (github.com/glaudiston/elf)
# - base64 (gnu-coreutils)
#

. elf_fn.sh

instructions="";
instructions="${instructions}\nwrite $(echo -en "hello world\n" | base64 -w0)";
instructions="${instructions}\nexit 3";
write_elf elf "${instructions}";

它產生:

$ xxd elf
00000000: 7f45 4c46 0201 0100 0000 0000 0000 0000  .ELF............
00000010: 0200 b700 0100 0000 7800 0100 0000 0000  ........x.......
00000020: 4000 0000 0000 0000 0000 0000 0000 0000  @...............
00000030: 0000 0000 4000 3800 0100 0000 0000 0000  ....@.8.........
00000040: 0100 0000 0500 0000 0000 0000 0000 0000  ................
00000050: 0000 0100 0000 0000 0000 0000 0000 0000  ................
00000060: 7800 0000 0000 0000 7800 0000 0000 0000  x.......x.......
00000070: 0000 0000 0000 0000 2000 80d2 010c 0058  ........ ......X
00000080: 8201 80d2 0808 80d2 0100 00d4 6000 80d2  ............`...
00000090: a80b 80d2 0100 00d4 6865 6c6c 6f20 776f  ........hello wo
000000a0: 726c 640a           
$ ./make-elf.sh 0 && ./elf; echo $?
3
$ cat elf | base64 -w0; echo
f0VMRgIBAQAAAAAAAAAAAAIAtwABAAAAeAABAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAEAAOAABAAAAAAAAAAEAAAAFAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAeAAAAAAAAAB4AAAAAAAAAAAAAAAAAAAAIACA0gEMAFiCAYDSCAiA0gEAANRgAIDSqAuA0gEAANRoZWxsbyB3b3JsZAo=

它返回預期的退出代碼,沒有非法異常,但sys_write調用沒有打印任何內容。

隱藏所有ELF開銷,我們有這個:

00000078:                     2000 80d2 010c 0058           ......X
00000080: 8201 80d2 0808 80d2 0100 00d4 6000 80d2  ............`...
00000090: a80b 80d2 0100 00d4 6865 6c6c 6f20 776f  ........hello wo
000000a0: 726c 640a                                rld.

exit 調用按預期工作,所以我也可以隱藏它:

00000078:                     2000 80d2 010c 0058           ......X
00000080: 8201 80d2 0808 80d2 0100 00d4            ............    
00000090:                     6865 6c6c 6f20 776f          hello wo
000000a0: 726c 640a                                rld.

所以我們有數據hello world.\n從 position 98開始。 我很困惑如何在這里進行sys_write調用。 x64中,我可以設置下一個數據地址,在這種情況下應該是65688 (由PH_VADDR_V(65536) + ELF_HEADER_SIZE(64) + ELF_BODY_SIZE(32) (沒有DATA_SECTION )組成)”

對於 output fd ,我在r0中將值 1 設置為2000 80d2

對於數據地址,我使用的是010c ,它是0c01little endian表示,這些位: 00001100000 00001最后 5 位是r1寄存器,用於數據地址。

鑒於我只有 11 位在這里我使用了LDR ( 0058 ) 但我也嘗試了MOV (這里80d2 )。 沒有成功

我嘗試了從 0 到 2048 的任何值,它開始報告Illegal instruction and exit code 132

我想也許aarch64不允許我在x64中使用的相同技巧來打印沒有標記數據部分的數據。 我會努力創建它,但這只是一個猜測,我真的很想了解為什么這不打印任何內容。

因此,您的字符串位於絕對地址0x10098 ,您需要將此地址放入x1寄存器中。

首先, LDR不是你想要的。 顧名思義就是從memory加載(讀取)。你根本不想讓你的指令去訪問memory,它只是想把值0x10098放到寄存器中。

MOV更接近,它向寄存器寫入一個立即數,但問題是立即數限制為 16 位,而你需要 17。因為指令是 32 位,所以立即數只有這么多位。 我的猜測是你溢出了它並最終改變了操作碼位,所以你編碼了一個完全不同的指令。 (不要猜測編碼。查找它們。這會向您顯示 16 位限制。)

為了將任意立即值存入寄存器,預期的方法是使用一系列MOV/MOVK指令一次寫入 16 位。 在這里你只需要其中兩個:

   0:   d2801301    mov x1, #0x98                   // #152
   4:   f2a00021    movk    x1, #0x1, lsl #16

雖然因為我們使用了一個額外的詞,字符串的地址也會發生變化,所以你必須相應地進行調整。

但是,特別是對於地址,AArch64 提供了相對於 pc 的地址生成指令ADR/ADRP 這些使您可以將立即值添加到程序計數器的當前值(即當前執行指令的地址)並將結果寫入寄存器。 作為獎勵,它們為立即數分配了更多位(盡管您將不再需要它們)。

這里我們可以使用ADR 它的操作碼在第 31 位為 0,在第 24-28 位為10000 目標寄存器是位 0-4,我們想要00001 立即數在第 29-30 位獲得低兩位,在 5-23 獲得高位。 ADR指令將位於絕對地址0x1007c ,我們需要0x10098 ,因此位移為0x1c = 0b11100 因此我們想要的編碼是

0 00 10000 0000000000000000111 00001 = 0x100000e1

一些一般提示:

  • 首先嘗試使用匯編程序編寫代碼,這樣您就可以學習指令集並能夠專注於試驗指令的作用,而不是陷入它們的編碼方式。 如果您想稍后回來手動進行編碼,那很好,但是使用匯編程序,您還可以通過一種方式來檢查您的工作。

  • 使用調試器單步執行您的程序。 那會向您表明您的LDR給了您一個完全虛假的值,並且可能暗示它沒有按照您認為的那樣進行。

  • 使用strace查看您的程序進行了哪些系統調用。 那會告訴你(我想,我沒有測試) write確實被調用但是地址錯誤。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM