首页
社区
课程
招聘
[分享]010算法分析,附带注册机,网络验证分析
发表于: 6天前 1319

[分享]010算法分析,附带注册机,网络验证分析

6天前
1319

010分析

本文对010 16.0.2版本进行分析,参考solly大佬的文章,经过验证,其注册算法与之前版本并未改变,新人第一次写贴,如有违规侵权,请联系会尽快处理。

1.查看文件基本信息

用die对010分析查看基本信息
图片描述
使用 Qt 6.4.3 图形界面库、由 Microsoft Visual Studio 2019(完整IDE)开发的程序,没有壳。

2.010暴力破解

通过报错信息定位判断点
图片描述
Ida中位置如下
图片描述
使用x64dbg进行调试
在程序入口使用shift+D字符串搜索-invalid name
图片描述
图片描述
双击进入
图片描述
查看交叉引用,跳转到引用点
图片描述
到此处,可以看见上面有三个跳转,再jmp下面一行中继续查看应用跟踪
图片描述
到达此处,这里跟上面情况一样,仍然是只做了判断,下断点之后继续往上跟
图片描述
此处0xdb是成功关键位,流程图如下
图片描述
红线是正确的走向,通过流程图可以对edi复制进行跟踪,
继续往上跟踪,发现有两个引用
图片描述
跟到这里我们会发现两个跳转,首先看887d方法
图片描述
其中反汇编如下,

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
__int64 __fastcall sub_7FF6484DC3B0(__int64 a1, __int64 a2, __int64 a3)
{
  unsigned int v3; // edi
  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 ( *(a1 + 124) )
    return 0x113LL;
  v6 = sub_7FF6480A3D5F(a1, a2, a3);
  switch ( v6 )
  {
    case 0x2D:
      return 0xDBLL;
    case 0x4E:
      v12 = sub_7FF6480AC879(a1, v3);
      v13 = 0x20C;
      if ( v12 != 23 )
        return 0xED;
      return v13;
    case 0xE7:
      return 0x177LL;
    default:
      v7 = sub_7FF6480AC879(a1, v3);
      if ( v7 == 23 )
        return 0x71LL;
      if ( v7 != 42 )
      {
        if ( v7 == 0x138 )
        {
          v8 = sub_7FF6480AEC00(a1);
          v9 = 0x2F;
          if ( v8 == 0x1A3 )
            return 0xF9;
          return v9;
        }
        return 0x177LL;
      }
      v10 = sub_7FF6480AEC00(a1);
      v11 = 0x177;
      if ( v10 == 419 )
        return 0xF9;
      return v11;
  }
}

可以看出对db有检测且v6调用3d5f方法,也就是上一个call,其具体为第一个call返回0x2d此处返回0xdb,验证成功。那么暴力破解的方法就很多了
此处更改这边的if跳转,与返回值
if ( *(a1 + 124) )
return 0x113LL;
具体如下
这种更改判断以及返回实现效果实现为不需要网络破解,(因为在010初始页面有剩余天数下,也就是在者许可证验证之前就有这个逻辑的实现,同样也是调用这个方法)
图片描述
对应x64进行更改打补丁
图片描述
成功破解
图片描述

3.算法分析

接下来我们开始跟踪其注册算法,先在这个位置下一个断点,如下图所示:
图片描述
按 F9 运行该软件,在注册界面,输入注册码假码信息,如下图所示:
图片描述
在上图中也可以看到目前的注册状态:Evaluation Version - 30 Days Left。运行,马上断了下来,如下图所示
图片描述
图片描述
在ida中代码如下
图片描述
到这里
图片描述
下面对方法进行讲解
第一个call中代码如下 主要是去除’ “

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
  v2 = *(int *)(a2 + 0x10);
  v3 = a1 + 24;
  QString::operator=(a1 + 24, a2);
  if ( (int)v2 > 2 )
  {
    v5 = *(_WORD *)QChar::QChar((QChar *)&v12, '\'');
    if ( *(_WORD *)QString::operator[](a2, &v13, 0LL) == v5 )
    {
      v6 = v2;
      v7 = *(_WORD *)QChar::QChar((QChar *)&v12, '\'');
      if ( *(_WORD *)QString::operator[](a2, &v13, v2 - 1) == v7 )
      {
LABEL_8:
        v10 = QString::mid(a2, v11, 1LL, (int)v2 - 2);
        QString::operator=(v3, v10);
        QString::~QString(v11);
        return;
      }
    }
    else
    {
      v6 = v2;
    }
    v8 = *(_WORD *)QChar::QChar((QChar *)&v12, '"');
    if ( *(_WORD *)QString::operator[](a2, &v13, 0LL) == v8 )
    {
      v9 = *(_WORD *)QChar::QChar((QChar *)&v12, '"');
      if ( *(_WORD *)QString::operator[](a2, &v13, v6 - 1) == v9 )
        goto LABEL_8;
    }
  }
}

第二个call如下,对0与l做替换

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
  v4 = 0LL;
  QString::QString(a2, a3);
  v17 = 1;
  v5 = *((_DWORD *)a2 + 4);
  if ( v5 > 0 )
  {
    v6 = (unsigned int)v5;
    do
    {
      v7 = *(_WORD *)QChar::QChar((QChar *)v14, 'O');
      if ( *(_WORD *)QString::operator[](a2, v4) == v7
        || (v8 = *(_WORD *)QChar::QChar((QChar *)v15, 'o'), *(_WORD *)QString::operator[](a2, v4) == v8) )
      {
        QChar::QChar((QChar *)&v18, 48);
        v9 = v18;
        *(_WORD *)QString::operator[](a2, v4) = v9;
      }
      v10 = *(_WORD *)QChar::QChar((QChar *)v16, 'l');
      if ( *(_WORD *)QString::operator[](a2, v4) == v10 )
      {
        QChar::QChar((QChar *)&v13, '1');
        v11 = v13;
        *(_WORD *)QString::operator[](a2, v4) = v11;
      }
      ++v4;
      --v6;
    }
    while ( v6 );
  }
  return a2;
}

