playboysen 发表于 2008-6-18 15:19:06

PDFcamp Printer (PDF Writer) V2.2 最新版算法分析及注册机源码

标 题: 【原创】PDFcamp Printer (PDF Writer) V2.2 最新版破解分析
作 者: playboysen
时 间: 2008-06-18


【文章标题】:【原创】PDFcamp Printer (PDF Writer) V2.2 最新版破解分析
【文章作者】: playboysen
【作者邮箱】: [email protected]
【作者相册】: playboysen2.photo.163.com
【软件名称】: PDFcamp Printer (PDF Writer) V2.2
【使用工具】: ollydbg
【操作平台】: Windows XP SP2
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!


      接触破解一年多,付出的心血多少自己知道,每天面对一堆的汇编指令,多少次想到了放弃,但是最终还是坚守住了自己的兴趣,一年多来经手的软件不下200个,大多是对她们实行”**“,只因水平不高,还看不太懂算法,这个小程序是我算法分析的**作,虽然简单,但是整体分析下来却很不易,希望能给小鸟一点提示,高手掠过:
      
      PDFcamp Printer,可以将doc、xls、ppt、txt文档直接“打印”成pdf文件,未注册版本试用30天,且转换后的pdf文件有水印。程序只有几百K,安装后在安装目录中没有主文件,经过半天的摸索才找到如何注册,汗,呵呵,随便打开一个word文档,选择“文件”——“打印(Ctrl+P)”,调出打印框后点“属性”可以看到它的界面,在About选项卡中就有注册框了,如图1

      大家看到了,只有一个文本框,没有机器码和用户名输入提示,输入任意假码后点“Register”,弹出提示框 “Your register number error ……”,用Wsyscheck查看word.exe加载的模块发现两个可疑dll—— pdfui.dll和pdfprn.dll(而且这两个文件是加了UPX壳的),由此猜测它是dll文件注册类型
      
      打开任意一个word文档,OD附加word.exe,bp GetWindowTextA下断后点注册,OD提示断下,Alt+F9返回后F8单步032961D9    8BB424 D0000000 mov   esi, dword ptr
