【破文标题】RMClock 算法分析
【破文作者】Ptero
【破解工具】Ollydbg, IDA
【注册方式】序列号
【加壳方式】无
【加密算法】进制转换
【软件限制】功能限制
【软件简介】一款给CPU降频降温的工具
【下载地址】http://cpu.rightmark.org/download/rm...0_bin_upd1.rar
【破解难度】简单
【作者声明】本文毫无技术含量,纯当练手。高手请飘过。

----------

【破解分析】

RMClock是Right Mark出品的众多小工具当中的一个,可以给CPU降频和降温,可以自动设置,也可以手动设置。

下载软件之后,查看其中的RMClock.htm,发现软件有功能限制,其中的升级模块和PRO模块需要注册才能使用。

用PEID查看主程序RMClock.exe,PEID报的是ARJ Archive,误报。看看区段,估计没有壳。省去不少麻烦。
结合IDA分析,发现是MFC编译的。

用OD载入,然后在PRO模块当中随便点其中一个功能,会弹出注册对话框。
输入用户名:Ptero,email:Ptero和任意注册码之后,激活按钮为灰色不可用。下断点GetWindwoTextA之后,不久来到这里:

0040189C  /$  8B51 78        mov edx, [ecx+78]
0040189F  |.  33C0           xor eax, eax
004018A1  |.  3942 F4        cmp [edx-C], eax        ; 用户名不能为空
004018A4  |.  74 15          je short RMClock.004018BB
004018A6  |.  8B51 7C        mov edx, [ecx+7C]
004018A9  |.  3942 F4        cmp [edx-C], eax        ; email不能为空
004018AC  |.  74 0D          je short RMClock.004018BB
004018AE  |.  8B91 80000000  mov edx, [ecx+80]
004018B4  |.  837A F4 19     cmp dword ptr [edx-C], 19    ; 注册码长度为25位
004018B8  |.  75 01          jnz short RMClock.004018BB
004018BA  |.  40             inc eax
004018BB  |>  50             push eax
004018BC  |.  6A 01          push 1
004018BE  |.  E8 88FF0300    call RMClock.0044184B    ; GetDlgItem
004018C3  |.  8BC8           mov ecx, eax
004018C5  |.  E8 75010400    call RMClock.00441A3F    ; EnableWindow
004018CA  \.  C3             ret

原来是要注册码长度为25位才能继续下去。

接着来到这里:

00429940  |.  FF75 10        push [arg.3]        ; 注册码
00429943  |.  8B10           mov edx, [eax]
00429945  |.  FF75 0C        push [arg.2]        ; email
00429948  |.  8BC8           mov ecx, eax
0042994A  |.  FF75 08        push [arg.1]        ; 用户名
0042994D  |.  FF52 10        call near [edx+10]    ; 进入RMCPRO.dll
00429950  |.  85C0           test eax, eax
00429952  |.  8D4D E8        lea ecx, [local.6]
00429955  |.  0F8D A9000000  jge RMClock.00429A04

call+test+jge结构,这个就是关键call了。跟进。
不一会儿来到这里:

01092509  |.  E8 F7FDFFFF    call RMCPRO.01092305
0109250E  |.  E8 7BFEFFFF    call RMCPRO.0109238E
01092513  |.  85C0           test eax, eax
01092515  |.  75 0A          jnz short RMCPRO.01092521

又是两个call+test+jnz。关键call。

第一个call,就是把用户名,email和某个特征字串做一个128位分组的加法。

    010BD068  52 4D 43 50 52 4F 20 32 2E 78 78 00 00 00 00 00  RMCPRO 2.xx.....    ; 特征字串

+    010BD078  50 74 65 72 6F 00 00 00 00 00 00 00 00 00 00 00  Ptero...........    ; 用户名
+    010BD088  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
+    010BD098  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
+    010BD0A8  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................

+    010BD0B8  50 74 65 72 6F 00 00 00 00 00 00 00 00 00 00 00  Ptero...........    ; email
+    010BD0C8  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
+    010BD0D8  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
+    010BD0E8  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
-------------------------------------------------------------------------------
=    010BD118  F2 35 0E 35 30 50 20 32 2E 78 78 00 00 00 00 00  ?50P 2.xx.....    ; 结果

下面看看第二个call做了什么:

