• 标 题:解除DLSupCBT的NAG窗和KEY文件制作(一)
  • 作 者:囚童
  • 时 间:2003/07/06 03:09am
  • 链 接:http://bbs.pediy.com

解除DLSupCBT的NAG窗和KEY文件制作(一)

OLLYDBG初级教程,给初学者

作者:囚童[FCG][BCG]
课题:解除DLSupCBT的NAG窗和30天时间限制,制作KEY文件
对象:DLSuperCBT - Byte Compare Differences 2.1e
平台:win95/98/ME, winNT/2000/XP
尺寸:743,936
作者:Don Ludlow
背景:Borland's Delphi 5,无壳
下载:http://www.dlsuperc.com/dlsupcbtni.zip
工具:OllyDbg v1.09 修正汉化版
   Ultraedit-32

通过这篇文章我们将向你介绍在OllyDbg中:

●如何设置/取消断点
●如何设置/取消硬件断点
●如何修改和永久保存代码
●如何用“回溯法”来跟踪数据源。
●如何修改主窗口标题栏
●如何查找KEY文件的关键项

在示例中我们还用到了一种颇有新意的演示跟踪过程的表达方法[首创]。

DLSupCBT 是一个按字节进行再同步比较的文件处理工具。它比较二进制文件之间的不同,在
不匹配的字节中进行再同步。在相邻行中以ASCII方式报告十六进制代码的不同。允许使用偏
移值在两个文件中进行局部比较。两个文件之间的变化可以添加到新的文件或从旧的文件删
除。在文件之间出现数据移位时,它具有与大多数其它按字节进行比较的文件处理工具不同的
特色,它显示具有指导意义的结果。换句话说,当字节数增加或减少时,大多数其它按字节进
行比较的文件处理工具不能够使自己再同步,而DLSupCBT可以再同步这种变化。

个人和非盈利组织在作者网站上可以免费注册。但我注册后,收到作者两封回信,声称:
“Attached is your registered package containing the DLSuperCBT program.”实际什
么也没有。

即便这样,我们在研究它时也不再有什么担心了。

下面的内容按由浅入深分层次来讲:

如果你是一个初学者,你只需要看**一楼**里的内容.

如果你是一个有心的初学者,你可以看一下**二楼**里的内容.

如果你是一个有耐心的初学者,你最好看一下**三楼**里的内容.

我们开始。

解除NAG窗

先试运行下载来的DLSupCBT,显示是一个30天试用版本。调整一下时间,只有一个NAG窗,好
象没有什么时间制。时间限制版本的意思是讲,超过时间限制,继续拥有时间限制版本将是违
法的。但有可能作者并没有采取技术措施来限制。

**一楼(入门)**
启动OLLYDBG,点菜单“文件/打开(或按F3)”将DLSupCBT装入OLLYDBG,按F9运行。

等到NAG窗出现,点OLLYDBG,使OLLYDBG成为活动窗口。
按F12暂停,按CTRL+F9(执行到返回),OLLYDBG将停留在返回指令RETN处,连续按CTRL+F9,
直到OLLYDBG不再响应。
点DLSupCBT,使DLSupCBT成为活动窗口。点“YES USE”按钮,此时OLLYDBG被激活,我们来
到OLLYDBG的CPU窗口:

00449A59  |. CALL DLSupCBT.004497D8
00449A5E  \. RETN                        //光标停在这里,按F8单步跳过
00449A5F   .^JMP DLSupCBT.0040372C
00449A64   .^JMP SHORT DLSupCBT.00449A56
00449A66   . XOR EAX,EAX                 //上面按F8后,光标停在这里
00449A68   . POP EDX
00449A69   . POP ECX

向上看,没有发现可疑的条件跳转。
继续按CTRL+F9,来到:

00449AED   > MOV EAX,DWORD PTR SS:[EBP-10]
00449AF0   . MOV DWORD PTR DS:[480950],EAX
00449AF5   . MOV EAX,DWORD PTR SS:[EBP-4]
00449AF8   . AND BYTE PTR DS:[EAX+2CC],0F7
00449AFF   . RETN                        //光标停在这里,按F8
00449B00   .^JMP DLSupCBT.0040372C
00449B05   .^JMP DLSupCBT.00449A73
00449B0A   . XOR EAX,EAX                 //上面按F8后,光标停在这里。
00449B0C   . POP EDX                     //向上看,没有发现可疑的条件跳转,
00449B0D   . POP ECX                     //继续按CTRL+F9
00449B0E   . POP ECX
00449B0F   . MOV DWORD PTR FS:[EAX],EDX
00449B12   . PUSH DLSupCBT.00449B27
00449B17   > LEA EAX,DWORD PTR SS:[EBP-20]
00449B1A   . CALL DLSupCBT.00403C94
00449B1F   . RETN                        //光标停在这里,按F8
00449B20   .^JMP DLSupCBT.0040372C
00449B25   .^JMP SHORT DLSupCBT.00449B17
00449B27   . MOV EAX,DWORD PTR SS:[EBP-8]//上面按F8后,光标停在这里。
00449B2A   . POP ESI               //向上看,没有发现可疑的条件跳转,继续按CTRL+F9
00449B2B   . POP EBX
00449B2C   . MOV ESP,EBP
00449B2E   . POP EBP
00449B2F   . RETN                        //光标停在这里,按F8

