当前位置: 首页 > news >正文

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

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

一.aLoNg3x.2功能

作者说不要打补丁,找出用户名和注册码,隐藏下面的按钮,算成功

还是用补丁方式,验证是否逆向成功

二.查壳

无壳,32位程序,Delphi语言

DeDe查看事件及控件相关信息:

事件:

00442B98 取消按钮事件

00442CC8 关于按钮事件

00442F28 注册按钮事件

004430BC 重试按钮事件

控件ID:

2E8 重试按钮控件ID

2E4 取消控件ID

2DC 注册码控件ID

2D8 输入名控件ID

2CC 注册控件ID

三.逆向分析

3.1 00442F28 注册按钮事件

还是使用nop爆破方法分析事件,注册按钮入口地址00442F28处下断点

根据DeDe以及dbg分析以下是爆破点注释

00442F9F处nop填充

00442FC0处nop填充

00442F9F处nop填充

00442FCF处mov dl,1-----修改为mov dl,0

修改后将该文件打补丁为3.exe

备注:源程序中对注册码也做了一些简单校验,本次爆破输入时全部为数字

00442F28|55|push ebp|注册按钮入口 00442F29|8BEC|mov ebp,esp|00442F2B|83C4 F8|addesp,FFFFFFF8|00442F2E|53|push ebx|00442F2F|56|push esi|esi:"U嬱兡舾(3D"00442F30|33C9|xor ecx,ecx|ecx:"U嬱兡舾(3D"00442F32|894D F8|mov dword ptr ss:[ebp-8],ecx|00442F35|8BD8|mov ebx,eax|00442F37|33C0|xor eax,eax|00442F39|55|push ebp|00442F3A|6822304400|push3.443022|00442F3F|64:FF30|push dword ptr fs:[eax]|00442F42|64:8920|mov dword ptr fs:[eax],esp|00442F45|8D55 F8|lea edx,dword ptr ss:[ebp-8]|00442F48|8B83 DC020000|mov eax,dword ptr ds:[ebx+2DC]|00442F4E|E8 ED02FEFF|call3.423240|00442F53|8B45 F8|mov eax,dword ptr ss:[ebp-8]|00442F56|8D55 FC|lea edx,dword ptr ss:[ebp-4]|[ebp-04]:BaseThreadInitThunk 00442F59|E8 FAF9FBFF|call3.402958|00442F5E|8BF0|mov esi,eax|esi:"U嬱兡舾(3D"00442F60|837D FC 00|cmpdword ptr ss:[ebp-4],0|[ebp-04]:BaseThreadInitThunk 00442F64|7437|je3.442F9D|00442F66|B838304400|mov eax,3.443038|443038:"You MUST insert a valid Long Integer Value in the Code Editor... Thank you :)"00442F6B|E8 00F6FFFF|call3.442570|00442F70|8D55 F8|lea edx,dword ptr ss:[ebp-8]|00442F73|8B83 DC020000|mov eax,dword ptr ds:[ebx+2DC]|00442F79|E8 C202FEFF|call3.423240|00442F7E|8B45 F8|mov eax,dword ptr ss:[ebp-8]|00442F81|E8 06FBFFFF|call3.442A8C|00442F86|A330584400|mov dword ptr ds:[445830],eax|00442F8B|BA90304400|mov edx,3.443090|edx:"U嬱兡舾(3D"00442F90|8B83 DC020000|mov eax,dword ptr ds:[ebx+2DC]|2DC 注册码控件ID 00442F96|E8 D502FEFF|call3.423270|00442F9B|EB 6F|jmp3.44300C|00442F9D|85F6|testesi,esi|esi:"U嬱兡舾(3D"00442F9F|90|nop|跳过隐藏注册按钮,显示Again按钮 00442FA0|90|nop|00442FA1|8D55 F8|lea edx,dword ptr ss:[ebp-8]|00442FA4|8B83 D8020000|mov eax,dword ptr ds:[ebx+2D8]|2D8 输入名字控件id 00442FAA|E8 9102FEFF|call3.423240|00442FAF|8B4D F8|mov ecx,dword ptr ss:[ebp-8]|00442FB2|8BD6|mov edx,esi|edx:"U嬱兡舾(3D", esi:"U嬱兡舾(3D"00442FB4|A130584400|mov eax,dword ptr ds:[445830]|00442FB9|E8 EAF9FFFF|call3.4429A8|00442FBE|84C0|testal,al|00442FC0|90|nop|第三处判断 跳过隐藏注册按钮 显示重试按钮 00442FC1|90|nop|00442FC2|33D2|xor edx,edx|edx:"U嬱兡舾(3D"00442FC4|8B83 CC020000|mov eax,dword ptr ds:[ebx+2CC]|2CC 注册控件ID 00442FCA|E8 6101FEFF|call3.423130|00442FCF|B2 00|mov dl,0|修改常量1 为0 00442FD1|8B83 E8020000|mov eax,dword ptr ds:[ebx+2E8]|2E8 重试按钮控件ID 00442FD7|E8 5401FEFF|call3.423130|00442FDC|33D2|xor edx,edx|2D8 输入名控件ID

