dustland

dustball in dustland

010editor 12.0.1注册破解补丁

010editor 12.0.1注册破解

过期again

已经受够了30天就得重装一次010editor,这次给他一劳永逸一下破解喽

010editor登录注册不需要联网,这表明它自己就带着账户密码了,或者说给定一个账户它通过某些哈希算法等等得到一串狗屁不同的数字作为密码,或者说A用户名对应a密码,B用户名对应b密码等等

这些都有可能

反正只要是不用联网麻烦服务器验证登录,一切就好说

ida64打开之

1
PS C:\Program Files\010Editor> ida64 010editor

等ida64分析完之后,直接看函数列表是令人失望的,全是哑名,

连个start或者main或者WinMain函数都找不到

还有一点儿发现就是010editor使用Qt写的

image-20220911203227392

静态分析是看不出来了,用动态的

选择使用本地windows调试器,啥断点也不用下,直接开始调试

必然在注册页面停下

image-20220911203350032

这里有一个猜想是,处理注册成功和失败的函数或者说过程离得不远,可能是在一个if-else条件控制下,就跟windows过程函数一样,对于A消息用这个分支处理,对于B消息用那个分支处理

还有一个事实是,这里胡乱尝试注册用户名和密码,成功的机率很小,但是几乎百分百失败(这不废话吗),这样说是因为,可以通过失败的情况看看周围有没有成功的情况

image-20220911204005784

乱输入一些东西然后Check License,弹出对话框了

好了现在用IDA的search Text(Alt+T)功能去查"Invalid name"等字样,果然查到了,令人意想不到的简单

1
2
3
4
.text:00007FF61CE45819 loc_7FF61CE45819:                       ; CODE XREF: sub_7FF61CE45130+61F↑j
.text:00007FF61CE45819 mov edx, 90h
.text:00007FF61CE4581E lea rcx, aInvalidNameOrP ; "Invalid name or password. Please enter "...
.text:00007FF61CE45825 call cs:?fromAscii_helper@QString@@CAPEAU?$QTypedArrayData@G@@PEBDH@Z ; QString::fromAscii_helper(char const *,int)

这里edx=90h是字符串的长度,rcx中存放的是字符串基地址

然后接着就调用Qt函数了

我估计和windows32程序设计中的对话框或者说messageBox是差不多的东西

在这里F5反编译一下看的更清楚

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
if ( v16 != 147 )
{
v48 = QString::fromAscii_helper(
"Invalid name or password. Please enter your name and password exactly as given when you purchased 010 Edit"
"or (make sure no quotes are included).",
144i64);
sub_7FF61CC55065(&v48);
v25 = (char *)&v48;
goto LABEL_68;
}
if ( v17 != 113 )
{
v48 = QString::fromAscii_helper("Password accepted but the trial period is already over.", 55i64);
sub_7FF61CC55065(&v48);
v25 = (char *)&v48;
goto LABEL_68;
}
v48 = QString::fromAscii_helper("Password accepted. Your trial period has been extended.", 55i64);
sub_7FF61CC55065(&v48);
v32 = &v48;

除了"Invalid name..."这句,还有其他各种情况

比如密码正确,但是试用期过了,

比如密码正确,试用期已经延长

...