按F8后,来到:

00478357   > MOV EAX,DWORD PTR SS:[EBP-4]
0047835A   . CMP BYTE PTR DS:[EAX+6AF],0       //可疑的条件跳转,双击设断
00478361     JE DLSupCBT.004783EE
00478367   . MOV EAX,DWORD PTR DS:[5A2F8C]
0047836C   . MOV EAX,DWORD PTR DS:[EAX+2E0]
00478372   . MOV EDX,DLSupCBT.00478B40  ;  ASCII "DLSuperCBT 30 Day Trial Version"
                .
                .
                .
004783D3   . MOV EAX,DWORD PTR DS:[4813CC]
004783D8   . MOV EAX,DWORD PTR DS:[EAX]
004783DA   . MOV EDX,DWORD PTR DS:[EAX]
004783DC   . CALL DWORD PTR DS:[EDX+D8]         //这是显示NAG的CALL
004783E2   . MOV EAX,DWORD PTR DS:[4813CC]      //光标停在这里,向上看
004783E7   . MOV EAX,DWORD PTR DS:[EAX]
004783E9   . CALL DLSupCBT.00449874

向上看47835A处是一个可疑的条件跳转,双击47835A左边第二栏设断(或按F2),0047835A将
变为红色,表示这里是一个断点。

仔细看下面的程序,4783DC是显示NAG的CALL,如果47835A处跳,显然NAG不会再显示。

强制跳转的方法很简单:重启后按F9运行,OLLYDBG将中断在47835A。将光标指向478361,按
空格键,OLLYDBG弹出一个汇编窗口,先把“用NOP填充”打上勾,然后将编辑框中的JE改写为
JMP,点“汇编”,看到什么?JE DLSupCBT.004783EE变成了红色的JMP DLSupCBT.004783EE,
后面不足的部分还自动补上了NOP。试着按一下F9运行,NAG窗不见了,DLSupCBT主窗口左下角
的一行字“DLSuperCBT 30 Day Trial Version”也不见了。

如果改好了以后,右键选“复制到可执行文件”,可以将改变永久保存。

我们已经知道,可以通过直接修改代码来解除NAG窗。

**一楼(结束)**

**二楼(更上一层楼)**

但我们不这样做,因为解除软件的限制可能要修改多处代码。

重新运行DLSupCBT,OLLYDBG将中断在47835A。
看OLLYDBG左边反汇编窗和DUMP窗中间夹着的部分,显示:DS:[00E72143]=01。
这是什么?这是告诉你[EAX+6AF]中的具体值为1,怪不得不跳呢。

如果你将光标指向这一行,按右键并选“修改数据”,你可以在修改数据窗口将01改为00,
再运行下去,NAG窗同样消失。

但我们不这样改。我们要找到它的根。

在OLLYDBG的CPU窗口的左下方是DUMP窗口,在DUMP窗口点一下HEX跟随栏,然后按CTL+G,在弹
出的转存跟随窗口中输入E72143,点“确定”。下面的DUMP窗将显示E72143起始的数据段。
用光标将DUMP窗口字符串第一个十六进制字“01”加亮,右击,在右键菜单上选“断点/硬件
写入/BYTE”,这样,我们就在E72143设置了一个硬件断点。

本来我们也可以设置内存写入断点来完成同样的工作,但它有很多缺点:
①该段数据处于非活动状态时,无法设置断点。
②为了观察数据段的活动状态,必须单独开启一个数据转存窗口。
③程序重启时断点自动清除,无法长时间保存。
④无法浏览内存断点列表。

顺手在上面CPU窗47835A处双击左边第二栏(或按F2),0047835A将变回原来的颜色,表示断
点已清除。

按CTRL+F2,重新开始DLSuperCBT。
按F9,OLLYDBG中断在

按F9运行,OLLYDBG第一次中断在:

0040302A   . REP STOS DWORD PTR ES:[EDI]  //EDI=E72140
                                         //EAX=0

