2012-03-10 2 views
1

나는 뒤집기의 기초를 배우려고 노력하고 있었고 작은 C 프로그램을 분해하려고했다. MacOS 10.7.2 (64 비트 - Intel)에서 gcc 4.2.1을 사용하고 있습니다. gcc -o test test.c 컴파일C를 분해하고 조작 코드를 바꾼다

#include <stdio.h> 

int main() { 

    char word[20]; 

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

난 후, 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> 

자, 어셈블러의 나의 이해에 따라 상황이 쉬워야한다 : 100000e89에서 strcmp 호출 후 %ecx의 값은 0

과 비교 한 후 저장되고 그렇지 않은 경우 equal (jne) 거기에 점프 (else)가 있습니다. 그렇지 않으면 계속해야합니다 (if).

매우 좋았습니다. jneje으로 잘못 입력 한 경우에도 "수정"해야합니다.

사실 나는 그렇지 않았습니다. 문제가있을 수 있습니다 이해하려고, 나는 동작 코드를 검사하기 위해 노력하고 내가 이상한 (나에게) 출력을 얻을 다음 0f85

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

흔적 jne의 코드해야합니다.

나는 약간 혼란 스럽다. 나는 점프를위한 작업 코드를 가져야하지 않겠는가? 누군가 내 실수를 설명해 주시겠습니까? http://ref.x86asm.net/coder64.html

그래서,이 예상되는 것입니다 :

답변

3

여기 JNE에 대한 연산 코드를 참조 0x8d481175 의 DWORD를 인쇄하기 때문에, 그리고 아키텍처는 리틀 엔디안, 해당 주소에서 시작하는 바이트의 순서를 다음과 가진 입니다 : 75 11 48 8d

및 75는 8 비트 rel 오프셋이있는 64 비트 모드의 JNE에 대한 opcode입니다.

확인 : 점프 주소는 다음 명령어 + 오프셋의 주소에서 계산됩니다. 그래서 0x0000000100000e95 + 0x11 = 0x0000000100000eA6 정확하게 gdb가 표시되는 내용입니다.

+0

감사합니다. 실제로 당신이 링크 한 동일한 페이지를 찾고 있었고 그 페이지에서'0f85'을 가져 왔습니다 ... "8 비트 rel offset"과 왜'0f85'가 잘못된지 설명해 주시겠습니까? – Saphrosit

+0

8 비트 rel 오프셋은 단일 바이트로 인코딩 된 상대 오프셋을 의미하므로 offset에 대해 -128 .. 127 사이의 값을 갖습니다. 64 비트 모드의 0f85 opcode는 16 비트 및 32 비트 rel 오프셋 (피연산자 크기 명령어 접두어에 따라 다름)에 사용됩니다. –

+0

점프 대상이 8 비트 또는 16 비트 정수 범위 내에있는 경우 다양한 오프셋 길이를 사용하면 코드 크기를 절약 할 수 있습니다. 즉, 32 비트 정수로 공간 오프셋을 낭비 할 필요가 없습니다. –

관련 문제