其中修改常量方式如下:ctrl+e 之前01修改为00

3.2 代码分析过程

004429A8|55|push ebp|关键call 004429A9|8BEC|mov ebp,esp|004429AB|83C4 F4|addesp,FFFFFFF4|004429AE|53|push ebx|004429AF|56|push esi|004429B0|57|push edi|004429B1|894D F8|mov dword ptr ss:[ebp-8],ecx|用户名入栈 004429B4|8955FC|mov dword ptr ss:[ebp-4],edx|004429B7|8BF8|mov edi,eax|004429B9|8B45 F8|mov eax,dword ptr ss:[ebp-8]|从栈中取用户名 004429BC|E8 2712FCFF|call along3x.2.403BE8|004429C1|33C0|xor eax,eax|004429C3|55|push ebp|004429C4|687A2A4400|push along3x.2.442A7A|004429C9|64:FF30|push dword ptr fs:[eax]|004429CC|64:8920|mov dword ptr fs:[eax],esp|004429CF|8B45 F8|mov eax,dword ptr ss:[ebp-8]|[ebp-08]:"11111"004429D2|E8 5D10FCFF|call along3x.2.403A34|跟进去 取用户名长度 返回eax 004429D7|83F8 04|cmpeax,4|004429DA|0F8E82000000|jle along3x.2.442A62|小于等于4则跳转,那么输入用户名必须大于4 004429E0|33DB|xor ebx,ebx|004429E2|8B45 F8|mov eax,dword ptr ss:[ebp-8]|[ebp-08]:"11111"004429E5|E8 4A10FCFF|call along3x.2.403A34|004429EA|85C0|testeax,eax|004429EC|7E38|jle along3x.2.442A26|004429EE|8945F4|mov dword ptr ss:[ebp-C],eax|用户名长度入栈 004429F1|BE 01000000|mov esi,1|循环起始 004429F6|8B45 F8|mov eax,dword ptr ss:[ebp-8]|[ebp-08]:"11111"004429F9|E8 3610FCFF|call along3x.2.403A34|004429FE|83F8 01|cmpeax,1|00442A01|7C 1D|jl along3x.2.442A20|小于则跳转,如果不跳转 则eax也就是用户名长度要大于1 00442A03|8B55 F8|mov edx,dword ptr ss:[ebp-8]|[ebp-08]:"11111"00442A06|0FB65432 FF|movzx edx,byte ptr ds:[edx+esi-1]|例如用户名输入为11111则从11111 中取1 显示31也就是第一个字符的ASCII值 00442A0B|8B4D F8|mov ecx,dword ptr ss:[ebp-8]|ecx等于用户名值 00442A0E|0FB64C01 FF|movzx ecx,byte ptr ds:[ecx+eax-1]|每次循环最后一个字符16进制ASCII值 00442A13|0FAFD1|imul edx,ecx|edx=edx*ecx 第一位和最后一位相乘 00442A16|0FAFD7|imul edx,edi|edx=edx*edi 00442A19|03DA|addebx,edx|ebx=ebx+edx 00442A1B|48|dec eax|eax递减 00442A1C|85C0|testeax,eax|eax是否为0 00442A1E|75E3|jne along3x.2.442A03|00442A20|46|inc esi|00442A21|FF4D F4|dec dword ptr ss:[ebp-C]|00442A24|75D0|jne along3x.2.4429F6|循环结果 00442A26|8BC3|mov eax,ebx|00442A28|99|cdq|将 eax 中的有符号数符号扩展为64位,结果保存在 edx:eax 中(edx 存放高位,eax 存放低位) 00442A29|33C2|xor eax,edx|00442A2B|2BC2|sub eax,edx|00442A2D|B9 2A2C0A00|mov ecx,A2C2A|00442A32|99|cdq|00442A33|F7F9|idiv ecx|eax / ecxeax=(商),edx=(余数) 00442A35|8BDA|mov ebx,edx|00442A37|8B45 FC|mov eax,dword ptr ss:[ebp-4]|00442A3A|B959000000|mov ecx,59|59:'Y'00442A3F|99|cdq|00442A40|F7F9|idiv ecx|ecx/59 商eax 余数 edx 00442A42|8BC8|mov ecx,eax|00442A44|8B45 FC|mov eax,dword ptr ss:[ebp-4]|00442A47|BE50000000|mov esi,50|50:'P'00442A4C|99|cdq|00442A4D|F7FE|idiv esi|esi/50 商eax 余数edx 00442A4F|03CA|addecx,edx|00442A51|41|inc ecx|ecx=ecx+1 00442A52|894D FC|mov dword ptr ss:[ebp-4],ecx|00442A55|3B5D FC|cmpebx,dword ptr ss:[ebp-4]|ebx和注册码比较 00442A58|7504|jne along3x.2.442A5E|不相等则直接跳转了 00442A5A|B3 01|mov bl,1|bl等于1正确
3.2.1 隐藏条件(必须先触发)
  • 原因:程序内部有一个全局变量[0x445830],初始值为0
    如果这个值是0,所有算法计算结果都是0,永远无法注册成功。
  • 触发方法
    Codice(注册码)输入框中输入至少 6 个英文字母(例如AAAAAA),然后点击Register按钮。
    此时会弹出错误提示(因为纯字母不是有效注册码),但程序内部调用call 00442A8C[0x445830]赋值为0x1686(十进制 5766)。
    这一步只需做一次,之后整个程序运行期间该值保持有效。
