• 标 题:Pexplorer 1.70 完全破解(KeyFile&Name+Code),附注册机~~~~~~~~~ (17千字)
  • 作 者:Sam.com
  • 时 间:2002-4-3 5:22:52
  • 链 接:http://bbs.pediy.com

名称:Pexplorer 1.70 中文版
下载:汉化新世纪

简介:一个强大的汉化工具,可以直接查看、修改软件的资源,包括菜单、对话框、字符串表等;另外,还具备有 W32DASM 软件的反编译能力和PEditor 软件的PE文件头编辑功能;该软件支持插件,你可以通过增加插件加强该软件的功能,该工具中捆绑了一个可以解开用 UPX 0.8-UPX 1.20版本加壳的软件的插件.

保护:KeyFile&Name+Code
原因:纯属练习
工具:Trw,DeDe 2.5中文版,WinHex,D_Peeper(可查看Delphi程序的控件等信息)


经过:此软件下载后是已经注册了的,刚开始我是拿1.60来开刀的,因为当时1.70我还没安装,确定了它的KeyFile找到算法后安装了1.7,发现它的KeyFile没变,而且还在帮助菜单多了个注册项,于是研究它的Name+Code算法,所以推迟几天发布此文.我们先来研究它的KeyFile,这样到研究注册码时就会很好理解.它的主程序是Delphi写的,没加壳,在安装目录下发现pexdata.rdat文件,改名后变成未注册版,KeyFile只有512字节,不算大,用WinHex打开它

00000000:  43 2C 0F C4-C5 49 1D 4F-38 40 33 D0-86 9E DA 48  C,呐IO8@3袉炡H
00000010:  72 CB 97 B9-AE 25 60 42-53 DB 1F 7D-4C 54 D8 1E  r藯巩%`BS?}LT?
00000020:  6D B5 5F 08-65 16 A8 9D-91 4B A0 77-5A 89 67 7A  m礯e慘爓Z塯z
00000030:  62 B2 DC 49-45 86 E0 39-43 A2 54 8D-A7 F7 58 65  b曹IE嗋9C崸鱔e

00000040:  43 2C 0F C4-C5 49 1D 4F-38 40 33 D0-86 9E DA 48  C,呐IO8@3袉炡H
00000050:  72 CB 97 B9-AE 25 60 42-53 DB 1F 7D-4C 54 D8 1E  r藯巩%`BS?}LT?
00000060:  6D B5 5F 08-65 16 A8 9D-91 4B A0 77-5A 89 67 7A  m礯e慘爓Z塯z
00000070:  62 B2 DC 49-45 86 E0 39-43 A2 54 8D-A7 F7 58 65  b曹IE嗋9C崸鱔e
.
.

.
000001F0:  62 B2 DC 49-45 86 E0 39-43 A2 54 8D-A7 F7 58 1E  b曹IE嗋9C崸鱔

----------------------------------------------------------------------------
发现了什么??其实它的内容只有前64个字节,后面的都是重复的,重复8次,共512字节,有点不同的是第512字节应该是65,但KeyFile里是1E,这个有用吗,请往后看,呵呵~~~看来我们分析的范围又缩小了一点.既然它要读KeyFile,那我们就下bpx readfile好了,为了不受其它程序的影响,我们用Trw载入pexplorer.exe,停在程序的入口,这时才下断点,按F5,拦下了,我们非常走运,第一次拦下的地方就是我们要找的,请看下面代码.建议参考一下API的说明,下面的edi就是readfile的参数---文件大小

==Step 1=======================================================
技巧:过了ReadFile一行就要用bpm来设断点了,然后可以用F5,只要程序一读内存的数据就会拦下来了,通常程序还会将这些数据复制到其它的地方,所以发现一个就下一个bpm断点(有限的!),不要有漏网之鱼了.

