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

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"文件复制到程序目录下。

相关推荐
缺点内向2 小时前
Java: 如何在Excel中添加或删除分页符?
java·excel
_pass_2 小时前
flask 框架的ORM 学习及应用
学习·flask·orm
m0_521329032 小时前
java-File的创建和删除
java
再睡一夏就好2 小时前
【C++闯关笔记】unordered_map与unordered_set的底层:哈希表(哈希桶)
开发语言·c++·笔记·学习·哈希算法·散列表
potato_15542 小时前
现代C++核心特性——内存篇
开发语言·c++·学习
August_._3 小时前
【JAVA】基础(一)
java·开发语言·后端·青少年编程
李白的粉3 小时前
基于springboot的新闻资讯系统
java·spring boot·毕业设计·课程设计·源代码·新闻资讯系统
麦麦鸡腿堡3 小时前
Java_LinkedList底层结构
java·开发语言
whatever who cares3 小时前
android/java中gson的用法
android·java·开发语言