为了提高我的二进制开发技能并加深对低级环境的了解,我尝试在pwnable.kr
中解决挑战,第一个挑战称为fd
,它具有以下C代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char buf[32];
int main(int argc, char* argv[], char* envp[]){
if(argc<2){
printf("pass argv[1] a number\n");
return 0;
}
int fd = atoi( argv[1] ) - 0x1234;
int len = 0;
len = read(fd, buf, 32);
if(!strcmp("LETMEWIN\n", buf)){
printf("good job :)\n");
system("/bin/cat flag");
exit(0);
}
printf("learn about Linux file IO\n");
return 0;
}
我使用objdump -S -g ./fd
来对其进行反汇编,但由于调用strcmp函数的局限性,我感到困惑。它只是比较字符串而不调用它。
这是我正在谈论的汇编代码:
80484c6: e8 05 ff ff ff call 80483d0 <atoi@plt>
80484cb: 2d 34 12 00 00 sub eax,0x1234
; eax = atoi( argv[1] ) - 0x1234;
; initialize fd=eax
80484d0: 89 44 24 18 mov DWORD PTR [esp+0x18],eax
; initialize len
80484d4: c7 44 24 1c 00 00 00 mov DWORD PTR [esp+0x1c],0x0
; Set up read variables
80484db: 00
80484dc: c7 44 24 08 20 00 00 mov DWORD PTR [esp+0x8],0x20 ; read 32 bytes
80484e3: 00
80484e4: c7 44 24 04 60 a0 04 mov DWORD PTR [esp+0x4],0x804a060 ; buf variable address
80484eb: 08
80484ec: 8b 44 24 18 mov eax,DWORD PTR [esp+0x18]
80484f0: 89 04 24 mov DWORD PTR [esp],eax ; fd variable
80484f3: e8 78 fe ff ff call 8048370 <read@plt>
80484f8: 89 44 24 1c mov DWORD PTR [esp+0x1c],eax
80484fc: ba 46 86 04 08 mov edx,0x8048646 ; "LETMEWIN\n" address
8048501: b8 60 a0 04 08 mov eax,0x804a060 ; buf address
8048506: b9 0a 00 00 00 mov ecx,0xa ; what is this?
; strcmp starts here?
804850b: 89 d6 mov esi,edx
804850d: 89 c7 mov edi,eax
804850f: f3 a6 repz cmps BYTE PTR ds:[esi],BYTE PTR es:[edi] ; <------- ?STRCMP?
我不明白的是:
strcmp
通话在哪里?为什么会这样呢? 8048506: b9 0a 00 00 00 mov ecx,0xa
的作用是什么? 答案 0 :(得分:5)
编译器使用实现Memcmp的repe cmpsb
向已知长度的字符串内联strcmp
。
它将常量文字字符串“ LETMEWIN \ n”的地址加载到寄存器esi
中。请注意,此字符串的长度为10(末尾为'\ 0')。
然后将buf
的地址加载到edi
寄存器中,然后调用x86指令:
repz cmps BYTE PTR ds:[esi],BYTE PTR es:[edi]
repz
重复以下指令,只要设置了零标志且最多存储ecx
中的次数(这为您解释了mov ecx,0xa ; what is this?
)。
重复的指令是cmps
,它比较字符串(逐字节),并在每次迭代时自动将指针加1。
当比较的字节相等时,它将设置零标志。
因此,根据您的问题:
strcmp调用在哪里?为什么会这样呢?
没有显式调用strcmp
,它已被优化并替换为内联代码:
80484fc: ba 46 86 04 08 mov edx,0x8048646 ; "LETMEWIN\n" address
8048501: b8 60 a0 04 08 mov eax,0x804a060 ; buf address
8048506: b9 0a 00 00 00 mov ecx,0xa ; number of bytes to compare
804850b: 89 d6 mov esi,edx
804850d: 89 c7 mov edi,eax
804850f: f3 a6 repz cmps BYTE PTR ds:[esi],BYTE PTR es:[edi] ;
实际上,它错过了应该检查strcmp
的返回值是否为零的部分。我想您只是没有在这里复制它。在je ...
行之后可能应该有类似jz ...
/ jne ...
/ jnz ...
/ repz ...
的内容。
这8048506:b9 0a 00 00 00 mov ecx,0xa是做什么的?
它设置要比较的最大字节数。