032961E0    8B3D 04112903   mov   edi, dword ptr          ; USER32.GetDlgItemTextA
032961E6    8D4C24 4C       lea   ecx, dword ptr
032961EA    68 80000000   push    80
032961EF    51            push    ecx
032961F0    68 EC030000   push    3EC
032961F5    56            push    esi
032961F6    FFD7            call    edi
032961F8    8D5424 0C       lea   edx, dword ptr
032961FC    6A 40         push    40
032961FE    52            push    edx
032961FF    68 EF030000   push    3EF
03296204    56            push    esi
03296205    FFD7            call    edi
03296207    8D4424 0C       lea   eax, dword ptr          ; 取假码
0329620B    8D4C24 4C       lea   ecx, dword ptr
0329620F    50            push    eax                              ; 假码入栈
03296210    51            push    ecx
03296211    E8 FA220000   call    03298510                         ; 关键Call,F7跟进
03296216    85C0            test    eax, eax
03296218    0F84 9A000000   je      032962B8                     ;关键跳转,不能跳
0329621E    8D5424 0C       lea   edx, dword ptr
03296222    8D4424 4C       lea   eax, dword ptr 在03296211处F7跟进后到这里03298510    8B5424 08       mov   edx, dword ptr
03298514    85D2            test    edx, edx
03298516    74 27         je      short 0329853F
03298518    803A 00         cmp   byte ptr , 0
0329851B    74 22         je      short 0329853F                   ; 比较输入的注册码是否为空
0329851D    57            push    edi
0329851E    8BFA            mov   edi, edx
03298520    83C9 FF         or      ecx, FFFFFFFF
03298523    33C0            xor   eax, eax
03298525    F2:AE         repne   scas byte ptr es:
03298527    F7D1            not   ecx
03298529    49            dec   ecx
0329852A    5F            pop   edi
0329852B    83F9 0D         cmp   ecx, 0D                        ; ecx中是假码位数,与13相比较,如果注册码小于等于13位就跳向错误
0329852E    7E 0F         jbe   short 0329853F
03298530    52            push    edx
03298531    E8 4AFFFFFF   call    03298480                         ; 唯一的“算法”比较处F7进去
03298536    F7D8            neg   eax
03298538    1BC0            sbb   eax, eax
0329853A    F7D8            neg   eax
0329853C    C2 0800         retn    8在03298531处F7跟进到下面03298483    56            push    esi
03298484    8B7424 20       mov   esi, dword ptr
03298488    8D5424 04       lea   edx, dword ptr
0329848C    57            push    edi
0329848D    8A06            mov   al, byte ptr
0329848F    8A4E 01         mov   cl, byte ptr
03298492    884424 14       mov   byte ptr , al
03298496    32C0            xor   al, al
03298498    52            push    edx
03298499    884424 19       mov   byte ptr , al
0329849D    884C24 0C       mov   byte ptr , cl
032984A1    884424 0D       mov   byte ptr , al
032984A5    E8 D0000000   call    0329857A                         ; 跟踪发现,至此假码第二位的十六进制放入ECX,得知此处为关键比较1,F7跟进
032984AA    8BF8            mov   edi, eax
032984AC    8D4424 18       lea   eax, dword ptr
032984B0    50            push    eax
032984B1    E8 C4000000   call    0329857A                         ; 此处为关键比较2
032984B6    03F8            add   edi, eax                         ; 上面两个call过去后这里的add的作用是:把注册码一二位数值的16进制值分别减去30后,两个余数相加——>结果放到EDI
032984B8    83C4 08         add   esp, 8
032984BB    83FF 08         cmp   edi, 8                           ; EDI必须是8****注册码的第一个约束条件****
032984BE    74 0A         je      short 032984CA
032984C0    5F            pop   edi
032984C1    33C0            xor   eax, eax
032984C3    5E            pop   esi
032984C4    83C4 18         add   esp, 18
032984C7    C2 0400         retn    4
032984CA    807E 02 56      cmp   byte ptr , 56             ; 注册码第三位是“V”
032984CE    74 0A         je      short 032984DA
032984D0    5F            pop   edi
032984D1    33C0            xor   eax, eax
032984D3    5E            pop   esi
032984D4    83C4 18         add   esp, 18
032984D7    C2 0400         retn    4
032984DA    807E 03 32      cmp   byte ptr , 32             ; 注册码第四位是“2”
032984DE    74 0A         je      short 032984EA
032984E0    5F            pop   edi
032984E1    33C0            xor   eax, eax
032984E3    5E            pop   esi
032984E4    83C4 18         add   esp, 18
032984E7    C2 0400         retn    4
032984EA    807E 05 31      cmp   byte ptr , 31             ; 注册码第六位是“1”
032984EE    74 0A         je      short 032984FA
032984F0    5F            pop   edi
032984F1    33C0            xor   eax, eax
032984F3    5E            pop   esi
032984F4    83C4 18         add   esp, 18
032984F7    C2 0400         retn    4
032984FA    8A4E 0F         mov   cl, byte ptr              ; 注册码第十六位的十六进制放入cl
032984FD    33C0            xor   eax, eax
032984FF    80F9 38         cmp   cl, 38                           ; 注册码第十六位是“8”
03298502    5F            pop   edi
03298503    0F94C0          sete    al                               ;如果条件全部满足则al置1
03298506    5E            pop   esi
03298507    83C4 18         add   esp, 18
0329850A    C2 0400         retn    4
0329850D    90            nop
0329850E    90            nop在跟进032984A5的CALL,到这里7C944C36    55            push    ebp
7C944C37    8BEC            mov   ebp, esp
7C944C39    56            push    esi
7C944C3A    8B75 08         mov   esi, dword ptr
7C944C3D    85F6            test    esi, esi
7C944C3F    0F84 B3AA0200   je      7C96F6F8
7C944C45    833D 70C1997C 0>cmp   dword ptr , 1
7C944C4C    0FB606          movzx   eax, byte ptr             ; 假码第二位十六进制放入eax
7C944C4F    0F8F AAAA0200   jg      7C96F6FF
7C944C55    8B0D 30C3997C   mov   ecx, dword ptr       
7C944C5B    0FB60441      movzx   eax, byte ptr
7C944C5F    83E0 08         and   eax, 8
7C944C62    85C0            test    eax, eax
7C944C64    0F85 A4AA0200   jnz   7C96F70E                         ; 这几句没看懂什么功能,但并不影响分析
7C944C6A    0FB60E          movzx   ecx, byte ptr             ; 假码第二位十六进制放入ecx
7C944C6D    46            inc   esi
7C944C6E    83F9 2D         cmp   ecx, 2D                        ; 假码第二位十六进制与“-”连接符比较
7C944C71    8BD1            mov   edx, ecx
7C944C73    74 2A         je      short 7C944C9F
7C944C75    83F9 2B         cmp   ecx, 2B
7C944C78    74 25         je      short 7C944C9F
7C944C7A    33C0            xor   eax, eax
7C944C7C    83F9 30         cmp   ecx, 30                        ; ********************************
7C944C7F    7C 19         jl      short 7C944C9A                   ; 这四句是比较第二位是否为数字
7C944C81    83F9 39         cmp   ecx, 39
7C944C84    7F 14         jg      short 7C944C9A                   ; **************************************
7C944C86    83E9 30         sub   ecx, 30                        ; 假码第二位十六进制减去30——>值放入ECX
7C944C89    83F9 FF         cmp   ecx, -1
7C944C8C^ 74 8A         je      short 7C944C18
7C944C8E    8D0480          lea   eax, dword ptr
7C944C91    8D0441          lea   eax, dword ptr        ; ecx+eax*2(其实这里eax大部分时候是0,那么这句就是把ecx值放入eax)——>值放入EAX
7C944C94    0FB60E          movzx   ecx, byte ptr
7C944C97    46            inc   esi
7C944C98^ EB E2         jmp   short 7C944C7C
7C944C9A    83C9 FF         or      ecx, FFFFFFFF
7C944C9D^ EB EA         jmp   short 7C944C89
7C944C9F    0FB60E          movzx   ecx, byte ptr
7C944CA2    46            inc   esi
7C944CA3^ EB D5         jmp   short 7C944C7A至此分析全部结束,算法过程总结如下:
首先注册码必须大于13位;
注册码第一二位16进制分别减去30后的余数之和必须等于8 ;
注册码第三位必须是 V;
第四位 2 ;
第六位 1 ;
十六位 8 ;