这是一个清空内存操作,不理它。

按F9运行,OLLYDBG第二次中断在:

004780EA   > MOV EAX,DWORD PTR DS:[4815C0]          //=408D01
004780EF   . MOV AL,BYTE PTR DS:[EAX]               //试用版标志来自这里,双击设断
004780F1   . MOV EDX,DWORD PTR SS:[EBP-4]           //
004780F4   . MOV BYTE PTR DS:[EDX+6AF],AL           //光标停在这里,向上看  
004780FA   . MOV EBX,1B

原来E72143中的值01来自[4815C0],这是一个常量,可以在4780EF设断来验证,得知来源地
址为481310,初始值为408D01。验证的方法算作一道作业,你自己去做。

按ALT+B(或在工具栏上点蓝色的方形“B”按钮)调出断点窗口,将光标指向00478336处,按
右键并选“DISABLE”(或直接按空格键)使断点处于非激活状态。

事实上,408D01是未注册版标志,408D00是注册版标志。用ULTRAEDIT很容易将408D01改为
408D00(在7FB10),NAG窗消失。我们不这样做。


或许你要问:DLSupCBT主窗口左下角的一行字“DLSuperCBT 30 Day Trial Version”不见
了,但原地还留有一个“a”,是不是没有解干净?

问得好。我们来查验一下。

当光标指向这个“a”时,出现“Registered User for Program”的黄色提示。

就是说,有了这个'a',恰恰意味着当前是正版。

不过,当光标指向“DLSuperCBT 30 Day Trial Version”时,也同样会出现“Registered
User for Program”的黄色提示。这与“DLSuperCBT 30 Day Trial Version”实际并没有时
间限制一样自相矛盾。

我们现在知道了从注册标志着手,比简单地改跳转要可靠,而且可能有较少的工作量。

剩下的问题是主窗口的标题栏还有"(UnRegistered) DLSuperCBT Resynchronizing Byte
Compare Program"的字样。它与'a'显得格格不入。

尝试了一些办法,比如内存搜索、资源分析,都没有找到上面的字符串。也没有发现有从文件
或注册表之类的地方读出。

或许是拼接?有道理。上面字符串的片断确实存在。

试着在内存中搜索"(UnRegistered)",倒是有一个,但跟踪下去就没有了结果。"DLSuperCBT"
也有不少,也没跟出什么结果。

好,我们盯上" Resynchronizing Byte Compare Program"了。

按CTRL+F2,重新开始DLSuperCBT。
按CTL+B,调出二进制搜索窗口,先将“整个段块”勾上,
在ASCII栏内键入“ Resynchronizing”,点“确定”,来到:

00478984   . 20 52 65 73 79>ASCII " Resynchronizing"
00478994   . 20 42 79 74 65>ASCII " Byte Compare Pr"
004789A4   . 6F 67 72 61 6D>ASCII "ogram",0

用光标将478984这一行加亮,右键选“在转存中跟随数值”,在OLLYDBG的CPU窗口的左下方的DUMP
窗将显示478984起始的代码段。

用光标将DUMP窗口字符串第一个十六进制字“20”加亮,右击,在右键菜单上选“断点/硬件
访问/BYTE”。

按F9,OLLYDBG中断在:

00402990  |. FD             STD
00402991  |. F3:A5          REP MOVS DWORD PTR ES:[EDI],DWORD PTR DS:[ESI]
00402993  |. 89C1           MOV ECX,EAX
00402995  |. 83E1 03        AND ECX,3
00402998  |. 83C6 03        ADD ESI,3
0040299B  |. 83C7 03        ADD EDI,3
0040299E  |. F3:A4          REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[ESI]
004029A0  |. FC             CLD                                         //光标停在这里

REP MOVS是一个数据传送指令,按指定的长度将数据由DS:ESI传送到DS:EDI。STD意味着从
后向前传送。

看看右面寄存器窗中的EDI,它指向字符串" Resynchronizing Byte Compare Program"前面的
一个值"T"。这个"T"隐含着什么?我们来看一下。

用光标将右面寄存器窗中的EDI的值00E8EE71加亮,右键选“在转存中跟随数值”,下面的
DUMP窗将显示E8EE71起始的数据段。

向上调整DUMP窗的滑块,我们看见什么?

00E8EE51                       20
00E8EE59  28 55 6E 52 65 67 69 73  (UnRegis
00E8EE61  74 65 72 65 64 29 20 44  tered) D
00E8EE69  4C 53 75 70 65 72 43 42  LSuperCB
00E8EE71  54 20 52 65 73 79 6E 63  T Resync
00E8EE79  68 72 6F 6E 69 7A 69 6E  hronizin
00E8EE81  67 20 42 79 74 65 20 43  g Byte C
00E8EE89  6F 6D 70 61 72 65 20 50  ompare P
00E8EE91  72 6F 67 72 61 6D        rogram

