帮助 IOLI crackme0x02

逆向工程 数据库 快手 雷达2
2021-06-15 19:40:04

我正在学习IOLI crackme0x02我很清楚,在没有说明的情况下重写 0x8048451 处的跳转可以修补破解版。但是,我想更好地理解代码的作用。我的问题是我无法找到输入的密码所在的位置。

我解释了radare2显示有3个局部变量的内容。

│          ; arg int arg_22_2     @ ebp+0x5a
│          ; arg int arg_123      @ ebp+0x1ec
│          ; var int local_1      @ ebp-0x4
│          ; var int local_2      @ ebp-0x8
│          ; var int local_3      @ ebp-0xc
...
|           0x0804840c      c70424618504.  movl $str.Password:, (%esp) ; [0x8048561:4]=0x73736150  LEA str.Password: ; "Password: " @ 0x8048561
|           0x08048413      e804ffffff     calll sym.imp.printf
|           0x08048418      8d45fc         leal -4(%ebp), %eax
|           0x0804841b      89442404       movl %eax, 4(%esp)
|           0x0804841f      c704246c8504.  movl $0x804856c, (%esp)     ; [0x804856c:4]=0x50006425 
|           0x08048426      e8e1feffff     calll sym.imp.scanf
|           0x0804842b      c745f85a0000.  movl $0x5a, -8(%ebp)        ; [0x5a:4]=-1 ; 'Z' ; 90
|           0x08048432      c745f4ec0100.  movl $0x1ec, -0xc(%ebp)     ; [0x1ec:4]=-1 ; 492
|           0x08048439      8b55f4         movl -0xc(%ebp), %edx
|           0x0804843c      8d45f8         leal -8(%ebp), %eax
|           0x0804843f      0110           addl %edx, (%eax)
|           0x08048441      8b45f8         movl -8(%ebp), %eax
|           0x08048444      0faf45f8       imull -8(%ebp), %eax
|           0x08048448      8945f4         movl %eax, -0xc(%ebp)
|           0x0804844b      8b45fc         movl -4(%ebp), %eax
|           0x0804844e      3b45f4         cmpl -0xc(%ebp), %eax
|       ,=< 0x08048451      750e           jne 0x8048461              
|       |   0x08048453      c704246f8504.  movl $str.Password_OK_:__n, (%esp) ; [0x804856f:4]=0x73736150  LEA str.Password_OK_:__n ; "Password OK :)." @ 0x804856f
|       |   0x0804845a      e8bdfeffff     calll sym.imp.printf
|      ,==< 0x0804845f      eb0c           jmp 0x804846d              
|      |`-> 0x08048461      c704247f8504.  movl $str.Invalid_Password__n, (%esp) ; [0x804857f:4]=0x61766e49  LEA str.Invalid_Password__n ; "Invalid Password!." @ 0x804857f
|      |    0x08048468      e8affeffff     calll sym.imp.printf
|      |    ; JMP XREF from 0x0804845f (sym.main)

由于我还不熟悉radare2,我在gdb之后放置了一个断点scanf (0x0804842b),并检查了局部变量。似乎他们和他们指向的地址都不是密码。

我对此有两个问题crackme

  1. 输入的密码在哪里?

  2. 我不明白我在这里得到了什么:

    Breakpoint 1, 0x0804843c in main ()
    (gdb) x/4x $ebp-8
    0xffffd1b0:    0x00000000    0x08048330    0x00000000    0xf7e1a72e
    

    因为 ingdb x/4x通常会打印 4 个字节。

2个回答

scanf()函数之后它可能会有点混乱,但是我可以为您解释这一点,因为我将这个二进制文件反转回没有源代码的 C 代码。

大会之后scanf()

|           0x08048426      e8e1feffff     call sym.imp.scanf
|           0x0804842b      c745f85a0000.  mov dword [ebp - local_8h], 0x5a ; 'Z'
|           0x08048432      c745f4ec0100.  mov dword [ebp - local_ch], 0x1ec
|           0x08048439      8b55f4         mov edx, dword [ebp - local_ch]
|           0x0804843c      8d45f8         lea eax, dword [ebp - local_8h]
|           0x0804843f      0110           add dword [eax], edx
|           0x08048441      8b45f8         mov eax, dword [ebp - local_8h]
|           0x08048444      0faf45f8       imul eax, dword [ebp - local_8h]
|           0x08048448      8945f4         mov dword [ebp - local_ch], eax
|           0x0804844b      8b45fc         mov eax, dword [ebp - local_4h]
|           0x0804844e      3b45f4         cmp eax, dword [ebp - local_ch]
|       ,=< 0x08048451      750e           jne 0x8048461
|       |   0x08048453      c704246f8504.  mov dword [esp], str.Password_OK_:__n ; [0x804856f:4]=0x73736150 LEA str.Password_OK_:__n ; "Password OK :)." @ 0x804856f
|       |   0x0804845a      e8bdfeffff     call sym.imp.printf
|      ,==< 0x0804845f      eb0c           jmp 0x804846d
|      ||   ; JMP XREF from 0x08048451 (sym.main)
|      |`-> 0x08048461      c704247f8504.  mov dword [esp], str.Invalid_Password__n ; [0x804857f:4]=0x61766e49 LEA str.Invalid_Password__n ; "Invalid Password!." @ 0x804857f
|      |    0x08048468      e8affeffff     call sym.imp.printf
|      |    ; JMP XREF from 0x0804845f (sym.main)
|      `--> 0x0804846d      b800000000     mov eax, 0
|           0x08048472      c9             leave
\           0x08048473      c3             ret

第一部分:

|           0x0804842b      c745f85a0000.  mov dword [ebp - local_8h], 0x5a ; 'Z'
|           0x08048432      c745f4ec0100.  mov dword [ebp - local_ch], 0x1e

在这里,我们可以看到值被“移动”到内存中的基指针减0x8和减号处0xc请记住,'h' 表示十六进制,本地表示只是十六进制值减去 ebp 或基指针的值。ebp 代表扩展基指针。

要弄清楚正在存储哪些值,请将十六进制转换为十进制:

0x5a = 90
0x1e = 492

将此视为将变量存储在内存中,例如:

int a = 90
int b = 492

第二部分:

|           0x08048439      8b55f4         mov edx, dword [ebp - local_ch]
|           0x0804843c      8d45f8         lea eax, dword [ebp - local_8h]
|           0x0804843f      0110           add dword [eax], edx
|           0x08048441      8b45f8         mov eax, dword [ebp - local_8h]

请记住,使用寄存器计算某些东西比从内存中计算要快,因此在每次操作之前,编译器将尝试将其可以移动到寄存器中以进行计算。

我们ebp-0xc -> 0x1e进入 edx 寄存器,然后加载 的有效地址(lea)ebp-0x8 -> 0x5a

add 指令将两个值相加并将它们保存到[eax]它现在与指向的指针相同,ebp-0x8因为它将它保存到内存我们可以假设我们正在用新的计算值替换现有变量,因为我们将返回的值从 add 移动到内存中的相同位置有效地覆盖它。

所以我们可以再次假设我们的代码是这样的:

int a = 90
int b = 492
a = a + b

第三方:

|           0x08048444      0faf45f8       imul eax, dword [ebp - local_8h]
|           0x08048448      8945f4         mov dword [ebp - local_ch], eax
|           0x0804844b      8b45fc         mov eax, dword [ebp - local_4h]
|           0x0804844e      3b45f4         cmp eax, dword [ebp - local_ch]
|       ,=< 0x08048451      750e           jne 0x8048461

您可能不熟悉该imul指令,但它只是将两个整数相乘。我们乘以eax它的值是加法操作的返回值,(582 or 90 + 492)然后存储该值以eax覆盖它的先前值582因此我们正在执行(a + b) * (a + b)or 582 * 582

然后我们将您输入的值scanf()从内存中移入eax并将其与 进行比较(a + b) * (a + b)如果之后跳转不等于零,它将0x8048461显示无效密码,否则将跳转到有效密码。如果密码有效或无效,它将退出。

现在你有了更好的理解,你可以像我一样把源代码放在一起:

#include <stdio.h>
int main(int argc, char *argv[]){
        int a,b,c;
        printf("IOLI Crackme Level 0x02\n");
        printf("Password: ");
        scanf("%d", &a);
        b = 90;
        c = 492;
        c = ((b + c) * (b + c));
        if(a == c){
                printf("Password OK :)\n");
        }
        else{
                printf("Invalid Password!\n");
        }
        return 0;
}

这是我编译的程序版本及其控制流图: 在此处输入图片说明

希望这对您的逆向工程之旅有所帮助并祝您好运!

如果你看看之前发生了什么scanf,你会看到这个:

[0x080483e4]> pd 4 @ 0x08048418
│           0x08048418      8d45fc         lea eax, [ebp-local_1]
│           0x0804841b      89442404       mov dword [esp + 4], eax
│           0x0804841f      c704246c8504.  mov dword [esp], 0x804856c  ; [0x804856c:4]=0x50006425 
│           0x08048426      e8e1feffff     call sym.imp.scanf
[0x080483e4]> psz @ 0x804856c
%d

0x804856c是格式字符串的地址(此处为%d),以及ebp-local_1存储结果的偏移量。

至于你的x/4x问题,radare2 会为你打印 4 个字,以十六进制表示,即0x00000000 0x08048330 0x00000000 0xf7e1a72e.