[Transshipment] The Analysis of Algorithm of PDF Password Remover v3.0

 

標 題: 【原創】PDF Password Remover v3.0註冊算法簡單分析
作 者: DarkBoxer
時 間: 2007-07-22,22:40
鏈 接: http://bbs.pediy.com/showthread.php?t=48390

【文章標題】: PDF Password Remover v3.0註冊算法簡單分析
【文章作者】: DarkBoxer暗夜拳師
【軟件名稱】: PDF Password Remover v3.0
【下載地址】: http://www.verypdf.com/pwdremover/pwdremover.exe
【使用工具】: OD
【操作平臺】: WindowsXPsp2
【軟件介紹】: 本軟件可以破解Adobe Acrobat PDF文件高達128-bit加密的“所有者密碼”。未破解“所有者密碼”的PDF文件是不能被編輯和打印的。該程序也可以破解用FileOpen插件加密的文件。破解可以立即完成。破解後的文件可以用各種PDF瀏覽器閱讀而無任何限制。
【作者聲明】: 只是感興趣,沒有其他目的。失誤之處敬請諸位大俠賜教!
-----------------------------------------------------------------------------------------

【詳細過程】
<背景>
今天要拷貝一個PDF文件裏面的代碼,不過有限制,所以就去某網站下載了一個PDF Password Remover v3.0,輕鬆搞定PDF。提供下載的網站給出了2個註冊碼,都可用,嘻嘻~反正今天還有點閒,索性分析下此軟件的註冊算法,結果發現是個軟柿子~~^_^

<脫殼>
軟件是UPX加殼,秒之~
測試試煉碼:12345678901darkboxer