哈,刚拼接出来的窗口标题!那么,标题的前半部分又是从哪里来的呢?

仔细看一下右面寄存器窗中的EBX,它指向字符串" (UnRegistered) DLSuperCBT",恰恰就是
那前半部分。

用光标将右面寄存器窗中的EBX的值00E8EBA0加亮,右键选“在转存中跟随数值”,下面的
DUMP窗将显示E8EBA0起始的数据段。


我们尝试使用“回溯法”来找到它的来源。

用我们前面用过的老办法,用光标将DUMP窗口字符串第一个十六进制字“20”加亮,右击,在
右键菜单上选“断点/硬件写入/BYTE”。

点菜单“调试/硬件断点”调出“硬件断点”窗,可以看到已经有了两个硬件断点。将478984
的断点删除。

按CTRL+F2,重新开始DLSuperCBT。

按F9,OLLYDBG产生一个中断。我们看到右面寄存器窗中ECX的值为E8EBA0,这表明E8EBA0所在的段
已经是活动段,我们可以跟随了。如果它是非活动的,可以继续按F9,直到它处于活动状态。

用光标将右面寄存器窗中的ECX的值00E8EBA0加亮,右键选“在转存中跟随数值”,下面的
DUMP窗将显示E8EBA0起始的数据段。

盯着CPU窗口左下方的DUMP窗口,连续按动F9,直到DUMP窗口中出现" Resynchronizing Byte
Compare Program"。

从CPU窗口可以看出,当前仍然是REP MOVS数据传送指令,看一下ESI-1的值,是0012FA8C,处
于堆栈中。堆栈的使用是相当频繁的,继续用原来的方法回溯,耗时费力。

我们可以这样:

点菜单“调试/硬件断点”调出“硬件断点”窗。将E8EBA0的断点删除。

连续按两下CTRL+F9,再按一下F8,来到:

00478165   . 8D55 81        LEA EDX,DWORD PTR SS:[EBP-7F]
00478168   . 8D85 74FCFFFF  LEA EAX,DWORD PTR SS:[EBP-38C]
0047816E   . E8 E9A9F8FF    CALL DLSupCBT.00402B5C
00478173   . BA 508A4700    MOV EDX,DLSupCBT.00478A50           ;  ASCII 0B," DLSuperCBT"
00478178   . 8D85 74FCFFFF  LEA EAX,DWORD PTR SS:[EBP-38C]
0047817E   . B1 65          MOV CL,65
00478180   . E8 A7A9F8FF    CALL DLSupCBT.00402B2C
00478185   . 8D95 74FCFFFF  LEA EDX,DWORD PTR SS:[EBP-38C]        //在这里设断
0047818B   . 8D85 DCFCFFFF  LEA EAX,DWORD PTR SS:[EBP-324]
00478191   . E8 22BDF8FF    CALL DLSupCBT.00403EB8
00478196   . 8B95 DCFCFFFF  MOV EDX,DWORD PTR SS:[EBP-324]         //光标停在这里

我们将这称作“向上回溯两级”。本来我们想把将新的断点设在478185。但向上一看,478173
引用了" DLSuperCBT",这种字符串前面加空格的做法显然是为了拼接。于是我们根据478191
的CALL的处理结果,推断478173之前,内存中应该已经有了“(UnRegistered)”。于是我们尝
试将新的断点设在478165。

重启DLSuperCBT,OLLYDBG中断在478165。

看OLLYDBG左边CPU窗和DUMP窗中间夹着的部分,显示:

Stack Address=0012FD99, (ASCII 0F, " (UnRegistered)")

如果再向上回溯,我们会发现,12FD99中的字符串" (UnRegistered)",是由另一个串
")XdXe8rXe2t4sXiXgXe2R4n6U8("(怎么样?似曾见过?在跟E8EBA0时?)经过4780E8至
478165的程序解密而来的。

此时只要将12FD99改为ASCII 0D, " (Registered)",标题栏将显示:

"(Registered) DLSuperCBT Resynchronizing Byte Compare Program"


由于我们的指导思想是:“不打菩萨”--不改动原作。所以我们另外编了一个小小的
LOADER(“再塑金身”),在入口处将4815C0的值408D01改为408D00,在4780E8将12FD99的值
ASCII 0F," (UnRegistered)"改为ASCII 0D, " (Registered)",然后直接跳到478165,不再
运行中间那一段解密程序。编写LOADER不是本文要讨论的内容,不再赘述。

