我正在学习使用汇编语言编程,我发现这段代码无法理解指令的执行方式
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指令?如果在
之前执行了一个调用指令答案 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
这有以下好处:
print
和exit_program
子例程。