Я пытался изучить основы реверсирования, и я попытался разобрать небольшую программу на C. Я работаю под MacOS 10.7.2 (64 бит - Intel) и с использованием 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>
Теперь, в соответствии с моим пониманием сборщика, все должно быть просто: после strcmp
вызова на 100000e89 значение %ecx
сохраняется и затем сравнивается с 0.
Если они не являются равно (jne
) есть прыжок (else), в противном случае он должен продолжаться (если).
Очень хорошо, я думал, что модифицировать jne
в je
Я должен получить «Правильно» даже с неправильным вводом.
На самом деле я этого не делал. Пытаясь понять, что проблема может быть, я попытался исследовать коды операции, и я получаю странный (для меня) вывода:
(gdb) x/8x 0x100000e93
0x100000e93 <main+83>: 0x8d481175 0x0000b005 0xc7894800 0x000044e8
0x100000ea3 <main+99>: 0x480feb00 0x00a7058d 0x89480000 0x0033e8c7
Нет знак 0f85
, который должен быть кодом для jne
.
Я немного растерялся тогда ... Разве я не должен получить код операции для прыжка? Может кто-нибудь объяснить мне мою ошибку?
Спасибо, это сработало. Я на самом деле смотрел ту же страницу, с которой вы связались, и я взял «0f85» с этой страницы. Можете ли вы объяснить «8-битное смещение релаксации» и почему «0f85» ошибочен? – Saphrosit
8-битное смещение реверса означает относительное смещение, закодированное в один байт, поэтому у вас есть значения в диапазоне от -128 до 127 для смещения. Код операции 0f85 в 64-битном режиме, используемый для 16-битных и 32-разрядных смещений смещения (в зависимости от префикса инструкций размера операнда). –
Использование различных длин смещения, очевидно, выполняется для сохранения размера кода, то есть вам не нужно отбрасывать смещение пространственного кодирования как 32-разрядное целое, если ваш целевой объект перехода находится в пределах 8 или 16-битного целочисленного диапазона. –