获取shellcode中数据的绝对地址

huangapple go评论71阅读模式
英文:

Getting absolute address of data in shellcode

问题

以下是您的shellcode:

	xor rax, rax
	xor rdi, rdi
	xor rsi, rsi
	xor rdx, rdx

	; 获取`pathname`的地址
	mov rdi, [something]
	mov al, 59
	mov rdi, rsp
	syscall

    xor rax, rax
	mov al, 60
	xor rdi, rdi
	syscall

_pathname:
	db "/usr/bin/shutdown",0

这是一个简单的execve和退出操作。问题在于我无法获取访问pathname所需的绝对地址。我找到的“解决方案”是将代码设置得像这样:

call _end

_start:
    pop rdi ; _start的绝对地址
    ; 然后添加字节以到达_end的地址

_end:
    call start
    db "/usr/bin/shutdown", 0

这对我来说从来都不合理,而且也不起作用。我还尝试使用FPU指令,但它们也不起作用。

有人有解决方案吗?

操作系统:Linux
架构:amd64

英文:

Here's my shellcode:

	xor rax, rax
	xor rdi, rdi
	xor rsi, rsi
	xor rdx, rdx

	; getting address of `pathname`
	mov rdi, [something]
	mov al, 59
	mov rdi, rsp
	syscall

    xor rax,rax
	mov al, 60
	xor rdi, rdi
	syscall

_pathname:
	db "/usr/bin/shutdown",0

Simple execve and exit, that's all. The problem is that I can't get the absolute address in order to access pathname. The "solution" to this, that I have found, is rigging the code something like this:

call _end

_start:
    pop rdi ; absolute address of _start
    ; then add bytes to get to address of _end

_end:
    call start
    db "/usr/bin/shutdown", 0

This never made sense to me, and it didn't work. I also tried using FPU instructions, which were supposed to work as well, but they didn't work either.

Anybody have a solution?

OS: Linux
Architecture: amd64

答案1

得分: 3

在x86-64上,您可以使用RIP相对寻址模式,所以您应该可以简单地执行 lea rdi, [rel _pathname]。汇编器会计算当前指令(或实际上是下一条指令)的地址与标签 _pathname 之间的位移,并将其编码到指令中。在运行时,这个位移会添加到 rip 中,然后将结果放入 rdi 寄存器中。

x86-32没有相对寻址模式,因此在32位模式下,您的 call/pop 技巧是完成此操作的标准方式,尽管有些笨拙。而且它在64位模式下也有效。但是,由 pop rdi 弹出的地址不是 _start 的地址;而是由 call _start 指令推送的返回地址,即 call _start 指令之后的字节地址。在这种情况下,它恰好是您的 /usr/bin/shutdown 字符串的第一个字节,因此实际上您不需要添加任何内容。

请注意,您将一个空指针传递给 execveargvenvp 参数。这对于内核是合法的,但shutdown 程序可能不会预期到这一点,启动时可能会崩溃。因此,您可能需要进行一些额外的工作,以构建一个至少包含 argv[0] == "shutdown" 的最小参数向量。

英文:

On x86-64 you have RIP-relative addressing modes, so you should be able to simply do lea rdi, [rel _pathname]. The assembler computes the displacement between the address of the current instruction (or actually the next one) and the label _pathname, and encodes it into the instruction. At runtime this displacement is added to rip and the result placed in rdi.

x86-32 doesn't have relative addressing modes, so in 32-bit mode, your call/pop trick is the standard way to accomplish this, despite being awkward. And it does work in 64-bit mode too. But the address popped by pop rdi isn't the address of _start; rather it's the return address pushed by the call _start instruction, i.e. the address of the byte following the call _start instruction. In this case it is exactly the first byte of your /usr/bin/shutdown string, so in fact you wouldn't have to add anything.

Note that you are passing a null pointer as the argv and envp arguments to execve. This is legal for the kernel, but the shutdown program is probably not expecting this and it may crash upon startup. So you might have to do some more work to construct a minimal argument vector with argv[0] == "shutdown" at least.

huangapple
  • 本文由 发表于 2023年7月4日 23:32:54
  • 转载请务必保留本文链接:https://go.coder-hub.com/76614100.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定