第三个核心算法

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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
__int64 __fastcall hexing_7FF774DCB840(__int64 a1, unsigned int a2, unsigned int a3)
{
  int v4; // ebp
  _QWORD *v5; // rbx
  char *v6; // rdi
  __int16 v7; // bx
  __int64 v8; // rax
  __int16 v9; // bx
  __int64 v10; // rax
  int v11; // r8d
  __int64 v12; // rax
  _BYTE *v13; // rdx
  char v14; // dl
  int v15; // r12d
  unsigned __int8 v16; // r9
  unsigned __int8 v17; // al
  int v18; // ebx
  char v19; // di
  __int16 v20; // bx
  unsigned __int16 v21; // ax
  unsigned int v22; // ecx
  char v23; // r14
  unsigned __int16 v24; // ax
  int v25; // ebx
  char *v26; // rax
  int v27; // eax
  unsigned int v28; // ebx
  int index_7FF6DED5B0C3; // eax
  unsigned int v31; // [rsp+20h] [rbp-78h]
  char v32[2]; // [rsp+24h] [rbp-74h] BYREF
  char v33[2]; // [rsp+26h] [rbp-72h] BYREF
  char v34[2]; // [rsp+28h] [rbp-70h] BYREF
  char v35[2]; // [rsp+2Ah] [rbp-6Eh] BYREF
  unsigned int v36; // [rsp+2Ch] [rbp-6Ch]
  unsigned int v37; // [rsp+30h] [rbp-68h]
  _BYTE v38[24]; // [rsp+38h] [rbp-60h] BYREF
  unsigned __int8 v39; // [rsp+50h] [rbp-48h] BYREF
  unsigned __int8 v40; // [rsp+51h] [rbp-47h]
  unsigned __int8 v41; // [rsp+52h] [rbp-46h]
  char v42; // [rsp+53h] [rbp-45h]
  unsigned __int8 v43; // [rsp+54h] [rbp-44h]
  unsigned __int8 v44; // [rsp+55h] [rbp-43h]
  unsigned __int8 v45; // [rsp+56h] [rbp-42h]
  char v46; // [rsp+57h] [rbp-41h]
  unsigned __int8 v47; // [rsp+58h] [rbp-40h]
  unsigned __int8 v48; // [rsp+59h] [rbp-3Fh]
 
  v37 = a3;
  v36 = a2;
  v4 = 0;                                       // 初始化局部变量
  v31 = 0;                                      // 初始化配对索引
  *(a1 + 128) = 0LL;                            // 清空结果字段1
  *(a1 + 104) = 0;                              // 清空结果字段2
  if ( *(a1 + 40) && *(a1 + 64) )               // 检查用户名和注册码是否都存在
  {
    parse_dashed_hex_7FF6DED5E1DD(a1, &v39);    // 解析注册码字符串
    v5 = &off_7FF6BBF4A5C0;                     // 指向黑名单数组
    do
    {
      if ( QString::operator==(a1 + 0x18, *v5) )// 比较用户名是否在黑名单中
        return 0xE7LL;                          // 如果在,返回错误码0xE7
      ++v5;
    }
    while ( v5 < &unk_7FF6BBF4A5D0 );           // 遍历整个黑名单数组
    if ( *(a1 + 40) > 1 )
    {
      v6 = &unk_7FF6BBF4A5D1;
      do
      {
        v7 = *QChar::QChar(v32, *(v6 - 1));     // 遍历所有特征条目
        v8 = QString::operator[](a1 + 24, 0LL); // 取用户名第0位(第1个字符)
        if ( *QChar::toUpper(v8, v33) == v7 )   // 转大写后对比
        {
          v9 = *QChar::QChar(v34, *v6);
          v10 = QString::operator[](a1 + 24, 1LL);// 取用户名第1位(第2个字符)
          if ( *QChar::toUpper(v10, v35) == v9 )// 转大写后对比
          {
            v11 = 0;                            // 步骤3:匹配注册码的10个核心字节
            v12 = 0LL;
            v13 = v6 + 10;                      // 指向特征条目中“注册码特征字节”的最后1
            do
            {                                   // &v39:之前parse_dashed_hex解析出的注册码原始字节数组
              if ( *(&v39 + v12) != *v13 )      // 逐字节对比注册码和特征值
                break;
              ++v11;
              ++v12;
              --v13;                            // 反向对比(从后往前)
            }
            while ( v12 < 10 );                 // 一共对比10个字节
            if ( v11 == 10 )                    // 如果10个字节全匹配,直接判定无效
              return 0xE7LL;
          }
        }
        v6 += 12;                               // 每个特征条目占12字节,跳到下一个条目
      }
      while ( v6 < byte_7FF6BBF4A5E9 );
    }
    v14 = v46;                                  // 字节7
    v15 = v44;                                  // 字节5
    v16 = v41;                                  // 字节2
    v17 = v40;                                  // 字节1
    v18 = v39;                                  // 字节0
    v19 = v42;                                  // 字节3(类型标识符)
                                                // 此处v42就是rsp也就是重新生成的密钥
    switch ( v42 )                              // 根据类型字节选择验证路径
    {
      case 0x9C:
        v20 = (v44 ^ v41) + ((v46 ^ v40) << 8); // 普通许可证)这个是没有免费技术支持,没有免费升级的注册类型,注册码中有版本号检查,必须大于当前软件的版本,否则提示注册码过期。注册码只有4段。
                                                // v20是 010 Editor 普通许可证的 16 位 “产品标识符”,由注册码 4 个固定字节异或计算得出;
                                                // 解释:步骤1: 计算许可证ID
                                                // v20 = ((v46 ^ v40) << 8) | (v44 ^ v41)
                                                // 即字节1^字节7作为高8位,字节5^字节2作为低8
        *(a1 + 108) = xor_add_transform_7FF6DED5AD3F(v45 ^ v39);// 步骤2: 计算有效期
                                                // 有效期 = transform(字节6 ^ 字节0)
                                                // transform函数: ((x ^ 0x18) + 61) ^ 0xA7
        v21 = validate_and_map_id_7FF6DED58C33(v20);
        *(a1 + 112) = v21;                      // 步骤3: 验证并映射ID
                                                // ID映射函数:
                                                // 1. tmp = ((v20 ^ 0x7892) + 19760) ^ 0x3421
                                                // 2. 如果tmp能被11整除,返回tmp/11,否则返回0
        v22 = *(a1 + 108);                      // 获取计算出的有效期
        if ( v22 && v21 - 1 <= 0x3E7 )          // 步骤4: 检查有效期和ID是否有效
                                                // 有效期非0ID1-1000范围内
        {
          v23 = 0;
          if ( v22 < 2 )
            v23 = *(a1 + 108);                  // 如果有效期小于2,v23=有效期,否则v23=0
LABEL_26:                                       // 进入公共验证部分
          QString::toUtf8(a1 + 24, v38);        // 步骤1: 获取用户名的UTF-8编码
          v25 = *(a1 + 112);                    // 获取映射后的ID
          LOBYTE(v4) = v19 != -4;               // 设置标志位: 如果类型不是0xFC则为1,否则为0
          v26 = QByteArray::data(v38);          // 获取用户名数据指针
          v27 = compute_custom_hash_7FF6DED5C97D(v26, v4, v23, v25);// 步骤2: 计算自定义哈希
                                                // 参数: 用户名, 标志位, 有效期/索引, ID
          if ( v43 == v27 && v15 == BYTE1(v27) && v45 == BYTE2(v27) && v46 == HIBYTE(v27) )// 步骤3: 验证哈希匹配
                                                // 哈希值的四个字节必须分别等于v43, v15, v45, v46
                                                // 即: 字节4=哈希最低字节, 字节5=哈希第二字节, 字节6=哈希第三字节, 字节7=哈希最高字节
                                                //
          {
            if ( v19 == '\x9C' )
            {
              if ( v36 > *(a1 + 108) )          // 如果当前时间(v36)大于有效期
              {
                v28 = 0x4E;                     // 返回错误码0x4E(可能表示过期)
LABEL_41:                                       // 清理并返回
                QByteArray::~QByteArray(v38);
                return v28;
              }
LABEL_33:
              v28 = 0x2D;                       // 否则返回成功码0x2D
              goto LABEL_41;
            }
            if ( v19 == -4 )                    // 0xFC
            {
              index_7FF6DED5B0C3 = validate_pair_and_get_index_7FF6DED5B0C3(v39 + (v40 << 8) + (v41 << 16), v27);// 验证配对: 计算(字节0 + 字节1<<8 + 字节2<<16)和哈希值的关系
              if ( index_7FF6DED5B0C3 )         // 如果配对有效
              {
                *(a1 + 104) = index_7FF6DED5B0C3;// 存储配对索引
                v28 = 0x93;                     // 返回成功码0x93
                goto LABEL_41;
              }
            }
            else if ( v31 )
            {
              if ( v37 > v31 )
              {
                v28 = 0x4E;
                goto LABEL_41;
              }
              goto LABEL_33;
            }
          }
          v28 = '\xE7';
          goto LABEL_41;
        }
        break;
      case 0xFC:
        v23 = -1;                               // 这个不算正式注册版本,是延长试用期版本,最长可延长为5年试用期(从发布日期算起),这个版本会有一些检查(注册表中的数据),保证延期合法。注册码只有4
        *(a1 + 108) = 255;
        *(a1 + 112) = 1;
        *(a1 + 128) = 1;
        goto LABEL_26;
      case 0xAC:
        *(a1 + 108) = 2;                        // 这个是有免费技术支持、有免费升级的完整注册类型,不过会检查注册码中的过期时间(天数,从发布时间算起),这些免费支持是有期限的,会过期。注册码有5段,是最完整的注册码。
                                                // a1是注册码验证结构体指针,a1+108是 “类型 / 有效期标记字段”,固定赋值为 2
        v24 = validate_and_map_id_7FF6DED58C33((v15 ^ v16) + ((v14 ^ v17) << 8));// 计算该类型的 16 位 “产品核心 ID”(类似 0x9C 分支的 v20,但验证逻辑更严格);
        *(a1 + 112) = v24;                      // 映射后的 ID 存入结构体a1+112字段(和 0x9C 分支存储映射 ID 的位置一致);
        if ( v24 - 1 <= 0x1387 )                // 验证映射后的 ID 是否在 “完整许可证有效范围” 内(比 0x9C 分支的 1~1000 范围大,对应 “更完整的注册码” 属性);
        {
          v31 = validate_pair_and_get_index_7FF6DED5B0C3(// validate_pair_and_get_index是 “配对验证 + 期限索引获取” 函数,输入 2 个参数,验证匹配则返回 “过期天数 / 支持期限索引”(非 0),失败则返回 0
                  (v45 ^ v18) + ((v15 ^ v48) << 16) + ((v47 ^ v43) << 8),
                  026706047);
          *(a1 + 132) = v31;
          v23 = v31;
          goto LABEL_26;
        }
        break;
    }
    return 0xE7LL;
  }
  return 0x93LL;
}
/* Orphan comments:
普通许可证)详细流程
*/

