我发现了这个"你好"(外壳代码(组装程序:
SECTION .data
SECTION .text
global main
main:
mov rax, 1
mov rsi, 0x6f6c6c6548 ; "Hello" is stored in reverse order "olleH"
push rsi
mov rsi, rsp
mov rdx, 5
syscall
mov rax, 60
syscall
我发现mov rdi, 1
不见了。在其他";你好世界";程序的指令出现,所以我想了解为什么会发生这种情况。
我本来打算说,使用argc
作为文件描述符来保存代码字节是一种有意的技巧或破解。(如果在没有额外命令行参数的情况下从shell运行1
(。main(int argc, char**argv)
分别在EDI和RSI中获取其参数,这是Linux上使用的x86-64 SysV调用约定。
但考虑到其他选择,比如mov rax, 1
而不是mov eax, edi
,这可能只是一个因为代码碰巧工作而被忽略的错误
对于代码注入攻击,不能在真实的shell代码中工作,在这种情况下,执行可能会使用EDI中的0、1或2以外的垃圾到达该代码。您链接的教程中的shell代码测试程序调用机器代码的const char[]
作为main中唯一的东西,它通常会编译为不涉及RDI的asm。
此代码也不适用于基于strcpy
或其他C字符串溢出的代码注入攻击,因为机器代码包含00
字节作为mov eax, 1
、mov edx, 5
和该字符串末尾的一部分。
此外,现代链接器不会将.rodata
链接到可执行段中,并且-zexecstack
只影响实际堆栈,而不是所有可读内存。所以shell代码测试不会起作用,尽管我预计它在编写时会起作用。请参阅如何获取c代码来执行十六进制机器代码?用于工作方式,如使用本地数组和使用-zexecstack
进行编译。
这个教程总体上不太好,可能是这个家伙在学习时写的。(但根据这个错误和Kali的使用,并没有我预期的那么糟糕;它至少写得很好,只是缺少了一些技巧。(
由于您使用的是NASM,因此不需要手动浪费时间查找ASCII代码并获得正确的字节顺序。与某些汇编程序不同,mov rsi, "Hello"
/push rsi
会导致这些字节按源顺序在内存中。
您也不需要空的.data
部分,尤其是在制作shell代码时,shell代码只是一个独立的机器代码片段,不能引用任何外部内容。
写入32位寄存器隐式零扩展到64位。NASM将mov rax,1
优化为mov eax,1
(如您在objdump -d
AT&D反汇编中所见;objdump -drwC -Mintel
使用类似于NASM的Intel语法反汇编。(
以下内容应该有效:
global main
main:
mov rax, `Hellon ` ; non-zero padding to fill 8 bytes
push rax
mov rsi, rsp
push 1 ; push imm8
pop rax ; __NR_write
mov edi, eax ; STDOUT_FD is also 1
lea edx, [rax-1 + 6] ; EDX = 6; using 3 bytes with no zeros
syscall
mov al, 60 ; assuming write success, RAX = 5, zero outside the low byte
;lea eax, [rdi-1 + 60] ; the safe way that works even with ./hello >&- to return -EBADF
syscall
这比原来的机器代码字节数少,并且避免了strcpy
会停止的x00
字节。我将字符串改为以换行符结尾,使用NASM反标记来支持C风格的转义序列,如n
作为0x0a
字节。
正常运行(我将它链接到一个没有CRT的静态可执行文件中,尽管它被称为main
而不是_start
。ld foo.o -o foo
(:
$ strace ./foo > /dev/null
execve("./foo", ["./foo"], 0x7ffecdc70a20 /* 54 vars */) = 0
write(1, "Hellon", 6) = 6
exit(1) = ?
在stdout关闭的情况下运行以打破mov al, 60
__NR_exit破解:
$ strace ./foo >&-
execve("./foo", ["./foo"], 0x7ffe3d24a240 /* 54 vars */) = 0
write(1, "Hellon", 6) = -1 EBADF (Bad file descriptor)
syscall_0xffffffffffffff3c(0x1, 0x7ffd0b37a988, 0x6, 0, 0, 0) = -1 ENOSYS (Function not implemented)
--- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0xffffffffffffffda} ---
+++ killed by SIGSEGV (core dumped) +++
Segmentation fault (core dumped)
要仍然干净地退出,请使用lea eax, [rdi-1 + 60]
(3个字节(而不是mov al, 60
(2个字节(根据未修改的EDI设置RAX,而不是依赖于RAX的高位字节为零(在返回错误后它们不是零(。
另请参阅https://codegolf.stackexchange.com/questions/132981/tips-for-golfing-in-x86-x64-machine-code