1.破解软件
名字为pwindpro,版本号5.00,该软件是通过NDIS来直接
读取网卡数据报,可以用它来做网络监听软件,有源代码的,
我目前在做的一个项目可能用到它,所以我就破解他了。
2.破解工具
icomp,w32dasm,trw2000,VC6.0
3.破解过程
若光破这个程序是很简单的,它是自解压的,解压后的
目录在C:\Windows\Temp下,我等它解压完,把其拷入另一个
目录,接着我观察该目录,发现在Disk1下面有setup.ins,这
个文件是经过压缩的,还有个_setup.lib,先用Fi查看文件类
型,发现他们均是.z结尾的,这种文件可以用icomp来解压。
然后我把_setup.lib解压,发现里面有个很可疑的dll即Serial.dll
.于是我把该文件用W32dasm反汇编。呵呵,它就导出一个函数
SerialCheck,肯定就是它了,然后吗,用trw跟进该函数,怎么
跟呢,它不是会弹出出错对话框吗,OK,bpx messageboxa,然后
F12,呵呵,是不是到了Serial啊,赶快往前翻,在SerialCheck的
入口点下一个断点,以后就每次都会在这中断了。跟踪发现它仅用
返回值来标记是否合法,所以我简单的把它的返回值始终设为1,
这样,一切OK,不用再输入序列号了。
接着呢,破是破掉了,但总觉得不爽,索性把它的注册机
也写出来了。下面是我写该注册机的过程,该程序的注册算法
比较简单,我只用了一天的时间把它写出来,最主要的时间
还浪费在写代码上,一开始我想用纯C语言来写,但碰到一个问
题,就是汇编指令imul调用之后会设置高位寄存器,如果两个
操作数均是DWORD,在C中如何取到结果的高位,C中调用乘法后
它自动帮你截断了,而我又必须要有该信息,所以,我就请教了
一个人,Craxy Z,从他那我获得了灵感,VC不是支持内嵌汇编语
句吗,我直接写汇编语句不就可以了,(顺带一句,那位能用C语
言来解决该问题的,能不能告诉我方法,那种将数字堪称数组,
然后自己写乘法的方法就不用说了),接下来的工作就很简单了。
4.注册机写作过程
* Referenced by a CALL at Address:
|:1000101A
|
:10001030 8B542408 mov edx, dword ptr [esp+08]
;[esp+08]指向输入的序列号
:10001034 83EC20 sub esp, 00000020
:10001037 83C9FF or ecx, FFFFFFFF
:1000103A 33C0 xor eax, eax
:1000103C 56 push esi
:1000103D 57 push edi
:1000103E 8BFA mov edi, edx
:10001040 F2 repnz
:10001041 AE scasb
:10001042 F7D1 not ecx
:10001044 49 dec ecx
:10001045 83F913 cmp ecx, 00000013
;看其长度是否为19,
;格式为xxxx-xxxx-xxxx-xxxx
:10001048 741F je 10001069
:1000104A 8B44242C mov eax, dword ptr [esp+2C]
:1000104E 6A30 push 00000030
* Possible StringData Ref from Data Obj ->"Invalid Serial Number"
|
:10001050 68EC910010 push 100091EC
* Possible StringData Ref from Data Obj ->"Serial number has incorrect
lengt
h!"
|
:10001055 68C8910010 push 100091C8
:1000105A 50 push eax
* Reference To: USER32.MessageBoxA, Ord:01C3h
|
:1000105B FF15EC800010 Call dword ptr [100080EC]
:10001061 5F pop edi
:10001062 33C0 xor eax, eax
:10001064 5E pop esi
:10001065 83C420 add esp, 00000020
:10001068 C3 ret
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:10001048(C)
|
:10001069 8BFA mov edi, edx
:1000106B 83C9FF or ecx, FFFFFFFF
:1000106E 33C0 xor eax, eax
:10001070 53 push ebx
:10001071 F2 repnz
:10001072 AE scasb
:10001073 F7D1 not ecx
:10001075 2BF9 sub edi, ecx
:10001077 8D5C240C lea ebx, dword ptr [esp+0C]
:1000107B 8BD1 mov edx, ecx
:1000107D 8BF7 mov esi, edi
:1000107F 8BFB mov edi, ebx
:10001081 8D44240C lea eax, dword ptr [esp+0C]
:10001085 C1E902 shr ecx, 02
:10001088 F3 repz
:10001089 A5 movsd
;拷贝字符串到另一个地方
:1000108A 8BCA mov ecx, edx
* Possible StringData Ref from Data Obj ->"-"
|
:1000108C 6830900010 push 10009030
:10001091 83E103 and ecx, 00000003
:10001094 50 push eax
:10001095 F3 repz
:10001096 A4 movsb
:10001097 E863050000 call 100015FF
;该函数将原来串中的"-"用00来替代了
* Possible StringData Ref from Data Obj ->"-"
|
:1000109C 6830900010 push 10009030
:100010A1 6A00 push 00000000
:100010A3 A3A09E0010 mov dword ptr [10009EA0], eax
:100010A8 E852050000 call 100015FF
* Possible StringData Ref from Data Obj ->"-"
|
:100010AD 6830900010 push 10009030
:100010B2 6A00 push 00000000
:100010B4 A3A49E0010 mov dword ptr [10009EA4], eax
:100010B9 E841050000 call 100015FF
* Possible StringData Ref from Data Obj ->"-"
|
:100010BE 6830900010 push 10009030
:100010C3 6A00 push 00000000
:100010C5 A3A89E0010 mov dword ptr [10009EA8], eax
:100010CA E830050000 call 100015FF
;上面的四个call 100015ff分别处理序列号的四项
:100010CF 8B3DA09E0010 mov edi, dword ptr [10009EA0]
:100010D5 83C420 add esp, 00000020
:100010D8 8BF0 mov esi, eax
:100010DA 85FF test edi, edi
:100010DC 8935AC9E0010 mov dword ptr [10009EAC], esi
:100010E2 5B pop ebx
:100010E3 0F841C020000 je 10001305
:100010E9 83C9FF or ecx, FFFFFFFF
:100010EC 33C0 xor eax, eax
:100010EE F2 repnz
:100010EF AE scasb
:100010F0 F7D1 not ecx
:100010F2 49 dec ecx
:100010F3 83F904 cmp ecx, 00000004
;我上面提到的序列号格式是由这获知的
;以下一长段都是在检查格式对不对的
:100010F6 0F8509020000 jne 10001305
:100010FC 8B3DA49E0010 mov edi, dword ptr [10009EA4]
:10001102 85FF test edi, edi
:10001104 0F84DC010000 je 100012E6
:1000110A 83C9FF or ecx, FFFFFFFF
:1000110D F2 repnz
:1000110E AE scasb
:1000110F F7D1 not ecx
:10001111 49 dec ecx
:10001112 83F904 cmp ecx, 00000004
:10001115 0F85CB010000 jne 100012E6
:1000111B 8B15A89E0010 mov edx, dword ptr [10009EA8]
:10001121 85D2 test edx, edx
:10001123 0F849E010000 je 100012C7
:10001129 8BFA mov edi, edx
:1000112B 83C9FF or ecx, FFFFFFFF
:1000112E F2 repnz
:1000112F AE scasb
:10001130 F7D1 not ecx
:10001132 49 dec ecx
:10001133 83F904 cmp ecx, 00000004
:10001136 0F858B010000 jne 100012C7
:1000113C 85F6 test esi, esi
:1000113E 0F8464010000 je 100012A8
:10001144 8BFE mov edi, esi
:10001146 83C9FF or ecx, FFFFFFFF
:10001149 F2 repnz
:1000114A AE scasb
:1000114B F7D1 not ecx
:1000114D 49 dec ecx
:1000114E 83F904 cmp ecx, 00000004
:10001151 0F8551010000 jne 100012A8
;到这为止,长度检查完毕
:10001157 52 push edx
;edx为序列号的第三项
:10001158 E817040000 call 10001574
;该函数将字符串xyzw转化为数字(十进制)
;返回值在eax中,例如串"0101"就变为数字101
:1000115D 8BC8 mov ecx, eax
:1000115F B867666666 mov eax, 66666667
:10001164 8BD1 mov edx, ecx
:10001166 81E2FFFF0000 and edx, 0000FFFF
:1000116C F7EA imul edx
:1000116E C1FA02 sar edx, 02
:10001171 8BC2 mov eax, edx
:10001173 C1E81F shr eax, 1F
:10001176 03D0 add edx, eax
:10001178 66891554A20010 mov word ptr [1000A254], dx
;以上计算得到一个值,其后要用到
;它共设置两个字节,根据其地址,
;我把它记做var4,var5,并把该段
;计算过程定义成func3.1
:1000117F 8AC2 mov al, dl
:10001181 B20A mov dl, 0A
:10001183 F6EA imul dl
:10001185 2AC8 sub cl, al
:10001187 A1AC9E0010 mov eax, dword ptr [10009EAC]
:1000118C 50 push eax
;eax为序列号的第四项
:1000118D 880D58A20010 mov byte ptr [1000A258], cl
;cl的就算过程定义为func3.2
;并把代表它的地址记做var8
:10001193 E8DC030000 call 10001574
:10001198 8B0DA49E0010 mov ecx, dword ptr [10009EA4]
:1000119E 66A356A20010 mov word ptr [1000A256], ax
;不作任何处理直接将结果存入,
;记为func4,变量记做var6,var7
:100011A4 51 push ecx
;ecx为序列号的第二项
:100011A5 E8CA030000 call 10001574
:100011AA 8BC8 mov ecx, eax
:100011AC B81F85EB51 mov eax, 51EB851F
:100011B1 8BD1 mov edx, ecx
:100011B3 81E2FFFF0000 and edx, 0000FFFF
:100011B9 F7EA imul edx
:100011BB C1FA05 sar edx, 05
:100011BE 8BF2 mov esi, edx
:100011C0 8BC2 mov eax, edx
:100011C2 C1EE1F shr esi, 1F
:100011C5 03C6 add eax, esi
:100011C7 B264 mov dl, 64
:100011C9 A252A20010 mov byte ptr [1000A252], al
;al的计算过程定义为func2.1
;变量记做var2
:100011CE F6EA imul dl
:100011D0 2AC8 sub cl, al
:100011D2 8D44243C lea eax, dword ptr [esp+3C]
:100011D6 880D53A20010 mov byte ptr [1000A253], cl
;cl的计算过程定义为func2.2
;变量记做var3
:100011DC 8B0DA09E0010 mov ecx, dword ptr [10009EA0]
:100011E2 50 push eax
;eax为序列号的第一项
* Possible StringData Ref from Data Obj ->"%x"
|
:100011E3 68C4910010 push 100091C4
:100011E8 51 push ecx
:100011E9 E852030000 call 10001540
;该函数将字符串xyzw转换为0Xxyzw(十六进制)
;例如将串"1234"转换为0x1234
:100011EE 668B542448 mov dx, word ptr [esp+48]
:100011F3 6850A20010 push 1000A250
:100011F8 66891550A20010 mov word ptr [1000A250], dx
;dx即为上面得到的十六进制数
;其计算过程我定义为func1
:100011FF E88C010000 call 10001390
;★★★注意,该函数就是关键的比较函数了,后面有分析
:10001204 83C41C add esp, 0000001C
:10001207 84C0 test al, al
:10001209 751F jne 1000122A
;此处必须跳转才是正确的
:1000120B 8B44242C mov eax, dword ptr [esp+2C]
:1000120F 6A30 push 00000030
* Possible StringData Ref from Data Obj ->"Invalid Serial Number"
|
:10001211 68EC910010 push 100091EC
* Possible StringData Ref from Data Obj ->"The serial number is invalid!"
|
:10001216 68A4910010 push 100091A4
:1000121B 50 push eax
* Reference To: USER32.MessageBoxA, Ord:01C3h
|
:1000121C FF15EC800010 Call dword ptr [100080EC]
:10001222 5F pop edi
:10001223 33C0 xor eax, eax
:10001225 5E pop esi
:10001226 83C420 add esp, 00000020
:10001229 C3 ret
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:10001209(C)
|
:1000122A 66A154A20010 mov ax, word ptr [1000A254]
;应该跳到1000126D处
;其后的比较告诉我们func3.1
;算出来的值var4,var5必须满足特定条件,
;即在【A--E】之间。
:10001230 663D0A00 cmp ax, 000A
:10001234 7437 je 1000126D
:10001236 663D0B00 cmp ax, 000B
:1000123A 7431 je 1000126D
:1000123C 663D0C00 cmp ax, 000C
:10001240 742B je 1000126D
:10001242 663D0D00 cmp ax, 000D
:10001246 7425 je 1000126D
:10001248 663D0E00 cmp ax, 000E
:1000124C 741F je 1000126D
:1000124E 8B4C242C mov ecx, dword ptr [esp+2C]
:10001252 6A30 push 00000030
* Possible StringData Ref from Data Obj ->"Invalid Serial Number"
|
:10001254 68EC910010 push 100091EC
* Possible StringData Ref from Data Obj ->"The serial number is not for
this
"
->"product!"
|
:10001259 6878910010 push 10009178
:1000125E 51 push ecx
* Reference To: USER32.MessageBoxA, Ord:01C3h
|
:1000125F FF15EC800010 Call dword ptr [100080EC]
:10001265 5F pop edi
:10001266 33C0 xor eax, eax
:10001268 5E pop esi
:10001269 83C420 add esp, 00000020
:1000126C C3 ret
* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:10001234(C), :1000123A(C), :10001240(C), :10001246(C), :1000124C(C)
|
:1000126D 6850A20010 push 1000A250
:10001272 E8D9010000 call 10001450
;这个call有点奇怪,但看了后面就知道了
;它可能是把一些特殊的序列号过滤掉
:10001277 83C404 add esp, 00000004
:1000127A 84C0 test al, al
:1000127C 741F je 1000129D
:1000127E 8B54242C mov edx, dword ptr [esp+2C]
:10001282 6A30 push 00000030
* Possible StringData Ref from Data Obj ->"Expired Serial Number"
|
:10001284 6860910010 push 10009160
* Possible StringData Ref from Data Obj ->"The period for free updates to
"
->"this product has expired."
|
:10001289 6824910010 push 10009124
:1000128E 52 push edx
* Reference To: USER32.MessageBoxA, Ord:01C3h
|
:1000128F FF15EC800010 Call dword ptr [100080EC]
:10001295 5F pop edi
:10001296 33C0 xor eax, eax
:10001298 5E pop esi
:10001299 83C420 add esp, 00000020
:1000129C C3 ret
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:1000127C(C)
|
:1000129D 5F pop edi
;正常的应该到达这
:1000129E B801000000 mov eax, 00000001
;eax为1表示通过检查
;简单的crack可以设置eax恒为1即可,
;当然,我们不满足于仅仅crack,
;下面我们来分析其注册过程,
:100012A3 5E pop esi
:100012A4 83C420 add esp, 00000020
:100012A7 C3 ret
××××××××××××××××××××××××××××××××××××××
pediy03_00088.html
注意:上传附件及图片大小不得大于30M。
⚠️ 版权声明:
本博客所有内容(含教程、源码、工具)仅供个人技术学习与研究交流使用,严禁商用、倒卖、二次分发及非法用途。
未经作者书面授权,任何组织或个人不得转载、复制或用于其他平台,违者将追究相关责任。
复制成功