0187:004074A2  PUSH    BYTE +00
0187:004074A4  LEA      EAX,[ESP+04]
0187:004074A8  PUSH    EAX
0187:004074A9  PUSH    EDI      <-------200h=512
0187:004074AA  PUSH    ESI
0187:004074AB  PUSH    EBX
0187:004074AC  CALL    `KERNEL32!ReadFile`
0187:004074B1  TEST    EAX,EAX  <-------d esi可看到pexdata.rdat的内容已经读到内存里了
0187:004074B3  JNZ      004074BC
0187:004074B5  MOV      DWORD [ESP],FFFFFFFF
0187:004074BC  MOV      EAX,[ESP]
0187:004074BF  POP      EDX
0187:004074C0  POP      EDI
0187:004074C1  POP      ESI
0187:004074C2  POP      EBX
0187:004074C3  RET

==Step 2======================================================
程序在这之前会将pexdata.rdat的内容复制到几个地方,还会比较读出来的文件长度是否是512字节,以上代码略,最后我们来到以下地方,因为pexdata.rdat里的数据都是重复前64字节的,所以后面的数据略,因为经过运算它们的结果都是一样的.

0187:00523322  MOV      DWORD [EBP-08],01FF <---1FFh=511
0187:00523329  PUSHA 
0187:0052332A  MOV      ESI,[EBP-04] <---esi指向KeyFile数据
0187:0052332D  MOV      ECX,[EBP-08]
0187:00523330  XOR      EDX,EDX      <---计数器
0187:00523332  MOV      EBX,3617E418 <---!!
0187:00523337  MOV      EAX,EBX
0187:00523339  XOR      [ESI+EDX],AL <---用AL和第一字节Xor
0187:0052333C  ROR      EBX,1        <---3617E418循环右移
0187:0052333E  XOR      EBX,A5A5A5A5 <---再Xor
0187:00523344  INC      EDX
0187:00523345  DEC      ECX
0187:00523346  JNZ      00523337    <---循环511次,这样pexdata.rdat的数据就面目全非了