大功告成,俨然一个正版。

解除DLSupCBT的NAG窗和KEY文件制作(二)

KEY文件制作

根据我们的“不打菩萨”的指导思想,能不能在主程序之外找到解决问题的办法呢?
有,甚至都可以不“再塑金身”。那就是KEY文件。

分析一下我们走过的路:

因为在47835A有DS:[EAX+6AF]=1才出现了NAG。我们人为地使DS:[EAX+6AF]=0成功地消除了
NAG。那注册版本一定在47835A之前有行动使DS:[EAX+6AF]=0。顺着这个思路我们从47835A
向上看,哇,这里似曾相识:

0047830F   > MOV EAX,DWORD PTR DS:[48146C]          //=408D00
00478314   . MOV AL,BYTE PTR DS:[EAX]
00478316   . MOV EDX,DWORD PTR SS:[EBP-4]
00478319   . MOV BYTE PTR DS:[EDX+6AF],AL

是不是长得与4780EA那一段象一对双胞胎?哪里不同呢?哈,第一行的地址常量不同,一个是
[4815C0]=01,一个是[48146C]=00(做过作业了么?)。显然,[48146C]里放的是正版标志。

那么,程序是怎样启动这个正版标志的呢?

下面我们给出启动这个正版标志的一段程序示例:

我们认为你是已经具有相应能力的读者,所以没有给出具体是怎样跟踪的,注释也不完整,相
信通过你自己的努力,完全可以看懂。

*******************************************************************

示例中用到的表达方法[首创]:

=>:跟进当前CALL

<=(XXXXXX):从XXXXXX的CALL中返回

<= 寄存器=值:从上一行的CALL返回的寄存器的值

行地址前面的0的个数和缩进可以区分该行所在的调用层次

********************************************************************

=>000445CE9   . CALL DWORD PTR DS:[EBX+2B8]=00476C38

/004780EA   > MOV EAX,DWORD PTR DS:[4815C0]
|004780EF   . MOV AL,BYTE PTR DS:[EAX]
|004780F1   . MOV EDX,DWORD PTR SS:[EBP-4]
|004780F4   . MOV BYTE PTR DS:[EDX+6AF],AL//=01,来自[481310]=01
|                 .                           00E72143 00//置未注册版标志
|                 .
|                 .
|                 .
|0047812E   . MOV EDX,DLSupCBT.00481384 //=")XdXe8rXe2t4sX"
|                      ||                              // "iXgXe2R4n6U8("
|                     \||/    解密窗口标题
|                      \/
|00478189   . LEA EDX,DWORD PTR SS:[EBP-7F]=" (UnRegistered)"
|
|=>004781F9   . CALL DLSupCBT.00408934

   0408934  /$ PUSH EBX
   0408935  |. MOV EBX,EAX
   0408937  |. MOV EAX,EBX
   =>0408939  |. CALL DLSupCBT.004088CC
 
      4088D8  |. LEA EAX,DWORD PTR SS:[EBP-14C][0012F8F8]=00E917F4
      4088DE  |. PUSH EAX                                          //DLSupCBT.lic
      4088DF  |. MOV EAX,EBX
      4088E1  |. CALL DLSupCBT.004040D8
      4088E6  |. PUSH EAX                           ; |FileName
      4088E7  |. CALL <JMP.&kernel32.FindFirstFileA>; \FindFirstFileA
      4088EC  |. CMP EAX,-1             <= ax=0013E240(A4)(REG) ax=ffffffff(2.1E)
      4088EF  |. JE SHORT DLSupCBT.00408925//跳(UNREG)
      4088F1  |. PUSH EAX                      ; /hSearch//不跳(REG)
      4088F2  |. CALL <JMP.&kernel32.FindClose>; \FindClose
      4088F7  |. TEST BYTE PTR SS:[EBP-14C],10               //[0012F8F0]=20(REG)
      4088FE  |. JNZ SHORT DLSupCBT.00408925
      408900  |. LEA EAX,DWORD PTR SS:[EBP-C]              //[12FA30]=E711EC(REG)
      408903  |. PUSH EAX                      ;/pLocalFileTime
      408904  |. LEA EAX,DWORD PTR SS:[EBP-138];|[12F904]=36FBD300(REG)
      40890A  |. PUSH EAX                      ;|pFileTime
      40890B  |. CALL <JMP.&kernel32.FileTimeT>;\FileTimeToLocalFileTime
      408910  |. LEA EAX,DWORD PTR SS:[EBP-4]            //[12FA38]=00476FA4(REG)
      408913  |. PUSH EAX                    ;/pDOSTime
      408914  |. LEA EAX,DWORD PTR SS:[EBP-2];|[12FA3A]=FE180047(REG)
      408917  |. PUSH EAX                    ;|pDOSDate
      408918  |. LEA EAX,DWORD PTR SS:[EBP-C];|[12FA30]=451F1300(REG)
      40891B  |. PUSH EAX                    ;|pFileTime
      40891C  |. CALL <JMP.&kernel32.FileTim>;\FileTimeToDosDateTime
      408921  |. TEST EAX,EAX <=EAX=01 [12FA38]=2ED6887D(REG)
      408923  |. JNZ SHORT DLSupCBT.0040892C
      408925  |> MOV DWORD PTR SS:[EBP-4],-1        //[0012FA44]<=FFFFFFFF(UNREG)
      40892C  \> MOV EAX,DWORD PTR SS:[EBP-4]       //[12FA38]=2ED6887D(REG)
   <=(408939) eax=ffffffff(UNREG无DLSupCBT.lic) eax=2ED6887D(REG 有DLSupCBT.lic)
   
  040893E  |. INC EAX                 //eax=0 Zf=1(UNREG) eax=2ED6887E(REG) Zf=0
  040893F  |. SETNE AL                //ZF取反 AL=0(UNREG) AL=01(REG)