<分析>
0040539D            68 10B54B00     push    004BB510                         ; ASCII "12345678901darkboxer"
004053A2            E8 59F8FFFF     call    00404C00                         ; //這裏就是驗證試煉碼是否正確
004053A7            83C4 04         add     esp, 4
004053AA            85C0            test    eax, eax
004053AC            74 44           je      short 004053F2                   ; //呵呵,爆破點
004053AE            6A 40           push    40
004053B0            68 946A4900     push    00496A94                         ; ASCII "Thank you."
004053B5            68 5C6A4900     push    00496A5C                         ; ASCII "Thanks for purchasing the PDF Password Remover v3.0."
004053BA            56              push    esi
004053BB            FF15 08844800   call    dword ptr [<&user32.MessageBoxA>>; USER32.MessageBoxA
004053C1            51              push    ecx
004053C2            8BCC            mov     ecx, esp
004053C4            896424 10       mov     dword ptr [esp+10], esp
004053C8            68 10B54B00     push    004BB510                         ; ASCII "12345678901darkboxer"
004053CD            E8 686B0700     call    0047BF3A
004053D2            E8 F9FBFFFF     call    00404FD0
004053D7            83C4 04         add     esp, 4
004053DA            C705 D8B54B00 0>mov     dword ptr [4BB5D8], 1
004053E4            6A 01           push    1
004053E6            56              push    esi
004053E7            FF15 04844800   call    dword ptr [<&user32.EndDialog>]  ; USER32.EndDialog
004053ED            E9 86020000     jmp     00405678
004053F2            6A 10           push    10
004053F4            6A 00           push    0
004053F6            68 146A4900     push    00496A14                         ; ASCII "Your registration key is wrong, please double check it and try again."
004053FB            56              push    esi
004053FC            FF15 08844800   call    dword ptr [<&user32.MessageBoxA>>; USER32.MessageBoxA

;跟進404c00
00404C00            83EC 18         sub     esp, 18
00404C03            83C9 FF         or      ecx, FFFFFFFF
00404C06            33C0            xor     eax, eax
00404C08            53              push    ebx
00404C09            56              push    esi
00404C0A            8B7424 24       mov     esi, dword ptr [esp+24]
00404C0E            57              push    edi
00404C0F            8BFE            mov     edi, esi
00404C11            F2:AE           repne   scas byte ptr es:[edi]
00404C13            F7D1            not     ecx
00404C15            49              dec     ecx
00404C16            83F9 14         cmp     ecx, 14                          ; 註冊碼長度必須爲十20(10進制)位
00404C19            74 07           je      short 00404C22                   ; 不滿足就拜拜
00404C1B            5F              pop     edi
00404C1C            5E              pop     esi
00404C1D            5B              pop     ebx
00404C1E            83C4 18         add     esp, 18
00404C21            C3              retn
00404C22            8A06            mov     al, byte ptr [esi]               ; 註冊碼第一位,這裏是‘1’
00404C24            8A4E 01         mov     cl, byte ptr [esi+1]             ; 註冊碼第二位,這裏是‘2’
00404C27            8D5424 0C       lea     edx, dword ptr [esp+C]           ; [edx]就是註冊碼12A45678903darkboxer
00404C2B            32DB            xor     bl, bl                           ; bl清零
00404C2D            52              push    edx
00404C2E            884424 1C       mov     byte ptr [esp+1C], al
00404C32            885C24 1D       mov     byte ptr [esp+1D], bl
00404C36            884C24 10       mov     byte ptr [esp+10], cl
00404C3A            885C24 11       mov     byte ptr [esp+11], bl
00404C3E            E8 AD090600     call    004655F0                         ; //關鍵點,多次被調用
00404C43            8BF8            mov     edi, eax                         ; //由第2位得出的結果->edi
00404C45            8D4424 1C       lea     eax, dword ptr [esp+1C]
00404C49            50              push    eax
00404C4A            E8 A1090600     call    004655F0
00404C4F            03F8            add     edi, eax                         ; //第2位得出的結果和第2位得出的結果相加
00404C51            83C4 08         add     esp, 8
00404C54            83FF 0A         cmp     edi, 0A                          ; //是否等於0Ah
00404C57            74 09           je      short 00404C62
00404C59            5F              pop     edi
00404C5A            5E              pop     esi
00404C5B            33C0            xor     eax, eax
00404C5D            5B              pop     ebx
00404C5E            83C4 18         add     esp, 18
00404C61            C3              retn
00404C62            8A4E 12         mov     cl, byte ptr [esi+12]            ; //註冊碼第19位
00404C65            8A56 13         mov     dl, byte ptr [esi+13]            ; //註冊碼第20位
00404C68            8D4424 0C       lea     eax, dword ptr [esp+C]
00404C6C            884C24 18       mov     byte ptr [esp+18], cl
00404C70            50              push    eax
00404C71            885C24 1D       mov     byte ptr [esp+1D], bl
00404C75            885424 10       mov     byte ptr [esp+10], dl
00404C79            885C24 11       mov     byte ptr [esp+11], bl
00404C7D            E8 6E090600     call    004655F0
00404C82            8D4C24 1C       lea     ecx, dword ptr [esp+1C]
00404C86            8BF8            mov     edi, eax                         ; //第20位得出的結果->edi
00404C88            51              push    ecx
00404C89            E8 62090600     call    004655F0
00404C8E            03F8            add     edi, eax                         ; //第19位得出的結果和第20位得出的結果相加
00404C90            83C4 08         add     esp, 8
00404C93            83FF 0C         cmp     edi, 0C                          ; //是否等於0Ch
00404C96            74 09           je      short 00404CA1
00404C98            5F              pop     edi
00404C99            5E              pop     esi
00404C9A            33C0            xor     eax, eax
00404C9C            5B              pop     ebx
00404C9D            83C4 18         add     esp, 18
00404CA0            C3              retn
00404CA1            8A56 05         mov     dl, byte ptr [esi+5]             ; //註冊碼第6位
00404CA4            8A46 0D         mov     al, byte ptr [esi+D]             ; //註冊碼第14位
00404CA7            8D4C24 0C       lea     ecx, dword ptr [esp+C]
00404CAB            885424 18       mov     byte ptr [esp+18], dl
00404CAF            51              push    ecx
00404CB0            885C24 1D       mov     byte ptr [esp+1D], bl
00404CB4            884424 10       mov     byte ptr [esp+10], al
00404CB8            885C24 11       mov     byte ptr [esp+11], bl
00404CBC            E8 2F090600     call    004655F0
00404CC1            8D5424 1C       lea     edx, dword ptr [esp+1C]
00404CC5            8BF8            mov     edi, eax                         ; //第14位得出的結果->edi
00404CC7            52              push    edx
00404CC8            E8 23090600     call    004655F0
00404CCD            03F8            add     edi, eax                         ; //第6位得出的結果和第14位得出的結果相加
00404CCF            83C4 08         add     esp, 8
00404CD2            83FF 0B         cmp     edi, 0B                          ; //是否等於0Bh
00404CD5            74 09           je      short 00404CE0
00404CD7            5F              pop     edi
00404CD8            5E              pop     esi
00404CD9            33C0            xor     eax, eax
00404CDB            5B              pop     ebx
00404CDC            83C4 18         add     esp, 18
00404CDF            C3              retn
00404CE0            807E 0C 52      cmp     byte ptr [esi+C], 52             ; //第13位是否等於52h,即‘R’
00404CE4            74 09           je      short 00404CEF
00404CE6            5F              pop     edi
00404CE7            5E              pop     esi
00404CE8            33C0            xor     eax, eax
00404CEA            5B              pop     ebx
00404CEB            83C4 18         add     esp, 18
00404CEE            C3              retn
00404CEF            807E 0E 33      cmp     byte ptr [esi+E], 33             ; //第15位是否等於33h,即‘3’
00404CF3            74 09           je      short 00404CFE
00404CF5            5F              pop     edi
00404CF6            5E              pop     esi
00404CF7            33C0            xor     eax, eax
00404CF9            5B              pop     ebx
00404CFA            83C4 18         add     esp, 18
00404CFD            C3              retn
00404CFE            8A4E 0F         mov     cl, byte ptr [esi+F]             ; //第16位->cl
00404D01            33C0            xor     eax, eax
00404D03            80F9 30         cmp     cl, 30                           ; //第16位是否等於30h,即0
00404D06            5F              pop     edi
00404D07            5E              pop     esi
00404D08            5B              pop     ebx
00404D09            0F94C0          sete    al                               ; //等於則置al爲1
00404D0C            83C4 18         add     esp, 18
00404D0F            C3              retn

在分析的過程中,發現被程序檢測的第19,20,14位填的字母,在調用4655f0後得出的結果都是0,反正在吃粉絲,嘻嘻,不好意思,分析的時候肚子餓了,乾脆就悠哉悠哉的多測試了幾組數據,發現註冊碼0~9之間,函數返回的就是0~9,而輸入字母,則統統爲0,嘻嘻,頗有點選擇明文攻擊的味道。加上看到原先下載的網站給出的註冊碼是通用的時候,我就已經懷疑機器ID是唬人的,再加上,註冊算法中確實沒看到機器ID的出現,莫非我眼花了。於是乎我就猜測它的註冊算法:
1.長度必須等於20(十進制)位
2.第1位和第2位的和必須等於A
3.第19位和第20位的和必須等於C
4.第6位和第14位必須等於B
5.第13位必須等於52h,即‘R’
6.第15位必須等於33h,即‘3’
7.第16位必須等於30h,即‘0’
OK!胡亂測試一組試煉碼:55@@@5@@@@@@R630@@66 
my god;差點噴面,居然成功了....GS運~~~嘻嘻~

<再分析>
現在的方面粉絲的份量真的太少了,沒幾下就被我解決了-_-!自己其實也想看看4655f0函數是咋樣的,所以索性接着看了下
;4655f0
004655F0            FF7424 04       push    dword ptr [esp+4]                ; //需要被計算的那位註冊碼,這裏是第2位‘2’
004655F4            E8 6CFFFFFF     call    00465565                         ; //繼續跟進看了
004655F9            59              pop     ecx
004655FA            C3              retn

;465565
00465565            53              push    ebx
00465566            55              push    ebp
00465567            56              push    esi
00465568            57              push    edi
00465569            8B7C24 14       mov     edi, dword ptr [esp+14]                   ; //edi存放被壓入的那位註冊碼'2'
0046556D            833D DCA84B00 0>cmp     dword ptr [4BA8DC], 1
00465574            7E 0F           jle     short 00465585
00465576            0FB607          movzx   eax, byte ptr [edi]
00465579            6A 08           push    8
0046557B            50              push    eax
0046557C            E8 A35E0000     call    0046B424
00465581            59              pop     ecx
00465582            59              pop     ecx
00465583            EB 0F           jmp     short 00465594
00465585            0FB607          movzx   eax, byte ptr [edi]
00465588            8B0D D0A64B00   mov     ecx, dword ptr [4BA6D0]                   ; //ds:[004BA6D0]=004BA6DA
0046558E            8A0441          mov     al, byte ptr [ecx+eax*2]                  ; //al<-84
00465591            83E0 08         and     eax, 8                                    ; //和8與
00465594            85C0            test    eax, eax                                  ; //是否爲0
00465596            74 03           je      short 0046559B
00465598            47              inc     edi
00465599          ^ EB D2           jmp     short 0046556D
0046559B            0FB637          movzx   esi, byte ptr [edi]                       ; //esi<-'2'
0046559E            47              inc     edi                                       ; //[edi]爲0,參考前面地址404c32
0046559F            83FE 2D         cmp     esi, 2D                                   ; //是否等於‘-’
004655A2            8BEE            mov     ebp, esi
004655A4            74 05           je      short 004655AB
004655A6            83FE 2B         cmp     esi, 2B                                   ; //是否等於‘+’
004655A9            75 04           jnz     short 004655AF
004655AB            0FB637          movzx   esi, byte ptr [edi]
004655AE            47              inc     edi
004655AF            33DB            xor     ebx, ebx
004655B1            833D DCA84B00 0>cmp     dword ptr [4BA8DC], 1
004655B8            7E 0C           jle     short 004655C6
004655BA            6A 04           push    4
004655BC            56              push    esi
004655BD            E8 625E0000     call    0046B424
004655C2            59              pop     ecx
004655C3            59              pop     ecx
004655C4            EB 0B           jmp     short 004655D1                            ; //下面纔是關鍵
004655C6            A1 D0A64B00     mov     eax, dword ptr [4BA6D0]                   ; //ds:[004BA6D0]=004BA6DA
004655CB            8A0470          mov     al, byte ptr [eax+esi*2]                  ; //al<-84,esi是註冊碼32h
004655CE            83E0 04         and     eax, 4                                    ; //和4相與
004655D1            85C0            test    eax, eax                                  ; //是否爲0
004655D3            74 0D           je      short 004655E2
004655D5            8D049B          lea     eax, dword ptr [ebx+ebx*4]
004655D8            8D5C46 D0       lea     ebx, dword ptr [esi+eax*2-30]             ; //ebx指向esi+eax*2-30的地方,而這個地方的值是:該位註冊碼+eax*2-30,而eax爲0,所以爲:註冊碼-30
004655DC            0FB637          movzx   esi, byte ptr [edi]
004655DF            47              inc     edi
004655E0          ^ EB CF           jmp     short 004655B1
004655E2            83FD 2D         cmp     ebp, 2D
004655E5            8BC3            mov     eax, ebx
004655E7            75 02           jnz     short 004655EB
004655E9            F7D8            neg     eax
004655EB            5F              pop     edi
004655EC            5E              pop     esi
004655ED            5D              pop     ebp
004655EE            5B              pop     ebx
004655EF            C3              retn

OK!關鍵的地方其實就在004655C6~004655D8之間,必須保證和4相與後的eax不爲0,按這條流程下去,纔會保證返回着是(註冊碼-30),否則返回值爲0
而eax的保證來源於內存4ba6da,即如下數組:
char eax_key[] = 
{
0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 
0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x28, 0x00, 
0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x20, 0x00, 
0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 
0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 
0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 
0x20, 0x00, 0x20, 0x00, 0x48, 0x00, 0x10, 0x00, 0x10, 0x00, 
0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 
0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 
0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x84, 0x00, 0x84, 0x00, 
0x84, 0x00, 0x84, 0x00, 0x84, 0x00, 0x84, 0x00, 0x84, 0x00, 
0x84, 0x00, 0x84, 0x00, 0x84, 0x00, 0x10, 0x00, 0x10, 0x00, 
0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 
0x81, 0x00, 0x81, 0x00, 0x81, 0x00, 0x81, 0x00, 0x81, 0x00, 
0x81, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 
0x01, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 
0x10, 0x00, 0x10, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 
0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x02, 0x00, 0x02, 0x00, 
0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 
0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 
0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 
0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x10, 0x00, 0x10, 0x00, 
0x10, 0x00, 0x10, 0x00, 0x20
};
如004655CB            8A0470          mov     al, byte ptr [eax+esi*2]                  ; //al<-84,esi是註冊碼32h
al就是eax_key[eax+esi*2],eax是004BA6DA=數組基址0,esi爲該位註冊碼‘2’,即32h*2=64h=100,所以爲eax_key[100] = 0x84; 0x84^4 = 4;
在來一個‘A’,16進制41,41h*2=82H=130,所以eax_key[130] = 0x81; 0x81^4=0
只有爲0x84,和4與纔不會爲0,而0x84正好是10個,正好是0~9十個即數組96開始,因爲乘2,正好相隔一個,自己算算吧~~
程序就是這樣來判斷的。。
<註冊機>
呵呵,不用了吧。手動計算貌似還更快,呵呵~今天撿到個軟柿子~~運氣不錯^_^
----------------------------------------------------------------------------------------------

【版權聲明】: 
本文原創於看雪技術論壇, 轉載請註明作者並保持文章的完整, 謝謝!


                                                       2007年07月22日 20:17:02
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章