破解入门学习笔记题三十四

1. 打开密钥文件

复制代码
00401028 | push C0000000              ; dwCreationDisposition = CREATE_NEW
0040102D | push cruehead.3.4020D7    ; lpFileName = "CRACKME3.KEY"
00401032 | call <JMP.&CreateFileA>    ; 创建/打开文件
00401037 | cmp eax,FFFFFFFF           ; 检查文件句柄是否有效
0040103A | jne 401043                 ; 有效则继续,否则跳转到错误处理

2. 读取18字节到缓冲区

复制代码
00401048 | mov eax,12                 ; 要读取的字节数 = 0x12(18)
0040104D | mov ebx,402008             ; 缓冲区地址
00401054 | push 4021A0                ; lpNumberOfBytesRead 接收实际读取字节数
00401059 | push eax                   ; nNumberOfBytesToRead = 18
0040105A | push ebx                   ; lpBuffer = 402008
0040105B | push dword ptr ds:[4020F5] ; hFile 文件句柄
00401061 | call <JMP.&ReadFile>       ; 读取文件

3. 检查读取字节数是否为18

复制代码
00401066 | cmp dword ptr ds:[4021A0],12 ; 比较实际读取字节数是否为18
0040106D | jne 401037                  ; 如果不是18,跳转到错误处理(显示错误消息)

4. 调用sub_401311处理前14字节

复制代码
0040106F | push 402008                 ; 传入缓冲区地址作为参数
00401074 | call <cruehead.3.sub_401311> ; 调用处理函数

sub_401311函数的详细汇编代码:

复制代码
00401311 | xor ecx,ecx                ; 清空计数器ECX
00401313 | xor eax,eax                ; 清空EAX
00401315 | mov esi,dword ptr ss:[esp+4] ; 获取参数(缓冲区地址)
00401319 | mov bl,41                  ; BL = 0x41 (起始XOR值)
0040131B | mov al,byte ptr ds:[esi]   ; 读取缓冲区的一个字节到AL
0040131D | xor al,bl                  ; AL = AL XOR BL
0040131F | mov byte ptr ds:[esi],al   ; 将结果存回缓冲区
00401321 | inc esi                    ; 指向下一个字节
00401322 | inc bl                     ; BL递增(0x41→0x42→...)
00401324 | add dword ptr ds:[4020F9],eax ; 累加结果到[4020F9](变量S)
0040132A | cmp al,0                   ; 检查结果是否为0
0040132C | je 401335                  ; 如果为0则提前结束
0040132E | inc cl                     ; 字节计数器递增
00401330 | cmp bl,4F                 ; 检查BL是否达到0x4F
00401333 | jne 40131B                 ; 循环处理下一个字节
00401335 | mov dword ptr ds:[402149],ecx ; 保存处理的字节数
0040133B | ret                        ; 返回

5. 将S与0x12345678异或

复制代码
00401079 | xor dword ptr ds:[4020F9],12345678 ; S = S XOR 0x12345678

6. 调用sub_40133C读取后4字节作为T

复制代码
0040108B | call <cruehead.3.sub_40133C> ; 调用函数获取T值

sub_40133C函数的详细汇编代码:

复制代码
0040133C | mov esi,dword ptr ss:[esp+4] ; 获取参数(缓冲区地址)
00401340 | add esi,0E                 ; ESI = 缓冲区地址 + 0x0E(14)
00401343 | mov eax,dword ptr ds:[esi]  ; 读取4字节到EAX(这就是T值)
00401345 | ret                        ; 返回EAX=T

7. 比较T和S

复制代码
00401090 | add esp,4                  ; 清理栈
00401093 | cmp eax,dword ptr ds:[4020F9] ; 比较EAX(T)和[4020F9](S)
00401099 | sete al                     ; 如果相等,AL=1,否则AL=0
0040109C | push eax                   ; 保存结果
0040109D | test al,al                 ; 测试AL
0040109F | je 401037                  ; 如果AL=0(不相等),跳转到错误处理

