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

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

一.AfKayAs.2.Exe功能

打开后弹出Nag窗口,过几秒后自动消失。程序主界面是账号序列号登录。

二.目的

去掉Nag窗口

登录爆破

分析算法编写注册机

三.开始破解

1.查壳

32位无壳vb语言

在这里插入图片描述

2.vb语言4c方法去掉Nag窗口

1.vb语言一般程序入口点push 后跟call指令

00401170 | 68 D4674000 | push afkayas.2.4067D4 |
00401175 | E8 F0FFFFFF | call <JMP.&ThunRTMain> |

2.数据窗口ctrl+g 4067D4 +4c

3.记下4067D4 +4c 值,数据窗口跳转到该值地址

在这里插入图片描述

4.00修改为01 01修改为00

入口地址+4c 后地址为406820 值为406868

数据窗口跳转到406868

双击修改后打补丁另存文件,Nag窗口已被破解掉

3.登录爆破

输入账号序列号弹出错误提示

根据错误提示找到关键跳转点(od中根据可根据VB语言按钮事件ctrl+b 816c24下断点 vb程序弹窗 rtcMsgBox 函数下断点)

详细找关键跳转点可参考[逆向工程]160个CrackMe入门实战之Acid_burn.exe解析(一)一文

在这里插入图片描述

在这里插入图片描述

找到关键跳转点直接爆破nop填充,保存程序

4.追码分析算法

账号输入:1111 序列号:1234

1.获取1111代码分析:

004081E3 | call __vbaHresultCheckObj  ; 验证前一步COM对象操作是否成功
004081E9 | mov edx, [ebp-B0]         ; 加载对象指针到EDX (可能是窗体或控件)
004081EF | mov eax, [ebp-1C]         ; 加载字符串1地址 (内容为"1111")
004081F2 | push eax                  ; 压栈字符串1参数
004081F3 | mov ebx, [edx]            ; 获取对象虚表指针
004081F5 | call __vbaLenBstr         ; 计算字符串1长度 → EAX=4
004081FB | mov edi, eax              ; EDI=4 (保存长度结果)
004081FD | mov ecx, [ebp-18]         ; 加载字符串2地址 (内容为"1111")
00408200 | imul edi, edi, 15B38      ; EDI=4 * 88888 = 355552
00408206 | push ecx                  ; 压栈字符串2参数
00408207 | jo 4087C4                 ; 检查乘法溢出(若溢出跳错误处理)
0040820D | call Ordinal#516          ; 调用关键函数 → 返回AX=49 (字符'1'ASCII)
00408213 | movsx edx, ax             ;16位返回值符号扩展至32EDX
00408216 | add edi, edx              ; EDI=355552 + 49 = 355601
00408218 | jo 4087C4                 ; 检查加法溢出
0040821E | push edi                  ; 压入最终计算结果355601
0040821F | call __vbaStrI4           ; 将整数转为字符串 → EAX="355601"指针
00408225 | mov edx, eax              ; EDX=结果字符串指针
00408227 | lea ecx, [ebp-20]         ; 加载目标变量地址
0040822A | call __vbaStrMove         ; 移动字符串到局部变量[ebp-20]
00408230 | mov edi, [ebp-B0]         ; 重新加载对象指针到EDI
00408236 | push eax                  ; 压入结果字符串指针 (__vbaStrMove返回相同指针)
00408237 | push edi                  ; 压入对象指针 (this指针)
00408238 | call dword ptr [ebx+A4]   ; 调用对象虚表方法(偏移A4)
0040823E | test eax, eax             ; 检查方法返回值
00408240 | jge 408254                ; 若返回值>=0 (成功) 则跳转

在这里插入图片描述

算法:

结果 = (len("1111") × 88888) + Asc("11111"第一个字符)
      = (4 × 88888) + 49 
      = 355601

2.三次浮点数计算

​ 1.第一次

; 1. 验证前序操作
004082D7 | call __vbaHresultCheckObj  ; 验证前一步对象操作成功
004082DD | mov ecx, [ebp-A8]         ; 加载对象指针
004082E3 | mov edx, [ebp-18]         ; 加载字符串"355601"地址
004082E6 | push edx                  ; 压栈字符串参数
004082E7 | mov ebx, [ecx]            ; 获取对象虚表指针
004082E9 | call __vbaR8Str           ; 将字符串转为双精度浮点 → ST0=355601.0

