我正在尝试读取程序集中的文件(x86,IA-32),我发现了这个例子:
mov ebx,eax
mov al,0x3
mov edi,esp
mov ecx,edi
xor edx,edx
mov dh,0xff
mov dl,0xff
int 0x80
其中在eax(第一条指令)中有open syscall的返回码 有两件事我还没有完全理解:
mov edi,esp
然后mov ecx,edi
而不是直接mov ecx,esp
?0xff
和0xff
放入edx寄存器? read syscall需要count
,因此在这种情况下需要文件大小。编辑(完整代码):
section .text
global _start
_start:
;read the file
jmp short call_rw
rw:
push 0x5
pop eax
pop ebx
xor ecx,ecx
int 0x80
mov ebx,eax
mov al,0x3
mov edi,esp
mov ecx,edi
xor edx,edx
mov dl,0xff
mov dh,0xff
int 0x80
mov edx,eax
push 0x4
pop eax
mov bl, 0x1
int 0x80
push 0x1
pop eax
inc ebx
int 0x80
call_rw:
call rw
message db "/home/user/file.txt"
答案 0 :(得分:1)
对于你的第一个问题,我可以看到几个相当明显的可能性,但问题并不包含足够的信息以确定哪些可能是准确的。
第一种可能性是edi
中的大小后来在代码中被用于其他目的,所以移动到edi
已经完成了一些有用的东西,但我们无法确切地看到在这里,因为我们看不到使用它的其他代码。
另一个明显的可能性是它只是一个错误。
有一些不太明显的可能性,例如mov ecx, edi
被用作其他代码的入口点,所以如果从这段代码的开头开始,它会使用{{1}中的值},但还有其他代码会将其他值加载到esp
然后跳转到edi
,从而使用不同的值而不是mov ecx, edi
中的值。
还有一些其他的可能性,例如某人基本上插入相当于一些NOP(例如)使某些部分代码与某些边界对齐,但没有像他们写的那样多的分心线esp
(比如说)5次。
对于第二个问题,NOP
中的0xffff基本上意味着它将从文件读取最多65535个字节。他们很可能分配了一个65535字节的缓冲区,因此他们不想在一次调用中读取任何内容。
编辑(在完成代码添加到问题后)。好的,现在我们可以看到完整的代码了,我们可以从代码(尽可能好)开始非常传统的 1 。
他首先跳到edx
,然后(显然已经足够)call_rw
call
从rw
开始。这会将地址 call_rw
后的地址立即推送到堆栈上。然后在rw
,他将返回值从堆栈弹出到ebx
。这会将message
的地址加载到ebx
中,然后将其用作下一个系统调用中的参数(函数5,它打开一个文件,期望ebx
包含指向该名称的指针该文件)。
另外,我只是猜测代码是故意(但相当无效)的混淆尝试,或者是内部产生某种面向堆栈的内部代码的编译器的结果,然后呢将其转换为面向寄存器的目标代码是一项非常糟糕的工作。或许我的第一印象(见下文脚注)是正确的。
删除了这个问题之后,前几个系统调用会解决这个常规命令:
; open the file
mov eax, 5
mov ebx, offset filename
xor ecx, ecx
int 0x80
; read the file
mov ebx, eax
mov eax, 3
mov ecx, esp
mov edx, 0xffff
int 0x80
抱歉,但是我太懒了,不能理清其余的一切。乍一看,它似乎进入了无限循环(call_rw
之前的代码流入call_rw
,再次调用rw
。它的一些体操可能会阻止实际发生这种情况,但如果没有令人信服的论据,我就缺乏更多这种特殊情况的理由。