完整的验证流程控制流

复制代码
; 成功路径:
00401093 | cmp eax,[4020F9]           ; 比较T和S
00401099 | sete al                     ; 相等则AL=1
0040109C | push eax
0040109D | test al,al                  ; 测试结果
0040109F | je 401037                   ; 不相等则跳转到错误
004010A1 | push 40210E                 ; 成功消息地址
004010A6 | call sub_401346             ; 显示成功消息
004010AB | add esp,4
; ... 继续执行程序
​
; 错误路径:
00401037 | push 40210E                 ; 错误消息地址
0040103C | call sub_4012F5             ; 显示错误消息
00401041 | jmp 4010AE                  ; 跳转到程序退出
生成"CRACKME3.KEY"文件
复制代码
•#include <stdio.h>
•#include <stdlib.h>
•#include <string.h>
•#include <windows.h>
​
 int main()
• {
•     char* username="test123";
•     char* filename="CRACKME3.KEY";
•     FILE* file;
•     unsigned char key[18];
•     unsigned int checksum = 0;
•     int i;
•     
• 
•    // 检查用户名长度并处理`
•    int name_len = strlen(username);
•    if (name_len > 14) 
•    {
•        printf("用户名超过14字节,将被截断\n");
•        name_len = 14;
•    }
•    
•    // 复制用户名到密钥缓冲区
•    memset(key, 0, sizeof(key));
•    memcpy(key, username, name_len);
•    
•    // 如果用户名不足14字节,用空格填充
•    for (i = name_len; i < 14; i++) 
•    {
•        key[i] = ' ';
•    }
•    
•    // 计算校验和`
•    for (i = 0; i < 14; i++) 
•    {
•        unsigned char xor_val = 0x41 + i;  // 从0x41递增到0x4E
•        unsigned char result = key[i] ^ xor_val;
•        checksum += result;
•    }
•    
•    // 最终校验值 = 校验和 XOR 0x12345678
•    unsigned int final_checksum = checksum ^ 0x12345678;
•    
•    // 将校验值写入密钥的最后4字节(小端序)
•    key[14] = (final_checksum >> 0) & 0xFF;   // 最低字节
•    key[15] = (final_checksum >> 8) & 0xFF;
•    key[16] = (final_checksum >> 16) & 0xFF;
•    key[17] = (final_checksum >> 24) & 0xFF;  // 最高字节
•    
•    // 创建密钥文件
•    file = fopen(filename, "wb");
•    if (file == NULL) 
•    {
•        printf("错误: 无法创建文件 %s\n", filename);
•        return FALSE;
•    }
•    
•    // 写入18字节密钥
•    fwrite(key, 1, 18, file);
•    fclose(file);
•    
•    printf("文件创建完成");
•    return 0;
• 
• }

把"CRACKME3.KEY"文件复制到程序目录下。

相关推荐
Seven972 分钟前
剑指offer-42、和为S的两个数字
java
Pa2sw0rd丶3 分钟前
Fastjson 反序列化漏洞深度解析:从原理到实战防护
java·后端·安全
带刺的坐椅5 分钟前
AspectJ、Spring AOP 与 Solon AOP:Java AOP 框架的三剑客
java·spring·solon·aop·aspectj
Coding_Doggy9 分钟前
链盾shieldchiain | 团队功能、邀请成员、权限修改、移除成员、SpringSecurity、RBAC权限控制
java·开发语言·数据库
Seven9710 分钟前
剑指offer-41、和为S的连续正数序列
java
零匠学堂202524 分钟前
如何通过培训考试系统提升网络学习平台的效果?
学习
程序员小假27 分钟前
有了解过 SpringBoot 的参数配置吗?
java·后端
f***241127 分钟前
java学习进阶之路,如果从一个菜鸟进阶成大神
java·开发语言·学习
ALex_zry31 分钟前
高并发系统渐进式改造技术调研报告:策略、架构与实战
java·运维·架构
SimonKing41 分钟前
等保那些事
java·后端·程序员