可以猜测,密码正确,注册成功 这种情况也在附近,划拉划拉看看,还真就有

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
if ( v17 == 219 )
{
sub_7FF61CC53508(v18, v46);
v43 = QString::fromAscii_helper("MMMM d, yyyy", 12i64);
v26 = (const struct QString *)QDate::toString(v46, v47, &v43);
v27 = (const struct QString *)QString::fromUtf8(
&v44,
"Password accepted. This license entitles you to:\n"
"\n"
" - Free Upgrades\n"
" - Free Support\n"
" - Free Repository Updates\n"
"\n"
"until ",
0xFFFFFFFFi64);

当v17=219的时候,对应密码通过,有驾驶证了

那么现在的焦点就是v17,怎样才能让v17=219呢?

在v17身上按X看交叉引用

image-20220911204910187

Line 157和Line 197都是写操作的交叉引用,并且这两个都在sub_7FF61CC584F54函数

后面五个都是读,读当然不会修改v17

去sub_7FF61CC584F54看看发生了什么

笑死,sub_7FF61CC584F54这个函数就是我们当前所在函数

其中会改变v17的是

1
v17 = sub_7FF61CC584F4(qword_7FF61D94EE50, 13i64, 18887i64);

再去sub_7FF61CC584F4看看

1
2
3
4
__int64 __fastcall sub_7FF61CC584F4(__int64 a1, __int64 a2, __int64 a3)
{
return sub_7FF61CF9AD70(a1, a2, a3);
}

再去sub_7FF61CF9AD70看看

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
__int64 __fastcall sub_7FF61CF9AD70(__int64 a1, __int64 a2, __int64 a3)
{
unsigned int v3; // edi
__int64 result; // rax
int v6; // eax
int v7; // eax
int v8; // eax
unsigned int v9; // ecx
int v10; // eax
unsigned int v11; // ecx
int v12; // eax
unsigned int v13; // ecx

v3 = a2;
if ( *(_DWORD *)(a1 + 60) )
return 275i64;
v6 = sub_7FF61CC56118(a1, a2, a3);
switch ( v6 )
{
case 45:
return 219i64;
case 78:
v12 = sub_7FF61CC58FCB(a1, v3);
v13 = 524;
if ( v12 != 23 )
v13 = 237;
result = v13;
break;
case 231:
return 375i64;
default:
v7 = sub_7FF61CC58FCB(a1, v3);
if ( v7 == 23 )
return 113i64;
if ( v7 != 42 )
{
if ( v7 == 312 )
{
v8 = sub_7FF61CC55B37(a1);
v9 = 47;
if ( v8 == 419 )
v9 = 249;
return v9;
}
return 375i64;
}
v10 = sub_7FF61CC55B37(a1);
v11 = 375;
if ( v10 == 419 )
v11 = 249;
result = v11;
break;
}
return result;
}

如果要返回219

需要

1
2
3
4
5
6
7
8
if ( *(_DWORD *)(a1 + 60) )//这里得是0
return 275i64;
v6 = sub_7FF61CC56118(a1, a2, a3);//返回45
switch ( v6 )
{
case 45:
return 219i64;
...

在前面这个if上下断点然后重新开始调试,结果它不会找茬,直接到

v6 = sub_7FF61CC56118(a1, a2, a3);这里

单步步过之后v6=0x93显然不是45,v6它故意找茬

这时候看看反汇编

1
2
.text:00007FF61CF9AD95 call    sub_7FF61CC56118
.text:00007FF61CF9AD9A cmp eax, 2Dh ; '-'

失败的尝试

2Dh=45d

既然v6从sub_7FF61CC56118(a1, a2, a3);出来等于0x93,那么我就让v6=0x93的时候返回219,直接修改指令,将2Dh改成93h

image-20220911211116648

这两步都在Edit->Patch program菜单中

image-20220911211234713

然而改了之后汇编指令成了这样:

1
.text:00007FF72357AD9A 83 F8 93                      cmp     eax, 0FFFFFF93h

83F8是操作码还有eax,剩下一个字节93是立即数,这里只给立即数留了1个字节,而93h=0x10010011正好相当于一个负数,改了白改

又得改回去

成功的尝试

改操作数指令不够长,那么可以改jz为jnz

1
2
.text:00007FF72357AD9A 83 F8 2D                      cmp     eax, 2Dh ; '-'
.text:00007FF72357AD9D 0F 84 C0 00 00 00 jz loc_7FF72357AE63

原来得是eax==2D,才能满足jz要求,现在直接让他jnz

image-20220911212949281
1
.text:00007FF72357AD9D 0F 85 C0 00 00 00             jnz     loc_7FF72357AE63

可以看见操作码从0F84变成了0F85

然后保存修改,Apply patches to input file...

或者x64dbg也可以干这个事情

image-20220911213946860

然后打开补丁后的程序,已经没人找茬了

image-20220911214059651

"证书颁发给:"

"0个用户证书"

就很喜感