3.2.2 隐藏 Register 按钮(第一次成功)
  1. 输入用户名:在Name框中输入任意长度大于4的字符串(例如admin)。
  2. 输入正确注册码:在Codice框中输入根据用户名计算出的纯数字注册码(由注册机生成)。
  3. 点击 Register
    • 程序用0x1686和用户名经过双层循环算出nTemp
    • 验证注册码 / 89 + 注册码 % 80 + 1 == nTemp
    • 验证通过后,Register 按钮隐藏,同时Again(重试)按钮出现

此时你看到的界面:Register 按钮消失,多了 Again 按钮。

3.2.3 隐藏 Again 按钮(第二次成功)

为了完全破解,还需要把 Again 按钮也隐藏掉。方法类似:

  1. 再次输入假注册码
    Codice框中再次输入至少6个英文字母(例如AAAAAA),点击Again按钮。
    会弹出错误提示(Again 按钮不会消失,但内部状态被重置)。
  2. 输入正确注册码
    Codice框中重新输入刚才的纯数字正确注册码,再次点击Again按钮。
  3. 验证通过后,Again 按钮隐藏,最终界面只剩下 Logo 和 Cancella(取消)按钮。

3.2.4 Cancella(取消)按钮的彩蛋

作者在取消按钮的事件(call 00442B30)中隐藏了一个特殊分支:

  • 普通情况:点击 Cancella 会把 Codice 输入框的内容清零。

  • 特殊情况
    Name 框的内容Codice 框的内容完全相等(字符串相同)时,点击 Cancella 会弹出两个信息框(而不是清空注册码)。

    注意:Codice 框通常要求纯数字,所以要想触发这个彩蛋,用户名也必须是一个纯数字字符串(例如12345)。此时点击 Cancella 会弹出两个提示框,算是作者留下的一个“惊喜”。

四、总结操作流程(完整版)

步骤操作结果
前置在 Codice 框输入AAAAAA,点击 Register弹出错误,但内部[0x445830] = 0x1686
1输入用户名(>4位)和正确纯数字注册码,点击 RegisterRegister 按钮隐藏,Again 按钮出现
2在 Codice 框再次输入AAAAAA,点击 Again弹出错误(Again 按钮还在)
3在 Codice 框重新输入正确纯数字注册码,点击 AgainAgain 按钮隐藏,破解完成
彩蛋用户名和 Codice 框输入相同数字(如12345),点击 Cancella弹出两个消息框(不清零)

五、注册机核心公式

正确注册码(纯数字整数)serial满足:

serial / 89 + serial % 80 + 1 == nTemp

其中nTemp = abs( sum ) % 666666
sum = Σ (0x1686 * username[j] * username[i]),双层循环 i=1…len, j=len…1。

用 C++ 注册机即可根据任意用户名(长度>4)计算出唯一正确的serial

注册机源码如下:

