【破文作者】xu_wh (yuyu)
【所属组织】PCG
【作者主页】
【 E-mail 】xu_wh@163.com
【 作者QQ 】
【文章题目】对企业短信快车1.7的破解
【软件名称】企业短信快车1.7
【下载地址】http://www.supcode.com/Soft/softdown/wangluogongju/lianluoliaotian/jianyiduanxinkuaicheEasySms1.7.sh

【加密方式】注册码
【加壳方式】ASPack 2.12 -> Alexey Solodovnikov
【破解工具】OD PE UltraEdit
【软件限制】Win9x/Me/NT/2000/XP 
【破解平台】Win XP
=======================================================================================================
【文章简介】

=======================================================================================================
【解密过程】

首先运行这个软件,对这个软件有一个基本的了解。
用PE测试壳:ASPack 2.12 -> Alexey Solodovnikov。用OD脱之。
脱壳后的软件3.5M,用PE检测为DELPHI。

运行这个软件,点注册窗口:可以看到我的机器码是:H-888066761。看来这个应该和最终注册码的验证有关(但是,事实证明这个程序只是测试版的程序,程序中没有过对注册码的校验。程序注册与否的标志是写死在程序的。)我们输入试验码:12345678900987654321。程序提示,谢谢注册,将在下次启动时对注册码进行校验。

关闭程序,在程序的目录下,有一个EasySms.ini的文件:
  FONTNAME=宋体
  FONTCHARSET=1
  REGUSER=
  REGSN=12345678900987654321
可见程序在重启后,要访问这个文件,字段是REGSN。有两处。(当然了,一处是程序开始运行时,要访问的。另一处是我们输入注册码时,程序要写入文件的)

所以要在OD中查找“REGSN”,在0062E8E5处下断,F9运行程序,对我们输入的注册码进行跟踪:
0062E8E5   |.  B9 90EC6200      mov ecx,11.0062EC90                ;  ASCII "REGSN"
0062E8EA   |.  BA 90EB6200      mov edx,11.0062EB90                ;  ASCII "SMS"
0062E8EF   |.  8BC3             mov eax,ebx
0062E8F1   |.  8B38             mov edi,dword ptr ds:[eax]
0062E8F3   |.  FF17             call near dword ptr ds:[edi]       ;  访问文件,拿到PASSWORD
0062E8F5   |.  8B55 C8          mov edx,dword ptr ss:[ebp-38]      ;  edx=01089728,password
0062E8F8   |.  A1 30C46300      mov eax,dword ptr ds:[63C430]      ;  eax=0063DF58,这个地址的值是 00000000
0062E8FD   |.  E8 B65FDDFF      call 11.004048B8
0062E902   |.  6A 01            push 1
0062E904   |.  B9 A0EC6200      mov ecx,11.0062ECA0                ;  ASCII "COM"
0062E909   |.  BA 90EB6200      mov edx,11.0062EB90                ;  ASCII "SMS"
0062E90E   |.  8BC3             mov eax,ebx
0062E910   |.  8B38             mov edi,dword ptr ds:[eax]
0062E912   |.  FF57 08          call near dword ptr ds:[edi+8]

呵呵,拿到注册码了,存放在EDX,01089728中:

01089718  94 97 08 01 26 00 00 00 01 00 00 00 14 00 00 00  敆&.........
01089728  31 32 33 34 35 36 37 38 39 30 30 39 38 37 36 35  1234567890098765
01089738  34 33 32 31 00 00 08 01 E4 6A 08 01 74 97 08 01  4321..鋔t?

注意:长度放在01089724,为 0x14 = 20 我们对长度和假注册码都下硬件访问断点(以免程序先对长度进行判断)。好了F9,等待我们的是程序运行了,奇怪,怎么没有对注册码进行校验? 经过若干次试验,都发现跟本就没有访问到我输入的注册码。作为菜鸟的我,已经黔驴技穷了。
难道是作者在骗人? 在输入假注册码的时候就对这个注册码进行判断了? 找找看了,实践是检验真理的唯一标准。
但是我们输入注册码后,程序什么做任何校验的动作,就连我输入的注册码和注册码的长度理都不理。郁闷ing....

难道是在退出时进行校验? 再试试。退出程序,在下面的断点中断:只是写文件时要访问我输入的注册码。MY GOD!!!

