资源ID用eXeScope软件查看,在代码地址40114D下断点,逐个勾选测试得到映射表:
| 界面位置 | 资源ID | 硬编码索引(ESI) | 硬编码值 |
|---|---|---|---|
| 第一行第1个 | 97 | 17 | 0x61 |
| 第一行第2个 | 73 | 2 | 0x49 |
| 第一行第3个 | 94 | 3 | 0x5E |
| 第一行第4个 | 22 | 1 | 0x16 |
| 第一行第5个 | 37 | 8 | 0x25 |
| 第一行第6个 | 38 | 6 | 0x26 |
| 第一行第7个 | 33 | 7 | 0x21 |
| 第一行第8个 | 89 | 10 | 0x59 |
| 第一行第9个 | 83 | 11 | 0x53 |
| 第二行第1个 | 21 | 4 | 0x15 |
| 第二行第2个 | 55 | 12 | 0x37 |
| 第二行第3个 | 49 | 13 | 0x31 |
| 第二行第4个 | 72 | 14 | 0x48 |
| 第二行第5个 | 93 | 15 | 0x5D |
| 第二行第6个 | 12 | 16 | 0x0C |
| 第二行第7个 | 82 | 18 | 0xx52 |
| 第二行第8个 | 39 | 5 | 0x27 |
| 第二行第9个 | 29 | 9 | 0x1D |
4020FE硬编码转十进制与资源ID一样,只是顺序不同。
![]() |
|---|
主要算法:
; DueList.3.exe 验证逻辑 ; ============================================= 00401117 | 33F6 | xor esi,esi | ; 初始化ESI寄存器为0 00401119 | 33D2 | xor edx,edx | ; 初始化EDX寄存器为0 0040111B | 8935 5E214000 | mov dword ptr ds:[40215E],esi | ; 将ESI的值(0)存储到内存地址40215E 00401121 | 8935 62214000 | mov dword ptr ds:[402162],esi | ; 将ESI的值(0)存储到内存地址402162 ; 主循环开始 00401127 | 0FBE8E FE204000 | movsx ecx,byte ptr ds:[esi+4020FE] | ; 从硬编码序列中读取一个字节到ECX 0040112E | 83F9 4D | cmp ecx,4D | ; 比较ECX是否等于0x4D(77) 00401131 | 74 2F | je duelist.3.401162 | ; 如果等于77,跳转到循环结束 00401133 | 890D 5E214000 | mov dword ptr ds:[40215E],ecx | ; 将ECX的值存储到内存地址40215E 00401139 | 51 | push ecx | ; 将ECX压栈(作为IsDlgButtonChecked的参数) 0040113A | FF75 08 | push dword ptr ss:[ebp+8] | ; 将对话框句柄压栈 0040113D | E8 D0010000 | call <JMP.&IsDlgButtonChecked> | ; 调用IsDlgButtonChecked检查复选框状态 00401142 | 46 | inc esi | ; ESI自增1 00401143 | 83F8 00 | cmp eax,0 | ; 检查EAX是否为0(复选框未被勾选) 00401146 | 74 DF | je duelist.3.401127 | ; 如果未被勾选,跳回循环开始 ; 复选框被勾选,计算贡献值 00401148 | A1 5E214000 | mov eax,dword ptr ds:[40215E] | ; 从内存地址40215E加载值到EAX 0040114D | 0FBE8E FE204000 | movsx ecx,byte ptr ds:[esi+4020FE] | ; 从硬编码序列中读取下一个字节到ECX 00401154 | 0FAFC1 | imul eax,ecx | ; EAX = EAX × ECX(前一个值 × 当前值) 00401157 | 0FAFC6 | imul eax,esi | ; EAX = EAX × ESI(乘以索引) 0040115A | 0105 62214000 | add dword ptr ds:[402162],eax | ; 将EAX的值累加到内存地址402162 00401160 | EB C5 | jmp duelist.3.401127 | ; 跳回循环开始 ; 循环结束,进行最终验证 00401162 | A1 62214000 | mov eax,dword ptr ds:[402162] | ; 从内存地址402162加载累加和到EAX 00401167 | 6BC0 4D | imul eax,eax,4D | ; EAX = EAX × 0x4D(77) 0040116A | 3D 6654F300 | cmp eax,F35466 | ; 比较EAX是否等于0xF35466(15,946,854)
程序实现:
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
// DueList.3.exe 注册机 - 基于映射关系
int main() {
printf("DueList.3.exe 注册机 - 基于映射关系\n");
printf("==================================\n\n");
// 硬编码序列(从地址 004020FE 开始)
uint8_t hardcoded_sequence[19] = {
0x16, 0x49, 0x5E, 0x15, 0x27, 0x26, 0x21, 0x25, 0x1D,
0x59, 0x53, 0x37, 0x31, 0x48, 0x5D, 0x0C, 0x61, 0x52, 0x4D
};
// 界面索引到硬编码索引(ESI)的映射
const uint8_t ui_index_to_esi[18] = {
17, // 界面索引0: 第一行第1个
2, // 界面索引1: 第一行第2个
3, // 界面索引2: 第一行第3个
1, // 界面索引3: 第一行第4个
8, // 界面索引4: 第一行第5个
6, // 界面索引5: 第一行第6个
7, // 界面索引6: 第一行第7个
10, // 界面索引7: 第一行第8个
11, // 界面索引8: 第一行第9个
4, // 界面索引9: 第二行第1个
12, // 界面索引10: 第二行第2个
13, // 界面索引11: 第二行第3个
14, // 界面索引12: 第二行第4个
15, // 界面索引13: 第二行第5个
16, // 界面索引14: 第二行第6个
18, // 界面索引15: 第二行第7个
5, // 界面索引16: 第二行第8个
9 // 界面索引17: 第二行第9个
};
// 目标值
uint32_t target_value = 0xF35466; // 15,946,854
uint32_t multiplier = 0x4D; // 77
uint32_t target_sum = target_value / multiplier; // 207,102
printf("目标累加和: %u (0x%X)\n\n", target_sum, target_sum);
// 基于映射关系的算法
printf("基于映射关系的算法:\n");
printf("贡献值 = 前一个硬编码值 × 当前硬编码值 × ESI\n");
printf("使用界面索引到ESI的映射关系\n\n");
// 计算所有可能的组合
uint32_t total_combinations = 1 << 18; // 2^18 = 262,144
uint32_t found_count = 0;
printf("正在计算所有可能的组合...\n");
printf("总组合数: %u\n", total_combinations);
for (uint32_t combo = 0; combo < total_combinations; combo++) {
uint32_t total = 0;
// 计算当前组合的累加和
for (uint8_t ui_index = 0; ui_index < 18; ui_index++) {
if (combo & (1 << ui_index)) {
// 获取对应的ESI值
uint8_t esi = ui_index_to_esi[ui_index];
// 贡献值 = 前一个值 × 当前值 × ESI
uint32_t contribution = hardcoded_sequence[esi - 1] * hardcoded_sequence[esi] * esi;
total += contribution;
}
}
// 检查是否精确匹配目标值
if (total == target_sum) {
found_count++;
printf("\n=== 成功组合 #%d ===\n", found_count);
printf("组合标识: 0x%06X\n", combo);
// 打印复选框状态
printf("复选框状态:\n");
printf("第一行: ");
for (uint8_t i = 0; i < 9; i++) {
if (combo & (1 << i)) {
printf("[%d] ", i + 1);
}
else {
printf("[ ] ");
}
}
printf("\n第二行: ");
for (uint8_t i = 9; i < 18; i++) {
if (combo & (1 << i)) {
printf("[%d] ", i - 8);
}
else {
printf("[ ] ");
}
}
printf("\n\n");
printf("==================================================\n");
}
}
return 0;
}
![]() |
|---|


593

被折叠的 条评论
为什么被折叠?