0109238E  /$  55             push ebp
0109238F  |.  8BEC           mov ebp, esp
01092391  |.  83EC 14        sub esp, 14
01092394  |.  53             push ebx
01092395  |.  56             push esi
01092396  |.  57             push edi
01092397  |.  8BF9           mov edi, ecx
01092399  |.  6A 10          push 10
0109239B  |.  8D87 C8010000  lea eax, [edi+1C8]
010923A1  |.  6A 00          push 0
010923A3  |.  50             push eax
010923A4  |.  E8 77B90000    call RMCPRO.0109DD20
010923A9  |.  8D87 98010000  lea eax, [edi+198]
010923AF  |.  83C4 0C        add esp, 0C
010923B2  |.  8945 F0        mov [local.4], eax
010923B5  |.  BA A0360B01    mov edx, RMCPRO.010B36A0    ; 一个数组
010923BA  |>  8B45 F0        /mov eax, [local.4]
010923BD  |.  0FBE00         |movsx eax, byte ptr [eax]    ; 依次取出字符串的每一位
010923C0  |.  8D48 D0        |lea ecx, [eax-30]
010923C3  |.  33DB           |xor ebx, ebx
010923C5  |.  83F9 09        |cmp ecx, 9        ; 如果是数字,OK
010923C8  |.  77 07          |ja short RMCPRO.010923D1
010923CA  |.  894D F4        |mov [local.3], ecx
010923CD  |.  8BC1           |mov eax, ecx
010923CF  |.  EB 12          |jmp short RMCPRO.010923E3
010923D1  |>  8D48 BF        |lea ecx, [eax-41]
010923D4  |.  83F9 19        |cmp ecx, 19        ; 如果是小写字母,Game Over
010923D7  |.  0F87 B5000000  |ja RMCPRO.01092492
010923DD  |.  83E8 37        |sub eax, 37        ; 如果不是数字,也不是小写字母,就默认为是大写字母
010923E0  |.  8945 F4        |mov [local.3], eax
010923E3  |>  8D8F C8010000  |lea ecx, [edi+1C8]
010923E9  |.  894D FC        |mov [local.1], ecx
010923EC  |.  8955 F8        |mov [local.2], edx
010923EF  |.  C745 EC 040000>|mov [local.5], 4
010923F6  |.  EB 03          |jmp short RMCPRO.010923FB
010923F8  |>  8B45 F4        |/mov eax, [local.3]    ; 这个小循环,把注册码的某一位跟数组的某个数(128位)相乘,再累加
010923FB  |>  8B4D FC        | mov ecx, [local.1]
010923FE  |.  8B31           ||mov esi, [ecx]
01092400  |.  33C9           ||xor ecx, ecx
01092402  |.  51             ||push ecx
01092403  |.  50             ||push eax
01092404  |.  8B45 F8        ||mov eax, [local.2]
01092407  |.  51             ||push ecx
01092408  |.  FF30           ||push dword ptr [eax]
0109240A  |.  03F3           ||add esi, ebx
0109240C  |.  33DB           ||xor ebx, ebx
0109240E  |.  E8 3DE70000    ||call RMCPRO.010A0B50
01092413  |.  03F0           ||add esi, eax
01092415  |.  8B45 FC        ||mov eax, [local.1]
01092418  |.  13DA           ||adc ebx, edx
0109241A  |.  8345 F8 04     ||add [local.2], 4
0109241E  |.  8345 FC 04     ||add [local.1], 4
01092422  |.  FF4D EC        ||dec [local.5]
01092425  |.  8930           ||mov [eax], esi
01092427  |.^ 75 CF          |\jnz short RMCPRO.010923F8
01092429  |.  8B55 F8        |mov edx, [local.2]
0109242C  |.  FF45 F0        |inc [local.4]
0109242F  |.  81FA 30380B01  |cmp edx, RMCPRO.010B3830    ; 比较数组是否已经遍历
01092435  |.^ 7C 83          \jl short RMCPRO.010923BA

这个循环,乍一看,是从注册码中依次取出每一位,跟一个数组的某个数相乘,再相加,相当于两个25维的向量点乘。
看看那个数组:

010B36A0  01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ...............
010B36B0  24 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  $...............
010B36C0  10 05 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ..............
010B36D0  40 B6 00 00 00 00 00 00 00 00 00 00 00 00 00 00  @?.............
010B36E0  00 A1 19 00 00 00 00 00 00 00 00 00 00 00 00 00  .?.............
010B36F0  00 A4 9A 03 00 00 00 00 00 00 00 00 00 00 00 00  .............
010B3700  00 10 BF 81 00 00 00 00 00 00 00 00 00 00 00 00  .............
010B3710  00 40 DE 3E 12 00 00 00 00 00 00 00 00 00 00 00  .@?...........
010B3720  00 00 41 D7 90 02 00 00 00 00 00 00 00 00 00 00  ..A..........
010B3730  00 00 24 45 5E 5C 00 00 00 00 00 00 00 00 00 00  ..$E^\..........
010B3740  00 00 10 B9 41 FD 0C 00 00 00 00 00 00 00 00 00  ..?.........
010B3750  00 00 40 06 3E 9D D3 01 00 00 00 00 00 00 00 00  ..@>........
010B3760  00 00 00 E1 B8 1C C2 41 00 00 00 00 00 00 00 00  ...岣........
010B3770  00 00 00 A4 FF 09 4C 3F 09 00 00 00 00 00 00 00  ...?.L?........
010B3780  00 00 00 10 F3 67 B1 E6 4C 01 00 00 00 00 00 00  ...辨L......
010B3790  00 00 00 40 2E 9E F2 70 D0 2E 00 00 00 00 00 00  ...@.p?......
010B37A0  00 00 00 00 81 3E 1E E2 4F 95 06 00 00 00 00 00  ....??.....
010B37B0  00 00 00 00 24 CA 40 CC 3B FF EC 00 00 00 00 00  ....$??....
010B37C0  00 00 00 00 10 6D 1C B9 68 E4 53 21 00 00 00 00  ....m!....
010B37D0  00 00 00 00 40 56 FF 07 BA 1E CC AF 04 00 00 00  ....@V?摊...
010B37E0  00 00 00 00 00 21 E8 1F 29 52 B4 B8 A8 00 00 00  .....!?)R锤?..
010B37F0  00 00 00 00 00 A4 A4 7C C8 8D 5B F9 B9 17 00 00  .....い|[..
010B3800  00 00 00 00 00 10 27 87 31 F0 DF 10 27 56 03 00  .....'?疬'V.
010B3810  00 00 00 00 00 40 7E 01 F7 C6 7D 5F 7E 1D 78 00  .....@~髌}_~x.
010B3820  00 00 00 00 00 00 C1 35 BC FA AF 6D C5 25 E4 10  ......?贱??