0062EE5B   |.  FF56 0C          call near dword ptr ds:[esi+C]
0062EE5E   |.  A1 30C46300      mov eax,dword ptr ds:[63C430]
0062EE63   |.  8B00             mov eax,dword ptr ds:[eax]
0062EE65   |.  50               push eax
0062EE66   |.  B9 80EF6200      mov ecx,11.0062EF80                ;  ASCII "REGSN"
0062EE6B   |.  BA E8EE6200      mov edx,11.0062EEE8                ;  ASCII "SMS"
0062EE70   |.  8BC3             mov eax,ebx
0062EE72   |.  8B30             mov esi,dword ptr ds:[eax]
0062EE74   |.  FF56 04          call near dword ptr ds:[esi+4]
0062EE77   |.  8BC3             mov eax,ebx                        ;  退出时,要写文件
0062EE79   |.  E8 F64ADDFF      call 11.00403974

那真的就没有办法了吗? 我就是要注册!下面就换个思路:

我们首先点击程序的帮助->关于,窗口显示目前的版本是“企业短信快车试用版”

启用OD,搜索字符串“企业短信快车试用版”,在地址 00618AEC 处,找到如下信息:

00618AEC  C6 F3 D2 B5 B6 CC D0 C5 BF EC B3 B5 D5 FD CA BD  企业短信快车正式
00618AFC  B0 E6 20 56 65 72 20 00 FF FF FF FF 17 00 00 00  版 Ver ....
00618B0C  C6 F3 D2 B5 B6 CC D0 C5 BF EC B3 B5 CA D4 D3 C3  企业短信快车试用
00618B1C  B0 E6 20 56 65 72 20 00 6A 01 6A 00 6A 00 68 48  版 Ver .jj.j.hH
00618B2C  8B 61 00 68 60 8B 61 00 A1 68 C5 63 00 8B 00 8B  媋.h`媋.與.?
00618B3C  40 30 50 E8 10 84 E2 FF C3 00 00 00 68 74 74 70  @0P?勨?..http
00618B4C  3A 2F 2F 77 77 77 2E 64 61 69 6C 79 70 69 6D 2E  ://www.dailypim.
00618B5C  63 6F 6D 00 6F 70 65 6E 00 00 00 00 6A 01 6A 00  com.open....jj.

我们可以推断,程序在显示这个关于窗口的时候,根据一个条件,判断是注册版,或试用版。

用OD在地址00618B0C 处下硬件访问断点。 重新点 帮助->关于。程序在

00618A2C   /.  55          push ebp
00618A2D   |.  8BEC        mov ebp,esp
00618A2F   |.  6A 00       push 0
00618A31   |.  6A 00       push 0
00618A33   |.  6A 00       push 0
00618A35   |.  53          push ebx
00618A36   |.  8BD8        mov ebx,eax
00618A38   |.  33C0        xor eax,eax
00618A3A   |.  55          push ebp
00618A3B   |.  68 D78A6100 push 11.00618AD7
00618A40   |.  64:FF30     push dword ptr fs:[eax]
00618A43   |.  64:8920     mov dword ptr fs:[eax],esp
00618A46   |.  A1 6CC56300 mov eax,dword ptr ds:[63C56C]      ;  EAX的值是0063DF90,其中存放的是数值2
00618A4B   |.  8338 01     cmp dword ptr ds:[eax],1           ;  如果是注册过的,这个值应该是 1
00618A4E   |.  75 25       jnz short 11.00618A75              ;  关键跳转
00618A50   |.  8B0D B8C663>mov ecx,dword ptr ds:[63C6B8]      ;  11.0063DF4C
00618A56   |.  8B09        mov ecx,dword ptr ds:[ecx]
00618A58   |.  8D45 FC     lea eax,dword ptr ss:[ebp-4]
00618A5B   |.  BA EC8A6100 mov edx,11.00618AEC                ;  企业短信快车正式版
00618A60   |.  E8 13C1DEFF call 11.00404B78
00618A65   |.  8B55 FC     mov edx,dword ptr ss:[ebp-4]
00618A68   |.  8B83 140300>mov eax,dword ptr ds:[ebx+314]
00618A6E   |.  E8 E96DE3FF call 11.0044F85C
00618A73   |.  EB 23       jmp short 11.00618A98
00618A75   |>  8B0D B8C663>mov ecx,dword ptr ds:[63C6B8]      ;  11.0063DF4C
00618A7B   |.  8B09        mov ecx,dword ptr ds:[ecx]
00618A7D   |.  8D45 F8     lea eax,dword ptr ss:[ebp-8]
00618A80   |.  BA 0C8B6100 mov edx,11.00618B0C                ;  企业短信快车试用版
00618A85   |.  E8 EEC0DEFF call 11.00404B78
00618A8A   |.  8B55 F8     mov edx,dword ptr ss:[ebp-8]
00618A8D   |.  8B83 140300>mov eax,dword ptr ds:[ebx+314]
00618A93   |.  E8 C46DE3FF call 11.0044F85C
00618A98   |>  8D55 F4     lea edx,dword ptr ss:[ebp-C]
00618A9B   |.  8B83 140300>mov eax,dword ptr ds:[ebx+314]
00618AA1   |.  E8 866DE3FF call 11.0044F82C
00618AA6   |.  8B55 F4     mov edx,dword ptr ss:[ebp-C]
00618AA9   |.  8B83 1C0300>mov eax,dword ptr ds:[ebx+31C]
00618AAF   |.  E8 A86DE3FF call 11.0044F85C
00618AB4   |.  33C0        xor eax,eax
00618AB6   |.  5A          pop edx
00618AB7   |.  59          pop ecx
00618AB8   |.  59          pop ecx
00618AB9   |.  64:8910     mov dword ptr fs:[eax],edx
00618ABC   |.  68 DE8A6100 push 11.00618ADE
00618AC1   |>  8D45 F4     lea eax,dword ptr ss:[ebp-C]
00618AC4   |.  E8 9BBDDEFF call 11.00404864
00618AC9   |.  8D45 F8     lea eax,dword ptr ss:[ebp-8]
00618ACC   |.  BA 02000000 mov edx,2
00618AD1   |.  E8 B2BDDEFF call 11.00404888
00618AD6   \.  C3          retn

在这里,如果直接将地址 0063DF90 处的值修改为:00000001,将会看到程序已经是注册版了。

下面我们就在地址 0063DF90 处设置硬件写入断点,然后重新运行:

通过对程序的跟踪,我们发现,程序只有在0062E68A处,才会对0063DF90处的变量赋值,这个值是 0。这个零来自xor edx,edx。能不是零吗?什么情况不,不赋零呢? 用UltraEdit拿到程序的静态汇编代码,遍历所有对地址0063DF90的赋值语句。只有两处,一处赋初始值为 0, 别处一处赋值为2(2说明没有注册)

所以,就这个程序而言,是不会对注册码进行校验的。看来程序确实不会对注册码进行检验!
只好使用暴力了,只能通过爆破的方法了,在程序运行时,第一时间对这个0063DF90处的值赋为 1(1表示程序已经注册)。(如果已经是 1 的话,就不会对这个值赋 2 )

修改前的代码:
0062E683   |.  A1 6CC56300      mov eax,dword ptr ds:[63C56C]
0062E688       33D2             xor edx,edx
0062E68A       8910             mov dword ptr ds:[eax],edx
0062E68C       A1 B8C66300      mov eax,dword ptr ds:[63C6B8]
0062E691   |.  BA 38EB6200      mov edx,22.0062EB38                ;  ASCII "1.7"

00634F00       0000             add byte ptr ds:[eax],al
00634F02       0000             add byte ptr ds:[eax],al
00634F04       0000             add byte ptr ds:[eax],al
00634F06       0000             add byte ptr ds:[eax],al
00634F08       0000             add byte ptr ds:[eax],al
00634F0A       0000             add byte ptr ds:[eax],al
00634F0C    .  0000             add byte ptr ds:[eax],al
00634F0E    .  0000             add byte ptr ds:[eax],al
00634F10    .  0000             add byte ptr ds:[eax],al

修改后的代码:

0062E683    .  A1 6CC56300      mov eax,dword ptr ds:[63C56C]
0062E688    .  E9 73680000      jmp 33.00634F00
0062E68D       90               nop
0062E68E       90               nop
0062E68F       90               nop
0062E690       90               nop
0062E691       BA 38EB6200      mov edx,33.0062EB38                ;  ASCII "1.7"

00634F00    .  33D2             xor edx,edx
00634F02    .  42               inc edx
00634F03    .  8910             mov dword ptr ds:[eax],edx
00634F05    .  A1 B8C66300      mov eax,dword ptr ds:[63C6B8]
00634F0A    .^ E9 8297FFFF      jmp 33.0062E691
00634F0F    .  90               nop

真是有力无处使!!!
既然程序没有注册码的算法,我们大家就看看程序是怎么计算机器码的吧。好歹也要找个算法看看呀。

0056D4A4   /$  83C4 F4     add esp,-0C
0056D4A7   |.  6A 00       push 0                                 ; /pFileSystemNameSize = NULL
0056D4A9   |.  6A 00       push 0                                 ; |pFileSystemNameBuffer = NULL
0056D4AB   |.  8D4424 10   lea eax,dword ptr ss:[esp+10]          ; |
0056D4AF   |.  50          push eax                               ; |pFileSystemFlags
0056D4B0   |.  8D4424 10   lea eax,dword ptr ss:[esp+10]          ; |
0056D4B4   |.  50          push eax                               ; |pMaxFilenameLength
0056D4B5   |.  8D4424 10   lea eax,dword ptr ss:[esp+10]          ; |
0056D4B9   |.  50          push eax                               ; |pVolumeSerialNumber
0056D4BA   |.  6A 00       push 0                                 ; |MaxVolumeNameSize = 0
0056D4BC   |.  6A 00       push 0                                 ; |VolumeNameBuffer = NULL
0056D4BE   |.  68 E8D45600 push 11.0056D4E8                       ; |RootPathName = "c:\\"
0056D4C3   |.  E8 009EE9FF call <jmp.&kernel32.GetVolumeInformati>; \GetVolumeInformationA
0056D4C8   |.  8B0424      mov eax,dword ptr ss:[esp]             ;  EAX=A865A81C,是我C盘的序列号
0056D4CB   |.  05 85000000 add eax,85
0056D4D0   |.  B9 22000000 mov ecx,22
0056D4D5   |.  33D2        xor edx,edx
0056D4D7   |.  F7F1        div ecx                                ;  EAX = ( EAX + 0x58 ) / 0x22
0056D4D9   |.  6BC0 29     imul eax,eax,29                        ;  eax * = 0x29
0056D4DC   |.  890424      mov dword ptr ss:[esp],eax             ;  EAX=CB112D37
0056D4DF   |.  8B0424      mov eax,dword ptr ss:[esp]             ;  后面生成的机器码和它有关
0056D4E2   |.  83C4 0C     add esp,0C
0056D4E5   \.  C3          retn

0040A5FC   |.  F7D8        neg eax                                ;  注意此处EAX的值;运算前EAX=CB112D37,后EAX=34EED2C9
0040A5FE   |.  E8 07000000 call 11.0040A60A                       ;  将EAX的值转换成十进制数,为888066761
0040A603   |.  B0 2D       mov al,2D                              ;  al=2D, '-'
0040A605   |.  41          inc ecx                                ;  机器码的长度 + 1
0040A606   |.  4E          dec esi                                ;  ESI = ESI -1,指针前移
0040A607   |.  8806        mov byte ptr ds:[esi],al               ;  强行在888066761前插入 '-'
0040A609   |.  C3          retn

00402A3B   |.  89C1        mov ecx,eax
00402A3D   |.  83E1 03     and ecx,3
00402A40   |.  83C6 03     add esi,3
00402A43   |.  83C7 03     add edi,3
00402A46   |.  F3:A4       rep movs byte ptr es:[edi],byte ptr>;  将0062ED10处的'H'复制到0108A6FC处
00402A48   |.  FC          cld
00402A49   |>  5F          pop edi
00402A4A   |.  5E          pop esi
00402A4B   \.  C3          retn

用UltraEdit打开这个可执行文件,在偏移0062ED10的值就是'H',所以,这个字符是写成了一个CONST变量了 :)
所以,机器码就必然是"H-XXXXXXXX"

我是一个小小的菜鸟,如果哪位老鸟能找到真正的算注册码的地方,请通告一下,不胜感激!
=======================================================================================================
【解密心得】

=======================================================================================================
【破解声明】我是一个小小菜虫子,文章如有错误,请高手指正!
【版权声明】本文纯属技术交流, 转载请注明作者并保持文章的完整, 谢谢! 
=======================================================================================================
                                                                    文章完成于2005-12-13 上午 16:33:38