比如这组注册码可用:
17V201playboyse8

注册机及其源码已经放出,详情请看10楼!!

附件在这里:
https://www.chinapyg.com/viewthread.php?tid=34083&extra=page%3D1

[ 本帖最后由 playboysen 于 2008-7-27 07:35 编辑 ]

Nisy 发表于 2008-6-18 15:36:45

不错 搞算法CALL在DLL中的一个不错的下段方法

Nisy 发表于 2008-6-18 16:30:41

这个软件不错 简单跟踪了一下


04B08499    884424 19       MOV BYTE PTR SS:,AL
04B0849D    884C24 0C       MOV BYTE PTR SS:,CL
04B084A1    884424 0D       MOV BYTE PTR SS:,AL               ; 放第一位和第二位
04B084A5    E8 D0000000   CALL pdfui.04B0857A                      ;   关键CALL 下文跟进分析
04B084AA    8BF8            MOV EDI,EAX                              ; 第二位 -30 结果送EDI
04B084AC    8D4424 18       LEA EAX,DWORD PTR SS:            ; 传KEY第一位
04B084B0    50            PUSH EAX
04B084B1    E8 C4000000   CALL pdfui.04B0857A                      ; JMP 到 ntdll.atoi
04B084B6    03F8            ADD EDI,EAX                              ; 余数做加法
04B084B8    83C4 08         ADD ESP,8
04B084BB    83FF 08         CMP EDI,8                              ; 前两位要位 数字 且 余数之和为8
04B084BE    74 0A         JE SHORT pdfui.04B084CA
04B084C0    5F            POP EDI
04B084C1    33C0            XOR EAX,EAX
04B084C3    5E            POP ESI
04B084C4    83C4 18         ADD ESP,18
04B084C7    C2 0400         RETN 4
04B084CA    807E 02 56      CMP BYTE PTR DS:,56               ; 第三位为 V
04B084CE    74 0A         JE SHORT pdfui.04B084DA
04B084D0    5F            POP EDI
04B084D1    33C0            XOR EAX,EAX
04B084D3    5E            POP ESI
04B084D4    83C4 18         ADD ESP,18
04B084D7    C2 0400         RETN 4
04B084DA    807E 03 32      CMP BYTE PTR DS:,32               ; 第四位为 2
04B084DE    74 0A         JE SHORT pdfui.04B084EA
04B084E0    5F            POP EDI
04B084E1    33C0            XOR EAX,EAX
04B084E3    5E            POP ESI
04B084E4    83C4 18         ADD ESP,18
04B084E7    C2 0400         RETN 4
04B084EA    807E 05 31      CMP BYTE PTR DS:,31               ; 第五位为 1
04B084EE    74 0A         JE SHORT pdfui.04B084FA
04B084F0    5F            POP EDI
04B084F1    33C0            XOR EAX,EAX
04B084F3    5E            POP ESI
04B084F4    83C4 18         ADD ESP,18
04B084F7    C2 0400         RETN 4
04B084FA    8A4E 0F         MOV CL,BYTE PTR DS:               ; 第16位为8
04B084FD    33C0            XOR EAX,EAX
04B084FF    80F9 38         CMP CL,38
04B08502    5F            POP EDI
04B08503    0F94C0          SETE AL                                  ; 设置AL
04B08506    5E            POP ESI
04B08507    83C4 18         ADD ESP,18
04B0850A    C2 0400         RETN 4