用计算器简单算一下前几项,就知道这是0x24的各次幂,也就是10进制36的各次幂。
想到注册码的范围从0-9,A-Z,正好是36个。于是,这个乘法无非是把一个25位的36进制数(注册码)转换成一个32位的16进制数(也就是2进制的128位)。

转换之后,来到这里:

01092437  |.  8D9F C8010000  lea ebx, [edi+1C8]
0109243D  |.  8B33           mov esi, [ebx]        ; 取出一个DWORD
0109243F  |.  56             push esi
01092440  |.  E8 36FBFFFF    call RMCPRO.01091F7B    ; 计算其二进制表示中1的各数
01092445  |.  8AC8           mov cl, al
01092447  |.  D3CE           ror esi, cl
01092449  |.  8933           mov [ebx], esi
0109244B  |.  8D9F CC010000  lea ebx, [edi+1CC]
01092451  |.  8B33           mov esi, [ebx]
01092453  |.  56             push esi
01092454  |.  E8 22FBFFFF    call RMCPRO.01091F7B
01092459  |.  8AC8           mov cl, al
0109245B  |.  D3CE           ror esi, cl
0109245D  |.  8933           mov [ebx], esi
0109245F  |.  8D9F D0010000  lea ebx, [edi+1D0]
01092465  |.  8B33           mov esi, [ebx]
01092467  |.  56             push esi
01092468  |.  E8 0EFBFFFF    call RMCPRO.01091F7B
0109246D  |.  8AC8           mov cl, al
0109246F  |.  D3CE           ror esi, cl
01092471  |.  81C7 D4010000  add edi, 1D4
01092477  |.  8933           mov [ebx], esi
01092479  |.  8B37           mov esi, [edi]
0109247B  |.  56             push esi
0109247C  |.  E8 FAFAFFFF    call RMCPRO.01091F7B
01092481  |.  8AC8           mov cl, al
01092483  |.  83C4 10        add esp, 10
01092486  |.  D3CE           ror esi, cl
01092488  |.  33C0           xor eax, eax
0109248A  |.  40             inc eax
0109248B  |.  8937           mov [edi], esi

把128位的结果分成4个dword,计算其中每一个的"1"的各数,然后循环右移相应的位数。

接着,再把这个结果跟前面用户名和email相加的那个指比较,如果相等,那就成功了。

算法:
A=特征字串+用户名+email
B=注册码(36进制→16进制)→分组ror

如果A=B,那就成功啦。

逆算法非常简单。只要把A分组rol,然后转换成36进制就OK了。

例如前面得到的结果:
A=F2 35 0E 35 30 50 20 32 2E 78 78 00 00 00 00 00
分组rol之后:
0E 35 F2 35 32 30 50 20 07 E0 82 87 00 00 00 00
再转换成36进制:(0-9=0-9,10-35=A-Z)
IVEBX5I0SFNIGAEKD240000000

注意这个是逆序的。这就是注册码了。

另一个update模块,非常地类似。

00436FAE  |.  FF75 10        push [arg.3]        ; 注册码
00436FB1  |.  8B10           mov edx, [eax]
00436FB3  |.  FF75 0C        push [arg.2]        ; email
00436FB6  |.  8BC8           mov ecx, eax
00436FB8  |.  FF75 08        push [arg.1]        ; 用户名
00436FBB  |.  FF52 10        call near [edx+10]    ; 进入RMCUpdater.dll

这里还是一样的:

100016A1  |.  E8 F7FDFFFF    call RMCUpdat.1000149D
100016A6  |.  E8 7BFEFFFF    call RMCUpdat.10001526
100016AB  |.  85C0           test eax, eax
100016AD  |.  75 0A          jnz short RMCUpdat.100016B9

唯一的不同就是,特征字符串变成了:
1002AF08  52 4D 43 55 70 64 20 32 2E 78 78 00 00 00 00 00  RMCUpd 2.xx.....

那就重新计算一下注册码吧:
2JEELTNFLDF4GAEKD240000000

测试成功,可以升级了。

【版权声明】   本文纯属技术交流, 转载请注明作者并保持文章的完整, 谢谢!