[逆向工程]160个CrackMe入门实战之ajj1.2解析(五)

[逆向工程]160个CrackMe入门实战之ajj1.2解析(五)

一.CKme002.exe功能

当"注册"按钮变为"注册了"则表明注册成功

以下是逆向步骤:

执行固定操作序列:程序会持续检查你是否遵循了特定的交互逻辑。你需要按顺序完成以下动作:

  • ok.txt 文件放入 X:\ajj.126.c0m\j\o\j\o\ok.txt路径下,解锁Edit2` 输入框。默认是X盘符,本次为方便修改内存为D盘。ok.txt的文本内容为

    shell 复制代码
    #写入文本 20 61 6A 6A D0 B4 B5 C4 43 4B 6D 65 D5 E6 C0 C3 21 FF FF 会在桌面生成一个ok.txt文件,将该文件拷贝到D:\ajj.126.c0m\j\o\j\o\ok.txt 该路径下
    $bytes = 0x20,0x61,0x6A,0x6A,0xD0,0xB4,0xB5,0xC4,0x43,0x4B,0x6D,0x65,0xD5,0xE6,0xC0,0xC3,0x21,0xFF,0xFF; [System.IO.File]::WriteAllBytes("$env:USERPROFILE\Desktop\ok.txt", $bytes)
  • 右键点击 程序界面的"注册"按钮 5次 ,当图片框中空白时左键双击,解除 Edit2 输入框的禁用状态。

  • 在用户名处输入 ajj

  • Edit2 框中输入 1_345,78,然后左键双击该输入框的任意位置。

  • 当图片显示为"性相近"时,将鼠标从程序窗口的右下角移入窗口内。

  • 当图片显示为"性本善"时,将鼠标从程序窗口的左下角移入窗口内。

  • 完成上述所有步骤后,label3 会显示一个介于 0 到 3 之间的数字,将它记录下来

  • 注册机源码如下,先编译为crackme_solver.exe可执行程序,运行注册机输入数字

    c++ 复制代码
    // crackme_solver.cpp
    // 编译方式:在 VSCode 中打开终端,执行:
    //  g++ crackme_solver.cpp -o crackme_solver.exe
    // 或者使用 MSVC:
    //   cl crackme_solver.cpp
    
    #include <iostream>
    #include <cstdio>
    
    #include <cstring>
    #include <algorithm>
    
    // 图片结构体
    struct Image {
        char szname[7];   // 图片名称,最多6个汉字+结束符
        int nNumber;      // 编号(1~4)
        int nLef;         // 左键点击对应的系数
        int nRight;       // 右键点击对应的系数
    };
    
    int main() {
        // 1. 初始化图片数组(与原始代码完全一致)
        Image aImage[4] = {0};
        sprintf_s(aImage[0].szname, sizeof(aImage[0].szname), "人之初");
        aImage[0].nNumber = 1;
        aImage[0].nLef = 0x2;   // 2
        aImage[0].nRight = 0x11; // 17
    
        sprintf_s(aImage[1].szname, sizeof(aImage[1].szname), "性本善");
        aImage[1].nNumber = 2;
        aImage[1].nLef = 0x3;   // 3
        aImage[1].nRight = 0x13; // 19
    
        sprintf_s(aImage[2].szname, sizeof(aImage[2].szname), "性相近");
        aImage[2].nNumber = 3;
        aImage[2].nLef = 0x5;   // 5
        aImage[2].nRight = 0x17; // 23
    
        sprintf_s(aImage[3].szname, sizeof(aImage[3].szname), "习相远");
        aImage[3].nNumber = 4;
        aImage[3].nLef = 0x7;   // 7
        aImage[3].nRight = 0x1B; // 27
    
        // 2. 获取用户输入
        int input;
        std::cout << "请输入前期步骤得到的数值 (1, 2, 3 或其他): ";
        std::cin >> input;
    
        // 3. 数值映射(与原始代码 switch 完全一致)
        int n;
        switch (input) {
        case 1:  n = 0x3D; break;   // 61
        case 2:  n = 0x34; break;   // 52
        case 3:  n = 0xDF; break;   // 223
        default: n = 0x41; break;   // 65
        }
    
        std::cout << "映射后的目标数值 n = " << n << std::endl;
    
        // 4. 暴力求解最优组合
        int nRes = 112;          // 最小点击次数初始值
        int nIL = 0, nIR = 0;    // 左键图片下标、右键图片下标
        int nJ = 0, nK = 0;      // 右键点击次数 j, 左键点击次数 k
    
        // 遍历所有图片组合
        for (int iL = 0; iL < 4; ++iL) {          // 左键图片(系数 nLef)
            for (int iR = 0; iR < 4; ++iR) {      // 右键图片(系数 nRight)
                // j 范围 1~14(右键次数,原始代码从1开始)
                for (int j = 1; j <= 14; ++j) {
                    // k 范围 0~112(左键次数,原始代码从0开始)
                    for (int k = 0; k <= 112; ++k) {
                        int value = aImage[iR].nRight * j + aImage[iL].nLef * k;
                        if (value == n && (j + k) < nRes) {
                            nIL = iL;
                            nIR = iR;
                            nJ = j;
                            nK = k;
                            nRes = j + k;
                        }
                    }
                }
            }
        }
    
        // 5. 输出结果
        if (nRes == 112) {
            std::cout << "未找到任何有效组合,请检查输入或算法边界!" << std::endl;
        } else {
            char szKey[512];
            sprintf_s(szKey, sizeof(szKey),
                "在"%s"图片时左键点击图片%d次\r\n\r\n在"%s"图片时右键点击图片%d次\r\n\r\n即可注册成功!",
                aImage[nIL].szname, nK,   // 注意:左键次数是 k
                aImage[nIR].szname, nJ);  // 右键次数是 j
            std::cout << szKey << std::endl;
        }
    
        // 暂停,方便查看结果(可选)
        system("pause");
        return 0;
    }
  • 当图是"习相远"时,左键点击一次,右键点击两次,注册成功

需要注意的点如下:

检查项 变量/地址 核心条件 逆向得出的操作要求
禁用点击注册 [ebx+31C] 其值不能为 0x3E7 绝对不能点击"注册"按钮
解锁第一个控件 [ebx+304] 其值不能为 0xC34 程序启动时,会检查固定路径下是否存在特定文件 (ok.txt)
解锁第二个控件 [ebx+308] 其值不能为 0x230D 需要右键点击 "注册"按钮5次 ,然后双击空白区域
鼠标移动与点击 [ebx+310] 其值必须为 0xF94 这是一个多步的、依赖上下文(如图片ID和鼠标坐标)的验证
用户名验证 [ebx+314] - 用户名必须为 ajj
另一个数据输入 [ebx+318] - 这对应于 Edit2 输入框的内容必须为 1_345,78

注册成功截图:

二.开始破解

2.1 Exeinfo查壳

32位程序,upx壳,未有明显语言标识

2.1.1 脱壳

既然有壳并且是upx壳,那么接下来可以用UPX 脱壳 工具进行脱壳操作

脱壳后重新命名程序为CKme002new.exe

再次查壳发现是Delphi语言编写,壳已经去掉了

注意:脱壳这一步可以不操作,因为现在一些的动态调试工具可以无视UPX壳,根据实际情况操作

2.2 x32dbg动态分析

2.2.1 查找核心逻辑

动态分析前先观察运行程序,运行程序有"注册"按钮,那么可以用E2A2工具查看"注册"按钮地址下断点

dbg在004474C0地址处下断点 输入注册名,点击"注册"按钮,运行至004474C0断点处

shift+f8 单步运行后发现代码处有ret ,相当于直接返回了,说明按正常思路找"注册",的思路是错误的,第一处就是不能点击注册那么在xdbg中继续查找发现有"注册了"字符串。依次在dbg反汇编窗口往上查看代码,发现有疑似段首代码

根据一般段首规则可猜测出入口地址代码

push ebx

mov ebx,eax

发现该代码地址为004473E4

004473E4在E2A2中是Timer2 事件入口地址

shell 复制代码
004473E4 | 53                       | push ebx                                             | ebx:&"<珺"
004473E5 | 8BD8                     | mov ebx,eax                                          | ebx:&"<珺", eax:&"<珺"
004473E7 | 81BB 04030000 340C0000   | cmp dword ptr ds:[ebx+304],C34                       |304=C34相等FormCreate读文件相关
004473F1 | 0F84 88000000            | je ckme002.44747F                                    | 
004473F7 | 81BB 08030000 0D230000   | cmp dword ptr ds:[ebx+308],230D                      |308不能等于230D Button1MouseDown相关
00447401 | 74 7C                    | je ckme002.44747F                                    |
00447403 | 81BB 10030000 940F0000   | cmp dword ptr ds:[ebx+310],F94                       |310 FormMouseMove Edit2双击图片框开启相关
0044740D | 75 70                    | jne ckme002.44747F                                   |
0044740F | 8B83 18030000            | mov eax,dword ptr ds:[ebx+318]                       | 318鼠标左键右键点不同图片累加不同的值,初始值为0
00447415 | 3B83 14030000            | cmp eax,dword ptr ds:[ebx+314]                       | 314 页面显示数字 1 2 3相关
0044741B | 75 62                    | jne ckme002.44747F                                   |
0044741D | 81BB 1C030000 E7030000   | cmp dword ptr ds:[ebx+31C],3E7                       |
00447427 | 74 56                    | je ckme002.44747F                                    |
00447429 | 33D2                     | xor edx,edx                                          | edx:&"<珺"
0044742B | 8B83 D8020000            | mov eax,dword ptr ds:[ebx+2D8]                       | eax:&"<珺"
00447431 | 8B08                     | mov ecx,dword ptr ds:[eax]                           | [eax]:"<珺"
00447433 | FF51 5C                  | call dword ptr ds:[ecx+5C]                           |
00447436 | 33D2                     | xor edx,edx                                          | edx:&"<珺"
00447438 | 8B83 DC020000            | mov eax,dword ptr ds:[ebx+2DC]                       | eax:&"<珺"
0044743E | 8B08                     | mov ecx,dword ptr ds:[eax]                           | [eax]:"<珺"
00447440 | FF51 5C                  | call dword ptr ds:[ecx+5C]                           |
00447443 | 33D2                     | xor edx,edx                                          | edx:&"<珺"
00447445 | 8B83 E0020000            | mov eax,dword ptr ds:[ebx+2E0]                       | eax:&"<珺"
0044744B | 8B08                     | mov ecx,dword ptr ds:[eax]                           | [eax]:"<珺"
0044744D | FF51 5C                  | call dword ptr ds:[ecx+5C]                           |
00447450 | 33D2                     | xor edx,edx                                          | edx:&"<珺"
00447452 | 8B83 E4020000            | mov eax,dword ptr ds:[ebx+2E4]                       | eax:&"<珺"
00447458 | 8B08                     | mov ecx,dword ptr ds:[eax]                           | [eax]:"<珺"
0044745A | FF51 5C                  | call dword ptr ds:[ecx+5C]                           |
0044745D | A1 A8984400              | mov eax,dword ptr ds:[4498A8]                        | eax:&"<珺"
00447462 | 83C0 70                  | add eax,70                                           | eax:&"<珺"
00447465 | BA 8C744400              | mov edx,ckme002.44748C                               | edx:&"<珺", 44748C:"厉害厉害真厉害!佩服佩服真佩服!!"
0044746A | E8 EDC4FBFF              | call ckme002.40395C                                  |
0044746F | BA B8744400              | mov edx,ckme002.4474B8                               | edx:&"<珺", 4474B8:"注册了"

从Timer2 事件中可以看到有不同的五个判断,这5个判断和内存中的值有关 分别是[ebx+304]、[ebx+308]、[ebx+310]、[ebx+318]、[ebx+314]、[ebx+31C] 这几个内存地址中的值和不同的常量进行判断,有一个判断不通过则注册不了

2.2.2 判断层分析

接下来逐层分析这五个判断所用到值,顺序依次为

ebx+31C

ebx+304

ebx+308

ebx+310

ebx+314

ebx+318

其中31C 304 308 310 314 318 这些为常量,在dbg中可以使用常量跟踪法,查看那些地方都对这些值做了操作

dbg中鼠标指定这行代码0044741D | 81BB 1C030000 E7030000 | cmp dword ptr ds:[ebx+31C],3E7

2.2.2.1.右键查找引用 常数31C搜寻

查询到两处

查看代码

shell 复制代码
004474C0 | C780 1C030000 E7030000   | mov dword ptr ds:[eax+31C],3E7                       |
004474CA | C3                       | ret                                                  |

004474C0 是Button1Click事件,也就是"注册"事件,点击"注册"按钮后会直接退出,所以"注册"按钮是第一层障碍,不需要去点击

2.2.2.2 右键查找引用 常数304搜寻
shell 复制代码
地址=00446D8F
反汇编=mov dword ptr ds:[ebx+304],C34
地址=00446DB8
反汇编=mov dword ptr ds:[ebx+304],C34
地址=004473E7
反汇编=cmp dword ptr ds:[ebx+304],C34

目的是cmp dword ptr ds:[ebx+304],C34这个比较不能相等,如果相等则je ckme002.44747F 注册会失败

如果mov dword ptr ds:[ebx+304],C34和mov dword ptr ds:[ebx+304],C34这两处赋值的地方跳过,则会绕过je ckme002.44747F 判断,接着走下面的判断了

排查mov dword ptr ds:[ebx+304],C34这个赋值产生的条件,继续浏览代码发现,发现段首

push ebp

mov ebp,esp 地址00446C1C为 FormCreate 事件函数入口地址

shell 复制代码
00446C1C | 55                       | push ebp                                             |
00446C1D | 8BEC                     | mov ebp,esp                                          |
00446C1F | 81C4 30FEFFFF            | add esp,FFFFFE30                                     |
00446C25 | 53                       | push ebx                                             | ebx:&"<珺"
00446C26 | 33C9                     | xor ecx,ecx                                          |
00446C28 | 894D FC                  | mov dword ptr ss:[ebp-4],ecx                         |
00446C2B | 8BD8                     | mov ebx,eax                                          | ebx:&"<珺", eax:&"<珺"
00446C2D | 33C0                     | xor eax,eax                                          | eax:&"<珺"
00446C2F | 55                       | push ebp                                             |
00446C30 | 68 D86D4400              | push ckme002.446DD8                                  |
00446C35 | 64:FF30                  | push dword ptr fs:[eax]                              |
00446C38 | 64:8920                  | mov dword ptr fs:[eax],esp                           |
00446C3B | 33D2                     | xor edx,edx                                          | edx:&"<珺"
00446C3D | 8B83 D8020000            | mov eax,dword ptr ds:[ebx+2D8]                       | eax:&"<珺"
00446C43 | E8 5CD3FDFF              | call ckme002.423FA4                                  |
00446C48 | 33D2                     | xor edx,edx                                          | edx:&"<珺"
00446C4A | 8B83 DC020000            | mov eax,dword ptr ds:[ebx+2DC]                       | eax:&"<珺"
00446C50 | E8 4FD3FDFF              | call ckme002.423FA4                                  |
00446C55 | 33D2                     | xor edx,edx                                          | edx:&"<珺"
00446C57 | 8B83 E0020000            | mov eax,dword ptr ds:[ebx+2E0]                       | eax:&"<珺"
00446C5D | E8 42D3FDFF              | call ckme002.423FA4                                  |
00446C62 | 33D2                     | xor edx,edx                                          | edx:&"<珺"
00446C64 | 8B83 E4020000            | mov eax,dword ptr ds:[ebx+2E4]                       | eax:&"<珺"
00446C6A | E8 35D3FDFF              | call ckme002.423FA4                                  |
00446C6F | 33D2                     | xor edx,edx                                          | edx:&"<珺"
00446C71 | 8B83 D8020000            | mov eax,dword ptr ds:[ebx+2D8]                       | eax:&"<珺"
00446C77 | E8 28D3FDFF              | call ckme002.423FA4                                  |
00446C7C | 33D2                     | xor edx,edx                                          | edx:&"<珺"
00446C7E | 8B83 FC020000            | mov eax,dword ptr ds:[ebx+2FC]                       | eax:&"<珺"
00446C84 | E8 1BD3FDFF              | call ckme002.423FA4                                  |
00446C89 | 33D2                     | xor edx,edx                                          | edx:&"<珺"
00446C8B | 8B83 F0020000            | mov eax,dword ptr ds:[ebx+2F0]                       | eax:&"<珺"
00446C91 | 8B08                     | mov ecx,dword ptr ds:[eax]                           | [eax]:"<珺"
00446C93 | FF51 5C                  | call dword ptr ds:[ecx+5C]                           |
00446C96 | 33D2                     | xor edx,edx                                          | edx:&"<珺"
00446C98 | 8B83 F0020000            | mov eax,dword ptr ds:[ebx+2F0]                       | eax:&"<珺"
00446C9E | E8 01D3FDFF              | call ckme002.423FA4                                  |
00446CA3 | BA 01000000              | mov edx,1                                            | edx:&"<珺"
00446CA8 | 8B83 D8020000            | mov eax,dword ptr ds:[ebx+2D8]                       | eax:&"<珺"
00446CAE | E8 19CCFDFF              | call ckme002.4238CC                                  |
00446CB3 | BA C0FEFFFF              | mov edx,FFFFFEC0                                     | edx:&"<珺"
00446CB8 | 8B83 D8020000            | mov eax,dword ptr ds:[ebx+2D8]                       | eax:&"<珺"
00446CBE | E8 E9CBFDFF              | call ckme002.4238AC                                  |
00446CC3 | BA 01000000              | mov edx,1                                            | edx:&"<珺"
00446CC8 | 8B83 DC020000            | mov eax,dword ptr ds:[ebx+2DC]                       | eax:&"<珺"
00446CCE | E8 F9CBFDFF              | call ckme002.4238CC                                  |
00446CD3 | BA 7E000000              | mov edx,7E                                           | edx:&"<珺", 7E:'~'
00446CD8 | 8B83 DC020000            | mov eax,dword ptr ds:[ebx+2DC]                       | eax:&"<珺"
00446CDE | E8 C9CBFDFF              | call ckme002.4238AC                                  |
00446CE3 | BA 01000000              | mov edx,1                                            | edx:&"<珺"
00446CE8 | 8B83 E0020000            | mov eax,dword ptr ds:[ebx+2E0]                       | eax:&"<珺"
00446CEE | E8 B9CBFDFF              | call ckme002.4238AC                                  |
00446CF3 | BA 7A000000              | mov edx,7A                                           | edx:&"<珺", 7A:'z'
00446CF8 | 8B83 E0020000            | mov eax,dword ptr ds:[ebx+2E0]                       | eax:&"<珺"
00446CFE | E8 C9CBFDFF              | call ckme002.4238CC                                  |
00446D03 | BA 01000000              | mov edx,1                                            | edx:&"<珺"
00446D08 | 8B83 E4020000            | mov eax,dword ptr ds:[ebx+2E4]                       | eax:&"<珺"
00446D0E | E8 99CBFDFF              | call ckme002.4238AC                                  |
00446D13 | BA C0FEFFFF              | mov edx,FFFFFEC0                                     | edx:&"<珺"
00446D18 | 8B83 E4020000            | mov eax,dword ptr ds:[ebx+2E4]                       | eax:&"<珺"
00446D1E | E8 A9CBFDFF              | call ckme002.4238CC                                  |
00446D23 | C783 08030000 8E020000   | mov dword ptr ds:[ebx+308],28E                       |
00446D2D | C783 0C030000 09000000   | mov dword ptr ds:[ebx+30C],9                         | 09:'\t'
00446D37 | C783 14030000 0B000000   | mov dword ptr ds:[ebx+314],B                         | 0B:'\v'
00446D41 | 33C0                     | xor eax,eax                                          | eax:&"<珺"
00446D43 | 8983 18030000            | mov dword ptr ds:[ebx+318],eax                       | eax:&"<珺"
00446D49 | BA EC6D4400              | mov edx,ckme002.446DEC                               | 原本作者要求的路径 "X:\\ajj.126.c0m\\j\\o\\j\\o\\ok.txt"
00446D4E | 8D85 30FEFFFF            | lea eax,dword ptr ss:[ebp-1D0]                       | [ebp-1D0]:"ヲA"
00446D54 | E8 EDE7FBFF              | call ckme002.405546                                  |
00446D59 | 8D85 30FEFFFF            | lea eax,dword ptr ss:[ebp-1D0]                       | [ebp-1D0]:"ヲA"
00446D5F | E8 07EAFBFF              | call ckme002.40576B                                  |
00446D64 | E8 8BBAFBFF              | call ckme002.4027F4                                  |
00446D69 | 85C0                     | test eax,eax                                         | 判断文件路径内容等是否正确
00446D6B | 75 4B                    | jne ckme002.446DB8                                   | 
00446D6D | 8D55 FC                  | lea edx,dword ptr ss:[ebp-4]                         |
00446D70 | 8D85 30FEFFFF            | lea eax,dword ptr ss:[ebp-1D0]                       | [ebp-1D0]:"ヲA"
00446D76 | E8 5DD1FBFF              | call ckme002.403ED8                                  |
00446D7B | E8 44BAFBFF              | call ckme002.4027C4                                  |
00446D80 | 8B45 FC                  | mov eax,dword ptr ss:[ebp-4]                         |从实际路径得到的字符串
00446D83 | BA 146E4400              | mov edx,ckme002.446E14                               | 实际的字符串
00446D88 | E8 0BCFFBFF              | call ckme002.403C98                                  |比较字符串
00446D8D | 74 0A                    | je ckme002.446D99                                    | 是必须要相等则跳过赋值,路径能找到,必须查找到字符串实际内容
00446D8F | C783 04030000 340C0000   | mov dword ptr ds:[ebx+304],C34                       |要越过这一步赋值
00446D99 | 8D85 30FEFFFF            | lea eax,dword ptr ss:[ebp-1D0]                       | [ebp-1D0]:"ヲA"
shell 复制代码
00446D54 | E8 EDE7FBFF              | call ckme003.405546                                  |
这行代码是跳转到405546地址,具体功能为
0040557A | 85D2                     | test edx,edx                                         | 检查传入的字符串指针(即文件路径 "D:\\ajj.126.c0m\\j\\o\\j\\o\\ok.txt")是否为 NULL
0040557C | 74 1B                    | je ckme003.405599                                    |

作者原本文件路径是X盘符,所以为了方便并且符合不为null将盘符修改为D盘

446DEC:"X:\ajj.126.c0m\j\o\j\o\ok.txt" 修改盘符

X 58 --->D 44 保证字符串长度一致 鼠标双击修改 修改为D盘 打补丁保存为CKme003.exe

DarkDe打开FormCreate 事件代码静态分析,发现字符串为' ajj写的CKme真烂! ' ,需注意前后都有不可见字符,那么需要跟代码在内存中查找前后空格十六进制值

跟踪代码找到 ajj写的CKme真烂! 对应的十六进制: 20 61 6A 6A D0 B4 B5 C4 43 4B 6D 65 D5 E6 C0 C3 21 FF FF

20 代表空格字符

FF FF 代表 ÿ ÿ (带分音符的小写 y)

需要用命令行将生成ok.txt文件以及将以上内容写入该文件,windows下Po'werShell执行以下命令,生成后将桌面生成的ok.txt复制到固定路径下:

shell 复制代码
#写入文本 20 61 6A 6A D0 B4 B5 C4 43 4B 6D 65 D5 E6 C0 C3 21 FF FF 会在桌面生成一个ok.txt文件,将该文件拷贝到D:\ajj.126.c0m\j\o\j\o\ok.txt 该路径下
$bytes = 0x20,0x61,0x6A,0x6A,0xD0,0xB4,0xB5,0xC4,0x43,0x4B,0x6D,0x65,0xD5,0xE6,0xC0,0xC3,0x21,0xFF,0xFF; [System.IO.File]::WriteAllBytes("$env:USERPROFILE\Desktop\ok.txt", $bytes)
2.2.2.3 右键查找引用 常数308搜寻
shell 复制代码
地址=00446D23
反汇编=mov dword ptr ds:[ebx+308],28E   FormCreate 事件赋初值
地址=00446FA7
反汇编=mov edx,dword ptr ds:[eax+308] 
地址=00446FBA
反汇编=add dword ptr ds:[eax+308],3
地址=00446FCB
反汇编=mov dword ptr ds:[eax+308],230D
地址=00446FDC
反汇编=cmp dword ptr ds:[eax+308],29D
地址=004473F7
反汇编=cmp dword ptr ds:[ebx+308],230D

从Timer2事件看,308不能等于230D,如果相等直接跳转到44747F 程序直接ret

shell 复制代码
004473F7 | 81BB 08030000 0D230000   | cmp dword ptr ds:[ebx+308],230D         | 308
00447401 | 74 7C                    | je ckme003.44747F                       |

Button1MouseDown 事件入口地址 注册按钮,需注意:

MouseDown 事件,其函数原型大致是 ,由此可判断是鼠标右键还是左键

shell 复制代码
procedure TForm1.Button1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);

其中 Button 参数是一个枚举类型:

  • mbLeft = 0(左键)
  • mbRight = 1(右键)
  • mbMiddle = 2(中键)

这个 Button 参数正是通过 cl 寄存器传入的。因此:

  • 左键点击cl = 0
  • 右键点击cl = 1
shell 复制代码
00446FA4 | 55                       | push ebp                                | Button1MouseDown 事件入口地址 注册按钮
00446FA5 | 8BEC                     | mov ebp,esp                             |
00446FA7 | 8B90 08030000            | mov edx,dword ptr ds:[eax+308]          |
00446FAD | 81FA 0D230000            | cmp edx,230D                            |
00446FB3 | 74 20                    | je ckme003.446FD5                       |
00446FB5 | 80F9 01                  | cmp cl,1                                | cl 要等于1 代表是鼠标右键点击 ECX低8位
00446FB8 | 75 09                    | jne ckme003.446FC3                      |
00446FBA | 8380 08030000 03         | add dword ptr ds:[eax+308],3            | 点击一次加3 直至29D 0x29D减去0x28E再除以0x3最后结果等于5 也就是点击5次
00446FC1 | EB 12                    | jmp ckme003.446FD5                      |
00446FC3 | 81FA 94020000            | cmp edx,294                             |
00446FC9 | 7D 0A                    | jge ckme003.446FD5                      |
00446FCB | C780 08030000 0D230000   | mov dword ptr ds:[eax+308],230D         |
00446FD5 | 5D                       | pop ebp                                 |
00446FD6 | C2 0C00                  | ret C                                   |
00446FD9 | 8D40 00                  | lea eax,dword ptr ds:[eax]              | eax:&"<珺", [eax]:"<珺"
00446FDC | 81B8 08030000 9D020000   | cmp dword ptr ds:[eax+308],29D          | 图片框左键双击 图片不能点击 双击事件的处理函数名通常包含 DblClick 这个是Panel1DblClick事件入口地址Panel1DblClick事件就可以解禁 Edit2控件  308值等于29D时
00446FE6 | 75 0D                    | jne ckme003.446FF5                      | 308不等于29D就跳转
00446FE8 | B2 01                    | mov dl,1                                |
00446FEA | 8B80 F0020000            | mov eax,dword ptr ds:[eax+2F0]          | 双击图片框启用Edit2 2F0是控件Edit2的ID
00446FF0 | 8B08                     | mov ecx,dword ptr ds:[eax]              | [eax]:"<珺"
00446FF2 | FF51 5C                  | call dword ptr ds:[ecx+5C]              |启用Edit2
00446FF5 | C3                       | ret                                     |

从寄存器中也可判断位右键,右键点击"注册":

2.2.2.4 右键查找引用 常数310搜寻

310值,必须等于0xF94

相关事件函数 FormMouseMove、Edit2DblClick

要令地址 [310] 最终被赋值为 0xF94,必须依次通过三重判断:

  1. **控件 ID 为 0xE20(图片"性相近")**时,鼠标右下角移动(FormMouseMove 的 XY 坐标均足够大)→ 将 [310] 暂赋值为 0x10
  2. **控件 ID 为 0x2DC(图片"性本善")**时,鼠标左下角移动(X 小、Y 大)。
  3. [30C] 不能等于初始值 0x9
    • [30C] 的赋值条件:Edit2 字符串长度为 8,且第 2 位为 _、第 6 位为 ,(如 1_345,78 符合);
    • 用户名长度须为 3 的整数倍;
    • Edit2左键双击 ,此时 [30C] 的值由磁盘剩余空间决定。

以上三重条件全部满足后,[310] 最终被赋值为 0xF94

此外,若用户名为 "ajj",则显示隐藏控件 ID=0x2FC(Label3),其显示内容为 [30C] 的值。

shell 复制代码
004470EC | 55                       | push ebp                                | FormMouseMove事件入口 鼠标移动
004470ED | 8BEC                     | mov ebp,esp                             |
004470EF | 6A 00                    | push 0                                  |
004470F1 | 6A 00                    | push 0                                  |
004470F3 | 53                       | push ebx                                | ebx:&"<珺"
004470F4 | 8BD8                     | mov ebx,eax                             | ebx:&"<珺", eax:&"<珺"
004470F6 | 8B55 08                  | mov edx,dword ptr ss:[ebp+8]            | y坐标
004470F9 | 8B45 0C                  | mov eax,dword ptr ss:[ebp+C]            | x坐标
004470FC | 33C9                     | xor ecx,ecx                             | ecx:"<FD"
004470FE | 55                       | push ebp                                |
004470FF | 68 17724400              | push <ckme003.sub_447217>               |
00447104 | 64:FF31                  | push dword ptr fs:[ecx]                 |
00447107 | 64:8921                  | mov dword ptr fs:[ecx],esp              |
0044710A | 8B8B E0020000            | mov ecx,dword ptr ds:[ebx+2E0]          | image3控件地址
00447110 | 8079 47 01               | cmp byte ptr ds:[ecx+47],1              |
00447114 | 75 19                    | jne ckme003.44712F                      |
00447116 | 3D E2000000              | cmp eax,E2                              | eax:&"<珺"
0044711B | 7E 12                    | jle ckme003.44712F                      | X小于E2则跳
0044711D | 81FA 2C010000            | cmp edx,12C                             | y小于12c则跳
00447123 | 7E 0A                    | jle ckme003.44712F                      |
00447125 | C783 10030000 10000000   | mov dword ptr ds:[ebx+310],10           |
0044712F | 8B8B DC020000            | mov ecx,dword ptr ds:[ebx+2DC]          | image2控件
00447135 | 8079 47 01               | cmp byte ptr ds:[ecx+47],1              |
00447139 | 75 6C                    | jne ckme003.4471A7                      | 不是image2则跳
0044713B | 83F8 17                  | cmp eax,17                              | eax:&"<珺"
0044713E | 7D 67                    | jge ckme003.4471A7                      | x大于17则跳
00447140 | 81FA 2C010000            | cmp edx,12C                             | edx:"h4D"
00447146 | 7E 5F                    | jle ckme003.4471A7                      | y小于12c则跳
00447148 | 83BB 10030000 10         | cmp dword ptr ds:[ebx+310],10           |
0044714F | 75 56                    | jne ckme003.4471A7                      | 满足第一步则跳
00447151 | 83BB 0C030000 09         | cmp dword ptr ds:[ebx+30C],9            | 30c值初始值为9则跳
00447158 | 74 4D                    | je ckme003.4471A7                       |
0044715A | C783 10030000 940F0000   | mov dword ptr ds:[ebx+310],F94          | 最终目标
shell 复制代码
00446FF8 | 55                       | push ebp                                | Edit2双击事件入口地址
00446FF9 | 8BEC                     | mov ebp,esp                             |
00446FFB | 33C9                     | xor ecx,ecx                             | ecx:"<FD"
00446FFD | 51                       | push ecx                                | ecx:"<FD"
00446FFE | 51                       | push ecx                                | ecx:"<FD"
00446FFF | 51                       | push ecx                                | ecx:"<FD"
00447000 | 51                       | push ecx                                | ecx:"<FD"
00447001 | 51                       | push ecx                                | ecx:"<FD"
00447002 | 53                       | push ebx                                | ebx:&"<珺"
00447003 | 8BD8                     | mov ebx,eax                             | ebx:&"<珺", eax:&"<珺"
00447005 | 33C0                     | xor eax,eax                             | eax:&"<珺"
00447007 | 55                       | push ebp                                |
00447008 | 68 DF704400              | push <ckme003.sub_4470DF>               |
0044700D | 64:FF30                  | push dword ptr fs:[eax]                 |
00447010 | 64:8920                  | mov dword ptr fs:[eax],esp              |
00447013 | 8D55 FC                  | lea edx,dword ptr ss:[ebp-4]            | [ebp-04]:"h4D"
00447016 | 8B83 F0020000            | mov eax,dword ptr ds:[ebx+2F0]          | Edit2控件ID
0044701C | E8 6BD0FDFF              | call <ckme003.sub_42408C>               |
00447021 | 8B45 FC                  | mov eax,dword ptr ss:[ebp-4]            | [ebp-04]:"h4D"
00447024 | E8 5FCBFBFF              | call <ckme003.sub_403B88>               |
00447029 | 83F8 08                  | cmp eax,8                               | 8个字符强制要求
0044702C | 0F85 92000000            | jne ckme003.4470C4                      |
00447032 | 8D55 F8                  | lea edx,dword ptr ss:[ebp-8]            |
00447035 | 8B83 F0020000            | mov eax,dword ptr ds:[ebx+2F0]          | eax:&"<珺", [ebx+2F0]:&"<珺"
0044703B | E8 4CD0FDFF              | call <ckme003.sub_42408C>               |
00447040 | 8B45 F8                  | mov eax,dword ptr ss:[ebp-8]            |
00447043 | 8078 01 5F               | cmp byte ptr ds:[eax+1],5F              | eax+01:"iD", 5F:'_' 第二个字符是_
00447047 | 75 7B                    | jne ckme003.4470C4                      |
00447049 | 8D55 F4                  | lea edx,dword ptr ss:[ebp-C]            |
0044704C | 8B83 F0020000            | mov eax,dword ptr ds:[ebx+2F0]          | eax:&"<珺", [ebx+2F0]:&"<珺"
00447052 | E8 35D0FDFF              | call <ckme003.sub_42408C>               |
00447057 | 8B45 F4                  | mov eax,dword ptr ss:[ebp-C]            |
0044705A | 8078 05 2C               | cmp byte ptr ds:[eax+5],2C              | 2C:',' 第六个字符,
0044705E | 75 64                    | jne ckme003.4470C4                      |
00447060 | 8D55 F0                  | lea edx,dword ptr ss:[ebp-10]           |
00447063 | 8B83 E8020000            | mov eax,dword ptr ds:[ebx+2E8]          | 第一个输入框
00447069 | E8 1ED0FDFF              | call <ckme003.sub_42408C>               |
0044706E | 8B45 F0                  | mov eax,dword ptr ss:[ebp-10]           |
00447071 | E8 12CBFBFF              | call <ckme003.sub_403B88>               | eax = 用户名长度
00447076 | 83C0 03                  | add eax,3                               | eax = eax +3
00447079 | B9 03000000              | mov ecx,3                               | ecx:"<FD"
0044707E | 99                       | cdq                                     |
0044707F | F7F9                     | idiv ecx                                | 取模运算eax = eax % 3
00447081 | 85D2                     | test edx,edx                            | 不等于0则跳转
00447083 | 75 3F                    | jne ckme003.4470C4                      |
00447085 | 6A 00                    | push 0                                  |
00447087 | 6A 04                    | push 4                                  |
00447089 | 8D55 EC                  | lea edx,dword ptr ss:[ebp-14]           |
0044708C | 8B83 E8020000            | mov eax,dword ptr ds:[ebx+2E8]          | eax:&"<珺", [ebx+2E8]:&"<珺"
00447092 | E8 F5CFFDFF              | call <ckme003.sub_42408C>               |
00447097 | 8B45 EC                  | mov eax,dword ptr ss:[ebp-14]           |
0044709A | E8 E9CAFBFF              | call <ckme003.sub_403B88>               |
0044709F | 99                       | cdq                                     |
004470A0 | 52                       | push edx                                | edx:"h4D"
004470A1 | 50                       | push eax                                | eax:&"<珺"
004470A2 | 33C0                     | xor eax,eax                             | eax:&"<珺"
004470A4 | E8 E70EFCFF              | call <ckme003.sub_407F90>               | 磁盘余量的函数值当随机数
004470A9 | 030424                   | add eax,dword ptr ss:[esp]              | [esp]:"h4D"
004470AC | 135424 04                | adc edx,dword ptr ss:[esp+4]            | [esp+04]:sub_444774+12
004470B0 | 83C4 08                  | add esp,8                               |
004470B3 | 83C0 02                  | add eax,2                               | eax:&"<珺"
004470B6 | 83D2 00                  | adc edx,0                               | edx:"h4D"
004470B9 | E8 47ECFBFF              | call <ckme003.sub_405D05>               | 随机数hash 最终算出30c的值 只有0 1 2 3 四种可能

2.2.2.5 右键查找引用 常数314和318搜寻

314的值等于318的值

image1~4MouseDown 事件函数

[314] 已在上一流程中根据 [30C] 赋值:

  • 30C = 0/1/2/3 时,314 = 0x41 / 0x3D / 0x34 / 0xDF

[318] 通过点击第 1~4 幅图片(区分左/右键)累加不同数值得到。

最终条件[318] 必须等于 [314]

shell 复制代码
00447179 | C783 14030000 41000000   | mov dword ptr ds:[ebx+314],41           | 鼠标移动事件 依据30c值给314赋值
00447183 | EB 22                    | jmp ckme003.4471A7                      |
00447185 | C783 14030000 3D000000   | mov dword ptr ds:[ebx+314],3D           | 鼠标移动事件 依据30c值给314赋值
0044718F | EB 16                    | jmp ckme003.4471A7                      |
00447191 | C783 14030000 34000000   | mov dword ptr ds:[ebx+314],34           | 鼠标移动事件 依据30c值给314赋值
0044719B | EB 0A                    | jmp ckme003.4471A7                      |
0044719D | C783 14030000 DF000000   | mov dword ptr ds:[ebx+314],DF           | 鼠标移动事件 依据30c值给314赋值
004471A7 | 81BB 10030000 940F0000   | cmp dword ptr ds:[ebx+310],F94          |
004471B1 | 75 46                    | jne ckme003.4471F9                      |
004471B3 | 8D55 FC                  | lea edx,dword ptr ss:[ebp-4]            | [ebp-04]:"h4D"
004471B6 | 8B83 E8020000            | mov eax,dword ptr ds:[ebx+2E8]          | eax:&"<珺", [ebx+2E8]:&"<珺"
004471BC | E8 CBCEFDFF              | call <ckme003.sub_42408C>               |
004471C1 | 8B45 FC                  | mov eax,dword ptr ss:[ebp-4]            | [ebp-04]:"h4D"
004471C4 | BA 30724400              | mov edx,ckme003.447230                  | edx:"h4D", 447230:"ajj" 用户名是ajj 显示隐藏的label3 30c的值显示
004471C9 | E8 CACAFBFF              | call <ckme003.sub_403C98>               |
004471CE | 75 29                    | jne ckme003.4471F9                      |
004471D0 | B2 01                    | mov dl,1                                |
004471D2 | 8B83 FC020000            | mov eax,dword ptr ds:[ebx+2FC]          | label3 控件id
004471D8 | E8 C7CDFDFF              | call <ckme003.sub_423FA4>               |
004471DD | 8D55 F8                  | lea edx,dword ptr ss:[ebp-8]            |
004471E0 | 8B83 0C030000            | mov eax,dword ptr ds:[ebx+30C]          | eax:&"<珺"
004471E6 | E8 AD0AFCFF              | call <ckme003.sub_407C98>               |
004471EB | 8B55 F8                  | mov edx,dword ptr ss:[ebp-8]            |
004471EE | 8B83 FC020000            | mov eax,dword ptr ds:[ebx+2FC]          | label3 控件id

三.总结

整个验证流程涉及多重条件嵌套:控件图片触发、鼠标坐标范围、字符串格式与长度、磁盘剩余空间、以及多幅图片的左右键点击累加。

如果爆破会简单很多,目的是学习,更多细节还需慢慢补充,期待和大家一起进步!

相关推荐
qq_283720052 小时前
Python 爬虫实战:从入门到精通,爬取某站数据
爬虫·逆向·反爬虫
IT 行者10 小时前
Web逆向工程AI工具:JSHook MCP,80+专业工具让Claude变JS逆向大师
开发语言·javascript·ecmascript·逆向
嫂子的姐夫13 小时前
33-补环境介绍
爬虫·js逆向·逆向
嫂子的姐夫20 小时前
32-字体反爬
爬虫·逆向
IT 行者21 小时前
Web逆向工程AI工具:WebScout MCP Server,给AI装上眼睛和手
人工智能·逆向·web逆向·mcp
嫂子的姐夫1 天前
34-自动化补环境和jsdom补环境
爬虫·python·逆向
永远的超音速4 天前
buuctf逆向2
网络安全·逆向
LittleFishC8 天前
08_长调用与短调用
c语言·汇编·逆向·windows内核
sam.li11 天前
JADX MCP 原理与使用部署
android·逆向·jadx