db指令在调用后执行

时间:2017-02-17 07:24:09

标签: assembly x86 nasm shellcode

我正在学习使用汇编语言编程,我发现这段代码无法理解指令的执行方式

xor eax,eax
xor ebx,ebx
xor ecx,ecx
xor edx,edx
jmp short string
code:
pop ecx 
mov bl,1
mov dl,13
mov al,4
int 0x80
dec bl
mov al,1
int 0x80
string: 
call code 
db 'hello, world!'

调用代码后,为什么要执行db指令?如果在

之前执行了一个调用指令

2 个答案:

答案 0 :(得分:3)

只是指出我的意思"定义字节值的其他方式",这个代码的变体将做同样的事情,但它显示了如何通过指令定义字符串,以及如何定义指令通过db指令...两者都使得源更难以为人类读取,但对于Assembler,差异可以忽略不计,它将生成相同的二进制机器代码,而对于CPU,相同的机器代码是相同的机器代码,它并不关心你的来源看起来如何。

我还试图广泛评论每一行,它的作用以及为什么在代码中使用它。

此外,代码是以这种非平凡的方式编写的,因为它是shell-exploit有效负载的示例,其中您的程序集不仅必须执行您想要的操作,而且其生成的机器代码还必须符合其他约束,例如不能包含任何零(使其难以传递为"字符串"在注入有效负载代码期间使用某些漏洞),它必须是PIC(与位置无关的代码),并且它可以&# 39; t使用任何绝对地址,或在执行时假定任何特定位置等。

    ; sets basic registers eax,ebx,ecx,edx to zero (ecx not needed BTW)
    xor eax,eax
    db '1', 0xDB        ; xor ebx,ebx defined by "db" for fun
    db '1', 0xC9        ; xor ecx,ecx defined by "db" for fun
    xor edx,edx
    ; short-jump forward to make later "call code" to produce
    ; negative relative offset, so zero in "call" opcode is avoided
    ; "call code" from here would need zeroes in rel32 offset encoding
    jmp short string    ; the "jmp short string" is encoded as "EB 0F"
code:
    pop ecx             ; loads the address of string from the stack into ecx
    mov bl,1            ; ebx = 1 = STD_OUT stream, avoiding zeroes in
        ; "mov ebx,1" opcode, so instead "xor ebx,ebx mov bl,1" is used
    mov dl,13           ; edx = 13 = length of string
    mov al,4            ; eax = 4 = sys_write
    int 0x80            ; sys_write(STD_OUT, 'hello, world!', 13);
    dec bl              ; ebx = 0 = exit code "OK"
    mov al,1            ; eax = 1 = sys_exit
    int 0x80            ; sys_exit(0);
string:
    call code           ; return address == string address -> pushed on stack
    ; also "code:" is ahead, so relative offset is negative => no zero in opcode
    ; resulting call opcode is "E8 EC FF FF FF"

    ; following bytes are NOT executed as code, they contain string data
    push 0x6f6c6c65     ; 'hello'
    sub al,0x20         ; ', '
    ja  short $+0x6f+2  ; 'wo'
    jb  short $+0x6c+2  ; 'rl'
    db 'd!'

要编译,我确实使用nasm -f elf *.asm; ld -m elf_i386 -s -o demo *.o(忽略警告),反向反编译并检查实际机器代码如何形成可以应用的指令objdump -M intel -d demo

(上面的代码和objdump也适用于在线网站:http://www.tutorialspoint.com/compile_assembly_online.php如果您想测试一下

答案 1 :(得分:0)

永远不会执行字符串,因为您在到达该点之前发出exit_program系统调用。

这是普通代码的样子:

asm
asm
more asm
call subroutine   ->> will branch to subroutine
        subroutine:  asm
                     more asm
                     ret   ->> executing will return to point after call.
xor eax,eax          <<-- first instruction after the ret
ret                  <<-- return to caller.

这里是code子例程的注释版本。

code:
pop ecx        ;get 'hello world'
mov bl,1       ;write to stdout
mov dl,13      ;length is 14
mov al,4       ;syscall write
int 0x80       ;perform the write
dec bl         ;set exit code to 0 {success}
mov al,1       ;syscall exit
int 0x80       ;exit the program
;the executing does not return here!
string: 
call code 
db 'hello, world!'

更好的方法是按如下方式对最后一部分进行编码:

.code
hello: db 'hello, world!'

.text
move ecx,hello
mov edx,13
call print         //returns as normal
call exit_program  //will not return

print: mov eax,4
mov ebx,1
int 0x80
ret

exit_program: 
xor ebx,ebx
mov eax,1
int 0x80

这有以下好处:

  • 指示较少;
  • 通过不匹配的来电/退货
  • 不会造成缓慢
  • 它没有乱码字节寄存器
  • 简单易懂。
  • 您可以在程序的其他部分重用printexit_program子例程。