; 2. 浮点运算准备
004082EF | fld dword ptr [401008]    ; 加载单精度浮点常量AST0=A, ST1=355601.0
004082F5 | cmp dword ptr [409000],0  ; 检查浮点控制字状态
004082FC | jne 408306                ; 非标准状态跳转
004082FE | fdiv dword ptr [40100C]   ; ST0 = A / B (标准状态除法)
00408304 | jmp 408311                ; 跳过特殊处理
00408306 | push [40100C]             ; 非标准状态处理
0040830C | call <JMP.&_adj_fdiv_m32> ; 调整浮点控制字后除法
00408311 | sub esp,8                 ; 栈上分配8字节空间

; 3. 浮点运算与异常检查
00408314 | fnstsw ax                 ; 保存浮点状态字
00408316 | test al,0D                ; 检查浮点异常(PE/UE/IE)
00408318 | jne 4087BF                ; 有异常跳错误处理
0040831E | faddp st(1), st(0)        ; ST1 = ST1 + ST0ST0=355601.0 + (A/B)
00408320 | fnstsw ax                 ; 再存浮点状态
00408322 | test al,0D                ; 再查异常
00408324 | jne 4087BF                ; 有异常跳错误处理

; 4. 结果处理与存储
0040832A | fstp qword ptr [esp]      ; 存储浮点结果到栈顶
0040832D | call __vbaStrR8           ; 浮点转字符串 → EAX="355603"
00408333 | mov edx, eax              ; EDX=结果字符串指针
00408335 | lea ecx, [ebp-1C]         ; 目标变量地址[ebp-1C]
00408338 | call __vbaStrMove          ; 移动字符串到变量

; 5. 对象方法调用
0040833E | mov [ebp-CC], ebx         ; 保存虚表指针
00408344 | mov ebx, [ebp-A8]         ; 重载对象指针
0040834A | push eax                  ; 压入结果字符串
0040834B | mov eax, [ebp-CC]         ; 取回虚表指针
00408351 | push ebx                  ; 压入对象指针(this)
00408352 | call [eax+A4]             ; 调用对象方法(虚表偏移A4)
00408358 | test eax, eax             ; 检查返回值
0040835A | jge 40836E                ; 成功则跳转继续执行

在这里插入图片描述

2.第二次

1111

1066807

在这里插入图片描述

3.第三次

第三次计算,输入1111,正确值算出是1066822

在这里插入图片描述

从以上分析1111的正确码为1066822.至次分析出验证码的算法如下:

在这里插入图片描述

计算name长度–name长度*0x15b38+name的第一个字符ANSI码–计算浮点数10.0/5.0=2 --转换为浮点数+2.0–乘以3.0–j减去2–减去-15–得到的值转换为文本为正确序列号

5.注册机编写

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h> // 添加math.h头文件以使用浮点运算

int main()
{
    char username[50] = {0};
    char serial[100] = {0};
    
    printf("Enter Username: ");
    scanf("%s", username);
    
    if(strlen(username) < 4) {
        printf("Error: Username must be at least 4 characters!\n");
        // 添加暂停
        printf("Press Enter to exit...");
        getchar(); // 清除输入缓冲区残留的换行符
        getchar(); // 等待用户按键
        return 1;
    }
    
    // 新序列号生成算法
    int len = strlen(username);
    int baseValue = len * 0x15B38 + (int)username[0]; // 长度*0x15B38+首字符ASCII
    
    // 浮点运算部分
    float floatValue = (float)baseValue; // 转换为浮点数
    float step1 = 10.0f / 5.0f;        // 10.0/5.0=2.0
    float step2 = floatValue + step1;   // 加上2.0
    float step3 = step2 * 3.0f;         // 乘以3.0
    float step4 = step3 - 2.0f;         // 减去2
    float step5 = step4 - (-15.0f);     // 减去-15(相当于加15)
    
    // 将浮点数结果转换为整数序列号
    int serialNum = (int)roundf(step5); // 四舍五入取整
    sprintf(serial, "%d", serialNum);
    
    printf("Your Serial: %s\n", serial);
    
    // 添加暂停
    printf("Press Enter to exit...");
    getchar(); // 清除输入缓冲区残留的换行符
    getchar(); // 等待用户按键
    
    return 0;
}
//gcc -o afk2.exe afk2.c

注册机测试

在这里插入图片描述

如果你觉得本教程对你有帮助,请点赞❤️、收藏⭐、关注支持!欢迎在评论区留言交流技术细节!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

曼岛_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值