对应汇编如下

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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
000000014043B84 | mov qword ptr ss:[rsp+0x10],rbx                   |
000000014043B84 | mov qword ptr ss:[rsp+0x18],rbp                   |
000000014043B84 | push rsi                                          |
000000014043B84 | push rdi                                          |
000000014043B84 | push r12                                          |
000000014043B84 | push r14                                          |
000000014043B85 | push r15                                          |
000000014043B85 | sub rsp,0x70                                      |
000000014043B85 | mov rax,qword ptr ds:[0x140FF1FF8]                | rax:EntryPoint
000000014043B85 | xor rax,rsp                                       | rax:EntryPoint
000000014043B86 | mov qword ptr ss:[rsp+0x60],rax                   | rax:EntryPoint
000000014043B86 | mov dword ptr ss:[rsp+0x30],r8d                   | a3=0x4f4c
000000014043B86 | mov dword ptr ss:[rsp+0x2C],edx                   | a2  11
000000014043B86 | mov rsi,rcx                                       |
000000014043B87 | xor ebp,ebp                                       | v4=0 初始化局部变量
000000014043B87 | mov dword ptr ss:[rsp+0x20],ebp                   | 初始化配对索引
000000014043B87 | mov qword ptr ds:[rcx+0x80],rbp                   | a1 + 128
000000014043B87 | mov dword ptr ds:[rcx+0x68],ebp                   | a1 + 104
000000014043B88 | cmp qword ptr ds:[rcx+0x28],rbp                   |
000000014043B88 | je 010editor.14043BBA8                            |
000000014043B88 | cmp qword ptr ds:[rcx+0x40],rbp                   |
000000014043B88 | je 010editor.14043BBA8                            | 检查用户名和注册码是否都存在
000000014043B89 | lea rdx,qword ptr ss:[rsp+0x50]                   | rdx:EntryPoint
000000014043B89 | call 010editor.14000E1DD                          | decode_formatted_hex_id  序列号转换
000000014043B89 | lea rbx,qword ptr ds:[<sub_140E1A5C0>]            | 0000000140E1A5C0:&"999" 黑名单用户名
000000014043B8A | lea rdi,qword ptr ds:[0x140E1A5D0]                |
000000014043B8A | nop dword ptr ds:[rax],eax                        |
000000014043B8B | mov rdx,qword ptr ds:[rbx]                        | rdx:EntryPoint
000000014043B8B | lea rcx,qword ptr ds:[rsi+0x18]                   | 0x00000133F51AA700
000000014043B8B | call qword ptr ds:[<public: bool __cdecl QString: | 用户名比较 999与AnyOne
000000014043B8B | test al,al                                        | al==0 用户名!=999
000000014043B8B | jne 010editor.14043BBA1                           | al=1跳到注册码值正确
000000014043B8C | add rbx,0x8                                       |
000000014043B8C | cmp rbx,rdi                                       |
000000014043B8C | jl 010editor.14043B8B0                            |
000000014043B8C | cmp qword ptr ds:[rsi+0x28],0x1                   | 1
000000014043B8D | jle 010editor.14043B98F                           |
000000014043B8D | lea rdi,qword ptr ds:[0x140E1A5D1]                | v6 sint 3此处同样也是比较用户名,比较签名两个字符 43 ('c') 4F('0') 57 D6 30 E3 CA B9 AC AB A1 ('j') C4 ('u') 4A 55 59 2A 35 E2 C4 65 AC D3 A4 CB
000000014043B8E | lea r14,qword ptr ds:[0x140E1A5E9]                | co  与ju sint 5
000000014043B8E | nop word ptr ds:[rax+rax],ax                      |
000000014043B8F | movzx edx,byte ptr ds:[rdi-0x1]                   | 遍历黑名单数组,每个12
000000014043B8F | lea rcx,qword ptr ss:[rsp+0x24]                   | b7 01  v32
000000014043B8F | call qword ptr ds:[<public: __cdecl QChar::QChar( | 取出c
000000014043B8F | movzx ebx,word ptr ds:[rax]                       | c
000000014043B90 | xor edx,edx                                       |
000000014043B90 | lea rcx,qword ptr ds:[rsi+0x18]                   | unchar ch
000000014043B90 | call qword ptr ds:[<public: class QChar & __cdecl |
000000014043B90 | lea rdx,qword ptr ss:[rsp+0x26]                   | rdx:EntryPoint
000000014043B91 | mov rcx,rax                                       | rax:EntryPoint
000000014043B91 | call qword ptr ds:[<public: class QChar __cdecl Q | 转换成大写用户名第一个字符
000000014043B91 | cmp word ptr ds:[rax],bx                          | rax:EntryPoint
000000014043B91 | jne 010editor.14043B982                           |
000000014043B92 | movzx edx,byte ptr ds:[rdi]                       |
000000014043B92 | lea rcx,qword ptr ss:[rsp+0x28]                   |
000000014043B92 | call qword ptr ds:[<public: __cdecl QChar::QChar( |
000000014043B92 | movzx ebx,word ptr ds:[rax]                       | rax:EntryPoint
000000014043B93 | mov edx,0x1                                       |
000000014043B93 | lea rcx,qword ptr ds:[rsi+0x18]                   |
000000014043B93 | call qword ptr ds:[<public: class QChar & __cdecl |
000000014043B94 | lea rdx,qword ptr ss:[rsp+0x2A]                   | rdx:EntryPoint
000000014043B94 | mov rcx,rax                                       | rax:EntryPoint
000000014043B94 | call qword ptr ds:[<public: class QChar __cdecl Q |
000000014043B94 | cmp word ptr ds:[rax],bx                          | rax:EntryPoint
000000014043B95 | jne 010editor.14043B982                           |
000000014043B95 | mov r8d,ebp                                       |
000000014043B95 | mov rax,rbp                                       | rax:EntryPoint
000000014043B95 | lea rdx,qword ptr ds:[rdi+0xA]                    | rdx:EntryPoint
000000014043B95 | nop                                               |
000000014043B96 | movzx ecx,byte ptr ds:[rdx]                       | rdx:EntryPoint
000000014043B96 | cmp byte ptr ss:[rsp+rax+0x50],cl                 |
000000014043B96 | jne 010editor.14043B978                           |
000000014043B96 | inc r8d                                           |
000000014043B96 | inc rax                                           | rax:EntryPoint
000000014043B96 | dec rdx                                           | rdx:EntryPoint
000000014043B97 | cmp rax,0xA                                       | rax:EntryPoint, 0A:'\n'
000000014043B97 | jl 010editor.14043B960                            |
000000014043B97 | cmp r8d,0xA                                       | 0A:'\n'
000000014043B97 | je 010editor.14043BBA1                            |
000000014043B98 | add rdi,0xC                                       |
000000014043B98 | cmp rdi,r14                                       |
000000014043B98 | jl 010editor.14043B8F0                            |
000000014043B98 | movzx edx,byte ptr ss:[rsp+0x57]                  | v46  字节7,密钥第八个
000000014043B99 | movzx r12d,byte ptr ss:[rsp+0x55]                 | v44 字节5 6
000000014043B99 | movzx r9d,byte ptr ss:[rsp+0x52]                  | v41  字节2 3
000000014043B9A | movzx eax,byte ptr ss:[rsp+0x51]                  | v40 字节1 2
000000014043B9A | movzx ebx,byte ptr ss:[rsp+0x50]                  | v39  字节0 第一个
000000014043B9A | movzx edi,byte ptr ss:[rsp+0x53]                  | dil(EDI 低 8 位) 字节3 第四个
000000014043B9A | cmp dil,0x9C                                      |
000000014043B9B | jne 010editor.14043BA16                           | swith  0xfc跳转
000000014043B9B | movzx ecx,bl                                      | bl=v44,零扩展为32位存入ECX(ECX=0x000000[V44])
000000014043B9B | xor cl,byte ptr ss:[rsp+0x56]                     | cl是ECX低8位(即v44),和rsp+0x56(v41=rsp+0x52)异或 → cl = v44 ^ v41
000000014043B9B | xor al,dl                                         | al=v46,dl=v40 → al = v46 ^ v40(高8位原始值)
000000014043B9B | movzx ebx,al                                      | 把al(v46^v40)零扩展为32位存入EBX(EBX=0x000000[V46^V40])
000000014043B9C | mov eax,0x100                                     | EAX=0x100(十进制256,等价于2^8
000000014043B9C | imul ebx,eax                                      | EBX = EBX * EAX = (v46^v40) * 0x100 → 等价于 (v46^v40) << 8
000000014043B9C | movzx eax,r9b                                     | r9b存储的是之前计算的v44^v41(cl的值),零扩展存入EAX
000000014043B9C | xor al,r12b                                       | 校准:确保al=v44^v41
000000014043B9D | movzx edx,al                                      |  把al(v44^v41)零扩展到EDX(EDX=0x000000[V44^V41])
000000014043B9D | add bx,dx                                         | bx=EBX低16位(即(v46^v40)<<8),dx=EDX低16位(即v44^v41)→ bx = 8+ 8= v20
000000014043B9D | call 010editor.14000AD3F                          | xor_add_transform
000000014043B9D | movzx eax,al                                      |
000000014043B9D | mov dword ptr ds:[rsi+0x6C],eax                   | 计算版本号
000000014043B9E | movzx ecx,bx                                      |
000000014043B9E | call 010editor.140008C33                          | validate_and_map_id
000000014043B9E | movzx eax,ax                                      |
000000014043B9E | mov dword ptr ds:[rsi+0x70],eax                   | 验证产品ID
000000014043B9E | mov ecx,dword ptr ds:[rsi+0x6C]                   |
000000014043B9F | test ecx,ecx                                      |
000000014043B9F | je 010editor.14043BBA1                            |
000000014043B9F | dec eax                                           |
000000014043B9F | cmp eax,0x3E7                                     |
000000014043BA0 | ja 010editor.14043BBA1                            | 验证条件检查版本号必须非零:v22 != 0产品ID必须在1-1000范围内:v21 >= 1 && v21 <= 10000x3E7 = 999
000000014043BA0 | mov r14d,ebp                                      |
000000014043BA0 | cmp ecx,0x2                                       |
000000014043BA0 | cmovb r14d,ecx                                    | 设置哈希参数
000000014043BA1 | jmp 010editor.14043BABD                           |
000000014043BA1 | cmp dil,0xFC                                      | 比较0x fc
000000014043BA1 | jne 010editor.14043BA3C                           |
000000014043BA1 | mov r14d,0xFF                                     |
000000014043BA2 | mov dword ptr ds:[rsi+0x6C],r14d                  |
000000014043BA2 | mov dword ptr ds:[rsi+0x70],0x1                   |
000000014043BA2 | mov dword ptr ds:[rsi+0x80],0x1                   |
000000014043BA3 | jmp 010editor.14043BABD                           |
000000014043BA3 | cmp dil,0xAC                                      | 比较0xac
000000014043BA4 | jne 010editor.14043BBA1                           |
000000014043BA4 | mov dword ptr ds:[rsi+0x6C],0x2                   | 将2写入结构体的偏移108处(类型标记)
000000014043BA4 | xor al,dl                                         | 计算 v14 ^ v17(字节7^字节1)
000000014043BA4 | movzx ecx,al                                      |
000000014043BA5 | mov eax,0x100                                     | 左移8
000000014043BA5 | imul ecx,eax                                      |
000000014043BA5 | movzx eax,r9b                                     |
000000014043BA5 | xor al,r12b                                       | 计算 v15 ^ v16(字节5^字节2)
000000014043BA6 | movzx edx,al                                      |
000000014043BA6 | add cx,dx                                         | 计算16位产品id 两部分组合成16位数
000000014043BA6 | call 010editor.140008C33                          | 计算该类型的 16 位 “产品核心 ID
000000014043BA6 | movzx eax,ax                                      |
000000014043BA6 | mov dword ptr ds:[rsi+0x70],eax                   | 映射后的 ID 存入结构体a1+112字段
000000014043BA7 | dec eax                                           |
000000014043BA7 | cmp eax,0x1387                                    | 验证映射后的 ID 是否在 “完整许可证有效范围” 内(比 0x9C 分支的 1~1000 范围大,对应 “更完整的注册码” 属性)
000000014043BA7 | ja 010editor.14043BBA1                            |
000000014043BA7 | movzx ecx,byte ptr ss:[rsp+0x54]                  | 加载v43(字节4
000000014043BA8 | movzx eax,byte ptr ss:[rsp+0x58]                  | 加载v47(字节8
000000014043BA8 | xor ecx,eax                                       |
000000014043BA8 | shl ecx,0x8                                       | ecx = (v43 ^ v47) << 8
000000014043BA8 | movzx edx,byte ptr ss:[rsp+0x59]                  | 加载v48(字节9
000000014043BA9 | xor edx,r12d                                      | edx = v48 ^ r12d(r12d存放v15/字节5
000000014043BA9 | shl edx,0x10                                      | edx = (v48 ^ v15) << 16
000000014043BA9 | add ecx,edx                                       | ecx = ((v47 ^ v43) << 8) + ((v15 ^ v48) << 16)
000000014043BA9 | mov edx,ebx                                       | ebx存放v18(字节0
000000014043BA9 | movzx eax,byte ptr ss:[rsp+0x56]                  | 加载v45(字节6
000000014043BAA | xor edx,eax                                       | edx = v18 ^ v45
000000014043BAA | add ecx,edx                                       |
000000014043BAA | mov edx,0x5B8C27                                  | 第二个固定参数:026706047(八进制)
000000014043BAA | call 010editor.14000B0C3                          |
000000014043BAB | mov dword ptr ss:[rsp+0x20],eax                   |
000000014043BAB | mov dword ptr ds:[rsi+0x84],eax                   | 存储到结构体的偏移84h
000000014043BAB | mov r14d,eax                                      | 进入26分支
000000014043BAB | lea rdx,qword ptr ss:[rsp+0x38]                   | 目标地址,用于存储QByteArray
000000014043BAC | lea rcx,qword ptr ds:[rsi+0x18]                   | 用户名
000000014043BAC | call qword ptr ds:[<public: class QByteArray __cd | 序列号转UTF-8
000000014043BAC | nop                                               |
000000014043BAC | mov ebx,dword ptr ds:[rsi+0x70]                   | 获取产品id
000000014043BAD | cmp dil,0xFC                                      | 比较v19(类型)与0xFC
000000014043BAD | setne bpl                                         | 如果v19!=0xFC,则bpl=1,否则bpl=0
000000014043BAD | lea rcx,qword ptr ss:[rsp+0x38]                   |
000000014043BAD | call qword ptr ds:[<public: char * __cdecl QByteA | rax指向用户名UTF-8字节数据
000000014043BAE | mov r9d,ebx                                       | 第4个参数:产品ID
000000014043BAE | mov r8d,r14d                                      | 第3个参数:v23(对于0xAC类型是配对索引)
000000014043BAE | mov edx,ebp                                       | 第2个参数:标志位(bpl)
000000014043BAE | mov rcx,rax                                       | 第1个参数:用户名数据指针
000000014043BAE | call 010editor.14000C97D                          |  compute_custom_hash
000000014043BAF | mov edx,eax                                       | 保存哈希值到edx
000000014043BAF | cmp byte ptr ss:[rsp+0x54],al                     | 比较v43(字节4)与哈希最低字节
000000014043BAF | jne 010editor.14043BB8D                           | 不匹配则跳转到失败处理(返回0xE7)
000000014043BAF | mov ecx,eax                                       |
000000014043BB0 | shr ecx,0x8                                       | 右移8位,获取第二字节
000000014043BB0 | cmp r12b,cl                                       | 比较v15(字节5)与哈希第二字节
000000014043BB0 | jne 010editor.14043BB8D                           |
000000014043BB0 | mov ecx,eax                                       |
000000014043BB0 | shr ecx,0x10                                      | 右移16位,获取第三字节
000000014043BB1 | cmp byte ptr ss:[rsp+0x56],cl                     | 比较v45(字节6)与哈希第三字节
000000014043BB1 | jne 010editor.14043BB8D                           |
000000014043BB1 | mov ecx,eax                                       |
000000014043BB1 | shr ecx,0x18                                      | 右移24位,获取第四字节
000000014043BB1 | cmp byte ptr ss:[rsp+0x57],cl                     | 比较v46(字节7)与哈希最高字节
000000014043BB2 | jne 010editor.14043BB8D                           | 计算hash匹配
000000014043BB2 | cmp dil,0x9C                                      |
000000014043BB2 | jne 010editor.14043BB40                           |
000000014043BB2 | mov eax,dword ptr ss:[rsp+0x2C]                   |
000000014043BB2 | cmp eax,dword ptr ds:[rsi+0x6C]                   |
000000014043BB3 | jbe 010editor.14043BB39                           |
000000014043BB3 | mov ebx,0x4E                                      | 4E:'N'
000000014043BB3 | jmp 010editor.14043BB92                           |
000000014043BB3 | mov ebx,0x2D                                      | 2D:'-'
000000014043BB3 | jmp 010editor.14043BB92                           |
000000014043BB4 | cmp dil,0xFC                                      |
000000014043BB4 | jne 010editor.14043BB72                           |
000000014043BB4 | movzx ecx,byte ptr ss:[rsp+0x52]                  |
000000014043BB4 | shl ecx,0x10                                      |
000000014043BB4 | movzx eax,byte ptr ss:[rsp+0x51]                  |
000000014043BB5 | shl eax,0x8                                       |
000000014043BB5 | add ecx,eax                                       |
000000014043BB5 | movzx eax,byte ptr ss:[rsp+0x50]                  |
000000014043BB5 | add ecx,eax                                       |
000000014043BB5 | call 010editor.14000B0C3                          |
000000014043BB6 | test eax,eax                                      |
000000014043BB6 | je 010editor.14043BB8D                            |
000000014043BB6 | mov dword ptr ds:[rsi+0x68],eax                   |
000000014043BB6 | mov ebx,0x93                                      |
000000014043BB7 | jmp 010editor.14043BB92                           |
000000014043BB7 | cmp dil,0xAC                                      |
000000014043BB7 | jne 010editor.14043BB8D                           |
000000014043BB7 | mov eax,dword ptr ss:[rsp+0x20]                   |
000000014043BB7 | test eax,eax                                      |
000000014043BB7 | je 010editor.14043BB8D                            |
000000014043BB8 | cmp dword ptr ss:[rsp+0x30],eax                   |
000000014043BB8 | jbe 010editor.14043BB39                           |
000000014043BB8 | mov ebx,0x4E                                      | 4E:'N'
000000014043BB8 | jmp 010editor.14043BB92                           |
000000014043BB8 | mov ebx,0xE7                                      |
000000014043BB9 | lea rcx,qword ptr ss:[rsp+0x38]                   |
000000014043BB9 | call qword ptr ds:[<public: __cdecl QByteArray::~ |
000000014043BB9 | mov eax,ebx                                       |
000000014043BB9 | jmp 010editor.14043BBAD                           |
000000014043BBA | mov eax,0xE7                                      | 赋值0xe7
000000014043BBA | jmp 010editor.14043BBAD                           |
000000014043BBA | mov eax,0x93                                      |
000000014043BBA | mov rcx,qword ptr ss:[rsp+0x60]                   |
000000014043BBB | xor rcx,rsp                                       |
000000014043BBB | call 010editor.1400074A5                          | security_check_cookie
000000014043BBB | lea r11,qword ptr ss:[rsp+0x70]                   |
000000014043BBB | mov rbx,qword ptr ds:[r11+0x38]                   |
000000014043BBC | mov rbp,qword ptr ds:[r11+0x40]                   |
000000014043BBC | mov rsp,r11                                       |
000000014043BBC | pop r15                                           |
000000014043BBC | pop r14                                           |
000000014043BBC | pop r12                                           |
000000014043BBD | pop rdi                                           |
000000014043BBD | pop rsi                                           |
000000014043BBD | ret                                               |

其中在compute_custom_hash_7FF6DED5C97D中对应映射表如下

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
0x39CB44B8, 0x23754F67, 0x5F017211, 0x3EBB24DA, 0x351707C6, 0x63F9774B, 0x17827288, 0x0FE74821,
 0x5B5F670F, 0x48315AE8, 0x785B7769, 0x2B7A1547, 0x38D11292, 0x42A11B32, 0x35332244, 0x77437B60,
 0x1EAB3B10, 0x53810000, 0x1D0212AE, 0x6F0377A8, 0x43C03092, 0x2D3C0A8E, 0x62950CBF, 0x30F06FFA,
 0x34F710E0, 0x28F417FB, 0x350D2F95, 0x5A361D5A, 0x15CC060B, 0x0AFD13CC, 0x28603BCF, 0x3371066B,
 0x30CD14E4, 0x175D3A67, 0x6DD66A13, 0x2D3409F9, 0x581E7B82, 0x76526B99, 0x5C8D5188, 0x2C857971,
 0x15F51FC0, 0x68CC0D11, 0x49F55E5C, 0x275E4364, 0x2D1E0DBC, 0x4CEE7CE3, 0x32555840, 0x112E2E08,
 0x6978065A, 0x72921406, 0x314578E7, 0x175621B7, 0x40771DBF, 0x3FC238D6, 0x4A31128A, 0x2DAD036E,
 0x41A069D6, 0x25400192, 0x00DD4667, 0x6AFC1F4F, 0x571040CE, 0x62FE66DF, 0x41DB4B3E, 0x3582231F,
 0x55F6079A, 0x1CA70644, 0x1B1643D2, 0x3F7228C9, 0x5F141070, 0x3E1474AB, 0x444B256E, 0x537050D9,
 0x0F42094B, 0x2FD820E6, 0x778B2E5E, 0x71176D02, 0x7FEA7A69, 0x5BB54628, 0x19BA6C71, 0x39763A99,
 0x178D54CD, 0x01246E88, 0x3313537E, 0x2B8E2D17, 0x2A3D10BE, 0x59D10582, 0x37A163DB, 0x30D6489A,
 0x6A215C46, 0x0E1C7A76, 0x1FC760E7, 0x79B80C65, 0x27F459B4, 0x799A7326, 0x50BA1782, 0x2A116D5C,
 0x63866E1B, 0x3F920E3C, 0x55023490, 0x55B56089, 0x2C391FD1, 0x2F8035C2, 0x64FD2B7A, 0x4CE8759A,
 0x518504F0, 0x799501A8, 0x3F5B2CAD, 0x38E60160, 0x637641D8, 0x33352A42, 0x51A22C19, 0x085C5851,
 0x032917AB, 0x2B770AC7, 0x30AC77B3, 0x2BEC1907, 0x035202D0, 0x0FA933D3, 0x61255DF3, 0x22AD06BF,
 0x58B86971, 0x5FCA0DE5, 0x700D6456, 0x56A973DB, 0x5AB759FD, 0x330E0BE2, 0x5B3C0DDD, 0x495D3C60,
 0x53BD59A6, 0x4C5E6D91, 0x49D9318D, 0x103D5079, 0x61CE42E3, 0x7ED5121D, 0x14E160ED, 0x212D4EF2,
 0x270133F0, 0x62435A96, 0x1FA75E8B, 0x6F092FBE, 0x4A000D49, 0x57AE1C70, 0x004E2477, 0x561E7E72,
 0x468C0033, 0x5DCC2402, 0x78507AC6, 0x58AF24C7, 0x0DF62D34, 0x358A4708, 0x3CFB1E11, 0x2B71451C,
 0x77A75295, 0x56890721, 0x0FEF75F3, 0x120F24F1, 0x01990AE7, 0x339C4452, 0x27A15B8E, 0x0BA7276D,
 0x60DC1B7B, 0x4F4B7F82, 0x67DB7007, 0x4F4A57D9, 0x621252E8, 0x20532CFC, 0x6A390306, 0x18800423,
 0x19F3778A, 0x462316F0, 0x56AE0937, 0x43C2675C, 0x65CA45FD, 0x0D604FF2, 0x0BFD22CB, 0x3AFE643B,
 0x3BF67FA6, 0x44623579, 0x184031F8, 0x32174F97, 0x4C6A092A, 0x5FB50261, 0x01650174, 0x33634AF1,
 0x712D18F4, 0x6E997169, 0x5DAB7AFE, 0x7C2B2EE8, 0x6EDB75B4, 0x5F836FB6, 0x3C2A6DD6, 0x292D05C2,
 0x052244DB, 0x149A5F4F, 0x5D486540, 0x331D15EA, 0x4F456920, 0x483A699F, 0x3B450F05, 0x3B207C6C,
 0x749D70FE, 0x417461F6, 0x62B031F1, 0x2750577B, 0x29131533, 0x588C3808, 0x1AEF3456, 0x0F3C00EC,
 0x7DA74742, 0x4B797A6C, 0x5EBB3287, 0x786558B8, 0x00ED4FF2, 0x6269691E, 0x24A2255F, 0x62C11F7E,
 0x2F8A7DCD, 0x643B17FE, 0x778318B8, 0x253B60FE, 0x34BB63A3, 0x5B03214F, 0x5F1571F4, 0x1A316E9F,
 0x7ACF2704, 0x28896838, 0x18614677, 0x1BF569EB, 0x0BA85EC9, 0x6ACA6B46, 0x1E43422A, 0x514D5F0E,
 0x413E018C, 0x307626E9, 0x01ED1DFA, 0x49F46F5A, 0x461B642B, 0x7D7007F2, 0x13652657, 0x6B160BC5,
 0x65E04849, 0x1F526E1C, 0x5A0251B6, 0x2BD73F69, 0x2DBF7ACD, 0x51E63E80, 0x5CF2670F, 0x21CD0A03,
 0x5CFF0261, 0x33AE061E, 0x3BB6345F, 0x5D814A75, 0x257B5DF4, 0x0A5C2C5B, 0x16A45527, 0x16F23945

3.注册机

注册机最开始试着写了几个,没有成功,后面直接在solly大佬的基础上生成的,小编代码水平有限。

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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
import struct
from typing import List
 
# 类型定义
UCHAR = int
UWORD = int
ULONG = int
UINT32 = int
UINT64 = int
 
# 常量定义
RLSDATE = 0x473C  # 2019/12/06,发布日期
VERID = 0x0B  # 当前版本ID
FREE_UPGRADE_DAYS = 10549  # 免费升级天数
MAX_VERSION_ID = VERID + (FREE_UPGRADE_DAYS // 365)
 
name_tables = [
    0x39CB44B8, 0x23754F67, 0x5F017211, 0x3EBB24DA, 0x351707C6, 0x63F9774B, 0x17827288, 0x0FE74821,
    0x5B5F670F, 0x48315AE8, 0x785B7769, 0x2B7A1547, 0x38D11292, 0x42A11B32, 0x35332244, 0x77437B60,
    0x1EAB3B10, 0x53810000, 0x1D0212AE, 0x6F0377A8, 0x43C03092, 0x2D3C0A8E, 0x62950CBF, 0x30F06FFA,
    0x34F710E0, 0x28F417FB, 0x350D2F95, 0x5A361D5A, 0x15CC060B, 0x0AFD13CC, 0x28603BCF, 0x3371066B,
    0x30CD14E4, 0x175D3A67, 0x6DD66A13, 0x2D3409F9, 0x581E7B82, 0x76526B99, 0x5C8D5188, 0x2C857971,
    0x15F51FC0, 0x68CC0D11, 0x49F55E5C, 0x275E4364, 0x2D1E0DBC, 0x4CEE7CE3, 0x32555840, 0x112E2E08,
    0x6978065A, 0x72921406, 0x314578E7, 0x175621B7, 0x40771DBF, 0x3FC238D6, 0x4A31128A, 0x2DAD036E,
    0x41A069D6, 0x25400192, 0x00DD4667, 0x6AFC1F4F, 0x571040CE, 0x62FE66DF, 0x41DB4B3E, 0x3582231F,
    0x55F6079A, 0x1CA70644, 0x1B1643D2, 0x3F7228C9, 0x5F141070, 0x3E1474AB, 0x444B256E, 0x537050D9,
    0x0F42094B, 0x2FD820E6, 0x778B2E5E, 0x71176D02, 0x7FEA7A69, 0x5BB54628, 0x19BA6C71, 0x39763A99,
    0x178D54CD, 0x01246E88, 0x3313537E, 0x2B8E2D17, 0x2A3D10BE, 0x59D10582, 0x37A163DB, 0x30D6489A,
    0x6A215C46, 0x0E1C7A76, 0x1FC760E7, 0x79B80C65, 0x27F459B4, 0x799A7326, 0x50BA1782, 0x2A116D5C,
    0x63866E1B, 0x3F920E3C, 0x55023490, 0x55B56089, 0x2C391FD1, 0x2F8035C2, 0x64FD2B7A, 0x4CE8759A,
    0x518504F0, 0x799501A8, 0x3F5B2CAD, 0x38E60160, 0x637641D8, 0x33352A42, 0x51A22C19, 0x085C5851,
    0x032917AB, 0x2B770AC7, 0x30AC77B3, 0x2BEC1907, 0x035202D0, 0x0FA933D3, 0x61255DF3, 0x22AD06BF,
    0x58B86971, 0x5FCA0DE5, 0x700D6456, 0x56A973DB, 0x5AB759FD, 0x330E0BE2, 0x5B3C0DDD, 0x495D3C60,
    0x53BD59A6, 0x4C5E6D91, 0x49D9318D, 0x103D5079, 0x61CE42E3, 0x7ED5121D, 0x14E160ED, 0x212D4EF2,
    0x270133F0, 0x62435A96, 0x1FA75E8B, 0x6F092FBE, 0x4A000D49, 0x57AE1C70, 0x004E2477, 0x561E7E72,
    0x468C0033, 0x5DCC2402, 0x78507AC6, 0x58AF24C7, 0x0DF62D34, 0x358A4708, 0x3CFB1E11, 0x2B71451C,
    0x77A75295, 0x56890721, 0x0FEF75F3, 0x120F24F1, 0x01990AE7, 0x339C4452, 0x27A15B8E, 0x0BA7276D,
    0x60DC1B7B, 0x4F4B7F82, 0x67DB7007, 0x4F4A57D9, 0x621252E8, 0x20532CFC, 0x6A390306, 0x18800423,
    0x19F3778A, 0x462316F0, 0x56AE0937, 0x43C2675C, 0x65CA45FD, 0x0D604FF2, 0x0BFD22CB, 0x3AFE643B,
    0x3BF67FA6, 0x44623579, 0x184031F8, 0x32174F97, 0x4C6A092A, 0x5FB50261, 0x01650174, 0x33634AF1,
    0x712D18F4, 0x6E997169, 0x5DAB7AFE, 0x7C2B2EE8, 0x6EDB75B4, 0x5F836FB6, 0x3C2A6DD6, 0x292D05C2,
    0x052244DB, 0x149A5F4F, 0x5D486540, 0x331D15EA, 0x4F456920, 0x483A699F, 0x3B450F05, 0x3B207C6C,
    0x749D70FE, 0x417461F6, 0x62B031F1, 0x2750577B, 0x29131533, 0x588C3808, 0x1AEF3456, 0x0F3C00EC,
    0x7DA74742, 0x4B797A6C, 0x5EBB3287, 0x786558B8, 0x00ED4FF2, 0x6269691E, 0x24A2255F, 0x62C11F7E,
    0x2F8A7DCD, 0x643B17FE, 0x778318B8, 0x253B60FE, 0x34BB63A3, 0x5B03214F, 0x5F1571F4, 0x1A316E9F,
    0x7ACF2704, 0x28896838, 0x18614677, 0x1BF569EB, 0x0BA85EC9, 0x6ACA6B46, 0x1E43422A, 0x514D5F0E,
    0x413E018C, 0x307626E9, 0x01ED1DFA, 0x49F46F5A, 0x461B642B, 0x7D7007F2, 0x13652657, 0x6B160BC5,
    0x65E04849, 0x1F526E1C, 0x5A0251B6, 0x2BD73F69, 0x2DBF7ACD, 0x51E63E80, 0x5CF2670F, 0x21CD0A03,
    0x5CFF0261, 0x33AE061E, 0x3BB6345F, 0x5D814A75, 0x257B5DF4, 0x0A5C2C5B, 0x16A45527, 0x16F23945
]
 
 
def get_uncheck2(ul: ULONG) -> UWORD:
    """计算用户数的校验"""
    a = ul * 11
    return ((a ^ 0x3421) - 0x4D30) ^ 0x7892
 
 
def get_uncheck3(base: ULONG, rlsdate: ULONG) -> ULONG:
    """计算免费升级天数的校验(AC类型)"""
    end_of_date = rlsdate + FREE_UPGRADE_DAYS
    return (((end_of_date * 0x11) ^ 0xFFE53167) + 0x0002C175) ^ 0x0022C078 ^ base
 
 
def get_name_check(name: str, is_registed: ULONG, free_days: ULONG, user_count: ULONG) -> ULONG:
    """计算用户名的校验值"""
    name_check = 0
    idx3 = 0
    idx2 = 0
 
    n = len(name)
    idx4 = user_count * 15
    idx1 = free_days * 17
 
    for i in range(n):
        ch = name[i]
        idx0 = ord(ch.upper()) & 0xFF
        name_check += name_tables[idx0]
 
        if is_registed != 0# 正式注册版
            name_check ^= name_tables[(idx0 + 0x0D) & 0xFF]
            name_check *= name_tables[(idx0 + 0x2F) & 0xFF]
            name_check += name_tables[idx1 & 0xFF]
            name_check += name_tables[idx4 & 0xFF]
            name_check += name_tables[idx2 & 0xFF]
        else# 扩展评估版
            name_check ^= name_tables[(idx0 + 0x3F) & 0xFF]
            name_check *= name_tables[(idx0 + 0x17) & 0xFF]
            name_check += name_tables[idx1 & 0xFF]
            name_check += name_tables[idx4 & 0xFF]
            name_check += name_tables[idx3 & 0xFF]
 
        idx2 = (idx2 + 0x13) & 0xFF
        idx1 = (idx1 + 0x09) & 0xFF
        idx4 = (idx4 + 0x0D) & 0xFF
        idx3 = (idx3 + 0x07) & 0xFF
 
    return name_check & 0xFFFFFFFF  # 确保是32位
 
 
def generate_ac_license(name: str, user_count: int = 1000) -> str:
    """
    生成 AC 类型(全功能版,支持免费升级)的注册码
 
    Args:
        name: 用户名
        user_count: 用户数量(1=单用户,2-999=多用户,1000=站点许可证)
    """
    # 初始化 SN 数组
    sn_int = [0x11, 0x11, 0x22, 0x22, 0x33, 0x33, 0x44, 0x44, 0x55, 0x55]
 
    # 设置许可证类型为 AC(全功能版,支持免费升级)
    license_type = 0xAC
    sn_int[3] = license_type
 
    # 计算免费升级结束日期
    license_free_upgrade_end_of_date = RLSDATE + FREE_UPGRADE_DAYS
    print(f"免费升级结束日期: 0x{license_free_upgrade_end_of_date:08X}")
 
    # 计算用户名校验
    license_register_type = 1  # 正式注册版
    name_check = get_name_check(name, license_register_type, license_free_upgrade_end_of_date, user_count)
    print(f"用户名校验值: 0x{name_check:08X}")
 
    # 将用户名校验值写入 SN
    sn_int[4] = (name_check) & 0xFF
    sn_int[5] = (name_check >> 8) & 0xFF
    sn_int[6] = (name_check >> 16) & 0xFF
    sn_int[7] = (name_check >> 24) & 0xFF
 
    # 计算用户数校验
    user_count_encoded = get_uncheck2(user_count)
    print(f"用户数校验: 0x{user_count_encoded:04X}")
 
    # 将用户数校验写入 SN
    sn_int[1] = ((user_count_encoded >> 8) & 0xFF) ^ sn_int[7]
    sn_int[2] = (user_count_encoded & 0xFF) ^ sn_int[5]
 
    # 计算免费升级天数校验
    sn_date = get_uncheck3(0x005B8C27, RLSDATE)
    sn_date &= 0x00FFFFFF
    print(f"免费升级天数编码: 0x{sn_date:08X}")
 
    # 将免费升级天数校验写入 SN
    sn_int[0] = (sn_date & 0xFF) ^ sn_int[6]
    sn_int[8] = ((sn_date >> 8) & 0xFF) ^ sn_int[4]
    sn_int[9] = ((sn_date >> 16) & 0xFF) ^ sn_int[5]
 
    # 格式化为注册码字符串
    license_key = f"{sn_int[0]:02X}{sn_int[1]:02X}-{sn_int[2]:02X}{sn_int[3]:02X}-" \
                  f"{sn_int[4]:02X}{sn_int[5]:02X}-{sn_int[6]:02X}{sn_int[7]:02X}-" \
                  f"{sn_int[8]:02X}{sn_int[9]:02X}"
 
    return license_key
 
 
def main():
    """主函数"""
    print("=== AC 类型(全功能版,支持免费升级)注册机 ===\n")
 
    # 获取用户名
    name = input("请输入用户名: ").strip()
    if not name:
        name = "admin"
 
    # 获取用户数量
    try:
        user_input = input("请输入用户数量 (1=单用户, 2-999=多用户, 1000=站点许可证) [默认1000]: ").strip()
        if not user_input:
            user_count = 1000
        else:
            user_count = int(user_input)
    except ValueError:
        print("输入无效,使用默认值1000")
        user_count = 1000
 
    # 确保用户数量在有效范围内
    if user_count < 1:
        user_count = 1
    elif user_count > 1000:
        user_count = 1000
 
    print(f"\n生成注册信息...")
    print(f"用户名: {name}")
    print(f"用户数量: {user_count}")
 
    # 生成注册码
    license_key = generate_ac_license(name, user_count)
 
    print(f"\n生成的注册码:")
    print(f"SN: {license_key}")
 
    # 显示注册信息
    print(f"\n注册信息:")
    print(f"- 许可证类型: AC (全功能版,支持免费升级)")
    print(f"- 发布日期: 2019/12/06")
    print(f"- 免费升级截止: 2048/10/24")
    print(f"- 用户数量: {user_count}")
    print(f"- 版本ID: {VERID}")
 
 
 
 
 
if __name__ == "__main__":
        main()

图片描述
图片描述

5.网络认证

定位

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
00000001402B1BF8    41:B8 4C4F0000  mov r8d,0x4F4C  18236
00000001402B1BFE    48:8B0D B371D400    mov rcx,qword ptr ds:[0x140FF8DB8]  第3次引用140ff8db8
00000001402B1C05    E8 5521D5FF call 010editor.140003D5F    注册码检查
00000001402B1C0A    44:8BF0 mov r14d,eax   
00000001402B1C0D    BA 11000000 mov edx,0x11   
00000001402B1C12    41:B8 4C4F0000  mov r8d,0x4F4C  18236
00000001402B1C18    48:8B0D 9971D400    mov rcx,qword ptr ds:[0x140FF8DB8]  第4次引用140ff8db8
00000001402B1C1F    E8 596CD5FF call 010editor.14000887D    注册码检查 及 试用期扩充的检查
00000001402B1C24    8BD8    mov ebx,eax
00000001402B1C26    48:8B0D 8B71D400    mov rcx,qword ptr ds:[0x140FF8DB8]  第5次引用140ff8db8
00000001402B1C2D    41:81FE E7000000    cmp r14d,0xE7  
00000001402B1C34    0F84 43010000   je 010editor.1402B1D7D  成功标志3, r14d=0xe7
00000001402B1C3A    8379 7C 00  cmp dword ptr ds:[rcx+0x7C],0x0 是否进行网络验证,0-不验证,1-验证
00000001402B1C3E    0F84 39010000   je 010editor.1402B1D7D  成功标志4,与3选一
00000001402B1C44    33D2    xor edx,edx
00000001402B1C46    48:8BCE mov rcx,rsi
00000001402B1C49    E8 CDCDD5FF call 010editor.14000EA1B    网络验证
00000001402B1C4E    85C0    test eax,eax    eax 为返回验证id
00000001402B1C50    0F89 E0000000   jns 010editor.1402B1D36 非负跳转,eax非负,需要再次判断
00000001402B1C56    41:B8 0A000000  mov r8d,0xA 0A:'\n'
00000001402B1C5C    8BD0    mov edx,eax
00000001402B1C5E    48:8D4D E7  lea rcx,qword ptr ss:[rbp-0x19]

再ida中网络验证代码如下

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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
// Hidden C++ exception states: #wind=5
__int64 __fastcall sub_7FF6BB3E4320(int a1, int a2)
{
  QByteArray *v4; // rax
  char *v5; // rax
  _BYTE *v6; // rdx
  char v7; // cl
  __int64 v8; // rax
  __int64 v9; // rax
  QByteArray *v10; // rax
  char *v11; // rax
  _BYTE *v12; // rdx
  char v13; // cl
  char *v14; // rcx
  char *v15; // rcx
  char *v16; // rcx
  char *v17; // rcx
  char *v18; // rdx
  char *v19; // rcx
  char *v20; // rcx
  char *v21; // rcx
  char *v22; // rcx
  char *v23; // rcx
  char *v24; // rcx
  char *v25; // rcx
  char *v26; // rcx
  char *v27; // rcx
  char *v28; // rcx
  char *v29; // rcx
  char *v30; // rcx
  char *v31; // rcx
  char *v32; // rcx
  char *v33; // rcx
  char *v34; // rcx
  char *v35; // rcx
  char *v36; // rcx
  char *v37; // rcx
  char *v38; // rcx
  char *v39; // rcx
  char *v40; // rcx
  char *v41; // rcx
  char *v42; // rcx
  char *v43; // rcx
  char *v44; // rcx
  char *v45; // rcx
  int v46; // ebx
  unsigned int v47; // ebx
  unsigned int v49; // [rsp+30h] [rbp-D0h] BYREF
  void *Block; // [rsp+38h] [rbp-C8h] BYREF
  _BYTE v51[24]; // [rsp+40h] [rbp-C0h] BYREF
  _BYTE v52[24]; // [rsp+58h] [rbp-A8h] BYREF
  _BYTE v53[31]; // [rsp+70h] [rbp-90h] BYREF
  char v54; // [rsp+8Fh] [rbp-71h] BYREF
  char v55[2048]; // [rsp+90h] [rbp-70h] BYREF
  char Buffer[1024]; // [rsp+890h] [rbp+790h] BYREF
  _BYTE v57[512]; // [rsp+C90h] [rbp+B90h] BYREF
  _BYTE v58[512]; // [rsp+E90h] [rbp+D90h] BYREF
 
  Block = 0LL;
  v49 = 1024;
  if ( qword_7FF6BC128DB8 )
  {
    QString::QString(v51, (qword_7FF6BC128DB8 + 24));
    v4 = QString::toUtf8(v51, v52);
    v5 = QByteArray::data(v4);
    v6 = (v57 - v5);
    do
    {
      v7 = *v5;
      v5[v6] = *v5;
      ++v5;
    }
    while ( v7 );
    QByteArray::~QByteArray(v52);
    QString::~QString(v51);
    v8 = sub_7FF6BB138C0B(qword_7FF6BC128DB8, v53);
    v9 = replaceConfusingCharacters_7FF6DED588EB(qword_7FF6BC128DB8, v51, v8);
    v10 = QString::toLocal8Bit(v9, v52);
    v11 = QByteArray::data(v10);
    v12 = (v58 - v11);
    do
    {
      v13 = *v11;
      v11[v12] = *v11;
      ++v11;
    }
    while ( v13 );
    QByteArray::~QByteArray(v52);
    QString::~QString(v51);
    QString::~QString(v53);
    sub_7FF6BB1396BF(qword_7FF6BC128DB8, v57);
    strcpy(v55, "317K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6%4N6%4N6Q4x3X3g2K6N6$3g2W2N6s2y4U0j5i4m8W2i4K6u0W2j5$3!0E0i4K6u0r3");
    v14 = &v54;
    do
      ++v14;
    while ( *v14 );
    strcpy(v14, "cgibin");
    v15 = &v54;
    do
      ++v15;
    while ( *v15 );
    *v15 = 47;
    v16 = &v54;
    do
      ++v16;
    while ( *v16 );
    strcpy(v16, "010editor");
    v17 = &v54;
    do
      ++v17;
    while ( *v17 );
    *v17 = 95;
    v18 = &v54;
    do
      ++v18;
    while ( *v18 );
    strcpy(v18, "check");
    v19 = &v54;
    do
      ++v19;
    while ( *v19 );
    *v19 = 95;
    v20 = &v54;
    do
      ++v20;
    while ( *v20 );
    *v20 = 0x65736E6563696CLL;
    v21 = &v54;
    do
      ++v21;
    while ( *v21 );
    *v21 = 95;
    v22 = &v54;
    do
      ++v22;
    while ( *v22 );
    *v22 = 57;
    v23 = &v54;
    do
      ++v23;
    while ( *v23 );
    *v23 = 98;
    v24 = &v54;
    do
      ++v24;
    while ( *v24 );
    *v24 = 46;
    v25 = &v54;
    do
      ++v25;
    while ( *v25 );
    *v25 = 7366768;
    v26 = &v54;
    do
      ++v26;
    while ( *v26 );
    strcpy(v26, "?");
    v27 = &v54;
    do
      ++v27;
    while ( *v27 );
    *v27 = 116;
    v28 = &v54;
    do
      ++v28;
    while ( *v28 );
    *v28 = 61;
    sub_7FF6BB13C82E(v57, Buffer);
    v29 = &v54;
    do
      ++v29;
    while ( *v29 );
    strcpy(v29, Buffer);
    v30 = &v54;
    do
      ++v30;
    while ( *v30 );
    strcpy(v30, "&");
    v31 = &v54;
    do
      ++v31;
    while ( *v31 );
    *v31 = 7173491;
    v32 = &v54;
    do
      ++v32;
    while ( *v32 );
    *v32 = 61;
    sub_7FF6BB13C82E(v58, Buffer);
    v33 = &v54;
    do
      ++v33;
    while ( *v33 );
    strcpy(v33, Buffer);
    v34 = &v54;
    do
      ++v34;
    while ( *v34 );
    strcpy(v34, "&");
    v35 = &v54;
    do
      ++v35;
    while ( *v35 );
    strcpy(v35, "id");
    v36 = &v54;
    do
      ++v36;
    while ( *v36 );
    *v36 = 61;
    sub_7FF6BB13D319(Buffer, "%d");
    v37 = &v54;
    do
      ++v37;
    while ( *v37 );
    strcpy(v37, Buffer);
    v38 = &v54;
    do
      ++v38;
    while ( *v38 );
    strcpy(v38, "&");
    v39 = &v54;
    do
      ++v39;
    while ( *v39 );
    *v39 = 7039075;
    v40 = &v54;
    do
      ++v40;
    while ( *v40 );
    *v40 = 61;
    sub_7FF6BB13D319(Buffer, "%d");
    v41 = &v54;
    do
      ++v41;
    while ( *v41 );
    strcpy(v41, Buffer);
    v42 = &v54;
    do
      ++v42;
    while ( *v42 );
    strcpy(v42, "&");
    v43 = &v54;
    do
      ++v43;
    while ( *v43 );
    *v43 = 7371124;
    v44 = &v54;
    do
      ++v44;
    while ( *v44 );
    *v44 = 61;
    sub_7FF6BB13D319(Buffer, "%d");
    v45 = &v54;
    do
      ++v45;
    while ( *v45 );
    strcpy(v45, Buffer);
    QString::QString(v51, v55);
    if ( a2 )
    {
      sub_7FF6BB13F8B7(qword_7FF6BC128DD8, v51, 0, a1, "1On_HttpCheckLicenseFinished(char*,int)");
      QString::~QString(v51);
      return 0LL;
    }
    v46 = sub_7FF6BB1399F3(qword_7FF6BC128DD8, v51, &Block, &v49, 1, 0LL);
    QString::~QString(v51);
    if ( !v46 )
    {
      v47 = sub_7FF6BB132B44(qword_7FF6BC128DB8, Block, v49);
      j_j_j_j_free_0(Block);
      return v47;
    }
  }
  return 0xFFFFFFFFLL;
}

错误提示如下
图片描述
下面对里面函数解析
其中在sub_7FF6BB13C82E(v58, Buffer);这个里面主要是对密钥与字符串做的替换

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
// Hidden C++ exception states: #wind=5
void __fastcall sub_7FF6BB6014C0(char *a1, _BYTE *a2)
{
  char v2; // r10
  char v3; // r11
  char *v4; // r9
  char v5; // al
  unsigned __int8 v6; // r8
  char v7; // cl
  unsigned __int8 v8; // r8
  char v9; // al
 
  v2 = *a1;
  v3 = 0;
  v4 = a1;
  if ( *a1 )
  {
    do
    {
      ++v4;
      a2 += 2;
      v5 = 48;
      v6 = v2 ^ (93 - 83 * v3);
      v7 = v6 >> 4;
      if ( (v6 >> 4) >= 0xAu )
        v5 = 55;
      v8 = v6 & 0xF;
      *(a2 - 2) = v7 + v5;
      v9 = 48;
      if ( v8 >= 0xAu )
        v9 = 55;
      ++v3;
      *(a2 - 1) = v8 + v9;
      v2 = *v4;
    }
    while ( *v4 );
    *a2 = 0;
  }
  else
  {
    *a2 = 0;
  }
}

函数在栈上构造一个URL字符串,格式如下:
e6dK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6%4N6%4N6Q4x3X3g2K6N6$3g2W2N6s2y4U0j5i4m8W2i4K6u0W2j5$3!0E0i4K6u0r3j5$3N6A6j5X3W2F1i4K6u0r3x3o6p5H3k6h3c8A6N6r3!0J5i4K6g2X3j5$3S2W2j5$3E0Q4y4h3k6D9K9h3y4W2L8Y4y4W2i4K6g2X3z5h3u0Q4x3X3g2H3K9s2m8Q4x3@1k6@1i4K6y4p5i4K6g2n7N6X3q4D9N6h3g2Q4y4f1c8Q4x3U0k6S2L8i4m8Q4x3@1u0K6i4K6y4p5i4K6g2n7N6X3q4D9N6h3g2Q4y4f1c8Q4x3U0k6S2L8i4m8Q4x3@1u0A6k6q4)9K6c8q4)9#2b7Y4k6S2L8s2g2W2i4K6g2p5i4K6t1$3j5h3#2H3i4K6y4n7N6X3g2J5i4K6y4p5i4K6g2n7N6X3q4D9N6h3g2Q4y4f1c8Q4x3U0k6S2L8i4m8Q4x3@1u0T1K9h3c8Q4x3@1c8Q4y4f1u0$3j5h3I4#2k6g2)9#2c8l9`.`.
测试
00000045D10F48A8 0000020D5EB625B0 L"23dK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6%4N6%4N6Q4x3X3g2K6N6$3g2W2N6s2y4U0j5i4m8W2i4K6u0W2j5$3!0E0i4K6u0r3j5$3N6A6j5X3W2F1i4K6u0r3x3o6p5H3k6h3c8A6N6r3!0J5i4K6g2X3j5$3S2W2j5$3E0Q4y4h3k6D9K9h3y4W2L8Y4y4W2i4K6g2X3z5h3u0Q4x3X3g2H3K9s2m8Q4x3@1k6@1i4K6y4p5x3K6x3$3x3@1x3J5x3o6j5%4z5o6R3^5y4f1b7J5c8g2)9J5y4X3q4E0M7q4)9K6b7Y4y4#2L8g2)9K6c8o6k6o6x3@1t1^5x3e0t1J5x3@1x3^5b7K6f1^5y4e0V1^5y4U0g2r3y4f1b7^5c8e0c8p5y4U0c8r3c8f1t1I4x3e0R3&6b7@1t1$3x3e0W2m8y4@1x3^5y4@1k6p5c8W2)9J5y4X3q4E0M7q4)9K6b7X3W2V1i4K6y4p5x3q4)9J5y4X3q4E0M7q4)9K6b7X3y4Z5K9#2)9K6c8o6f1K6x3K6j5%4i4K6t1$3j5h3#2H3i4K6y4n7N6s2W2H3i4K6y4p5x3l9`.`."
图片描述
下面我们进行破解就很简单,直接改跳转
图片描述
0x00000001402B1D36将这个地址改成上面两个跳转的地址0x00000001402B1D7D
对响应进行分析

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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
__int64 __fastcall sub_7FF67E9FD990(__int64 a1, const char *a2, int a3)
{
  size_t v3; // rbx
  char *v6; // rsi
  __int64 v8; // r8
  __int64 v9; // rcx
  char v10; // al
  __int64 v11; // rax
  __int64 v12; // rcx
  bool v13; // zf
  int v14; // eax
  int v15; // eax
  __int64 v16; // rdx
  __int64 v17; // rcx
  __int64 v18; // r8
  __int64 v19; // r9
  int v20; // eax
  char String[1040]; // [rsp+30h] [rbp-438h] BYREF
 
  v3 = a3;
  v6 = j_j_j___2_YAPEAX_K_Z(a3 + 1LL);
  strncpy(v6, a2, v3);
  v6[v3] = 0;
  if ( sub_7FF67E5C5A6F(a1, v6, "ss", String, 1024) >= 0 )
  {
    v8 = 0LL;
    v9 = 0LL;
    while ( 1 )
    {
      v10 = String[v9++];
      if ( v10 != aError_1[v9 - 1] )            // 判断是不是error
        break;
      if ( v9 == 6 )
      {
        j_j_j_j_free_0(v6);
        return 0xFFFFFFFALL;
      }
    }
    v11 = 0LL;
    while ( 1 )
    {
      v12 = String[v11++];
      v13 = v12 == aInvalid[v11 - 1];           // 判断invalid  无效
      if ( v12 != aInvalid[v11 - 1] )
        break;
      if ( v11 == 8 )
      {
        v13 = v12 == aInvalid[7];
        break;
      }
    }
    LOBYTE(v8) = v13;
    *(a1 + 124) = v8;
    v14 = sub_7FF67E5C3FA3(v12, String, v8, "invalid");
    sub_7FF67E5C2860(v14);
    if ( *(a1 + 124) == 1 )
    {
      j_j_j_j_free_0(v6);
      return 0LL;
    }
    else if ( sub_7FF67E5C5A6F(a1, v6, &word_7FF67ED820A0, String, 1024) >= 0 )// 读取并验证ID字段
    {
      v15 = atoi(String);
      *(a1 + 120) = v15;
      if ( v15 )
      {
        v20 = sub_7FF67E5C3FA3(v17, v16, v18, v19);
        sub_7FF67E5C2EE6(v20);                  // 注册表写入id1690216811
        j_j_j_j_free_0(v6);
        return *(a1 + 120);                     // 返回ID
      }
      else
      {
        j_j_j_j_free_0(v6);
        return 0xFFFFFFFDLL;                    // ID0,无效
      }
    }
    else
    {
      j_j_j_j_free_0(v6);
      return 4294967292LL;
    }
  }
  else
  {
    j_j_j_j_free_0(v6);
    return 4294967289LL;
  }
}

本地做一个验证服务器

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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
import socket
import sys
import threading
 
 
def handle_client(client_socket, client_addr):
    """处理客户端连接"""
    try:
        # 接收数据
        request_data = client_socket.recv(999).decode('utf-8')
        if not request_data:
            return
 
        print(f"接收来自 {client_addr} 的数据:")
        print(request_data)
        print("-" * 50)
 
        # 检查是否包含退出指令
        if "?quit=1" in request_data:
            print("收到退出指令,服务器将关闭")
            return "quit"
 
        # 准备响应数据
        response_body = "<ss><id>33333</id></ss>"
        response_headers = [
            "HTTP/1.0 200 OK",
            "Content-type: text/html",
            f"Content-length: {len(response_body)}",
            "",
            response_body
        ]
        response = "\r\n".join(response_headers)
 
        print("发送响应数据:")
        print(response)
        print("-" * 50)
 
        # 发送响应
        client_socket.send(response.encode('utf-8'))
 
    except Exception as e:
        print(f"处理客户端 {client_addr} 时出错: {e}")
    finally:
        # 关闭连接
        try:
            client_socket.shutdown(socket.SHUT_RDWR)
        except:
            pass
        client_socket.close()
 
 
def start_http_server(host='127.0.0.1', port=80):
    """启动HTTP服务器"""
 
    # 创建socket
    try:
        server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    except socket.error as e:
        print(f"创建socket失败: {e}")
        return False
 
    # 绑定地址和端口
    try:
        server_socket.bind((host, port))
        server_socket.listen(10)
    except socket.error as e:
        print(f"绑定端口 {port} 失败: {e}")
        print("请确保有权限使用80端口,或尝试使用其他端口")
        server_socket.close()
        return False
 
    print(f"WebServer 已启动...")
    print(f"访问 http://{host}:{port}")
    print(f"退出服务器,请访问 http://{host}:{port}/?quit=1")
    print("-" * 60)
 
    try:
        while True:
            try:
                # 接受客户端连接
                client_socket, client_addr = server_socket.accept()
                print(f"新连接来自: {client_addr}")
 
                # 处理客户端请求
                result = handle_client(client_socket, client_addr)
 
                if result == "quit":
                    break
 
            except socket.error as e:
                print(f"接受连接时出错: {e}")
                continue
 
    except KeyboardInterrupt:
        print("\n收到中断信号,服务器关闭")
    except Exception as e:
        print(f"服务器运行出错: {e}")
    finally:
        server_socket.close()
        print("服务器已关闭")
 
    return True
 
 
def start_server_with_fallback():
    """尝试启动服务器,如果80端口被占用则使用备用端口"""
 
    # 尝试的端口列表
    ports_to_try = [80, 8080, 8000, 8888]
 
    for port in ports_to_try:
        print(f"尝试启动在端口 {port}...")
        if start_http_server('127.0.0.1', port):
            break
        else:
            print(f"端口 {port} 启动失败,尝试下一个端口...")
            if port == ports_to_try[-1]:
                print("所有端口尝试失败,请检查系统权限或端口占用情况")
 
 
if __name__ == "__main__":
    print("Python HTTP 服务器")
    print("=" * 60)
 
    # 检查管理员权限(在Windows上需要管理员权限才能绑定80端口)
    if sys.platform == "win32":
        try:
            # 尝试绑定80端口来检查权限
            test_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            test_socket.bind(('127.0.0.1', 80))
            test_socket.close()
            print("检测到有权限使用80端口")
            start_http_server()
        except PermissionError:
            print("没有管理员权限,无法使用80端口")
            print("将尝试使用备用端口...")
            start_server_with_fallback()
        except Exception as e:
            print(f"检测权限时出错: {e}")
            start_server_with_fallback()
    else:
        # 在Linux/macOS上,可能需要sudo权限
        start_server_with_fallback()

然后hosts文件中加上如下数据:
127.0.0.1 752K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8Y4N6%4N6#2)9J5k6i4y4%4k6h3g2@1M7$3y4S2M7r3g2Q4x3X3g2U0L8$3@1`.
经过调试
图片描述
此处发送数据包
对应v46 = sub_7FF67E5C99F3(qword_7FF67F5B8DD8, v51, &Block, &v49, 1, 0LL);// HTTP请求发送
图片描述
然后再此处写入id可对应注册表查看
图片描述
如果是 1690216811,表示成功,这个数字解码后是 0,如果是 1690236428,则表示失败,这个数字解码后是 1(这块解码没有跟进,直接照搬)
图片描述
图片描述
最后成功,也就是注册表中有这两个注册信息就可以绕过网络验证了
Solly大佬文章链接:b36K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6%4N6%4N6Q4x3X3f1#2x3Y4m8G2K9X3W2W2i4K6u0W2j5$3&6Q4x3V1k6@1K9s2u0W2j5h3c8Q4x3X3b7I4x3o6V1#2z5o6f1#2i4K6u0V1x3g2)9J5k6o6q4Q4x3X3g2Z5N6r3#2D9


传播安全知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 6
支持
分享
最新回复 (4)
雪    币: 155
活跃值: (4096)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
学习!!!
6天前
0
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
3
nb
5天前
0
雪    币: 454
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
4
Study!!!
4天前
0
雪    币: 4625
活跃值: (6189)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
5
你这名字取的 很牛马
3天前
0
游客
登录 | 注册 方可回帖
返回