標 題: 【原創】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
作 者: 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