学逆向论坛

找回密码
立即注册

只需一步,快速开始

发新帖

2万

积分

41

好友

1157

主题

[转载图文] 逆向分析010editor

发表于 2020-8-8 00:06:01 | 查看: 4681| 回复: 1
逆向分析010editor
跟着看雪大牛的这篇文章:https://bbs.pediy.com/thread-258428.htm 分析完FSViewer的注册算法后就想靠自己分析一个程序,于是选择了010editor

010editor的注册算法比较简单,作者也没有进行防破解的任何操作,甚至可以直接用IDA静态分析出算法

分析的是最新版的64位便携版(010EditorWin64Portable10.0.2.exe)

注册机和patch代码见附件

1. 准备工作
  • 首先x64的传参方式是从第一个参数开始按 rcx rdx r8 r9 依次传参,超过的用栈传参
  • 通过字符串可以定位到On_BtnCheckLicense_Clicked按钮事件位于0x1401CF170(这里是相对于ImageBase因为程序有ASLR)
  • 修改PE头关闭aslr便于动态调试

2. 分析Check License按钮事件
对于Qt程序,IDA的反编译效果非常好,虽然会有一些细小的反编译错误,但是不影响整体逻辑

一开始是判断Name是否为空,PassWord是否输入完整:

逆向分析010editor

逆向分析010editor

通过动态调试可以发现*((QString *)var + 4)是字符串长度:

逆向分析010editor

逆向分析010editor

之后会对输入的Name和PassWord进行一些判断和替换:

逆向分析010editor

逆向分析010editor

clearQuot函数是除去输入的Name中的引号,并赋值给arg1+8:

逆向分析010editor

逆向分析010editor

repalceOol函数是将PassWord中的O和o替换为0,l替换为1并赋值给arg1+16:

逆向分析010editor

逆向分析010editor

那么关键在于这个arg1,也就是qword_1406F01F8肯定是个结构体
这是分析后的结构体命名为stKey:

逆向分析010editor

逆向分析010editor

然后就是最关键的验证函数了:

逆向分析010editor

逆向分析010editor
2.1 注册算法验证函数VerifyNamePsw
一开始会将PassWord转成10组16进制数,比如 ABCD-1234-...
会转成 0xAB,0xCD,0x12,0x34...:暂且命名为数组str2Hex[]
并会对一些禁止掉的Name和PassWord进行判断

逆向分析010editor

逆向分析010editor

注册算法在之后的switch语句里,通过IDA可以看到返回值有231,78和45

231是验证失败,通过对验证函数之后函数的分析:
v11 == 219则弹出成功MessageBox,v11是sub_140009D77的返回值

逆向分析010editor

逆向分析010editor

sub_140009D77:又调用了v6 = VerifyNamePsw(), v6为45则返回219

逆向分析010editor

逆向分析010editor

所以注册算法一定要返回45,而switch判断str2Hex[3] (psw转为16进制数的数组),
str2Hex[3] 只能= 0x9C || 0xFC || 0xAC
case 0x9C or case 0xAC 都可以return 45, 但是0x9C这条分支没有对到期时间(stKey->dueTime)赋值,所以要分析case 0xAC.
这里贴出我分析的伪C代码:
case 0xAC:    stKey->field_2C = 2;    vNum2 = ((hex7^hex1)<<8) + (hex5^hex2);    vNum2 = ((vNum2^0x7892) + 0x4D30) ^ 0x3421;    vNum2 = vNum2 % 0xB != 0 ? 0 : vNum2/0xB; //必须>0    stKey->field_30 = vNum2;    if (vNum2 - 1 <= 0x3E7)    {        vNum1 = ((hex5^hex9)<<16) + ((hex8^hex4)<<8) + (hex6^hex0);        vNum1 = (((vNum1^0x5B8C27^0x22C078)-0x2C175)^0xFFE53167) & 0xFFFFFF;        vNum1 = vNum1 % 0x11 !=  0 ? 0 : v2/0x11; //必须>0        stKey->dueTime = vNum1;         cmpValue = sub_140006901(nameChar, 1, vNum1, vNum2);            if (str2Hex[4..7] == cmpValue[0..3])        {            if (vNum1 < 0x473C)            {                return 78;//wrong;            }            return 45;             }    }    break;uint sub_140006901(a1,a2,vNum1,vNum2){    datas[] = {..}; //dword_1406DF020 共308个,可以用LazyIDA插件导出    int j = 15*vNum2, k = 0, m = 17*vNum1;    int ret = 0;    for (int i = 0; i < nameLen; ++i)    {        up = toupper(nameChar);          ret = datas[j] + datas[m] + datas[k] + datas[up+47]*((ret+datas[up]) ^ datas[up+13]);           j += 13;        m += 9;        k += 19;    }    return ret;}
3. 逆推注册算法写注册机
vNum2必须整除0xB, vNum1必须整除0x11, 并把vNum1和vNum2作为参数传进sub_140006901和name一起计算一个32位数, 然后str2Hex的第4到7位等于这个数(BYTE)的0到3位
那么可以随机选取vNum1和vNum2, 通过sub_140006901计算出str2Hex的4到7位, 然后xor是可逆的,所以就可以生成剩下的5位16进制数。
关于到期时间的计算是通过stKey->dueTime*86400作为localtime函数的参数算出到期时间,stKey->dueTime被赋值为伪代码中的vNum1

4. 去掉网络验证
因为一开始用插件查了一下程序用到的密码学算法,有CRC32和MD5,所以以为会有线程在进行完整性校验,就没有直接patch程序
4.1 伪造http_server
通过抓包可以发现,程序会发送一个get请求,返回的内容是 invalid

逆向分析010editor

逆向分析010editor

那么可以修改host, 并伪造一个http_server返回valid就可以了,但是我自己试了一下,发现会进入网络错误那个分支,学艺不精具体是为什么没有深究

逆向分析010editor

逆向分析010editor
4.2 Patch程序
这个jz会跳过网络验证,所以改成jmp就行了:

逆向分析010editor

逆向分析010editor

// patch
RAW: 001CE7C8
把opCode: OF84 32010000 改成 E9 33010000 90
5. 注册机效果

逆向分析010editor

逆向分析010editor

scripts.zip

949.29 KB, 下载次数: 8, 下载积分: 学币 -3

逆向分析010editor

温馨提示:
1.如果您喜欢这篇帖子,请给作者点赞评分,点赞会增加帖子的热度,评分会给作者加学币。(评分不会扣掉您的积分,系统每天都会重置您的评分额度)。
2.回复帖子不仅是对作者的认可,还可以获得学币奖励,请尊重他人的劳动成果,拒绝做伸手党!
3.发广告、灌水回复等违规行为一经发现直接禁言,如果本帖内容涉嫌违规,请点击论坛底部的举报反馈按钮,也可以在【投诉建议】板块发帖举报。
论坛交流群:672619046

    发表于 2020-8-8 23:02:28
    太给力了,这么多好东西!

    小黑屋|手机版|站务邮箱|学逆向论坛 ( 粤ICP备2021023307号 )|网站地图

    GMT+8, 2024-4-24 15:31 , Processed in 0.095602 second(s), 45 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表