关键CALL 04B0857A 其实就是判断参数是否为数字 并求其数值

7C944C3A    8B75 08         MOV ESI,DWORD PTR SS:             ; 将参数送地址 ESI
7C944C3D    85F6            TEST ESI,ESI
7C944C3F    0F84 B3AA0200   JE ntdll.7C96F6F8
7C944C45    833D 70C1997C 0>CMP DWORD PTR DS:,1
7C944C4C    0FB606          MOVZX EAX,BYTE PTR DS:            ; 将参数(内存单元的一个字节)做零扩展送EAX
7C944C4F    0F8F AAAA0200   JG ntdll.7C96F6FF
7C944C55    8B0D 30C3997C   MOV ECX,DWORD PTR DS:          ; ECX=20
7C944C5B    0FB60441      MOVZX EAX,BYTE PTR DS:      ; 零扩展并传送至EAX20+EAX*2
7C944C5F    83E0 08         AND EAX,8                              ; 和8做与运算
7C944C62    85C0            TEST EAX,EAX
7C944C64    0F85 A4AA0200   JNZ ntdll.7C96F70E
7C944C6A    0FB60E          MOVZX ECX,BYTE PTR DS:
7C944C6D    46            INC ESI
7C944C6E    83F9 2D         CMP ECX,2D                               ; 是否是 -
7C944C71    8BD1            MOV EDX,ECX
7C944C73    74 2A         JE SHORT ntdll.7C944C9F                  ; 是的话则跳走
7C944C75    83F9 2B         CMP ECX,2B                               ; +
7C944C78    74 25         JE SHORT ntdll.7C944C9F
7C944C7A    33C0            XOR EAX,EAX
7C944C7C    83F9 30         CMP ECX,30                               ; 和 0 比较
7C944C7F    7C 19         JL SHORT ntdll.7C944C9A
7C944C81    83F9 39         CMP ECX,39                               ; 9
7C944C84    7F 14         JG SHORT ntdll.7C944C9A
7C944C86    83E9 30         SUB ECX,30                               ; - 30
7C944C89    83F9 FF         CMP ECX,-1


简单给兄弟解释一下这几句指令:

7C944C4C    0FB606          MOVZX EAX,BYTE PTR DS:            ; 将参数(内存单元的一个字节)做零扩展送EAX
7C944C4F    0F8F AAAA0200   JG ntdll.7C96F6FF
7C944C55    8B0D 30C3997C   MOV ECX,DWORD PTR DS:          ; ECX=7C946CAA =20
7C944C5B    0FB60441      MOVZX EAX,BYTE PTR DS:      ; 零扩展并传送至EAX20+EAX*2
7C944C5F    83E0 08         AND EAX,8                              ; 和8做与运算
7C944C62    85C0            TEST EAX,EAX
7C944C64    0F85 A4AA0200   JNZ ntdll.7C96F70E

我们注意到 ECX为定值 ECX=7C946CAA 且 =20
若参数 为 数字 0123456789则 ECX+EAX*2 结果范围为 7C946D0A ~ 7C946D1C

ECX+30H*2 = 7C946D0A
ECX+39H*2 = 7C946D1C

我们来查看一下该内存的数据 , 发现偶地址全都是数值 84 且 奇地址为 00(因为奇地址我们用不到)


如果是 84 执行 AND EAX,8 结果EAX=0
84H的2进制: 10000100
8的2进制: 00001000

则该跳转不实现 继续向下走 适参数 - 30H, 因为结果要求两个参数 KEY1 + KEY2 = 8, 如果KEY非数字的话 必然不需要继续判断了 肯定KEY1+KEY2 不等于 8所以这几句也可以理解成 判断参数是否为数字

playboysen 发表于 2008-6-18 17:34:07

对了,软件的注册信息是保存在以下两个位置:

"RegisterNO"="17V201playboyse8"


"RegisterNO"="17V201playboyse8"

如果要练手的话,必须同时删除上面两处注册信息才能变回未注册版本,请留意/:023

flyskey 发表于 2008-6-19 00:28:32

不知道怎么回事 我下载后 运行不起来 提示说RPC服务器不可用....

dlzxggh 发表于 2008-6-19 09:18:37

这个能爆破吗?要是能,怎么个爆法

playboysen 发表于 2008-6-19 11:48:19

这个软件很有代表性,没有exe的主程序,只是相当于office的插件,所有功能用dll文件来实现,而且dll文件是加了壳的,要爆破当然可以,你要做的有以下几步:
    1.想办法找到主程序dll和实现注册功能的dll(有的程序并不是一个dll)
    2.对dll文件常规脱壳,并修复重定位表(前提是此文件加的壳比较简单,且没有自校验)
    3.反汇编去找关键并修改保存
    可以看到,整个过程是比较痛苦的,而且你不能保证爆破后的软件百分之百没有暗桩,所以如果有可能,这类程序还是尽量去分析算法或者去跟踪注册码,相应还省力一些的。

playboysen 发表于 2008-7-20 18:51:26

原帖由 flyskey 于 2008-6-19 00:28 发表 https://www.chinapyg.com/images/common/back.gif
不知道怎么回事 我下载后 运行不起来 提示说RPC服务器不可用....
对不起,你说了这个问题以后我就开始进行了反复测试,终于找到了问题的症结,呵呵
因为本软件是虚拟打印机,所以你的打印机相关服务必须是“启动”的,而现在深度或者番茄的精简XP等都对系统服务进行了优化,打印机相关服务默认是“禁止”的,所以会导致无法安装。解决的方法是:
开始——运行——输入“services.msc”
会打开“本地服务设置”,往下找在print Spooler上双击将其设置成“启动”即可(具体设置如下图)

playboysen 发表于 2008-7-27 07:33:41

顺便写出注册机,源码公布如下(Delphi 7.0编译通过):
procedure TForm1.btn1Click(Sender: TObject);
var
a,b,c,Temp:integer;
begin
    randomize; //初始化随机数
    repeat
    a:=Random(10);
    b:=Random(10);
    c:=Random(10);
    Temp:=a + b;
    until Temp=8;
    Form1.Edit1.Text:=IntToStr(a) + IntToStr(b) + 'V2'+IntToStr(c)+'1Senhuan018';
end;

end.

[ 本帖最后由 playboysen 于 2008-7-27 08:06 编辑 ]
页: [1]
查看完整版本: PDFcamp Printer (PDF Writer) V2.2 最新版算法分析及注册机源码