本帖最后由 solly 于 2020-1-30 22:27 编辑
外面疫情严重,窝家里没事,对论坛中下手较多的 _010_Editor 进行完整和彻底的注册算法分析。通过分析和测试,其所有版本的算法是一样的(经测试,Windows 下从 v2.1.4 到 v10.0.0 的 x86 及 x64 版本是通用的,其它平台,如 MacOS 和 Linux,没有测试)。
下面以 v10.0.0 x86 版本为例进行分析。
惯例,首先看看文件信息:
是由 VS + QT5 编译而来的,没有加壳,是分析算法的良心软件。节信息如下:
没有什么不良信息,一切正常。
首先进入软件看看,启动该软件,界面如下:
这个配色,有点骚,进行注册看看(菜单 “Tools”->"Register"进入),输入注册假码数据:
点击 “Check License”,看到如下提示信息:
很良心地提示你下手的地点和方法了。
用 OD 载入软件,显示如下:
基于 QT 框架编译的标准模式,也没什么特别的地方。在 OD 中直接搜索字符串,定位 ”invalid name or password.“,如下图所示:
双击该字符串,来到引用其的代码处,如下图所示:
再在该代码指令上右键菜单,可以看到,有另一条指令跳转到这里,我们”转到“菜单,跳转到该指令,如下图所示:
可以看到,这里有3个比较,检查注册结果。上面(0x0123BA36,可能地址不一样,但应该也是 0xnnnnBA36形式,最高2字节可能不同)有一个 jmp 指令,在其下一条指令处右键”转到“,如下图所示:
可以看到,这里也是从另一指令跳转而来的,同样方法,跳转上一条指令,如下图所示:
这里又是一条比较指令(cmp edi, 0xDB),先説一下,这个0xDB是成功注册的标志。
再一次在这一条指令上右键”转到“,如下图所示:
可以看到有两个地方的指令跳转到这里了。我们先不跳转,再往上看,又有一条JMP 指令(JMP 0x0123BBD9),我们在这条指令的下面一条指令上右键”转到“,如下图所示:
可以看到,也有一条指令跳转到这里,这里跳转过去,有一条JNZ指令,如下图所示:
同样方法继续回溯,就会来到下面位置:
这里就是注册算法调用处了,如上图所示,这几行代码就是调用注册算法的:
[Asm] 纯文本查看 复制代码 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 | 016FB7D3 . 8B0D 5C80BD03 mov ecx , dword ptr [0x3BD805C]
016FB7D9 . 68 3C470000 push 0x473C
016FB7DE . 6A 0B push 0xB
016FB7E0 . E8 07F350FF call 00C0AAEC
016FB7E5 . 8B0D 5C80BD03 mov ecx , dword ptr [0x3BD805C]
016FB7EB . 8BD8 mov ebx , eax
016FB7ED . 68 3C470000 push 0x473C
016FB7F2 . 6A 0B push 0xB
016FB7F4 . E8 5FE650FF call 00C09E58
016FB7F9 . 8B0D 5C80BD03 mov ecx , dword ptr [0x3BD805C]
016FB7FF . 8BF8 mov edi , eax
016FB801 . 81FB E7000000 cmp ebx , 0xE7
016FB807 . 0F84 F3000000 je 016FB900
016FB80D . 8379 2C 00 cmp dword ptr [ ecx +0x2C], 0x0
016FB811 . 0F84 E9000000 je 016FB900
|
注意:前面説了,由于系统重定位的原因,每次运行的指令地址和数据地址的高2字节是变化的,从上面代码与截图的对比就可以看出来,因此我们只看低2字节的偏移量即可。
另外,下面的位置也调用了注册算法函数,我们前面也看过这个位置了,如下图所示:
具体调用代码如下:
[Asm] 纯文本查看 复制代码 1 2 3 4 5 6 7 8 | 016FB8E6 > \8B0D 5C80BD03 mov ecx , dword ptr [0x3BD805C]
016FB8EC . 68 3C470000 push 0x473C
016FB8F1 . 6A 0B push 0xB
016FB8F3 . E8 60E550FF call 00C09E58
016FB8F8 . 8B0D 5C80BD03 mov ecx , dword ptr [0x3BD805C]
016FB8FE . 8BF8 mov edi , eax
016FB900 > 81FF DB000000 cmp edi , 0xDB
016FB906 . 0F85 2C010000 jnz 016FBA38
|
下面我们开始跟踪其注册算法,先在这个位置下一个断点,如下图所示:
在 0xnnnnB7A7 位置下一个断点。
按 F9 运行该软件,在注册界面,输入注册码假码信息,如下图所示:
在上图中也可以看到目前的注册状态:Evaluation Version - 30 Days Left。点 ”Check License“ 按钮,OD 马上断了下来,如下图所示:
这一段代码如下所示:
[Asm] 纯文本查看 复制代码 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | 016FB7A7 . 8B0D 5C80BD03 mov ecx , dword ptr [0x3BD805C]
016FB7AD . 50 push eax
016FB7AE . C645 FC 08 mov byte ptr [ ebp -0x4], 0x8
016FB7B2 . E8 F8E450FF call 00C09CAF
016FB7B7 . 8D4D D8 lea ecx , dword ptr [ ebp -0x28]
016FB7BA . C645 FC 01 mov byte ptr [ ebp -0x4], 0x1
016FB7BE . FF15 B094BD03 call dword ptr [<&Qt5Core.QString::~QS>; 用户名字符串的引用计数减 1,为0时就释放内存
016FB7C4 . 8B0D 5C80BD03 mov ecx , dword ptr [0x3BD805C]
016FB7CA . 8D45 E8 lea eax , dword ptr [ ebp -0x18]
016FB7CD . 50 push eax
016FB7CE . E8 B07550FF call 00C02D83
016FB7D3 . 8B0D 5C80BD03 mov ecx , dword ptr [0x3BD805C]
016FB7D9 . 68 3C470000 push 0x473C
016FB7DE . 6A 0B push 0xB
016FB7E0 . E8 07F350FF call 00C0AAEC
016FB7E5 . 8B0D 5C80BD03 mov ecx , dword ptr [0x3BD805C]
016FB7EB . 8BD8 mov ebx , eax
016FB7ED . 68 3C470000 push 0x473C
016FB7F2 . 6A 0B push 0xB
016FB7F4 . E8 5FE650FF call 00C09E58
016FB7F9 . 8B0D 5C80BD03 mov ecx , dword ptr [0x3BD805C]
016FB7FF . 8BF8 mov edi , eax
016FB801 . 81FB E7000000 cmp ebx , 0xE7
016FB807 . 0F84 F3000000 je 016FB900
016FB80D . 8379 2C 00 cmp dword ptr [ ecx +0x2C], 0x0
016FB811 . 0F84 E9000000 je 016FB900
016FB817 . 6A 00 push 0x0
016FB819 . 8BCE mov ecx , esi
016FB81B . E8 BB6D50FF call 00C025DB
016FB820 . 85C0 test eax , eax
016FB822 . 0F89 8C000000 jns 016FB8B4
[/ size ][ size =4]
|
按 F8 运行到如下位置:
这个调用就是调用注册算法函数。不过,所有的 call 调用,都是调用一个 JMP 指令,通过JMP指令再跳转到相应的函数。如下图所示,就是注册算法函数,但是其开始地址并不是 call 后面的地址。
按 F7 进入注册算法函数。
该函数结尾如下图所示,有三种退出方式:
我们回到函数前面,如下图所示:
可以看到,最下面有一个调用(call 00749D0E),这是一个对注册格式进行检查的函数,先 F8 执行到该调用,再按 F7 进入调用,如下图所示:
首先检查长度,并进行内码转换,由 Unicode 码转换成 utf-8 编码。转换结果如下图OD数据区所示:
下面説一下 QT 字符串(QString)在内存中保存的格式,定义如下:
[C++] 纯文本查看 复制代码 1 2 3 4 5 6 7 | struct QString {
ULONG Reference_Count;
ULONG Length;
ULONG Capacity;
ULONG Unknow;
char Buffer[16];
};
|
从上图中 OD 的数据区可以看到,保存的注册码数据存贮格式:引用次数为 1,长度为 0x18,字符串容量为 0x19,其它属性为 0x00000010,内容为 "1111-2222-3333-4444-5555"。
下面是注册码以 Unicode 格式保存时的存贮格式:
[Asm] 纯文本查看 复制代码 1 2 3 4 5 | 06D45538 01 00 00 00 18 00 00 00 38 00 00 00 10 00 00 00 ......8......
06D45548 31 00 31 00 31 00 31 00 2D 00 32 00 32 00 32 00 1.1.1.1.-.2.2.2.
06D45558 32 00 2D 00 33 00 33 00 33 00 33 00 2D 00 34 00 2.-.3.3.3.3.-.4.
06D45568 34 00 34 00 34 00 2D 00 35 00 35 00 35 00 35 00 4.4.4.-.5.5.5.5.
06D45578 00 00 AD BA 0D F0 AD BA ...瓠?瓠?
|
函数再检查注册码的”-“号分隔符是否符合要求,并调用 call 0xnnnn984A 函数,将大写”O“,小写”o“字母转换成数字”0“,将小写”l“字母转换成数字”1“,然后将字母按 36 进制(0~9,A~Z)转换成数字。调用完成后,将这此转换后成数字组合成一个字节数组 。
从该函数返回后,就会将字符串注册码全部转换并组成一个字节数组了,如下图OD的数据区所示:
然后就从注册码字节数组(sn_int[])中取出 sn_int[3],这个字节标示的是注册类型,有3种类型,如下所示:
1、0x9C,这个是没有免费技术支持,没有免费升级的注册类型,注册码中有版本号检查,必须大于当前软件的版本,否则提示注册码过期。注册码只有4段。
2、0xAC,这个是有免费技术支持、有免费升级的完整注册类型,不过会检查注册码中的过期时间(天数,从发布时间算起),这些免费支持是有期限的,会过期。注册码有5段,是最完整的注册码。
3、0xFC,这个不算正式注册版本,是延长试用期版本,最长可延长为5年试用期(从发布日期算起),这个版本会有一些检查(注册表中的数据),保证延期合法。注册码只有4段。
具体见下图,是对 0x9C 类型的注册码进行检查:
上图中,调用函数 call 0xnnnn7351,就是解码版本数据,即解码 sn_int[0] ^ sn_int[6] 的值,这个值在 v10.0.0 版中,要大于或等于 0x0B。
注册算法函数的完整代码如下,其中加了注释:
[Asm] 纯文本查看 复制代码 001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031 032 033 034 035 036 037 038 039 040 041 042 043 044 045 046 047 048 049 050 051 052 053 054 055 056 057 058 059 060 061 062 063 064 065 066 067 068 069 070 071 072 073 074 075 076 077 078 079 080 081 082 083 084 085 086 087 088 089 090 091 092 093 094 095 096 097 098 099 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 | 01DDCC20 > \55 push ebp
01DDCC21 . 8BEC mov ebp , esp
01DDCC23 . 6A FF push -0x1
01DDCC25 . 68 898F3002 push 02308F89
01DDCC2A . 64:A1 00000000 mov eax , dword ptr fs :[0]
01DDCC30 . 50 push eax
01DDCC31 . 83EC 18 sub esp , 0x18
01DDCC34 . 53 push ebx
01DDCC35 . 56 push esi
01DDCC36 . 57 push edi
01DDCC37 . A1 E039BD03 mov eax , dword ptr [0x3BD39E0]
01DDCC3C . 33C5 xor eax , ebp
01DDCC3E . 50 push eax
01DDCC3F . 8D45 F4 lea eax , dword ptr [ ebp -0xC]
01DDCC42 . 64:A3 00000000 mov dword ptr fs :[0], eax
01DDCC48 . 8BF9 mov edi , ecx
01DDCC4A . 8D5F 04 lea ebx , dword ptr [ edi +0x4]
01DDCC4D . C745 F0 00000000 mov dword ptr [ ebp -0x10], 0x0
01DDCC54 . 8BCB mov ecx , ebx
01DDCC56 . C747 30 00000000 mov dword ptr [ edi +0x30], 0x0
01DDCC5D . C747 18 00000000 mov dword ptr [ edi +0x18], 0x0
01DDCC64 . C747 34 00000000 mov dword ptr [ edi +0x34], 0x0
01DDCC6B . FF15 C494BD03 call dword ptr [<&Qt5Core.QString::isEmpty>]
01DDCC71 . 84C0 test al , al
01DDCC73 . 0F85 75020000 jnz 01DDCEEE
01DDCC79 . 8D4F 08 lea ecx , dword ptr [ edi +0x8]
01DDCC7C . FF15 C494BD03 call dword ptr [<&Qt5Core.QString::isEmpty>]
01DDCC82 . 84C0 test al , al
01DDCC84 . 0F85 64020000 jnz 01DDCEEE
01DDCC8A . 8D45 DC lea eax , dword ptr [ ebp -0x24]
01DDCC8D . 8BCF mov ecx , edi
01DDCC8F . 50 push eax
01DDCC90 . E8 79D0E2FE call 00C09D0E
01DDCC95 . BE 74ADBC03 mov esi , 03BCAD74
01DDCC9A . 8D9B 00000000 lea ebx , dword ptr [ ebx ]
01DDCCA0 > FF36 push dword ptr [ esi ]
01DDCCA2 . 8BCB mov ecx , ebx
01DDCCA4 . FF15 A09DBD03 call dword ptr [<&Qt5Core.QString::operator==>]
01DDCCAA . 84C0 test al , al
01DDCCAC . 0F85 23020000 jnz 01DDCED5
01DDCCB2 . 83C6 04 add esi , 0x4
01DDCCB5 . 81FE 78ADBC03 cmp esi , 03BCAD78
01DDCCBB .^ 7C E3 jl short 01DDCCA0
01DDCCBD . 8A5D DF mov bl , byte ptr [ ebp -0x21]
01DDCCC0 . 8A7D E1 mov bh , byte ptr [ ebp -0x1F]
01DDCCC3 . 80FB 9C cmp bl , 0x9C
01DDCCC6 . 75 70 jnz short 01DDCD38
01DDCCC8 . 8A45 DC mov al , byte ptr [ ebp -0x24]
01DDCCCB . 3245 E2 xor al , byte ptr [ ebp -0x1E]
01DDCCCE . 8845 E8 mov byte ptr [ ebp -0x18], al
01DDCCD1 . 8A45 DD mov al , byte ptr [ ebp -0x23]
01DDCCD4 . 3245 E3 xor al , byte ptr [ ebp -0x1D]
01DDCCD7 . FF75 E8 push dword ptr [ ebp -0x18]
01DDCCDA . 0FB6C8 movzx ecx , al
01DDCCDD . B8 00010000 mov eax , 0x100
01DDCCE2 . 66:0FAFC8 imul cx , ax
01DDCCE6 . 8A45 DE mov al , byte ptr [ ebp -0x22]
01DDCCE9 . 32C7 xor al , bh
01DDCCEB . 0FB6C0 movzx eax , al
01DDCCEE . 66:03C8 add cx , ax
01DDCCF1 . 0FB7F1 movzx esi , cx
01DDCCF4 . E8 58A6E2FE call 00C07351
01DDCCF9 . 0FB6C0 movzx eax , al
01DDCCFC . 56 push esi
01DDCCFD . 8947 1C mov dword ptr [ edi +0x1C], eax
01DDCD00 . E8 A1B5E2FE call 00C082A6
01DDCD05 . 8B4F 1C mov ecx , dword ptr [ edi +0x1C]
01DDCD08 . 83C4 08 add esp , 0x8
01DDCD0B . 0FB7C0 movzx eax , ax
01DDCD0E . 8947 20 mov dword ptr [ edi +0x20], eax
01DDCD11 . 85C9 test ecx , ecx
01DDCD13 . 0F84 BC010000 je 01DDCED5
01DDCD19 . 85C0 test eax , eax
01DDCD1B . 0F84 B4010000 je 01DDCED5
01DDCD21 . 3D E8030000 cmp eax , 0x3E8
01DDCD26 . 0F87 A9010000 ja 01DDCED5
01DDCD2C . 83F9 02 cmp ecx , 0x2
01DDCD2F . 1BF6 sbb esi , esi
01DDCD31 . 23F1 and esi , ecx
01DDCD33 . E9 B3000000 jmp 01DDCDEB
01DDCD38 > 80FB FC cmp bl , 0xFC
01DDCD3B . 75 1F jnz short 01DDCD5C
01DDCD3D . C747 1C FF000000 mov dword ptr [ edi +0x1C], 0xFF
01DDCD44 . BE FF000000 mov esi , 0xFF
01DDCD49 . C747 20 01000000 mov dword ptr [ edi +0x20], 0x1
01DDCD50 . C747 30 01000000 mov dword ptr [ edi +0x30], 0x1
01DDCD57 . E9 8F000000 jmp 01DDCDEB
01DDCD5C > 80FB AC cmp bl , 0xAC
01DDCD5F . 0F85 70010000 jnz 01DDCED5
01DDCD65 . 8A45 DD mov al , byte ptr [ ebp -0x23]
01DDCD68 . 3245 E3 xor al , byte ptr [ ebp -0x1D]
01DDCD6B . 0FB6C8 movzx ecx , al
01DDCD6E . B8 00010000 mov eax , 0x100
01DDCD73 . 66:0FAFC8 imul cx , ax
01DDCD77 . 8A45 DE mov al , byte ptr [ ebp -0x22]
01DDCD7A . 32C7 xor al , bh
01DDCD7C . C747 1C 02000000 mov dword ptr [ edi +0x1C], 0x2
01DDCD83 . 0FB6C0 movzx eax , al
01DDCD86 . 66:03C8 add cx , ax
01DDCD89 . 0FB7C1 movzx eax , cx
01DDCD8C . 50 push eax
01DDCD8D . E8 14B5E2FE call 00C082A6
01DDCD92 . 0FB7C0 movzx eax , ax
01DDCD95 . 83C4 04 add esp , 0x4
01DDCD98 . 8947 20 mov dword ptr [ edi +0x20], eax
01DDCD9B . 85C0 test eax , eax
01DDCD9D . 0F84 32010000 je 01DDCED5
01DDCDA3 . 3D E8030000 cmp eax , 0x3E8
01DDCDA8 . 0F87 27010000 ja 01DDCED5
01DDCDAE . 0FB655 E5 movzx edx , byte ptr [ ebp -0x1B]
01DDCDB2 . 0FB64D E0 movzx ecx , byte ptr [ ebp -0x20]
01DDCDB6 . 0FB6C7 movzx eax , bh
01DDCDB9 . 33D0 xor edx , eax
01DDCDBB . 0FB645 E4 movzx eax , byte ptr [ ebp -0x1C]
01DDCDBF . 33C8 xor ecx , eax
01DDCDC1 . C1E2 08 shl edx , 0x8
01DDCDC4 . 0FB645 E2 movzx eax , byte ptr [ ebp -0x1E]
01DDCDC8 . 03D1 add edx , ecx
01DDCDCA . 0FB64D DC movzx ecx , byte ptr [ ebp -0x24]
01DDCDCE . C1E2 08 shl edx , 0x8
01DDCDD1 . 33C8 xor ecx , eax
01DDCDD3 . 03D1 add edx , ecx
01DDCDD5 . 68 278C5B00 push 0x5B8C27
01DDCDDA . 52 push edx
01DDCDDB . E8 71DCE2FE call 00C0AA51
01DDCDE0 . 83C4 08 add esp , 0x8
01DDCDE3 . 8945 F0 mov dword ptr [ ebp -0x10], eax
01DDCDE6 . 8947 34 mov dword ptr [ edi +0x34], eax
01DDCDE9 . 8BF0 mov esi , eax
01DDCDEB > 8D45 EC lea eax , dword ptr [ ebp -0x14]
01DDCDEE . 50 push eax
01DDCDEF . 8D4F 04 lea ecx , dword ptr [ edi +0x4]
01DDCDF2 . FF15 1C9CBD03 call dword ptr [<&Qt5Core.QString::toUtf8>]
01DDCDF8 . FF77 20 push dword ptr [ edi +0x20]
01DDCDFB . 33C0 xor eax , eax
01DDCDFD . C745 FC 00000000 mov dword ptr [ ebp -0x4], 0x0
01DDCE04 . 80FB FC cmp bl , 0xFC
01DDCE07 . 8D4D EC lea ecx , dword ptr [ ebp -0x14]
01DDCE0A . 56 push esi
01DDCE0B . 0F95C0 setne al
01DDCE0E . 50 push eax
01DDCE0F . FF15 9C94BD03 call dword ptr [<&Qt5Core.QByteArray::data>]
01DDCE15 . 50 push eax
01DDCE16 . E8 D263E2FE call 00C031ED
01DDCE1B . 8BD0 mov edx , eax
01DDCE1D . 83C4 10 add esp , 0x10
01DDCE20 . 3855 E0 cmp byte ptr [ ebp -0x20], dl
01DDCE23 . 0F85 81000000 jnz 01DDCEAA
01DDCE29 . 8BCA mov ecx , edx
01DDCE2B . C1E9 08 shr ecx , 0x8
01DDCE2E . 3AF9 cmp bh , cl
01DDCE30 . 75 78 jnz short 01DDCEAA
01DDCE32 . 8BCA mov ecx , edx
01DDCE34 . C1E9 10 shr ecx , 0x10
01DDCE37 . 384D E2 cmp byte ptr [ ebp -0x1E], cl
01DDCE3A . 75 6E jnz short 01DDCEAA
01DDCE3C . C1E8 18 shr eax , 0x18
01DDCE3F . 3845 E3 cmp byte ptr [ ebp -0x1D], al
01DDCE42 . 75 66 jnz short 01DDCEAA
01DDCE44 . 80FB 9C cmp bl , 0x9C
01DDCE47 . 75 0F jnz short 01DDCE58
01DDCE49 . 8B45 08 mov eax , dword ptr [ ebp +0x8]
01DDCE4C . 3B47 1C cmp eax , dword ptr [ edi +0x1C]
01DDCE4F . 76 52 jbe short 01DDCEA3
01DDCE51 . BE 4E000000 mov esi , 0x4E
01DDCE56 . EB 57 jmp short 01DDCEAF
01DDCE58 > 80FB FC cmp bl , 0xFC
01DDCE5B . 75 2E jnz short 01DDCE8B
01DDCE5D . 0FB64D DE movzx ecx , byte ptr [ ebp -0x22]
01DDCE61 . 0FB645 DD movzx eax , byte ptr [ ebp -0x23]
01DDCE65 . C1E1 08 shl ecx , 0x8
01DDCE68 . 03C8 add ecx , eax
01DDCE6A . 0FB645 DC movzx eax , byte ptr [ ebp -0x24]
01DDCE6E . C1E1 08 shl ecx , 0x8
01DDCE71 . 52 push edx
01DDCE72 . 03C8 add ecx , eax
01DDCE74 . 51 push ecx
01DDCE75 . E8 D7DBE2FE call 00C0AA51
01DDCE7A . 83C4 08 add esp , 0x8
01DDCE7D . 85C0 test eax , eax
01DDCE7F . 74 29 je short 01DDCEAA
01DDCE81 . 8947 18 mov dword ptr [ edi +0x18], eax
01DDCE84 . BE 93000000 mov esi , 0x93
01DDCE89 . EB 24 jmp short 01DDCEAF
01DDCE8B > 80FB AC cmp bl , 0xAC
01DDCE8E . 75 1A jnz short 01DDCEAA
01DDCE90 . 8B45 F0 mov eax , dword ptr [ ebp -0x10]
01DDCE93 . 85C0 test eax , eax
01DDCE95 . 74 13 je short 01DDCEAA
01DDCE97 . 3945 0C cmp dword ptr [ ebp +0xC], eax
01DDCE9A . 76 07 jbe short 01DDCEA3
01DDCE9C . BE 4E000000 mov esi , 0x4E
01DDCEA1 . EB 0C jmp short 01DDCEAF
01DDCEA3 > BE 2D000000 mov esi , 0x2D
01DDCEA8 . EB 05 jmp short 01DDCEAF
01DDCEAA > BE E7000000 mov esi , 0xE7
01DDCEAF > 8D4D EC lea ecx , dword ptr [ ebp -0x14]
01DDCEB2 . C745 FC FFFFFFFF mov dword ptr [ ebp -0x4], -0x1
01DDCEB9 . FF15 8C94BD03 call dword ptr [<&Qt5Core.QByteArray::~QByteArray>]
01DDCEBF . 8BC6 mov eax , esi
01DDCEC1 . 8B4D F4 mov ecx , dword ptr [ ebp -0xC]
01DDCEC4 . 64:890D 00000000 mov dword ptr fs :[0], ecx
01DDCECB . 59 pop ecx
01DDCECC . 5F pop edi
01DDCECD . 5E pop esi
01DDCECE . 5B pop ebx
01DDCECF . 8BE5 mov esp , ebp
01DDCED1 . 5D pop ebp
01DDCED2 . C2 0800 retn 0x8
01DDCED5 > B8 E7000000 mov eax , 0xE7
01DDCEDA . 8B4D F4 mov ecx , dword ptr [ ebp -0xC]
01DDCEDD . 64:890D 00000000 mov dword ptr fs :[0], ecx
01DDCEE4 . 59 pop ecx
01DDCEE5 . 5F pop edi
01DDCEE6 . 5E pop esi
01DDCEE7 . 5B pop ebx
01DDCEE8 . 8BE5 mov esp , ebp
01DDCEEA . 5D pop ebp
01DDCEEB . C2 0800 retn 0x8
01DDCEEE > B8 93000000 mov eax , 0x93
01DDCEF3 . 8B4D F4 mov ecx , dword ptr [ ebp -0xC]
01DDCEF6 . 64:890D 00000000 mov dword ptr fs :[0], ecx
01DDCEFD . 59 pop ecx
01DDCEFE . 5F pop edi
01DDCEFF . 5E pop esi
01DDCF00 . 5B pop ebx
01DDCF01 . 8BE5 mov esp , ebp
01DDCF03 . 5D pop ebp
01DDCF04 . C2 0800 retn 0x8
|
从上面函数返回后,我们马上再进入另一个函数(call 0xnnnn9E58),这个函数还会再次调用上面的注册算法函数,同时还会调另一个函数,对试用期延长的注册码进行检查,如下图所示:
从上图可以看,首先再次调用注册码检查函数(0xnnnnD55E call 0xnnnnAAEC),然后再调用另一个函数(call 0xnnnn2CE8),这个函数对 0xFC 类型的注册码进行进一步的合法性检查。下面我们"F7"再次进入注册码算法函数,看看函数内其它几个调用,如下所示:
[Asm] 纯文本查看 复制代码 01 02 03 04 05 06 07 08 09 10 11 12 | 01DDCDF8 . FF77 20 push dword ptr [ edi +0x20]
01DDCDFB . 33C0 xor eax , eax
01DDCDFD . C745 FC 00000000 mov dword ptr [ ebp -0x4], 0x0
01DDCE04 . 80FB FC cmp bl , 0xFC
01DDCE07 . 8D4D EC lea ecx , dword ptr [ ebp -0x14]
01DDCE0A . 56 push esi
01DDCE0B . 0F95C0 setne al
01DDCE0E . 50 push eax
01DDCE0F . FF15 9C94BD03 call dword ptr [<&Qt5Core.QByteArray::data>]
01DDCE15 . 50 push eax
01DDCE16 . E8 D263E2FE call 00C031ED
01DDCE1B . 8BD0 mov edx , eax
|
注册算法函数调用了一个函数(call 0xnnnn31ED),对用户名进行处理,该函数如下图所示:
通过查表方式,对用户名进行变换,生成一个32位的整数,如下图所示:
循环对名字每个字符进行处理,如下图所示:
用户名处理函数具体代码如下:
[Asm] 纯文本查看 复制代码 01 02 03 04 05 06 07 08 09 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 | 01DDC180 /> \55 push ebp
01DDC181 |. 8BEC mov ebp , esp
01DDC183 |. 83EC 10 sub esp , 0x10
01DDC186 |. 8B55 08 mov edx , dword ptr [ ebp +0x8]
01DDC189 |. 33C9 xor ecx , ecx
01DDC18B |. 56 push esi
01DDC18C |. 8BF2 mov esi , edx
01DDC18E |. 894D FC mov dword ptr [ ebp -0x4], ecx
01DDC191 |. 57 push edi
01DDC192 |. 8D7E 01 lea edi , dword ptr [ esi +0x1]
01DDC195 |> 8A06 / mov al , byte ptr [ esi ]
01DDC197 |. 46 | inc esi
01DDC198 |. 84C0 | test al , al
01DDC19A |.^ 75 F9 \ jnz short 01DDC195
01DDC19C |. 2BF7 sub esi , edi
01DDC19E |. 33FF xor edi , edi
01DDC1A0 |. 85F6 test esi , esi
01DDC1A2 |. 0F8E F0000000 jle 01DDC298
01DDC1A8 |. 53 push ebx
01DDC1A9 |. 8B5D 14 mov ebx , dword ptr [ ebp +0x14]
01DDC1AC |. 894D F0 mov dword ptr [ ebp -0x10], ecx
01DDC1AF |. 894D F4 mov dword ptr [ ebp -0xC], ecx
01DDC1B2 |. 8B4D 10 mov ecx , dword ptr [ ebp +0x10]
01DDC1B5 |. C1E3 04 shl ebx , 0x4
01DDC1B8 |. 2B5D 14 sub ebx , dword ptr [ ebp +0x14]
01DDC1BB |. C1E1 04 shl ecx , 0x4
01DDC1BE |. 034D 10 add ecx , dword ptr [ ebp +0x10]
01DDC1C1 |. 894D F8 mov dword ptr [ ebp -0x8], ecx
01DDC1C4 |> 0FB60417 / movzx eax , byte ptr [ edi + edx ]
01DDC1C8 |. 50 | push eax
01DDC1C9 |. FF15 B092BD03 | call dword ptr [<&MSVCR120.toupper>]
01DDC1CF |. 8BD0 | mov edx , eax
01DDC1D1 |. 83C4 04 | add esp , 0x4
01DDC1D4 |. 8B0C95 A8A8BC03 | mov ecx , dword ptr [ edx *4+0x3BCA8A8]
01DDC1DB |. 034D FC | add ecx , dword ptr [ ebp -0x4]
01DDC1DE |. 837D 0C 00 | cmp dword ptr [ ebp +0xC], 0x0
01DDC1E2 |. 74 4A | je short 01DDC22E
01DDC1E4 |. 8D42 0D | lea eax , dword ptr [ edx +0xD]
01DDC1E7 |. 25 FF000000 | and eax , 0xFF
01DDC1EC |. 330C85 A8A8BC03 | xor ecx , dword ptr [ eax *4+0x3BCA8A8]
01DDC1F3 |. 8D42 2F | lea eax , dword ptr [ edx +0x2F]
01DDC1F6 |. 25 FF000000 | and eax , 0xFF
01DDC1FB |. 0FAF0C85 A8A8BC03 | imul ecx , dword ptr [ eax *4+0x3BCA8A8]
01DDC203 |. 8B45 F8 | mov eax , dword ptr [ ebp -0x8]
01DDC206 |. 0FB6C0 | movzx eax , al
01DDC209 |. 030C85 A8A8BC03 | add ecx , dword ptr [ eax *4+0x3BCA8A8]
01DDC210 |. 0FB6C3 | movzx eax , bl
01DDC213 |. 030C85 A8A8BC03 | add ecx , dword ptr [ eax *4+0x3BCA8A8]
01DDC21A |. 8B45 F4 | mov eax , dword ptr [ ebp -0xC]
01DDC21D |. 0FB6C0 | movzx eax , al
01DDC220 |. 030C85 A8A8BC03 | add ecx , dword ptr [ eax *4+0x3BCA8A8]
01DDC227 |. 8BC1 | mov eax , ecx
01DDC229 |. 8945 FC | mov dword ptr [ ebp -0x4], eax
01DDC22C |. EB 48 | jmp short 01DDC276
01DDC22E |> 8D42 3F | lea eax , dword ptr [ edx +0x3F]
01DDC231 |. 25 FF000000 | and eax , 0xFF
01DDC236 |. 330C85 A8A8BC03 | xor ecx , dword ptr [ eax *4+0x3BCA8A8]
01DDC23D |. 8D42 17 | lea eax , dword ptr [ edx +0x17]
01DDC240 |. 25 FF000000 | and eax , 0xFF
01DDC245 |. 0FAF0C85 A8A8BC03 | imul ecx , dword ptr [ eax *4+0x3BCA8A8]
01DDC24D |. 8B45 F8 | mov eax , dword ptr [ ebp -0x8]
01DDC250 |. 0FB6C0 | movzx eax , al
01DDC253 |. 030C85 A8A8BC03 | add ecx , dword ptr [ eax *4+0x3BCA8A8]
01DDC25A |. 0FB6C3 | movzx eax , bl
01DDC25D |. 030C85 A8A8BC03 | add ecx , dword ptr [ eax *4+0x3BCA8A8]
01DDC264 |. 8B45 F0 | mov eax , dword ptr [ ebp -0x10]
01DDC267 |. 0FB6C0 | movzx eax , al
01DDC26A |. 030C85 A8A8BC03 | add ecx , dword ptr [ eax *4+0x3BCA8A8]
01DDC271 |. 8BC1 | mov eax , ecx
01DDC273 |. 894D FC | mov dword ptr [ ebp -0x4], ecx
01DDC276 |> 8345 F4 13 | add dword ptr [ ebp -0xC], 0x13
01DDC27A |. 47 | inc edi
01DDC27B |. 8345 F8 09 | add dword ptr [ ebp -0x8], 0x9
01DDC27F |. 83C3 0D | add ebx , 0xD
01DDC282 |. 8345 F0 07 | add dword ptr [ ebp -0x10], 0x7
01DDC286 |. 8B55 08 | mov edx , dword ptr [ ebp +0x8]
01DDC289 |. 3BFE | cmp edi , esi
01DDC28B |.^ 0F8C 33FFFFFF \ jl 01DDC1C4
01DDC291 |. 5B pop ebx
01DDC292 |. 5F pop edi
01DDC293 |. 5E pop esi
01DDC294 |. 8BE5 mov esp , ebp
01DDC296 |. 5D pop ebp
01DDC297 |. C3 retn
01DDC298 |> 5F pop edi
01DDC299 |. 8BC1 mov eax , ecx
01DDC29B |. 5E pop esi
01DDC29C |. 8BE5 mov esp , ebp
01DDC29E |. 5D pop ebp
01DDC29F \. C3 retn
|
另外,当注册类型为 0xFC 时,会读取注册表中的数据进行检查,如下图所示的几个注册表键值:
不过数据都是编码加密过的,需要解码才能识别,包括试用剩余次数(0x09),版本标识(0x0B),发布(或安装)日期,有效可用日期(试用期或正式版免费支持时间)等等数据。试用版有效时长检查调用(call 0xnnnn2CE8)的代码如下:
[Asm] 纯文本查看 复制代码 001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031 032 033 034 035 036 037 038 039 040 041 042 043 044 045 046 047 048 049 050 051 052 053 054 055 056 057 058 059 060 061 062 063 064 065 066 067 068 069 070 071 072 073 074 075 076 077 078 079 080 081 082 083 084 085 086 087 088 089 090 091 092 093 094 095 096 097 098 099 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 | 01DDC720 > \55 push ebp
01DDC721 . 8BEC mov ebp , esp
01DDC723 . 6A FF push -0x1
01DDC725 . 68 E98E3002 push 02308EE9
01DDC72A . 64:A1 00000000 mov eax , dword ptr fs :[0]
01DDC730 . 50 push eax
01DDC731 . 51 push ecx
01DDC732 . 57 push edi
01DDC733 . A1 E039BD03 mov eax , dword ptr [0x3BD39E0]
01DDC738 . 33C5 xor eax , ebp
01DDC73A . 50 push eax
01DDC73B . 8D45 F4 lea eax , dword ptr [ ebp -0xC]
01DDC73E . 64:A3 00000000 mov dword ptr fs :[0], eax
01DDC744 . 8BF9 mov edi , ecx
01DDC746 . FF75 08 push dword ptr [ ebp +0x8]
01DDC749 . E8 DDEAE2FE call 00C0B22B
01DDC74E . FF75 08 push dword ptr [ ebp +0x8]
01DDC751 . 8BCF mov ecx , edi
01DDC753 . E8 71B1E2FE call 00C078C9
01DDC758 . 8BCF mov ecx , edi
01DDC75A . E8 3262E2FE call 00C02991
01DDC75F . 8D45 F0 lea eax , dword ptr [ ebp -0x10]
01DDC762 . 50 push eax
01DDC763 . E8 AFC2E2FE call 00C08A17
01DDC768 . 8BC8 mov ecx , eax
01DDC76A . E8 1EF2E2FE call 00C0B98D
01DDC76F . 84C0 test al , al
01DDC771 . 74 08 je short 01DDC77B
01DDC773 . 8B45 F0 mov eax , dword ptr [ ebp -0x10]
01DDC776 . 8947 10 mov dword ptr [ edi +0x10], eax
01DDC779 . EB 17 jmp short 01DDC792
01DDC77B > E8 20BCE2FE call 00C083A0
01DDC780 . 6A 01 push 0x1
01DDC782 . 50 push eax
01DDC783 . 8947 10 mov dword ptr [ edi +0x10], eax
01DDC786 . E8 8CC2E2FE call 00C08A17
01DDC78B . 8BC8 mov ecx , eax
01DDC78D . E8 81DAE2FE call 00C0A213
01DDC792 > 837F 18 00 cmp dword ptr [ edi +0x18], 0x0
01DDC796 . 76 0D jbe short 01DDC7A5
01DDC798 . 837F 30 00 cmp dword ptr [ edi +0x30], 0x0
01DDC79C . 74 07 je short 01DDC7A5
01DDC79E . 8BCF mov ecx , edi
01DDC7A0 . E8 04BDE2FE call 00C084A9
01DDC7A5 > 8B4F 10 mov ecx , dword ptr [ edi +0x10]
01DDC7A8 . 8D45 F0 lea eax , dword ptr [ ebp -0x10]
01DDC7AB . 83C1 1E add ecx , 0x1E
01DDC7AE . 394F 18 cmp dword ptr [ edi +0x18], ecx
01DDC7B1 . 50 push eax
01DDC7B2 . 0F434F 18 cmovnb ecx , dword ptr [ edi +0x18]
01DDC7B6 . 894F 18 mov dword ptr [ edi +0x18], ecx
01DDC7B9 . E8 59C2E2FE call 00C08A17
01DDC7BE . 8BC8 mov ecx , eax
01DDC7C0 . E8 F09CE2FE call 00C064B5
01DDC7C5 . 84C0 test al , al
01DDC7C7 . 0F84 8F000000 je 01DDC85C
01DDC7CD . 8B45 F0 mov eax , dword ptr [ ebp -0x10]
01DDC7D0 . 8947 14 mov dword ptr [ edi +0x14], eax
01DDC7D3 . 3B47 18 cmp eax , dword ptr [ edi +0x18]
01DDC7D6 . 0F83 95000000 jnb 01DDC871
01DDC7DC . E8 BFBBE2FE call 00C083A0
01DDC7E1 . 8B4F 14 mov ecx , dword ptr [ edi +0x14]
01DDC7E4 . 8BD0 mov edx , eax
01DDC7E6 . 3BD1 cmp edx , ecx
01DDC7E8 . 73 17 jnb short 01DDC801
01DDC7EA . B8 38010000 mov eax , 0x138
01DDC7EF . 8B4D F4 mov ecx , dword ptr [ ebp -0xC]
01DDC7F2 . 64:890D 00000000 mov dword ptr fs :[0], ecx
01DDC7F9 . 59 pop ecx
01DDC7FA . 5F pop edi
01DDC7FB . 8BE5 mov esp , ebp
01DDC7FD . 5D pop ebp
01DDC7FE . C2 0400 retn 0x4
01DDC801 > 8B47 10 mov eax , dword ptr [ edi +0x10]
01DDC804 . 85C0 test eax , eax
01DDC806 . 74 1E je short 01DDC826
01DDC808 . 85C9 test ecx , ecx
01DDC80A . 74 1A je short 01DDC826
01DDC80C . 3BC8 cmp ecx , eax
01DDC80E . 72 16 jb short 01DDC826
01DDC810 . 8B47 18 mov eax , dword ptr [ edi +0x18]
01DDC813 . 2BC1 sub eax , ecx
01DDC815 . 3D 21070000 cmp eax , 0x721
01DDC81A . 77 0A ja short 01DDC826
01DDC81C . 3BCA cmp ecx , edx
01DDC81E . 73 51 jnb short 01DDC871
01DDC820 . 8957 14 mov dword ptr [ edi +0x14], edx
01DDC823 . 52 push edx
01DDC824 . EB 3F jmp short 01DDC865
01DDC826 > 68 38D16A03 push 036AD138
01DDC82B . 8D4D 08 lea ecx , dword ptr [ ebp +0x8]
01DDC82E . FF15 AC9DBD03 call dword ptr [<&Qt5Core.QString::QString>]
01DDC834 . 8D45 08 lea eax , dword ptr [ ebp +0x8]
01DDC837 . C745 FC 00000000 mov dword ptr [ ebp -0x4], 0x0
01DDC83E . 50 push eax
01DDC83F . E8 7151E2FE call 00C019B5
01DDC844 . 83C4 04 add esp , 0x4
01DDC847 . C745 FC FFFFFFFF mov dword ptr [ ebp -0x4], -0x1
01DDC84E . 8D4D 08 lea ecx , dword ptr [ ebp +0x8]
01DDC851 . FF15 B094BD03 call dword ptr [<&Qt5Core.QString::~QString>]
01DDC857 . 8B47 18 mov eax , dword ptr [ edi +0x18]
01DDC85A . EB 05 jmp short 01DDC861
01DDC85C > E8 3FBBE2FE call 00C083A0
01DDC861 > 50 push eax
01DDC862 . 8947 14 mov dword ptr [ edi +0x14], eax
01DDC865 > E8 ADC1E2FE call 00C08A17
01DDC86A . 8BC8 mov ecx , eax
01DDC86C . E8 0D00E3FE call 00C0C87E
01DDC871 > 8B47 14 mov eax , dword ptr [ edi +0x14]
01DDC874 . 3B47 18 cmp eax , dword ptr [ edi +0x18]
01DDC877 . 1BC0 sbb eax , eax
01DDC879 . 83E0 ED and eax , 0xFFFFFFED
01DDC87C . 83C0 2A add eax , 0x2A
01DDC87F . 8B4D F4 mov ecx , dword ptr [ ebp -0xC]
01DDC882 . 64:890D 00000000 mov dword ptr fs :[0], ecx
01DDC889 . 59 pop ecx
01DDC88A . 5F pop edi
01DDC88B . 8BE5 mov esp , ebp
01DDC88D . 5D pop ebp
01DDC88E . C2 0400 retn 0x4
|
上面説的调用注册算法函数和试用期检查函数的函数代码如下:
[Asm] 纯文本查看 复制代码 01 02 03 04 05 06 07 08 09 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 | 01DDD540 /> \55 push ebp
01DDD541 |. 8BEC mov ebp , esp
01DDD543 |. 56 push esi
01DDD544 |. 8BF1 mov esi , ecx
01DDD546 |. 837E 2C 00 cmp dword ptr [ esi +0x2C], 0x0
01DDD54A |. 74 0A je short 01DDD556
01DDD54C |. B8 13010000 mov eax , 0x113
01DDD551 |. 5E pop esi
01DDD552 |. 5D pop ebp
01DDD553 |. C2 0800 retn 0x8
01DDD556 |> 57 push edi
01DDD557 |. FF75 0C push dword ptr [ ebp +0xC]
01DDD55A |. 8B7D 08 mov edi , dword ptr [ ebp +0x8]
01DDD55D |. 57 push edi
01DDD55E |. E8 89D5E2FE call 00C0AAEC
01DDD563 |. 83F8 2D cmp eax , 0x2D
01DDD566 |. 0F84 A3000000 je 01DDD60F
01DDD56C |. 83F8 4E cmp eax , 0x4E
01DDD56F |. 74 78 je short 01DDD5E9
01DDD571 |. 3D E7000000 cmp eax , 0xE7
01DDD576 |. 74 66 je short 01DDD5DE
01DDD578 |. 57 push edi
01DDD579 |. 8BCE mov ecx , esi
01DDD57B |. E8 6857E2FE call 00C02CE8
01DDD580 |. 83F8 17 cmp eax , 0x17
01DDD583 |. 74 4E je short 01DDD5D3
01DDD585 |. 83F8 2A cmp eax , 0x2A
01DDD588 |. 74 28 je short 01DDD5B2
01DDD58A |. 3D 38010000 cmp eax , 0x138
01DDD58F |. 75 4D jnz short 01DDD5DE
01DDD591 |. 8BCE mov ecx , esi
01DDD593 |. E8 FBCEE2FE call 00C0A493
01DDD598 |. 3D A3010000 cmp eax , 0x1A3
01DDD59D |. B9 2F000000 mov ecx , 0x2F
01DDD5A2 |. BA F9000000 mov edx , 0xF9
01DDD5A7 |. 0F44CA cmove ecx , edx
01DDD5AA |. 5F pop edi
01DDD5AB |. 8BC1 mov eax , ecx
01DDD5AD |. 5E pop esi
01DDD5AE |. 5D pop ebp
01DDD5AF |. C2 0800 retn 0x8
01DDD5B2 |> 8BCE mov ecx , esi
01DDD5B4 |. E8 DACEE2FE call 00C0A493
01DDD5B9 |. 3D A3010000 cmp eax , 0x1A3
01DDD5BE |. B9 77010000 mov ecx , 0x177
01DDD5C3 |. BA F9000000 mov edx , 0xF9
01DDD5C8 |. 0F44CA cmove ecx , edx
01DDD5CB |. 5F pop edi
01DDD5CC |. 8BC1 mov eax , ecx
01DDD5CE |. 5E pop esi
01DDD5CF |. 5D pop ebp
01DDD5D0 |. C2 0800 retn 0x8
01DDD5D3 |> 5F pop edi
01DDD5D4 |. B8 71000000 mov eax , 0x71
01DDD5D9 |. 5E pop esi
01DDD5DA |. 5D pop ebp
01DDD5DB |. C2 0800 retn 0x8
01DDD5DE |> 5F pop edi
01DDD5DF |. B8 77010000 mov eax , 0x177
01DDD5E4 |. 5E pop esi
01DDD5E5 |. 5D pop ebp
01DDD5E6 |. C2 0800 retn 0x8
01DDD5E9 |> 57 push edi
01DDD5EA |. 8BCE mov ecx , esi
01DDD5EC |. E8 F756E2FE call 00C02CE8
01DDD5F1 |. 83F8 17 cmp eax , 0x17
01DDD5F4 |. 74 0E je short 01DDD604
01DDD5F6 |. 5F pop edi
01DDD5F7 |. 83F8 2A cmp eax , 0x2A
01DDD5FA |. B8 ED000000 mov eax , 0xED
01DDD5FF |. 5E pop esi
01DDD600 |. 5D pop ebp
01DDD601 |. C2 0800 retn 0x8
01DDD604 |> 5F pop edi
01DDD605 |. B8 0C020000 mov eax , 0x20C
01DDD60A |. 5E pop esi
01DDD60B |. 5D pop ebp
01DDD60C |. C2 0800 retn 0x8
01DDD60F |> 5F pop edi
01DDD610 |. B8 DB000000 mov eax , 0xDB
01DDD615 |. 5E pop esi
01DDD616 |. 5D pop ebp
01DDD617 \. C2 0800 retn 0x8
|
当试用周期过期,就会要求注册,如下图所示:
我们输入一个延长试用期的注册码,注册码类型:0xFC,如下图所示:
点 ”Check License“,如果正确,则提示如上图所示,下图的 "About" 中,会显示延长了多少天数,如下图所示,延长了 1825 天(从 2019/12/06 开始计算,所以还剩 1772 天的试用期)。
如果要换一注册类型,先要移除原有注册码,如下图所示:
在注册界面,点 ”Remove my license from this machine“,再次确认”Remove“就可以了。
下面是输入 0x9C 类型的注册码,可以看到,没有任何免费支持和升级,一开始就显示免费支持过期(1970/1/2过期)了:
下面是输入 0xAC 类型的注册码,这个是有免费支持和升级的,我设置的过期日期为:2048-10-24,即20481024,程序员喜欢的数字!!!
提示框会显示什么时候过期:十月 24,2048。注册界面上也会显示,如下图所示:
上面都是单用户的注册授权,下面来一个多用户的:999用户。
还有一种不限用户数的:Site License。如下图所示:
在v10.0.0 x64 位的版本上,也可以通过(界面与x86版一样,不截图了)。
下面看看老版本是否可用,在 Windows 7 下的 v3.2.2 版没有问题:
在 Windows 98 下的 v2.1.4 也没有问题:
经过几个版本测试,表示其注册码算法没有改变过。0x9C 类型因为版本标识检查会过期(当然可以在SN中预设一个很大的版本号),不一定适于新版本。 但 0xAC 注册类型是可能通用各版本的。
另外,除了30天试用期,还有一种对使用次数进行限制的试用,可使用次数保存在注册表中。如下图所示,还有9次可用:
以上就是该软件的注册分析,下面放出其注册机源码,可以生成以上3种类型(0x9C, 0xAC, 0xFC)的注册码,也可以更改注册用户数(1-single user license, 2~999-multiply user license, 1000-site license)。源码通过 dev-c++ 调试通过,代码如下:
[C++] 纯文本查看 复制代码 001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031 032 033 034 035 036 037 038 039 040 041 042 043 044 045 046 047 048 049 050 051 052 053 054 055 056 057 058 059 060 061 062 063 064 065 066 067 068 069 070 071 072 073 074 075 076 077 078 079 080 081 082 083 084 085 086 087 088 089 090 091 092 093 094 095 096 097 098 099 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 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 | #include <iostream>
#include <string.h>
#include "name_tables.h"
typedef unsigned char UCHAR ;
typedef unsigned short UWORD;
typedef unsigned long ULONG ;
typedef unsigned int UINT32 ;
typedef unsigned long long UINT64 ;
ULONG RLSDATE = 0x473C;
ULONG VERID = 0x0B;
ULONG FREE_UPGRADE_DAYS = 10549;
ULONG MAX_VERSION_ID = VERID + (FREE_UPGRADE_DAYS/365);
int char36ToInt( char ch);
int stringToBytes( char * str, char * bytes);
int checkName( char * name);
ULONG getUncheck3( ULONG base, ULONG rlsdate);
ULONG calcSN_Date();
ULONG reverseSN_Date( ULONG sn_date);
UCHAR getUncheck1( char ch);
UWORD getUncheck2( ULONG ul);
ULONG getCheck3( ULONG sn_date, ULONG base);
ULONG getNameCheck( char * name, ULONG is_registed, ULONG free_days, ULONG user_count);
int getDays( int base, int year2, int month2, int day2);
int getDate( int days, int * year, int * month, int * day);
ULONG decodeVersionID( ULONG encVerId);
ULONG decodeBeginDays( ULONG encDays);
ULONG decodeEndDays( ULONG encDays);
ULONG decodeUsesLeft( ULONG encUsesLeft);
ULONG encodeEndDays( ULONG days);
ULONG encodeUsesLeft( ULONG usesLeft);
#define RESULT0 0x93
#define RESULT1 0xE7
char * name_list[] = { "999" , NULL};
UCHAR sn_int[] = {0x11, 0x11, 0x22, 0x22, 0x33, 0x33, 0x44, 0x44, 0x55, 0x55};
int main( int argc, char ** argv) {
char name[] = "solly" ;
ULONG license_type = 0xAC;
ULONG license_user_count = 1000;
ULONG license_register_type = 1;
ULONG license_free_upgrage_end_of_date = 0;
int black = checkName(name);
if (black == RESULT1) {
printf ( "Your name is in the black names list.\n" );
return 0;
}
if (license_type == 0xAC) {
license_free_upgrage_end_of_date = RLSDATE + FREE_UPGRADE_DAYS;
printf ( "EndOf Date = 0x%08X\n" , license_free_upgrage_end_of_date);
}
if (license_type == 0xFC) {
license_register_type = 0;
license_user_count = 1;
license_free_upgrage_end_of_date = 0xFF;
FREE_UPGRADE_DAYS = 1825;
}
sn_int[3] = ( UCHAR )license_type;
int name_check = getNameCheck(name, license_register_type, license_free_upgrage_end_of_date, license_user_count);
printf ( "name_check = 0x%08X\n" , name_check);
sn_int[4] = ( UCHAR )(name_check );
sn_int[5] = ( UCHAR )(name_check>>8 );
sn_int[6] = ( UCHAR )(name_check>>16);
sn_int[7] = ( UCHAR )(name_check>>24);
if (license_type == 0xFC) {
int eval_days_check = getUncheck3(name_check, RLSDATE);
printf ( "evaluation_days_encoded = 0x%08X\n" , eval_days_check);
sn_int[0] = ( UCHAR )(eval_days_check );
sn_int[1] = ( UCHAR )(eval_days_check>>8 );
sn_int[2] = ( UCHAR )(eval_days_check>>16);
int eval_days = getCheck3(name_check, eval_days_check);
printf ( "evaluation extends days = 0x%08X\n" , eval_days);
} else {
int user_count = getUncheck2(license_user_count);
printf ( "user_count = 0x%08X\n" , user_count);
sn_int[1] = ( UCHAR )(user_count>>8) ^ sn_int[7];
sn_int[2] = ( UCHAR )user_count ^ sn_int[5];
if (license_type == 0xAC) {
ULONG sn_date = getUncheck3(0x005B8C27, RLSDATE);
sn_date &= 0x00FFFFFF;
printf ( "days_in_sn = 0x%08X\n" , sn_date);
sn_int[0] = ( UCHAR )(sn_date ) ^ sn_int[6];
sn_int[8] = ( UCHAR )(sn_date>>8 ) ^ sn_int[4];
sn_int[9] = ( UCHAR )(sn_date>>16) ^ sn_int[5];
} else {
sn_int[0] = getUncheck1(MAX_VERSION_ID) ^ sn_int[6];
printf ( "version_id = 0x%08X\n" , VERID);
}
}
printf ( "\n\nName: %s\n\n" , name);
if (license_type == 0xFC) {
printf ( " SN: %02X%02X-%02X%02X-%02X%02X-%02X%02X\n" ,
sn_int[0], sn_int[1], sn_int[2], sn_int[3], sn_int[4],
sn_int[5], sn_int[6], sn_int[7]);
} else if (license_type == 0xAC) {
printf ( " SN: %02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X\n" ,
sn_int[0], sn_int[1], sn_int[2], sn_int[3], sn_int[4],
sn_int[5], sn_int[6], sn_int[7], sn_int[8], sn_int[9]);
} else {
printf ( " SN: %02X%02X-%02X%02X-%02X%02X-%02X%02X\n" ,
sn_int[0], sn_int[1], sn_int[2], sn_int[3], sn_int[4],
sn_int[5], sn_int[6], sn_int[7]);
}
return 0;
}
int checkName( char * name) {
for ( int i=0; ; i++) {
if (name_list[i] == NULL) {
break ;
}
if ( strcmp (name, name_list[i])) {
continue ;
}
return RESULT1;
}
return 0;
}
int stringToBytes( char * str, char * bytes) {
int idx = 0;
for ( int i=0; i<5; i++) {
char ch_hi = str[idx++];
char ch_lo = str[idx++];
bytes[i*2] = (char36ToInt(ch_hi) << 4) + char36ToInt(ch_lo);
ch_hi = str[idx++];
ch_lo = str[idx++];
bytes[i*2+1] = (char36ToInt(ch_hi) << 4) + char36ToInt(ch_lo);
idx++;
}
printf ( "SN_INT[] = (%02X %02X - %02X %02X - %02X %02X - %02X %02X - %02X %02X)\n" ,
bytes[0], bytes[1], bytes[2], bytes[3], bytes[4],
bytes[5], bytes[6], bytes[7], bytes[8], bytes[9]);
return idx;
}
int char36ToInt( char ch) {
if ((ch== 'O' ) || (ch== 'o' )) {
return 0;
}
if (ch == 'l' ) {
return 1;
}
if ((ch>= '0' ) && (ch<= '9' )) {
return ch - '0' ;
}
if ((ch>= 'A' ) && (ch<= 'Z' )) {
return ch - 'A' + 10;
}
if ((ch>= 'a' ) && (ch<= 'z' )) {
return ch - 'a' + 10;
}
return 0;
}
UCHAR getCheck1( char ch) {
return ( UCHAR )(((ch ^ 0x18) + 0x3D) ^ 0xA7);
}
UWORD getCheck2( ULONG ul) {
ULONG a = (UWORD)(((ul ^ 0x7892) + 0x4D30) ^ 0x3421);
if (a % 11) {
return 0;
}
return (UWORD)a;
}
ULONG getCheck3( ULONG sn_date, ULONG base) {
ULONG check1 = (((sn_date ^ base ^ 0x0022C078) - 0x0002C175) ^ 0xFFE53167) & 0X00FFFFFF;
UINT64 check2 = ( UINT64 )check1 * 0xF0F0F0F1UL;
ULONG check3 = ( UINT64 )(check2 >> (32+4));
ULONG check4 = check3 << 4;
ULONG check = check1 - (check4 + check3);
return (check == 0)?check3:0;
}
ULONG getUncheck3( ULONG base, ULONG rlsdate) {
ULONG end_of_date = rlsdate + FREE_UPGRADE_DAYS;
return (((end_of_date * 0x11) ^ 0xFFE53167) + 0x0002C175) ^ 0x0022C078 ^ base;
}
ULONG calcSN_Date() {
ULONG a = sn_int[5] ^ sn_int[9];
ULONG b = sn_int[4] ^ sn_int[8];
ULONG c = sn_int[6] ^ sn_int[0];
ULONG d = (((a<<8) + b)<<8) + c;
return d;
}
ULONG reverseSN_Date( ULONG sn_date) {
sn_int[0] = ( UCHAR )(sn_date ) ^ sn_int[6];
sn_int[8] = ( UCHAR )(sn_date>>8 ) ^ sn_int[4];
sn_int[9] = ( UCHAR )(sn_date>>16) ^ sn_int[5];
return 0;
}
ULONG getUncheck3( ULONG count) {
return 0;
}
UCHAR getUncheck1( char ch) {
return ( UCHAR )(((ch ^ 0xA7) - 0x3D) ^ 0x18);
}
UWORD getUncheck2( ULONG ul) {
ULONG a = ul * 11;
return (UWORD)(((a ^ 0x3421) - 0x4D30) ^ 0x7892);
}
ULONG getNameCheck( char * name, ULONG is_registed, ULONG free_days, ULONG user_count) {
ULONG name_check = 0;
ULONG idx3 = 0;
ULONG idx2 = 0;
int n = strlen (name);
ULONG idx4 = user_count * 15;
ULONG idx1 = free_days * 17;
for ( int i=0; i<n; i++) {
ULONG idx0 = toupper (( UCHAR )name[i]);
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[( UCHAR )idx1];
name_check += name_tables[( UCHAR )idx4];
name_check += name_tables[( UCHAR )idx2];
} else {
name_check ^= name_tables[(idx0 + 0x3F) & 0xFF];
name_check *= name_tables[(idx0 + 0x17) & 0xFF];
name_check += name_tables[( UCHAR )idx1];
name_check += name_tables[( UCHAR )idx4];
name_check += name_tables[( UCHAR )idx3];
}
idx2 += 0x13;
idx1 += 0x09;
idx4 += 0x0D;
idx3 += 0x07;
}
return name_check;
}
int monthdays[2][12] = { { 31,28,31,30,31,30,31,31,30,31,30,31 },{ 31,29,31,30,31,30,31,31,30,31,30,31 } };
int yeardays[2] = { 365,366 };
int isLearYear( int year)
{
if (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0))
return 1;
else
return 0;
}
int getDays( int base, int year2, int month2, int day2) {
int sumdays = 0;
int year1 = 1970;
int month1 = 1;
int day1 = 1;
if (year1 == year2 && month1 == month2)
{
sumdays = day2 - day1;
} else {
if (year1 == year2)
{
sumdays += monthdays[isLearYear(year1)][month1-1] - day1;
for ( int i = month1; i < month2-1; i++) {
sumdays += monthdays[isLearYear(year1)][i];
}
sumdays += day2;
} else {
sumdays += monthdays[isLearYear(year1)][month1-1] - day1;
for ( int i = month1; i < 12; i++) {
sumdays += monthdays[isLearYear(year1)][i];
}
for ( int i = year1 + 1; i < year2; i++) {
sumdays += yeardays[isLearYear(i)];
}
for ( int i = 0; i < month2 - 1; i++) {
sumdays += monthdays[isLearYear(year2)][i];
}
sumdays += day2;
}
}
return sumdays - base;
}
int getDate( int days, int * year, int * month, int * day) {
int year1 = 1969;
int month1= 0;
int day1 = 0;
int n = days;
do {
year1 ++;
days = n;
n = days - yeardays[isLearYear(year1)];
} while (n>0);
n = days;
do {
days = n;
n = days - monthdays[isLearYear(year1)][month1];
month1 ++;
} while (n>0);
day1 = days;
day1 ++;
*year = year1;
*month= month1;
*day = day1;
return 0;
}
ULONG decodeVersionID( ULONG encVerId) {
return (((encVerId ^ 0xC7329CD4) - 0x2749B4FF) ^ 0x7C4280C0) / 0x3519;
}
ULONG encodeVersionID( ULONG VerId) {
return (((VerId * 0x3519) ^ 0x7C4280C0) + 0x2749B4FF) ^ 0xC7329CD4;
}
ULONG decodeBeginDays( ULONG encDays) {
ULONG c = (((encDays ^ 0x3F6197DA) - 0x656A0BB2) ^ 0xCB139CB7);
ULONG d = ((( UINT64 )c * 0xB21642C9UL)>>36);
ULONG a = d * 0x17;
return (c == a)?d:0;
}
ULONG encodeBeginDays( ULONG days) {
return ((((days * 0x17) ^ 0xCB139CB7) + 0x656A0BB2) ^ 0x3F6197DA);
}
ULONG decodeEndDays( ULONG encDays) {
return ((((encDays ^ 0x18C5B72) - 0x329BD55E) ^ 0x7521BDEF) / 0x71);
}
ULONG encodeEndDays( ULONG days) {
return ((((days * 0x71) ^ 0x7521BDEF) + 0x329BD55E) ^ 0x18C5B72);
}
ULONG decodeUsesLeft( ULONG encUsesLeft) {
return (((encUsesLeft ^ 0x7328B47A) - 0x18B3C906) ^ 0xBF32ABCE) / 0x049B;
}
ULONG encodeUsesLeft( ULONG usesLeft) {
return ((((usesLeft * 0x049B) ^ 0xBF32ABCE) + 0x18B3C906) ^ 0x7328B47A);
}
|
代码内还有一些多余函数和代码,是在跟踪分析过程中进行测试或解码用的,没有删除。
另外,还有一个文件是用户名转换时的查表数据,文件名为:name_tables.h,代码如下:[C++] 纯文本查看 复制代码 01 02 03 04 05 06 07 08 09 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 | #ifndef __name_tables__
#define __name_tables__
long 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
};
#endif
|
该软件在注册码验证时,还会进行网络验证,因此,还需要进行网络验证的处理,软件会向其服务器发送一个如下的http字符串进行验证:
[Shell] 纯文本查看 复制代码 1 2 | [url=http: //www .sweetscape.com /cgibin/010editor_check_license_9b .php?t=2E65DB0868& sum =1F4BF35D3CFC5A59865F2CF44167FEC268EDB719D6CD0ADE& id =0&chk=14611&typ=0]http: //www .sweetscape.com /cgibin ... d=0&chk=14611&typ=0[ /url ]
|
其中有几个参数説明如下:
1、t=2E65DB0868,这个是由用户名字符串编码加密而来的。
2、sum=1F4BF35D3CFC5A59865F2CF44167FEC268EDB719D6CD0ADE,这个是由上面的 t 参数与注册码一起加密而来的。
3、id=0,这个 id 是每次验证返回的验证成功值,会保存到注册表,不过第一次验证时是 0,后面验证时取的注册表键值。如果验证成功,id大于0了。
4、chk=14611,这个值也是由用户名字符串编码来的,16bits整数。
5、typ=0,这个是一个bool数据,当 typ=0,则进行网验证,typ=1,则发送验证已完成给服务器(发送字符串"1On_HttpCheckLicenseFinished(char*,int)"),并且也不再验证返回的数据。
以上是在线网络验证参数分析,下面进行具体的验证过程分析,另外,不对以上几个用户名和注册码的加密进行分析,因为那个不是客户端的事,服务端完成的工作我们不必去多费心分析。我们要做就是不管其发送什么内容,我们都给他回复一个“验证成功”的标志!
如下图,先定位网络验证的入口:
其实就在我们前面注册算法函数的后面一点点,如上图所示,传入网络验证函数参数只有一个:typ=0,表示需要进行验证。代码如下:
[Asm] 纯文本查看 复制代码 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 | 016FB7D3 . 8B0D 5C80BD03 mov ecx , dword ptr [0x3BD805C]
016FB7D9 . 68 3C470000 push 0x473C
016FB7DE . 6A 0B push 0xB
016FB7E0 . E8 07F350FF call 00C0AAEC
016FB7E5 . 8B0D 5C80BD03 mov ecx , dword ptr [0x3BD805C]
016FB7EB . 8BD8 mov ebx , eax
016FB7ED . 68 3C470000 push 0x473C
016FB7F2 . 6A 0B push 0xB
016FB7F4 . E8 5FE650FF call 00C09E58
016FB7F9 . 8B0D 5C80BD03 mov ecx , dword ptr [0x3BD805C]
016FB7FF . 8BF8 mov edi , eax
016FB801 . 81FB E7000000 cmp ebx , 0xE7
016FB807 . 0F84 F3000000 je 016FB900
016FB80D . 8379 2C 00 cmp dword ptr [ ecx +0x2C], 0x0
016FB811 . 0F84 E9000000 je 016FB900
016FB817 . 6A 00 push 0x0
016FB819 . 8BCE mov ecx , esi
016FB81B . E8 BB6D50FF call 00C025DB
016FB820 . 85C0 test eax , eax
016FB822 . 0F89 8C000000 jns 016FB8B4
|
进入该函数,如下图所示:
首先取得用户名,如下图所示,取得界面上的用户名字符串:
对用户名字符串进行类型转换并转成字符数组,如下图所示:
接下来取注册码,一样也进行转换成字符数组之类的操作,如下图所示:
接下来,对用户名进行编码,得到一个整数,如下图所示,编码方法不管,这个编码是 chk 参数:
接下一大段代码就是将分而在软件中不同位置的一些常量字符串进行拼接,拼接出一个 http 连接串,如下图所示:
上图中,OD 数据区显示的就是拼接好的字符串的前面一部分。
接下来,又是对用户名编码,这次是编码成一个字符串,作为 t 参数,如下图所示:
上面完成后,然后将 t 参数与注册码进行一起编码为一个更长的字符串,作为 sum 参数,如下图所示:
如下图所示,在 OD 的数据区显示,已经将上面的编码,添加到 http 连接串后面了:
接下来就是ID参数的处理,第一次验证时,注册表中没有数据,默认就是 t=0,如下图所示:
接下来,就是将最前面的用户名编码后的整数也添加上来,作为 chk 参数,如下图所示:
这个操作完成,只有最后一个参数了,typ 参数是函数传入的,当前传入是的 0,如下图所示:
这样,整个 http 验证字符串就拼接完成了,下面再转换成 QString 类型 Unicode 字符串,如下图所示:
我们先看看,手动发送一下,是什么效果,将这一串(没有转换成 unicode前的)字符串复制出来,在 IE 中直接连接,如下图所示:
直接返回是的 <ss>invalid</ss>,表示验证失败,注册码无效。
下面我们进行破解,先在 hosts 文件中加上如下数据:
127.0.0.1 www.sweetscape.com
然后在管理员权限下,在命令行运行如下命令,刷新 DNS:
ipconfig /flushdns
切记不要录错了。
下面,从网上抓一段 http server 代码,稍加改造,自己做一个验证服务器,代码如下:
[C++] 纯文本查看 复制代码 01 02 03 04 05 06 07 08 09 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 | #include <iostream>
#include <stdio.h>
#include <winsock.h>
#pragma comment(lib,"WSock32.Lib") //GCC 需要指定库 "libwsock32.a"
int main( int argc, char ** argv)
{
WSADATA wsaData;
if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0) {
fprintf (stderr, "WSAStartup failed.\n" );
exit (1);
}
printf ( "WebServer started...\r\nvisit [url=http://127.0.0.1:80]http://127.0.0.1:80[/url]\r\n\r\n" );
printf ( "Exit the http server, visit [url=http://127.0.0.1:80/?quit=1]http://127.0.0.1:80/?quit=1[/url]\r\n" );
SOCKET server_socket;
SOCKET acc_socket;
int sock_size = sizeof ( struct sockaddr_in);
struct sockaddr_in client_addr;
struct sockaddr_in server_addr;
server_socket = socket(PF_INET, SOCK_STREAM, 0);
if (server_socket == -1) {
return -1;
}
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(80);
server_addr.sin_addr.s_addr = inet_addr( "127.0.0.1" );
memset (&(server_addr.sin_zero), '\0' , 8);
if (bind(server_socket, ( struct sockaddr *)&server_addr,
sizeof (server_addr)) == -1) {
printf ( "bind error!\n" );
return -1;
}
if (listen(server_socket, 10) == -1 ) {
printf ( "listen error!\n" );
return -1;
}
if (server_socket == -1) {
printf ( "Server exception!\n" );
}
while ( true ) {
acc_socket = accept(server_socket, ( struct sockaddr *)&client_addr, &sock_size);
int numbytes;
char recv_buff[1000];
if ((numbytes=recv(acc_socket, recv_buff, 999, 0)) == -1) {
perror ( "recv error!\n" );
numbytes = 0;
}
recv_buff[numbytes] = '\0' ;
printf ( "recv data:\n %s\n" , recv_buff);
char reponse[] =
"HTTP/1.0 200 OK\r\n" \
"Content-type: text/html\r\n" \
"Content-length: 26\r\n\r\n" \
"<ss><id>78787878</id></ss>" ;
printf ( "send data:\n %s\n" , reponse);
send(acc_socket, reponse, strlen (reponse), 0);
shutdown(acc_socket, 2);
closesocket(acc_socket);
if ( strstr (recv_buff, "?quit=1" )) {
break ;
}
printf ( "\r\n\r\n" );
}
closesocket(server_socket);
WSACleanup();
return 0;
}
|
注意,这只是一个简单的验证,不过很有效。另外,GCC 编译时,要加上 libwsock32.a 库。
启动我们自己的验证服务器后,就可以进入下一步了。
如上图所示,发送了网络连接字符串。如果 bl ==1,表示成功发送和接收了。这是成功的第一步。这一段关键代码如下:
[Asm] 纯文本查看 复制代码 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | 016FD601 . 8B0D 6C80BD03 mov ecx , dword ptr [0x3BD806C]
016FD607 . 8D85 D8EFFFFF lea eax , dword ptr [ ebp -0x1028]
016FD60D . 53 push ebx
016FD60E . 6A 01 push 0x1
016FD610 . 50 push eax
016FD611 . 8D85 E4EFFFFF lea eax , dword ptr [ ebp -0x101C]
016FD617 . C745 FC 05000000 mov dword ptr [ ebp -0x4], 0x5
016FD61E . 50 push eax
016FD61F . 8D85 ECEFFFFF lea eax , dword ptr [ ebp -0x1014]
016FD625 . 50 push eax
016FD626 . E8 1F7C50FF call 00C0524A
016FD62B . 85C0 test eax , eax
016FD62D . C745 FC FFFFFFFF mov dword ptr [ ebp -0x4], -0x1
016FD634 . 8D8D ECEFFFFF lea ecx , dword ptr [ ebp -0x1014]
016FD63A . 0F94C3 sete bl
016FD63D . FF15 B094BD03 call dword ptr [<&Qt5Core.QString::~QString>]
016FD643 . 84DB test bl , bl
016FD645 .^ 0F84 ABF9FFFF je 016FCFF6
016FD64B . FFB5 D8EFFFFF push dword ptr [ ebp -0x1028]
016FD651 . 8B0D 5C80BD03 mov ecx , dword ptr [0x3BD805C]
016FD657 . FFB5 E4EFFFFF push dword ptr [ ebp -0x101C]
016FD65D . E8 046F50FF call 00C04566
016FD662 . FFB5 E4EFFFFF push dword ptr [ ebp -0x101C]
016FD668 . 8BF0 mov esi , eax
016FD66A . E8 6106A200 call < jmp .&MSVCR120.operator delete[]>
016FD66F . 83C4 04 add esp , 0x4
016FD672 . 8BC6 mov eax , esi
016FD674 . EB 47 jmp short 016FD6BD
|
如果验证失败,则收到如下数据(这是在改 hosts 文件 之前从官网接收的):
如果验证正确,则接收到如下图所示数据(这是从我的验证服务器接收的):
验证服务器显示如下:
可以清楚的看到接收和发送的数据。
接收到数据后,就会对数据进行解析,调用如下函数:
如上图所示,先解析<ss></ss>标签。检查接收到的字符串是不是 <ss>error</ss>和<ss>invalid</ss>,如果不是,则保存一个标志到注册表,表示验证成功:
这一段关键代码如下:
[Asm] 纯文本查看 复制代码 01 02 03 04 05 06 07 08 09 10 11 12 13 14 | 01DDE870 |> \1BC0 sbb eax , eax
01DDE872 |. 83C8 01 or eax , 0x1
01DDE875 |> 85C0 test eax , eax
01DDE877 |. 75 0B jnz short 01DDE884
01DDE879 |. C746 2C 01000000 mov dword ptr [ esi +0x2C], 0x1
01DDE880 |. 6A 01 push 0x1
01DDE882 |. EB 09 jmp short 01DDE88D
01DDE884 |> C746 2C 00000000 mov dword ptr [ esi +0x2C], 0x0
01DDE88B |. 6A 00 push 0x0
01DDE88D |> E8 85A1E2FE call 00C08A17
01DDE892 |. 8BC8 mov ecx , eax
01DDE894 |. E8 E35FE2FE call 00C0487C
01DDE899 |. 837E 2C 01 cmp dword ptr [ esi +0x2C], 0x1
01DDE89D |. 75 14 jnz short 01DDE8B3
|
具体的注册表标志保存位置如下:
如果是 1690216811,表示成功,这个数字解码后是 0,如果是 1690236428,则表示失败,这个数字解码后是 1。
保存完注册表后,就对“<id>78787878</id>”解析,如下图所示:
如果没有发现问题,则将“<id>78787878</id>”中的数据“78787878”解析出来,如上图所示。
如果解析成功,则将解析出来的 id 转换成一个整数,并保存到注册表中,并且是明文件保存的,没有加密,如下图所示:
解析函数完成后,返回我们前面的拼接函数,如果到这里还没有错误,网络就验证就完成了,如下图所示,要退出函数了:
至此,网络验证成功了。
注册表中保存的ID数据如下图所示:
因此,在注册表中手动添加好这两条注册信息,就可以完成离线网络验证:
[Shell] 纯文本查看 复制代码 01 02 03 04 05 06 07 08 09 10 11 12 13 | Windows Registry Editor Version 5.00
[HKEY_CURRENT_USER\Software\SweetScape\010 Editor\CLASSES\CLSID]
[HKEY_CURRENT_USER\Software\SweetScape\010 Editor\CLASSES\CLSID\{F531AB73-8493-A83D-7C94-016296B3CF17}]
[HKEY_CURRENT_USER\Software\SweetScape\010 Editor\CLASSES\CLSID\{F531AB73-8493-A83D-7C94-016296B3CF17}\InProcServer32A]
"ThreadingModel" = "78787878"
[HKEY_CURRENT_USER\Software\SweetScape\010 Editor\CLASSES\CLSID\{FA1395FC-83C3-0732-7D11-0134937462A0}]
[HKEY_CURRENT_USER\Software\SweetScape\010 Editor\CLASSES\CLSID\{FA1395FC-83C3-0732-7D11-0134937462A0}\InProcServer32A]
"ThreadingModel" = "1690216811"
|
前面説了,网络验证函数的参数为1时不会验证,只会 post 一条字符串 "1On_HttpCheckLicenseFinished(char*,int)" 给服务器。typ=1的网络验证函数调用在如下位置:
好象这个验证是界面显示刷新或定时器里用到了,没有深究,不一定准确。
另外,验证完成后,就可以恢复 hosts 文件了。
全部分析完毕!!!!

|