为什么带有jmp指令的shellcode工作,为什么标签不能在C包装器内工作?

vik*_*cks 3 x86 assembly machine-code shellcode

我有两个汇编代码,如下所示

file:a.asm

section .text
global _start
_start: mov eax, 4
        mov ebx, 1
        mov ecx, mesg
        mov edx, 10
        int 0x80
        mov eax, 1
        int 0x80
mesg    db      "KingKong",0xa
Run Code Online (Sandbox Code Playgroud)

和另一个汇编代码

档案:b.asm

section .text
global _start

_start: jmp mesg

prgm:   mov eax, 4
        mov ebx, 1
        pop ecx
        mov edx, 10
        int 0x80
        mov eax,1
        int 0x80
mesg:   call prgm
        db "KingKong",0xa
Run Code Online (Sandbox Code Playgroud)

在获取这两个代码的十六进制并将其放入此C包装器之后

char *b = "\xb8\x04\x00\x00\x00\xbb\x01\x00\x00\x00\xb9\x7d\x80\x04\x08\xba\x0a\x00\x00\x00\xcd\x80\xb8\x01\x00\x00\x00\xcd\x80\x4b\x69\x6e\x67\x4b\x6f\x6e\x67\x0a";

char *b = "\xe9\x19\x00\x00\x00\xb8\x04\x00\x00\x00\xbb\x01\x00\x00\x00\x59\xba\x0a\x00\x00\x00\xcd\x80\xb8\x01\x00\x00\x00\xcd\x80\xe8\xe2\xff\xff\xff\x4b\x69\x6e\x67\x4b\x6f\x6e\x67\x0a";
int main()
{
        (*(int (*)(void))a)();
}
Run Code Online (Sandbox Code Playgroud)

第一个汇编代码(b)按预期打印'KingKong',但第二个汇编代码a打印垃圾.像显示的那样

root@bt:~/Arena# ./a
?root@bt:~/Arena#
root@bt:~/Arena# ./b
KingKong
Run Code Online (Sandbox Code Playgroud)

a(第一个)生成的输出是这个?奇怪的字符,而第二个(b)kingkong按预期打印.现在有人可以解释为什么第二个汇编代码工作而第一个汇编代码没有.

编辑: 从答案我看到第一个程序硬编码地址.即使是第二种方法也使用标签,例如jmp mesg,现在这条指令不会使程序与第一种程序非常相似,它们都不是labels用来决定位置的cos .我所知道的是,为了使代码位置独立,我们需要使用具有相对寻址方案espebp寄存器或寄存器.不要第二个程序的jmp指令使它像第一个程序一样.

NPE*_*NPE 7

地址mesg可能会有所不同,具体取决于程序在内存中的布局方式.

以下内容将对特定地址进行硬编码,并且无法可靠地(或根本不)工作:

    mov ecx, mesg
Run Code Online (Sandbox Code Playgroud)

作为参考,第一种方法硬编码以下地址:

    mov ecx, 0x804807d
Run Code Online (Sandbox Code Playgroud)

第二种方法确实有效,因为它mesg使用call指令的返回地址在运行时计算出地址.

换句话说,第一个版本仅在加载到特定地址时才有效,而第二个版本与位置无关.

值得注意的是,第二版中出现jmpcall指令和指令使用相对寻址,这意味着操作码指定到目标的距离而不是目标的地址.这使得这些指令无论在内存中的位置如何都可以工作.

如果检查操作码,您将看到jmp编码为

e9 19 00 00 00
Run Code Online (Sandbox Code Playgroud)

(即跳转0x19,或25 10,字节向前),并call编码为

e8 e2 ff ff ff
Run Code Online (Sandbox Code Playgroud)

其中0xffffffe2是一个小的负数(-30).

  • `jmp`和条件跳转,`call`使用相对寻址.我们编写`jmp target`并将其反汇编为"jmp address_of_target",但是如果你看一下操作码/操作数,它就是"jmp distance_to_target".这就是区别. (2认同)