use*_*356 1 c x86 assembly gcc strcmp
为了提高我的二进制开发技能,并加深我在低级环境中的理解,我尝试解决 中的挑战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;
}
Run Code Online (Sandbox Code Playgroud)
我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?
Run Code Online (Sandbox Code Playgroud)
我不明白的事情是:
strcmp电话在哪里?为什么会这样?8048506: b9 0a 00 00 00 mov ecx,0xa?编译器strcmp使用repe cmpsb实现 memcmp的已知长度字符串内联。
它将esi常量文字字符串“LETMEWIN\n”的地址加载到寄存器中。请注意,此字符串的长度为 10(以 '\0' 结尾)。然后将 的地址加载buf到edi寄存器中,然后调用 x86 指令:
repz cmps BYTE PTR ds:[esi],BYTE PTR es:[edi]
Run Code Online (Sandbox Code Playgroud)
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] ;
Run Code Online (Sandbox Code Playgroud)
实际上它错过了它应该检查的返回值strcmp是否为零的部分。我想你只是没有在这里复制它。在该行之后可能应该有类似je .../ jz .../ jne .../ 之类的东西。jnz ...repz ...
这个 8048506: b9 0a 00 00 00 mov ecx,0xa 有什么作用?
它设置要比较的最大字节数。