#include <iostream> #include <string> #include <cctype> #include <limits> // 检查字符串是否全为数字 bool isAllDigits(const std::string& str) { for (char c : str) { if (!std::isdigit(static_cast<unsigned char>(c))) return false; } return true; } int main() { std::string username, fakeSerial; int lenx = 0, leny = 0; // 输入用户名(长度至少5) while (lenx < 5) { std::cout << "请输入用户名(5位以上): "; std::getline(std::cin, username); lenx = username.length(); if (lenx < 5) { std::cout << "用户名太短,请重新输入。\n"; } } // 输入错误注册码(不能全数字,长度至少6) while (leny < 6) { std::cout << "请输入错误注册码(不能全数字6位以上): "; std::getline(std::cin, fakeSerial); leny = fakeSerial.length(); if (leny < 6) { std::cout << "长度不足6,请重新输入。\n"; continue; } if (isAllDigits(fakeSerial)) { std::cout << "不能全为数字,请重新输入。\n"; leny = 0; // 重置,继续循环 } } // 计算隐藏值 edi int edi = 0x37B; // 891 for (size_t i = 1; i < fakeSerial.length(); ++i) { unsigned char cur = static_cast<unsigned char>(fakeSerial[i]); unsigned char prev = static_cast<unsigned char>(fakeSerial[i - 1]); edi += (cur % 0x11 + 1) * prev; } edi %= 0x7148; // 29000 std::cout << "EDI为: " << edi << std::endl; // 根据用户名和 edi 计算 ebx long long ebx = 0; size_t len = username.length(); for (size_t i = 0; i < len; ++i) { for (size_t j = len; j > 0; --j) { unsigned char ch_i = static_cast<unsigned char>(username[i]); unsigned char ch_j = static_cast<unsigned char>(username[j - 1]); ebx += static_cast<long long>(ch_i) * ch_j * edi; } } ebx %= 0xA2C2A; // 666666 std::cout << "EBX为: " << ebx << std::endl; ebx -= 1; int code = 0; // 原C代码中的近似求解 code = static_cast<int>(ebx * 0x59); // 取最大值 code = code - (code % 0x50) + 1; // 调整满足 %0x50 条件 std::cout << "正确注册码为: " << code << "\n\n"; // 枚举所有可能的解 std::cout << "所有可能的注册码:\n"; int start = static_cast<int>((ebx - 0x50) * 0x59); int end = static_cast<int>(ebx * 0x59); for (int i = start; i < end; ++i) { if (i / 0x59 + i % 0x50 == ebx) { std::cout << i << std::endl; } } std::cout << "\n按回车键退出..."; std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); std::cin.get(); return 0; }
http://www.jsqmd.com/news/662085/

相关文章:

  • 重新定义企业级PDF处理:Poppler Windows预编译包的技术哲学与架构价值
  • 如何用Path of Building打造完美流放之路角色:离线Build规划终极指南
  • OpenClaw如何部署?2026年4月本地配置Coding Plan零基础指南
  • 题目一: 准备生日礼物 100分
  • Uncle小说桌面阅读器:打造你的私人数字图书馆,掌握全网小说自由
  • fre:ac音频转换器:免费跨平台的终极音频转换指南
  • 3步免费解锁WeMod Pro高级功能的完整指南:终极WeMod增强工具使用教程
  • 3分钟快速上手:Jellyfin智能中文字幕插件完全指南
  • OpenPLC Editor 技术架构全解与工业自动化开发实战指南
  • 告别Tkinter!用PyQtGraph打造你的专属股票盯盘工具(附完整源码)
  • 日照做养发哪个店好?黑奥秘AI智能检测,90秒精准定位毛发问题 - 美业信息观察
  • 告别错过直播的烦恼:LiveAutoRecord 直播自动录制完全指南
  • 装备类项目审价应对详细实施方案
  • 如何快速优化Windows系统:Winhance中文版完整指南
  • 【地平线开发环境实战】从零构建Docker化AI模型部署平台
  • 域名回购前,为什么建议你先做一次专业评估?
  • @monkeycode-ai就能搞定?Git机器人实测,解放双手不是吹的
  • 深度解析UnityLive2DExtractor:高效提取Live2D Cubism 3资源的完整实战指南
  • 如何实现多平台直播自动录制?LiveAutoRecord 一站式解决方案揭秘
  • 【OS】RTOS任务的几种状态
  • 如何在iOS 15-16设备上绕过激活锁:开源工具完整指南
  • cpp刷题打卡记录29——矩阵置零 旋转图像 除了自身以外数组的乘积
  • abinit学习日记十九——tgw1_6.abi
  • 2026届学术党必备的六大降重复率方案解析与推荐
  • 如何快速掌握几何无衬线字体:开源字体完全指南
  • QT打印 文本 + png公章
  • 【OS】RTOS的任务切换原理
  • 如何用keil5软件的debug进行仿真调试
  • 硬件级精细温控:FanControl 风扇控制系统的技术架构与实战应用
  • 从EEPROM转战SPI Flash?STM32F103驱动W25Q64,你必须搞懂的‘页卷’与擦除机制