|<=(4781F9) AL=0(UNREG) AL=1(REG)
|    
|004781FE   . TEST AL,AL  《 AL=01(REG)<= AL=00(UNREG)
|00478200   . JE DLSupCBT.00478357
|    
|=>0047825F   . CALL DWORD PTR DS:[EBX+40]           ;  DLSupCBT.00453114
  =>0453167  |. CALL DWORD PTR DS:[EBX+38]           ;  DLSupCBT.0045300C

     453067  |. MOV EAX,DWORD PTR DS:[EBX+4][E91AF4]            //="DLSupCBT.lic"
     45306A  |. CALL DLSupCBT.004040D8
     45306F  |. PUSH EAX                           //<= EAX=E91AF4 "DLSupCBT.lic"
     453070  |. PUSH 4000                          //允许字符串值的最大长度
     453075  |. MOV EAX,DWORD PTR SS:[EBP-8]
     453078  |. PUSH EAX                           //ReturnBuffer=00E935C8
     453079  |. PUSH 0                             //出错返回默认值
     45307B  |. PUSH 0                             //读取的的键 (Key) 名称
     45307D  |. MOV EAX,ESI
     45307F  |. CALL DLSupCBT.004040D8
     453084  |. PUSH EAX                             ; |读取Section="DLSupCBT"
     453085  |. CALL <JMP.&kernel32.GetPrivateProfil>; \GetPrivateProfileStringA
             |.                                //读取私有文件DLSupCBT.lic中的信息
     45308A  |. TEST EAX,EAX                              <= eax=d读到字节数(REG)
     45308C  |. JE SHORT DLSupCBT.004530B7
     45308E  |. MOV EBX,DWORD PTR SS:[EBP-8]
     453091  |. JMP SHORT DLSupCBT.004530B2
     453093  |> /LEA EAX,DWORD PTR SS:[EBP-C]
     453096  |. |MOV EDX,EBX
     453098  |. |CALL DLSupCBT.00403E4C
     45309D  |. |MOV EDX,DWORD PTR SS:[EBP-C]
     4530A0  |. |MOV EAX,DWORD PTR SS:[EBP-4]
     4530A3  |. |MOV ECX,DWORD PTR DS:[
    =>4530A5  |. |CALL DWORD PTR DS:[ECX+34]=4117FA
      =>411844   . CALL DLSupCBT.00411B24//调用2次

        411B7C  |. INC DWORD PTR DS:[EBX+10]//执行2次,为45318B不跳做准备
                                   ++E91B58(REG)
      <=(411844)
    <=(4530A5)
  <=(0453167)

  =>0453185  |. CALL DWORD PTR DS:[EDX+14]        ;  DLSupCBT.00411A44 //++E91B58

     411A44   . MOV EAX,DWORD PTR DS:[EAX+10]
                                      E91B58 02(REG)
  <=(0453185) eax=0(UNREG) EAX=2(REG)
 0453188  |. MOV ESI,EAX
 045318A  |. DEC ESI
 045318B  |. TEST ESI,ESI ESI                      //=FFFFFFFF(UNREG)
 045318D  |. JL SHORT DLSupCBT.004531D3            //跳(UNREG)
 045318F  |. INC ESI                               //不跳(REG) EAX=2

  =>04531CA  |. |CALL DLSupCBT.00411678            //调用2次
    =>4116B6  |. FF51 34        CALL DWORD PTR DS:[ECX+34]   ;  DLSupCBT.004117FC
      =>411844   . CALL DLSupCBT.00411B24          //调用2次

        411B7C  |. INC DWORD PTR DS:[EBX+10]       //执行2次,为47829F不跳做准备
                                   ++E8F1CC
      <=(411844)
    <=(4116B6)
  <=(4531CA)调用2次EAX=12F9F4(REG)
|<=(47825F) [E8F1CC]=2|
|00478262   . MOV EAX,DWORD PTR SS:[EBP-1C]
|00478265   . PUSH EAX
|00478266   . LEA EAX,DWORD PTR SS:[EBP-398]
|0047826C   . PUSH EAX
|0047826D   . MOV ECX,DLSupCBT.00478A98          ;  ASCII "PgmId"
|00478272   . MOV EDX,DLSupCBT.00478690          ;  ASCII "DLSupCBT"
|00478277   . MOV EAX,DWORD PTR SS:[EBP-10]
|0047827A   . MOV EBX,DWORD PTR DS:[EAX]
|=>0047827C   . CALL DWORD PTR DS:[EBX]            ;  DLSupCBT.00452E40
   
   0452E5A  |. PUSH EAX                                //[E91AF4]="DLSupCBT.lic"
   0452E5B  |. PUSH 800
   0452E60  |. LEA EAX,DWORD PTR SS:[EBP-800]
   0452E66  |. PUSH EAX
   0452E67  |. MOV EAX,DWORD PTR SS:[EBP+C]
   0452E6A  |. CALL DLSupCBT.004040D8
   0452E6F  |. PUSH EAX                          ; EAX=0
   0452E70  |. MOV EAX,EDI
   0452E72  |. CALL DLSupCBT.004040D8
   0452E77  |. PUSH EAX                          ; EAX=00478A98,KEY指向"PgmId"
   0452E78  |. MOV EAX,ESI
   0452E7A  |. CALL DLSupCBT.004040D8
   0452E7F  |. PUSH EAX                           ; |Section = "DLSupCBT"
   0452E80  |. CALL <JMP.&kernel32.GetPrivateProf>; \GetPrivateProfileStringA
                                                    //读KEY
   0452E85  |. MOV ECX,EAX
   0452E87  |. LEA EDX,DWORD PTR SS:[EBP-800]
   0452E8D  |. MOV EAX,DWORD PTR SS:[EBP+8]
   0452E90  |. CALL DLSupCBT.00403D7C

|<=(47827C)
|0047827E   . MOV EDX,DWORD PTR SS:[EBP-398]
|00478284   . LEA EAX,DWORD PTR SS:[EBP-1C]
|00478287   . CALL DLSupCBT.00403D2C
|0047828C   . XOR EAX,EAX
|0047828E   . PUSH EBP
|0047828F   . PUSH DLSupCBT.0047834D
|00478294   . PUSH DWORD PTR FS:[EAX]
|00478297   . MOV DWORD PTR FS:[EAX],ESP
|0047829A   . MOV EAX,DWORD PTR SS:[EBP-14]
|0047829D   . MOV EDX,DWORD PTR DS:[EAX]
|0047829F   . CALL DWORD PTR DS:[EDX+14]
|0047829F   . CALL DWORD PTR DS:[EDX+14][E8F1CC]=2
|004782A2   . CMP EAX,2  <= EAX=02(REG) <= EAX=00(UNREG)
|004782A5   . JNZ DLSupCBT.00478343               //跳(UNREG)
|
|004782AB   . LEA EAX,DWORD PTR SS:[EBP-39C]
|004782B1   . MOV EDX,DLSupCBT.004813A0       ; 指向"(D4DCE3E0D3E2E6)攒汔逾?"
|004782B6   . MOV ECX,7
|004782BB   . CALL DLSupCBT.00403EC4
|004782C0   . MOV EDX,DWORD PTR SS:[EBP-39C]//[4813A0]=(D4DCE3E0D3E2E6)攒汔逾?
|004782C6   . MOV EAX,DWORD PTR SS:[EBP-1C]
|004782C9   . CALL DLSupCBT.00404024
|004782CE   . JNZ SHORT DLSupCBT.00478343                         <= FZ=1(REG)
|004782D0   . 8B45 E8        MOV EAX,DWORD PTR SS:[EBP-18]
|004782D3   . 50             PUSH EAX
|004782D4   . 8D85 60FCFFFF  LEA EAX,DWORD PTR SS:[EBP-3A0]
|004782DA   . 50             PUSH EAX
|004782DB   . B9 A88A4700    MOV ECX,DLSupCBT.00478AA8         ;  ASCII "UserId"
|004782E0   . BA 90864700    MOV EDX,DLSupCBT.00478690         ;  ASCII "DLSupCBT"
|004782E5   . 8B45 F0        MOV EAX,DWORD PTR SS:[EBP-10]
|004782E8   . 8B18           MOV EBX,DWORD PTR DS:[EAX]
|004782EA   . FF13           CALL DWORD PTR DS:[EBX]    ;  DLSupCBT.00452E40 读KEY
|
|00478333   > MOV EAX,DWORD PTR DS:[48146C]                  //[00481314]=00408D00
|00478338   . MOV AL,BYTE PTR DS:[EAX]
|0047833A   . MOV EDX,DWORD PTR SS:[EBP-4]
|0047833D   . MOV BYTE PTR DS:[EDX+6AF],AL=0                 //置注册版标志
\                              00E72143     01
<=(000445CE9)

这个示例展示了REG和UNREG的两条路线:

REG:置未注册版标志/解密窗口标题/在当前目录查找DLSupCBT.lic文件+转换文件的时间格式
  /两者都成功,退出4781F9时置成功标志AL=01/执行47825F以保证在执行47829F时返回
  EAX=02+执行4782C9时返回FZ=1/置注册版标志/到478357去判断是否显示NAG窗(不显示)

UNREG:置未注册版标志/解密窗口标题/在当前目录查找DLSupCBT.lic文件+转换文件的时间格
   式/其中一项不成功,退出4781F9时置失败标志AL=0/带着未注册版标志到478357去判断
   是否显示NAG窗(当然是显示NAG窗喽)

看起来是KEY文件DLSupCBT.lic在决定是否启动注册版标志的。


如果你什么也没有做,程序将按UNREG的路线走。

如果你在当前目录中生成一个长度为0的文件,将它命名为DLSupCBT.lic,你就可以沿着REG的
路线走到47829F。

如果你在SupCBT.lic文件中加入以下内容:

[DLSupCBT]              //在453084你可以看到Section="DLSupCBT"
User=囚童               //随便写的
Password=8765432        //随便写的

你就可以沿着REG的路线走到4782C9。

或许你要问:你怎么知道DLSupCBT要加方括号呢?
我们只能告诉你:积累。在ini文件中,Section是用方括号括起来的段名。

那为什么随便写的KEY写了两条,而不是三条,比如还有COMPANY=呢?
因为在4782A2的条件是2。

因为你还无法走到478333,结果还是和UNREG一样。不过不要气馁,毕竟你已经看到了希望。

我们现在停在4782C9,我们是不是无事可做了呢?来看一下SS:[EBP-39C]指向哪里?
[4813A0]="(D4DCE3E0D3E2E6)攒汔逾?"这是一堆什么东西?老外在什么情况下才用这样的
码?怎么?还是个常量?不会就是PASSWORD吧?

好,不妨试一试。到ULTRAEDIT-32中搜索一下"D4DCE3E0D3E2E6",把它拷贝到.lic文件的
PASSWORD=后面,代替随便写的“8765432”。

如果你跟进了47827C,你会发现Section(DLSupCBT)的两个KEY中,有一个是"PgmId",我们随
便写的KEY中,哪一个会是"PgmId"呢,应该是"PASSWORD"。好,把它换成"PgmId"。

那么,由于4782EA调用的是相同的CALL(452E40),在调用前引用的字符串变量"UserId"就一定
是另一个KEY了。好,把"User"换成"UserId"。

试运行。哈,NAG窗不见了,主窗口标题变成了"(Registered) DLSuperCBT Resynchronizing
Byte Compare Program"。主窗口左下角的一行字“DLSuperCBT 30 Day Trial Version”不见
了,代替它的是“囚童”。怎么样?不错吧。只是“囚童”显得单调了些。来,我们动手把
KEY文件DLSuperCBT.lic再润色一下:

[DLSupCBT]
UserId=This copy of DLSupCBT is licensed to : 囚童
PgmId=攒汔逾?                                         //D4DCE3E0D3E2E6

再运行一次,好多了。


啊哈,这篇文章刚刚写上最后的句号,收到作者的来信:

Sorry. I forgot the attachment.

Don Ludlow

随信附来已注册版本。文件尺寸为743,936,与未注册版本大小相同,只是文件包中多了一个
文件DLSuperCBT.lic。打开来看一下:

[DLSupCBT]
UserId=Registered to 囚童
PgmId=攒汔逾?

哈,作者到底比我强,表达得即精炼又不单调,佩服。