2012-03-10 187 views
1

我正试图学习反转的基础知识,并试图反汇编一个小C程序。我正在使用MacOS 10.7.2(64位 - 英特尔)并使用gcc 4.2.1。反汇编C代替操作代码

#include <stdio.h> 

int main() { 

    char word[20]; 

    scanf("%s",word); 
    if (strcmp(word,"password")==0) 
     printf("Correct\n"); 
    else 
     printf("Fail\n"); 
} 

gcc -o test test.c编译,然后,工作用gdb了一会儿,我把一个断点strcmp调用(100000e8e)后得到(我认为是)相关的汇编代码:

0x0000000100000e40 <main+0>: push %rbp 
0x0000000100000e41 <main+1>: mov %rsp,%rbp 
0x0000000100000e44 <main+4>: sub $0x30,%rsp 
0x0000000100000e48 <main+8>: mov 0x1e9(%rip),%rax  # 0x100001038 
0x0000000100000e4f <main+15>: mov (%rax),%rax 
0x0000000100000e52 <main+18>: mov %rax,-0x8(%rbp) 
0x0000000100000e56 <main+22>: lea -0x20(%rbp),%rax 
0x0000000100000e5a <main+26>: mov %rax,%rcx 
0x0000000100000e5d <main+29>: xor %dl,%dl 
0x0000000100000e5f <main+31>: lea 0xda(%rip),%rsi  # 0x100000f40 
0x0000000100000e66 <main+38>: mov %rsi,%rdi 
0x0000000100000e69 <main+41>: mov %rcx,%rsi 
0x0000000100000e6c <main+44>: mov %rax,-0x28(%rbp) 
0x0000000100000e70 <main+48>: mov %dl,%al 
0x0000000100000e72 <main+50>: callq 0x100000eee <dyld_stub_scanf> 
0x0000000100000e77 <main+55>: mov -0x28(%rbp),%rcx 
0x0000000100000e7b <main+59>: xor %dl,%dl 
0x0000000100000e7d <main+61>: lea 0xbf(%rip),%rsi  # 0x100000f43 
0x0000000100000e84 <main+68>: mov %rcx,%rdi 
0x0000000100000e87 <main+71>: mov %dl,%al 
0x0000000100000e89 <main+73>: callq 0x100000ef4 <dyld_stub_strcmp> 
0x0000000100000e8e <main+78>: mov %eax,%ecx 
0x0000000100000e90 <main+80>: cmp $0x0,%ecx 
0x0000000100000e93 <main+83>: jne 0x100000ea6 <main+102> 
0x0000000100000e95 <main+85>: lea 0xb0(%rip),%rax  # 0x100000f4c 
0x0000000100000e9c <main+92>: mov %rax,%rdi 
0x0000000100000e9f <main+95>: callq 0x100000ee8 <dyld_stub_puts> 
0x0000000100000ea4 <main+100>: jmp 0x100000eb5 <main+117> 
0x0000000100000ea6 <main+102>: lea 0xa7(%rip),%rax  # 0x100000f54 
0x0000000100000ead <main+109>: mov %rax,%rdi 
0x0000000100000eb0 <main+112>: callq 0x100000ee8 <dyld_stub_puts> 
0x0000000100000eb5 <main+117>: mov -0xc(%rbp),%eax 
0x0000000100000eb8 <main+120>: mov 0x179(%rip),%rcx  # 0x100001038 
0x0000000100000ebf <main+127>: mov (%rcx),%rcx 
0x0000000100000ec2 <main+130>: mov -0x8(%rbp),%rdx 
0x0000000100000ec6 <main+134>: cmp %rdx,%rcx 
0x0000000100000ec9 <main+137>: mov %eax,-0x2c(%rbp) 
0x0000000100000ecc <main+140>: jne 0x100000ed7 <main+151> 
0x0000000100000ece <main+142>: mov -0x2c(%rbp),%eax 
0x0000000100000ed1 <main+145>: add $0x30,%rsp 
0x0000000100000ed5 <main+149>: pop %rbp 
0x0000000100000ed6 <main+150>: retq 
0x0000000100000ed7 <main+151>: callq 0x100000edc <dyld_stub___stack_chk_fail> 

现在,根据我的汇编程序的理解,事情应该是轻松:%ecx值在100000e89的strcmp调用后保存,然后用0

进行比较。如果他们不等于(jne)有跳跃(else),否则应该继续(if)。

很好,我认为修改jneje即使输入错误,我也应该得到“正确”。

其实我没有。试图了解这个问题可能是什么,我试图检查操作码和我得到一个奇怪的(对我)输出:

(gdb) x/8x 0x100000e93 
0x100000e93 <main+83>: 0x8d481175 0x0000b005 0xc7894800 0x000044e8 
0x100000ea3 <main+99>: 0x480feb00 0x00a7058d 0x89480000 0x0033e8c7 

0f85的标志应该是jne的代码。

我有点困惑,然后......我不应该得到跳转的操作代码?有人可以解释我的错误吗?

回答

3

为JNE见操作码在这里: http://ref.x86asm.net/coder64.html

那么,是什么预期: 0x8d481175 因为它的DWORD印刷,建筑是小端,您有以下从该地址开始的字节序列 : 75 11 48 8d

和75是64位模式下的JNE操作码,具有8位rel偏移量。

验证:从下一条指令的地址+偏移量计算跳转地址。 因此, 0x0000000100000e95 + 0x11 = 0x0000000100000eA6 这正是gdb显示的内容

+0

谢谢,它工作。我实际上正在查看你链接的同一页面,并且我从该页面拿出了'0f85' ...你能解释一下“8位rel offset”和为什么'0f85'是错误的吗? – Saphrosit 2012-03-10 02:32:21

+0

8位rel偏移量表示以单个字节编码的相对偏移量,因此您的偏移量值在-128..127之间。 64位模式下的0f85操作码用于16位和32位相对偏移量(取决于操作数大小的指令前缀)。 – 2012-03-10 18:23:31

+0

为了节省代码长度,显然要使用各种偏移长度,即如果跳转目​​标位于8位或16位整数范围内,则不需要浪费空间编码偏移量为32位整数。 – 2012-03-10 18:35:02