最后得到以下数据:
------------------------------------------------------------------------------
018F:016A70CC 5B 85 7E 59 2E 99 50 CC-DC 17 BD 32 52 D1 58 2C [厏Y.橮誊.?R裍,
018F:016A70DC 65 65 65 65 65 65 65 65-65 65 65 65 65 65 65 65 eeeeeeeeeeeeeeee
018F:016A70EC 75 1C 2E 95 8E C6 E5 1E-75 1C 2E 95 8E C6 E5 1E u..晭棋.u..晭棋.
018F:016A70FC 75 1C 2E 95 8E C6 E5 1E-75 1C 2E 95 8E C6 E5 1E u..晭棋.u..晭棋.
------------------------------------------------------------------------------

0187:00523348  POPA   
0187:00523349  LEA      EDX,[EBP-41]
0187:0052334C  MOV      EAX,[EBP-20]
0187:0052334F  ADD      EAX,BYTE +2C
0187:00523352  MOV      ECX,20
0187:00523357  CALL    0040279C    <---这里将上面数据的前32字节复制到内存
0187:0052335C  PUSHA 
0187:0052335D  MOV      EDI,[EBP-0C]
0187:00523360  MOV      ESI,[EBP-10]
0187:00523363  MOV      EAX,[EDI]
0187:00523365  XOR      EAX,[EDI+04]
0187:00523368  MOV      EBX,[EDI+08]
0187:0052336B  XOR      EBX,[EDI+0C] <---这两个Xor可以先不理它
0187:0052336E  MOV      EAX,3617E418
0187:00523373  XOR      [EDI],EAX    <---edi指向数据首位
0187:00523375  MOV      EAX,A935FC2E
0187:0052337A  XOR      [EDI+04],EAX
0187:0052337D  MOV      EAX,57D872B9
0187:00523382  XOR      [EDI+08],EAX
0187:00523385  MOV      EAX,493DB437
0187:0052338A  XOR      [EDI+0C],EAX <---经过这四个数Xor后,数据又变化了

看看我们得到了什么??Caio不就是那个注册用户吗,呵呵呵呵~~~~看来程序的保护还很一般哟
------------------------------------------------------------------------------
018F:0086F81B 43 61 69 6F 00 65 65 65-65 65 65 65 65 65 65 65 Caio.eeeeeeeeeee
018F:0086F82B 65 65 65 65 65 65 65 65-65 65 65 65 65 65 65 65 eeeeeeeeeeeeeeee
------------------------------------------------------------------------------

0187:0052338D  MOV      EAX,[EDI]
0187:0052338F  MOV      [ESI],EAX
0187:00523391  MOV      EAX,[EDI+04]
0187:00523394  MOV      [ESI+04],EAX
0187:00523397  MOV      EAX,[EDI+08]
0187:0052339A  MOV      [ESI+08],EAX
0187:0052339D  MOV      EAX,[EDI+0C]
0187:005233A0  MOV      [ESI+0C],EAX
0187:005233A3  MOV      EAX,[EDI+10]
0187:005233A6  MOV      [ESI+10],EAX
0187:005233A9  MOV      EAX,[EDI+14]
0187:005233AC  MOV      [ESI+14],EAX
0187:005233AF  MOV      EAX,[EDI+18]
0187:005233B2  MOV      [ESI+18],EAX
0187:005233B5  MOV      EAX,[EDI+1C]
0187:005233B8  MOV      [ESI+1C],EAX
0187:005233BB  MOV      EDI,[EBP-04]
0187:005233BE  MOV      EAX,[EDI+20]
0187:005233C1  MOV      [EBP-08],EAX
0187:005233C4  MOV      EAX,[EDI+24]
0187:005233C7  MOV      [EBP-14],EAX <---上面复制数据
0187:005233CA  MOV      EDI,[EBP-0C]
0187:005233CD  MOV      EAX,3617E418
0187:005233D2  XOR      [EDI],EAX
0187:005233D4  MOV      EAX,A935FC2E
0187:005233D9  XOR      [EDI+04],EAX
0187:005233DC  MOV      EAX,57D872B9
0187:005233E1  XOR      [EDI+08],EAX
0187:005233E4  MOV      EAX,493DB437
0187:005233E9  XOR      [EDI+0C],EAX

将数据打回原形,
------------------------------------------------------------------------------
018F:016A70CC 5B 85 7E 59 2E 99 50 CC-DC 17 BD 32 52 D1 58 2C [厏Y.橮誊.?R裍,
018F:016A70DC 65 65 65 65 65 65 65 65-65 65 65 65 65 65 65 65 eeeeeeeeeeeeeeee
018F:016A70EC 75 1C 2E 95 8E C6 E5 1E-75 1C 2E 95 8E C6 E5 1E u..晭棋.u..晭棋.
018F:016A70FC 75 1C 2E 95 8E C6 E5 1E-75 1C 2E 95 8E C6 E5 1E u..晭棋.u..晭棋.
------------------------------------------------------------------------------

0187:005233EC  MOV      EAX,[EDI]    <---这里注意了,程序拿前16字节的数据做运算
0187:005233EE  XOR      EAX,[EDI+04]    用第1和第2个dword相Xor
0187:005233F1  MOV      EBX,[EDI+08]    用第3和第4个dowrd相Xor
0187:005233F4  XOR      EBX,[EDI+0C]    也就是:597E855B xor CC50992E=952E1C75
0187:005233F7  MOV      [EBP-18],EAX            32BD17DC xor 2C58D152=1EE5C68E
0187:005233FA  MOV      [EBP-1C],EBX
0187:005233FD  POPA   
0187:005233FE  MOV      EAX,[EBP-18] <---取出来与[ebp-8]来比较
0187:00523401  CMP      EAX,[EBP-08] <---[ebp-8]里其实就是上面数据第3行的第1个dword
0187:00523404  JNZ      00523454
0187:00523406  MOV      EAX,[EBP-1C]
0187:00523409  CMP      EAX,[EBP-14] <---[ebp-14]里其实就是上面数据第3行的第2个dword
0187:0052340C  JNZ      00523454    <---象这样跳得比较远的应该都是出错的地方
0187:0052340E  MOV      EAX,00549C14
0187:00523413  LEA      EDX,[EBP-62]
0187:00523416  MOV      ECX,21
0187:0052341B  CALL    00403B90    <---这个Call将下面数据中的注册名读出来

注册名以0结尾,这时如果你将Caio改成你自己的名字,程序运行时注册用户就是你了
------------------------------------------------------------------------------
018F:0086F81B 43 61 69 6F 00 65 65 65-65 65 65 65 65 65 65 65 Caio.eeeeeeeeeee
018F:0086F82B 65 65 65 65 65 65 65 65-65 65 65 65 65 65 65 65 eeeeeeeeeeeeeeee
------------------------------------------------------------------------------

0187:00523420  LEA      ECX,[EBP-68]
0187:00523423  MOV      EDX,08
0187:00523428  MOV      EAX,[EBP-1C]

总结:后面的程序根本就没用到KeyFile里40字节后的数据,所以KeyFile的内容只有40字节是有用的,其它的都是垃圾,你可以试一下将其它数据改成其它,程序照样是已注册的.有用数据的关系也很简单,前32字节是存放注册名的,只要前16字节和第33到40字节的关系成立,而KeyFile的大小是512字节的话这个KeyFile就是合法的,因为它的运算过程只用了Xor(例:A xor B=C , C xor B=A),所以我们可以写个注册机来生成一个KeyFile,不然用人工算可就麻烦了,赶快做一个属于你自己的KeyFile吧,哈哈~~~~~~~~~


下面我们来看看注册码的部分~~~~~
==============================================================================
因为1.7可以通过输入注册码来注册,所以也来研究研究吧.按惯例先填入注册名Sam Von和假注册码6767676767676767(注意:输入注册信息后不要直接按回车键,因为光标正处于取消键上,要用鼠标点击或用TAB键,不然你无论如何都拦不下来),为什么是16位,因为下面有比较呀,呵呵.接着就下断点bpx hmemcpy,F5,谁知程序给我来个蓝屏,但下其它断点程序却又正常,照我推断程序应该没有防Debug的地方,可能是程序下面窗口的提示信息在作怪吧.不怕,我们还有其它的工具嘛,先用D_peeper查看它的注册窗口是TrForm,顺便看看它的一些控件以方便作判断,用DeDe打开主程序,过程很顺利,在DeDe的"程序"窗口里点击TrForm,然后在右边的"事件"里双击第一行的Button1Click,可看到下面代码:

***** TRY
|
004B3375  64FF30                push    dword ptr fs:[eax]
004B3378  648920                mov    fs:[eax], esp
004B337B  8D55F4                lea    edx, [ebp-$0C]
004B337E  8B45FC                mov    eax, [ebp-$04]

* Reference to control TrForm.Edit1 : TEdit
|
004B3381  8B8000020000          mov    eax, [eax+$0200]

|
004B3387  E8DCE5F6FF            call    00421968
004B338C  8B55F4                mov    edx, [ebp-$0C] <---过此行打d edx是注册名的保存地址
004B338F  A118A75400            mov    eax, dword ptr [$54A718]

|
004B3394  E81F06F5FF            call    004039B8
004B3399  8D55F4                lea    edx, [ebp-$0C]
004B339C  8B45FC                mov    eax, [ebp-$04]

* Reference to control TrForm.Edit2 : TEdit
|
004B339F  8B8004020000          mov    eax, [eax+$0204]

|
004B33A5  E8BEE5F6FF            call    00421968
004B33AA  8B55F4                mov    edx, [ebp-$0C] <---过此行打d edx是假注册码的保存地址
004B33AD  A1E0A95400            mov    eax, dword ptr [$54A9E0]

|
004B33B2  E80106F5FF            call    004039B8
004B33B7  33C0                  xor    eax, eax
004B33B9  5A                    pop    edx
004B33BA  59                    pop    ecx
004B33BB  59                    pop    ecx
004B33BC  648910                mov    fs:[eax], edx

****** FINALLY

找到程序保存数据的地方后,用bpm来设断点,不一定能拦下,还可能会蓝屏,如果拦不下但没蓝屏退出的话请再次输入注册信息,保持bpm的两个断点(如果失败,请重复上面过程以确定注册信息的保存地址,因为程序退出后地址就会改变了),注意观察内存,最后可发现下面代码,是否很眼熟:-)

0187:0052302E  MOV      CL,65
0187:00523030  MOV      EDX,21
0187:00523035  CALL    00402A8C        <---在内存中放入32个"e"
0187:0052303A  XOR      EAX,EAX
0187:0052303C  MOV      [EBP-08],EAX
0187:0052303F  XOR      EAX,EAX
0187:00523041  MOV      [EBP-0C],EAX
0187:00523044  LEA      EAX,[EBP-45]
0187:00523047  MOV      EDX,[00549C24]
0187:0052304D  CALL    00407954        <---将用户名复制到32个"e"最前端
0187:00523052  LEA      EAX,[EBP-45]
0187:00523055  MOV      [EBP-04],EAX    <---d eax可看到下面内容

018F:0086F81B 53 61 6D 20 56 6F 6E 00-65 65 65 65 65 65 65 65 Sam Von.eeeeeeee
018F:0086F82B 65 65 65 65 65 65 65 65-65 65 65 65 65 65 65 65 eeeeeeeeeeeeeeee

0187:00523058  PUSHA 
0187:00523059  MOV      EDI,[EBP-04]
0187:0052305C  MOV      EAX,3617E418
0187:00523061  XOR      [EDI],EAX
0187:00523063  MOV      EAX,A935FC2E
0187:00523068  XOR      [EDI+04],EAX
0187:0052306B  MOV      EAX,57D872B9
0187:00523070  XOR      [EDI+08],EAX
0187:00523073  MOV      EAX,493DB437  <---其实这里就是读KeyFile的逆过程
0187:00523078  XOR      [EDI+0C],EAX
0187:0052307B  MOV      EAX,[EDI]      <---又来了
0187:0052307D  XOR      EAX,[EDI+04]
0187:00523080  MOV      EBX,[EDI+08]
0187:00523083  XOR      EBX,[EDI+0C]
0187:00523086  MOV      [EBP-08],EAX  <---注意它保存的地址
0187:00523089  MOV      [EBP-0C],EBX      eax=952E1C75
0187:0052308C  POPA                        ebx=1EE5C68E
0187:0052308D  MOV      EAX,[00549C28]
0187:00523092  CALL    00403BE0
0187:00523097  CMP      EAX,BYTE +10  <---比较注册码长度是否为16位
0187:0052309A  JL      NEAR 0052328A      现在让你猜,你能猜出正确的注册码是什么吗?
0187:005230A0  LEA      EAX,[EBP-18]
0187:005230A3  PUSH    EAX
0187:005230A4  MOV      ECX,08
0187:005230A9  MOV      EDX,01
0187:005230AE  MOV      EAX,[00549C28]
0187:005230B3  CALL    00403DE4
0187:005230B8  LEA      EAX,[EBP-1C]
0187:005230BB  PUSH    EAX
0187:005230BC  MOV      ECX,08
0187:005230C1  MOV      EDX,09
0187:005230C6  MOV      EAX,[00549C28]
0187:005230CB  CALL    00403DE4
0187:005230D0  LEA      ECX,[EBP-4C]
0187:005230D3  MOV      EDX,08
0187:005230D8  MOV      EAX,[EBP-08]
0187:005230DB  CALL    004072E8
0187:005230E0  MOV      EDX,[EBP-4C]
0187:005230E3  MOV      EAX,[EBP-18]
0187:005230E6  CALL    00403CF0      <---下面有个跳转,说明这个Call有问题了,上面的几个
0187:005230EB  JNZ      NEAR 0052326A      Call将eax和ebx的数变成ASC码也就是说我们得到
0187:005230F1  LEA      ECX,[EBP-4C]      了2个字符串"952E1C75"和"1EE5C68E",而这个Call
0187:005230F4  MOV      EDX,08            就是用这两个字符串与我输入的假注册码比较,相等
0187:005230F9  MOV      EAX,[EBP-0C]      的话就注册成功了,程序会自动生成一个新的KeyFile
0187:005230FC  CALL    004072E8          如果这里不明白的话请看KeyFile部分
0187:00523101  MOV      EDX,[EBP-4C]
0187:00523104  MOV      EAX,[EBP-1C]
0187:00523107  CALL    00403CF0      <---比较第2部分,和上面是同一个Call
0187:0052310C  JNZ      NEAR 0052326A

-=End=-

==============================================================
下面是KeyFile的注册机,输入注册名后自动生成pexdata.rdat文件,将文件复制到程序的安装目录即可,注册名支持中文名.请将下面源程序保存为.rek文件,用注册机编写器编译,注册机编写器1.69测试通过!注册机的算法很简单,写这个注册机有点困难的是API的调用,API的原型请查找相关资料


.data
szHomePage db "http://www.365hz.net",0
szEmail    db "mailto:ljyljx@163.com",0
szErrMess  db "输入的序列号不正确!",0
szFileName db "pexdata.rdat",0
SizeReadWrite dd ?
szTemp    db 512 dup(0)
.code

;请在声明中加入以下两句
;CreateFileA proto :DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD
;WriteFile proto :DWORD,:DWORD,:DWORD,:DWORD,:DWORD

mov esi,eax
mov eax,65656565h
mov ecx,8
lea edi,szTemp
push edi
rep stosd
pop edi
invoke lstrlen,esi
mov ecx,eax
rep movsb
mov [edi],byte ptr 0
lea edi,szTemp
mov eax,3617E418h
xor [edi],eax
mov eax,0A935FC2Eh
xor [edi+4],eax
mov eax,57D872B9h
xor [edi+8],eax
mov eax,493DB437h
xor [edi+0Ch],eax
mov eax,[edi]
xor eax,[edi+4]
mov ebx,[edi+8]
xor ebx,[edi+0Ch]
mov [edi+32],eax
mov [edi+36],ebx
mov [edi+40],eax
mov [edi+44],ebx
mov [edi+48],eax
mov [edi+52],ebx
mov [edi+56],eax
mov [edi+60],ebx

invoke lstrcpynA,addr szTemp+64,addr szTemp,65
invoke lstrcpynA,addr szTemp+128,addr szTemp,129
invoke lstrcpynA,addr szTemp+256,addr szTemp,257

mov ecx,511
xor edx,edx
mov ebx,3617E418h
PRO1:
mov eax,ebx
xor [edi+edx],al
ror ebx,1
xor ebx,0A5A5A5A5h
inc edx
dec ecx
jnz PRO1

invoke CreateFileA,addr szFileName,0C0000000h,3,0,2,0,0
invoke WriteFile,eax,edi,200h,addr SizeReadWrite,0


=================================================================
下面是生成注册码的注册机,注册名支持中文名.请将下面源程序保存为.rek文件,用注册机编写器编译,注册机编写器1.69测试通过!


.data
szHomePage db "http://www.365hz.net",0
szEmail    db "mailto:ljyljx@163.com",0
szErrMess  db "输入的序列号不正确!",0
szErr      db "注册名不能大于32位!",0
szFmt      db "%lX",0
szTemp    db 32 dup(0)
szBuffer  db 17 dup(0)
.code
mov esi,eax
mov eax,65656565h
mov ecx,4
lea edi,szTemp
push edi
rep stosd
pop edi
invoke lstrlen,esi
cmp eax,32
jg ERR

mov ecx,eax
rep movsb
mov [edi],byte ptr 0
lea edi,szTemp
mov eax,3617E418h
xor [edi],eax
mov eax,0A935FC2Eh
xor [edi+4],eax
mov eax,57D872B9h
xor [edi+8],eax
mov eax,493DB437h
xor [edi+0Ch],eax
mov eax,[edi]
xor eax,[edi+4]
mov ebx,[edi+8]
xor ebx,[edi+0Ch]
invoke wsprintf,addr szBuffer,addr szFmt,eax
invoke wsprintf,addr szBuffer+8,addr szFmt,ebx
lea eax,szBuffer
jmp Sam

ERR:
lea eax,szErr

Sam:

-=End=-

      _/_/_/
    _/          _/_/_/  _/_/_/  _/_/
    _/_/    _/    _/  _/    _/    _/
        _/  _/    _/  _/    _/    _/
_/_/_/      _/_/_/  _/    _/    _/

                                              Sam.com
                                          5:04 2002-4-3