ollydbg -- WinISO v5.3中文版註冊演算法
【軟體名稱】:WinISO v5.3中文版
【主要功能】:一款功能超級強大的光碟工具,它可以轉換CD-ROM映像檔案格式,並且可以直接編輯光碟映像檔案,
可以處理幾乎所有的CD-ROM 映像檔案,包括 ISO 和 BIN 。透過 WinISO,你可以在映像檔案內部新增/刪除/重新命名/提取檔案。
你可以將其他格式的映像檔案轉換為標準的ISO格式,同時你也可以從你的 CD-ROM 中建立 ISO 映像檔案。
【軟體限制】:未註冊版不支援超過100M的檔案且每次啟動彈出註冊提示框。
【作者宣告】:破解該軟體純粹出於興趣,無其他目的,失誤之處敬請指教。
【破解工具】:ollydbg1.08, FI2.50,UPX1.2x
――――――――――――――――――――――――――――――――――――
【破解過程】:
FI檢視是UPX1.20加的殼,用UPX脫之,存為WinISO1.exe。再查是BC編的。
使用者名稱:worldhello
試煉碼:12345678
程式要求重啟驗證,稍加觀察可發現程式把註冊資訊寫到登錄檔了。
用ollydbg載入,找和登錄檔有關的api,最後發現RegQueryValueExA能迅速找到註冊碼驗證之處。
一路往下,來到0041BCD7,這裡的call計算試煉碼的長度並與48比較,超過則截掉48位以後的,不足就補足48位。
再往下:
0041BCDF LEA ECX,DWORD PTR SS:[EBP-D0]
0041BCE5 PUSH ECX ; /Arg1
0041BCE6 CALL WinISO1.004BBE6C ; WinISO1.004BBE6C
0041BCEB POP ECX
0041BCEC XOR ESI,ESI
0041BCEE MOV EBX,WinISO1.004D0DBC
0041BCF3 /MOV EAX,DWORD PTR DS:[EBX]
0041BCF5 |LEA EDX,DWORD PTR SS:[EBP-D0]
0041BCFB |/MOV CL,BYTE PTR DS:[EAX]
0041BCFD ||CMP CL,BYTE PTR DS:[EDX]
0041BCFF ||JNZ SHORT WinISO1.0041BD38
0041BD01 ||TEST CL,CL
0041BD03 ||JE SHORT WinISO1.0041BD17
0041BD05 ||MOV CL,BYTE PTR DS:[EAX+1]
0041BD08 ||CMP CL,BYTE PTR DS:[EDX+1]
0041BD0B ||JNZ SHORT WinISO1.0041BD38
0041BD0D ||ADD EAX,2
0041BD10 ||ADD EDX,2
0041BD13 ||TEST CL,CL
0041BD15 |JNZ SHORT WinISO1.0041BCFB
0041BD17 |JNZ SHORT WinISO1.0041BD38
0041BD19 |DEC DWORD PTR SS:[EBP-30] ;到這裡就說明輸入的試煉碼和某組黑名單相同
0041BD1C |LEA EAX,DWORD PTR SS:[EBP-4]
0041BD1F |MOV EDX,2
0041BD24 |CALL WinISO1.004C37FC
0041BD29 |MOV ECX,DWORD PTR SS:[EBP-4C]
0041BD2C |MOV DWORD PTR FS:[0],ECX
0041BD33 |JMP WinISO1.0041BE5D ;跳出整個驗證註冊碼的call,玩完啦
0041BD38 |INC ESI
0041BD39 |ADD EBX,4
0041BD3C |CMP ESI,12 ;總共18組黑名單
0041BD3F JL SHORT WinISO1.0041BCF3
0041BD41 MOV WORD PTR SS:[EBP-3C],14
上面一段程式碼是把試煉碼和一組黑名單上的註冊碼比較,如果碰巧相同,就不進行以後的驗證了。
...........
0041BD55 /MOV AL,BYTE PTR DS:[EBX]
0041BD57 |PUSH EAX
0041BD58 |CALL WinISO1.0041BA48
0041BD5D |SHL EAX,4
0041BD60 |POP ECX
0041BD61 |MOV BYTE PTR DS:[ESI],AL
0041BD63 |MOV DL,BYTE PTR DS:[EBX+1]
0041BD66 |PUSH EDX ; /Arg1
0041BD67 |CALL WinISO1.0041BA48 ; WinISO1.0041BA48
0041BD6C |POP ECX
0041BD6D |ADD BYTE PTR DS:[ESI],AL
0041BD6F |INC EDI
0041BD70 |INC ESI
0041BD71 |ADD EBX,2
0041BD74 |CMP EDI,18
0041BD77 JL SHORT WinISO1.0041BD55
上面把48位的試煉碼換成24個位元組,不允許註冊碼中含0-9及A-F(a-f)中的字元。
0041BD79 MOV CX,WORD PTR SS:[EBP-E8]
0041BD80 CMP DWORD PTR DS:[4E1CA4],0
0041BD87 PUSH ECX
0041BD88 LEA EAX,DWORD PTR SS:[EBP-F4]
0041BD8E PUSH EAX
0041BD8F JE SHORT WinISO1.0041BD99
0041BD91 MOV EDX,DWORD PTR DS:[4E1CA4] ;edx為使用者名稱
0041BD97 JMP SHORT WinISO1.0041BD9E
0041BD99 MOV EDX,WinISO1.004D11D9
0041BD9E PUSH EDX ; |Arg1
0041BD9F CALL WinISO1.0041CAB8 ; WinISO1.0041CAB8,第一次加密,追進去看
0041BDA4 ADD ESP,0C
0041BDA7 PUSH 0C ; /Arg3 = 0000000C
0041BDA9 LEA EAX,DWORD PTR SS:[EBP-E8] ; |
0041BDAF PUSH EAX ; |Arg2
0041BDB0 LEA ECX,DWORD PTR SS:[EBP-F4] ; |
0041BDB6 PUSH ECX ; |Arg1
0041BDB7 CALL WinISO1.004B56B4 ; WinISO1.004B56B4,第一次驗證,比較12個位元組
0041BDBC ADD ESP,0C
0041BDBF TEST EAX,EAX ;測試eax
0041BDC1 JE SHORT WinISO1.0041BDDF ;eax為0則透過第一次驗證
0041BDC3 DEC DWORD PTR SS:[EBP-30]
0041BDC6 LEA EAX,DWORD PTR SS:[EBP-4]
0041BDC9 MOV EDX,2
0041BDCE CALL WinISO1.004C37FC
0041BDD3 MOV ECX,DWORD PTR SS:[EBP-4C]
0041BDD6 MOV DWORD PTR FS:[0],ECX
0041BDDD JMP SHORT WinISO1.0041BE5D ;到這裡就完嘍
0041BDDF PUSH 18 ; /Arg3 = 00000018
0041BDE1 LEA EAX,DWORD PTR SS:[EBP-E8] ; |
0041BDE7 PUSH EAX ; |Arg2
0041BDE8 MOV EDX,DWORD PTR SS:[EBP-50] ; |
0041BDEB ADD EDX,3 ; |
0041BDEE PUSH EDX ; |Arg1
0041BDEF CALL WinISO1.004B5404 ; WinISO1.004B5404
0041BDF4 ADD ESP,0C
0041BDF7 LEA ECX,DWORD PTR SS:[EBP-E8]
0041BDFD PUSH ECX ; /Arg1
0041BDFE CALL WinISO1.0041CA1C ; WinISO1.0041CA1C,第二次加密,追
0041BE03 POP ECX
0041BE04 PUSH 8 ; /Arg3 = 00000008
0041BE06 LEA EAX,DWORD PTR SS:[EBP-DC] ; |
0041BE0C PUSH EAX ; |Arg2
0041BE0D LEA EDX,DWORD PTR SS:[EBP-E8] ; |
0041BE13 PUSH EDX ; |Arg1
0041BE14 CALL WinISO1.004B56B4 ; WinISO1.004B56B4,第二次驗證,比較8個位元組
0041BE19 ADD ESP,0C
0041BE1C TEST EAX,EAX ;測試eax
0041BE1E JE SHORT WinISO1.0041BE3C ;eax為0則第二次驗證透過
0041BE20 DEC DWORD PTR SS:[EBP-30]
0041BE23 LEA EAX,DWORD PTR SS:[EBP-4]
0041BE26 MOV EDX,2
0041BE2B CALL WinISO1.004C37FC
0041BE30 MOV ECX,DWORD PTR SS:[EBP-4C]
0041BE33 MOV DWORD PTR FS:[0],ECX
0041BE3A JMP SHORT WinISO1.0041BE5D
0041BE3C MOV EAX,DWORD PTR SS:[EBP-50]
0041BE3F MOV BYTE PTR DS:[EAX+27],1 ;看來是註冊標誌了
0041BE43 DEC DWORD PTR SS:[EBP-30]
0041BE46 LEA EAX,DWORD PTR SS:[EBP-4]
0041BE49 MOV EDX,2
0041BE4E CALL WinISO1.004C37FC
0041BE53 MOV ECX,DWORD PTR SS:[EBP-4C]
0041BE56 MOV DWORD PTR FS:[0],ECX
0041BE5D POP EDI
0041BE5E POP ESI
0041BE5F POP EBX
0041BE60 MOV ESP,EBP
0041BE62 POP EBP
0041BE63 RETN
共有兩次加密和兩次驗證,不管驗證透過與否,下面幾句都會執行(包括註冊碼在黑名單上的情況):
DEC DWORD PTR SS:[EBP-30]
LEA EAX,DWORD PTR SS:[EBP-4]
MOV EDX,2
CALL WinISO1.004C37FC
MOV ECX,DWORD PTR SS:[EBP-4C]
MOV DWORD PTR FS:[0],ECX
唯一不同的是,若驗證透過,會多執行MOV EAX,DWORD PTR SS:[EBP-50]和MOV BYTE PTR DS:[EAX+27],1兩步,而這就應該是註冊標誌。
如果只要爆破的話,把驗證不透過的幾處跳轉轉向0041BE3C,處理MOV EAX,DWORD PTR SS:[EBP-50]和MOV BYTE PTR DS:[EAX+27],1。
當然我們的目的不僅是爆破了事。看看第一次加密的call:
0041CAB8 PUSH EBP
0041CAB9 MOV EBP,ESP
0041CABB ADD ESP,-28
0041CABE PUSH EBX
0041CABF PUSH ESI
0041CAC0 PUSH EDI
0041CAC1 PUSH 0C ; /Arg3 = 0000000C
0041CAC3 PUSH 0 ; |Arg2 = 00000000
0041CAC5 MOV EAX,DWORD PTR SS:[EBP+C] ; |
0041CAC8 PUSH EAX ; |Arg1
0041CAC9 CALL WinISO1.004B5474 ; WinISO1.004B5474
0041CACE ADD ESP,0C
0041CAD1 MOV EDX,DWORD PTR SS:[EBP+8]
0041CAD4 PUSH EDX
0041CAD5 CALL WinISO1.004B55A8 ;使用者名稱長度
0041CADA POP ECX
0041CADB MOV DWORD PTR SS:[EBP-4],EAX
0041CADE CMP DWORD PTR SS:[EBP-4],0
0041CAE2 JE WinISO1.0041CB68
0041CAE8 LEA EDI,DWORD PTR SS:[EBP-1C]
0041CAEB MOV ESI,WinISO1.004D1DAC ; ASCII "WinISO_Computing_Inc"
0041CAF0 MOV ECX,5
0041CAF5 LEA EAX,DWORD PTR SS:[EBP-1C]
0041CAF8 REP MOVS DWORD PTR ES:[EDI],DWORD PTR DS>
0041CAFA MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[ESI]
0041CAFB PUSH EAX
0041CAFC CALL WinISO1.004B55A8 ;WinISO_Computing_Inc長度
0041CB01 POP ECX
0041CB02 MOV DWORD PTR SS:[EBP-20],EAX
0041CB05 XOR EDX,EDX
0041CB07 XOR ECX,ECX
0041CB09 XOR EAX,EAX
0041CB0B MOV DWORD PTR SS:[EBP-24],EAX
0041CB0E XOR EAX,EAX
0041CB10 MOV DWORD PTR SS:[EBP-28],EAX
0041CB13 /MOV EAX,DWORD PTR SS:[EBP+8] ;使用者名稱=>eax
0041CB16 |MOV AL,BYTE PTR DS:[EAX+EDX]
0041CB19 |INC EDX
0041CB1A |CMP EDX,DWORD PTR SS:[EBP-4] ;是否超過使用者名稱長度
0041CB1D |JL SHORT WinISO1.0041CB21
0041CB1F |XOR EDX,EDX ;edx清零,重新計算
0041CB21 |XOR AL,BYTE PTR SS:[EBP+10] ;使用者名稱某位xor試煉碼第1位元組
0041CB24 |ADD AL,23 ;加23H
0041CB26 |XOR AL,BYTE PTR SS:[EBP+ECX-1C] ;xor WinISO_Computing_Inc的某位
0041CB2A |INC ECX
0041CB2B |CMP ECX,DWORD PTR SS:[EBP-20] ;是否超過WinISO_Computing_Inc長度
0041CB2E |JL SHORT WinISO1.0041CB32 ;
0041CB30 |XOR ECX,ECX ;ecx清零,重新計算
0041CB32 |MOVZX EBX,WORD PTR SS:[EBP+10] ;試煉碼前2位元組放到ebx
0041CB36 |SAR EBX,8 ;右移8,得到試煉碼第2位元組
0041CB39 |MOV ESI,DWORD PTR SS:[EBP-24] ;esi做計數器
0041CB3C |ADD AL,BL ;al加bl
0041CB3E |MOV EBX,DWORD PTR SS:[EBP+C] ;[EBP+C]初始為0,由此開始的12位元組將與輸入的前12位元組xor
0041CB41 |XOR BYTE PTR DS:[EBX+ESI],AL ;
0041CB44 |INC DWORD PTR SS:[EBP-24] ;
0041CB47 |CMP DWORD PTR SS:[EBP-24],0C ;計數器是否超過12
0041CB4B |JL SHORT WinISO1.0041CB52
0041CB4D |XOR EAX,EAX
0041CB4F |MOV DWORD PTR SS:[EBP-24],EAX ;超過計數器置0,重新開始
0041CB52 |INC DWORD PTR SS:[EBP-28] ;
0041CB55 |CMP DWORD PTR SS:[EBP-28],0FF ;是否超過255次
0041CB5C JL SHORT WinISO1.0041CB13 ;沒有就繼續
0041CB5E MOV EDX,DWORD PTR SS:[EBP+C]
0041CB61 MOV CX,WORD PTR SS:[EBP+10]
0041CB65 MOV WORD PTR DS:[EDX],CX ;把試煉碼前2位元組重新置回
0041CB68 POP EDI
0041CB69 POP ESI
0041CB6A POP EBX
0041CB6B MOV ESP,EBP
0041CB6D POP EBP
0041CB6E RETN
第二次的加密call:
0041CA1C PUSH EBP
0041CA1D MOV EBP,ESP
0041CA1F ADD ESP,-18
0041CA22 LEA EAX,DWORD PTR SS:[EBP-18]
0041CA25 PUSH EBX
0041CA26 PUSH ESI
0041CA27 PUSH EDI
0041CA28 MOV EDI,WinISO1.004D19AC
0041CA2D MOV EBX,DWORD PTR SS:[EBP+8]
0041CA30 MOV ESI,WinISO1.004D18AC
0041CA35 MOV DWORD PTR SS:[EBP-4],WinISO1.004D1AAC
0041CA3C MOV DWORD PTR SS:[EBP-8],WinISO1.004D1BAC
0041CA43 PUSH EAX ; /Arg1
0041CA44 CALL WinISO1.0041C464 ; WinISO1.0041C464
0041CA49 POP ECX
0041CA4A LEA EDX,DWORD PTR SS:[EBP-18] ; edx指向eax
0041CA4D PUSH EDX ; /Arg2
0041CA4E PUSH EBX ; |Arg1 試煉碼1-4位元組
0041CA4F CALL WinISO1.0041C524 ; WinISO1.0041C524
0041CA54 ADD ESP,8
0041CA57 LEA ECX,DWORD PTR SS:[EBP-18]
0041CA5A PUSH ECX ; /Arg2
0041CA5B LEA EAX,DWORD PTR DS:[EBX+4] ; |
0041CA5E PUSH EAX ; |Arg1 試煉碼5-8位元組
0041CA5F CALL WinISO1.0041C524 ; WinISO1.0041C524
0041CA64 ADD ESP,8
0041CA67 LEA EDX,DWORD PTR SS:[EBP-18]
0041CA6A PUSH EDX ; /Arg2
0041CA6B LEA ECX,DWORD PTR DS:[EBX+8] ; |
0041CA6E PUSH ECX ; |Arg1 試煉碼9-12位元組
0041CA6F CALL WinISO1.0041C524 ; WinISO1.0041C524
0041CA74 ADD ESP,8
0041CA77 LEA EAX,DWORD PTR DS:[EBX+C]
0041CA7A PUSH EDI ; /Arg3 引數2,3是內建的加密表
0041CA7B PUSH ESI ; |Arg2
0041CA7C PUSH EAX ; |Arg1 引數1指向試煉碼第13位元組
0041CA7D CALL WinISO1.0041C958 ; WinISO1.0041C958
0041CA82 ADD ESP,0C
0041CA85 MOV EDX,DWORD PTR SS:[EBP-8]
0041CA88 PUSH EDX ; /Arg3 另2組內建加密表
0041CA89 MOV ECX,DWORD PTR SS:[EBP-4] ; |
0041CA8C PUSH ECX ; |Arg2
0041CA8D LEA EAX,DWORD PTR DS:[EBX+10] ; |
0041CA90 PUSH EAX ; |Arg1 引數1指向試煉碼第17位元組
0041CA91 CALL WinISO1.0041C958 ; WinISO1.0041C958
0041CA96 ADD ESP,0C
0041CA99 XOR ECX,ECX ;ecx清0,計數器
0041CA9B LEA EDX,DWORD PTR DS:[EBX+C] ;edx指向試煉碼第13位元組
0041CA9E MOV EAX,WinISO1.004D18A0
0041CAA3 MOV BL,BYTE PTR DS:[EAX] ;eax所指位元組傳給bl
0041CAA5 ADD BYTE PTR DS:[EDX],BL ;edx所指地址加bl
0041CAA7 INC ECX ;計數器加1
0041CAA8 INC EDX
0041CAA9 INC EAX
0041CAAA CMP ECX,0C ;是否超過12
0041CAAD JL SHORT WinISO1.0041CAA3 ;小於12繼續
0041CAAF POP EDI
0041CAB0 POP ESI
0041CAB1 POP EBX
0041CAB2 MOV ESP,EBP
0041CAB4 POP EBP
0041CAB5 RETN
第二次加密有點BT,如果進0041CA44的call看一下,會發現MD5演算法的4個常數,很自然的會想到CALL WinISO1.0041C524用了MD5加密。
進去看一下,怎麼看都覺得是MD5,再研究一下發現,總共3次call 0041C524,第一次CALL之後把加密結果覆蓋了4個常數所在記憶體,
因此第二次加密時4個常數(還能稱常數嗎?)已改變,然後加密結果再度覆蓋同一記憶體地址再進行第三次加密。
說了這麼多,真正有用的是下面一句:以上這個類似MD5的演算法根本就是煙霧彈!在之後的加密及驗證中根本沒有用到加密後的資料。
(氣憤啊!浪費了我多少時間!)
CALL WinISO1.0041C958才是有用的call,去看一下:
0041C958 PUSH EBP
0041C959 MOV EBP,ESP
0041C95B ADD ESP,-0C
0041C95E XOR EDX,EDX
0041C960 XOR ECX,ECX
0041C962 PUSH EBX
0041C963 PUSH ESI
0041C964 PUSH EDI
0041C965 MOV EAX,DWORD PTR SS:[EBP+8] ;eax指向引數1
0041C968 ADD EAX,4 ;地址往前移4位元組
0041C96B XOR EBX,EBX
0041C96D MOV DWORD PTR SS:[EBP-4],EAX ;寫到臨時變數1中
0041C970 MOV DWORD PTR SS:[EBP-8],EDX ;0給臨時變數2
0041C973 MOV DWORD PTR SS:[EBP-C],ECX ;0給臨時變數3
0041C976 /MOV EAX,DWORD PTR SS:[EBP+8] ;引數1傳給eax
0041C979 |MOV EDX,DWORD PTR SS:[EBP-4] ;臨時變數1的值傳給edx
0041C97C |MOV ESI,DWORD PTR DS:[EAX] ;eax地址的值賦給esi
0041C97E |MOV EAX,DWORD PTR SS:[EBP+C] ;引數2的地址傳給eax
0041C981 |MOV EDI,DWORD PTR DS:[EDX] ;edx地址的值賦給edi
0041C983 |AND ESI,DWORD PTR DS:[EAX] ;esi 與 引數2
0041C985 |MOV EAX,DWORD PTR SS:[EBP+10] ;引數3的地址傳給eax
0041C988 |AND EDI,DWORD PTR DS:[EAX] ;edi 與 引數3
0041C98A |PUSH ESI ; /Arg1
0041C98B |CALL WinISO1.0041C93C ; WinISO1.0041C93C
0041C990 |POP ECX
0041C991 |PUSH EAX ;把第1次返回值入棧
0041C992 |PUSH EDI
0041C993 |CALL WinISO1.0041C93C
0041C998 |POP ECX
0041C999 |POP EDX ;第1次返回值出棧,即傳值給edx
0041C99A |XOR AL,DL ;第2次返回值xor第1次返回值
0041C99C |MOV EDX,DWORD PTR SS:[EBP-8] ;臨時變數2的值給edx
0041C99F |ADD DWORD PTR SS:[EBP-8],EDX ;臨時變數2的值加edx
0041C9A2 |AND EAX,0FF ;eax 與 11111111b
0041C9A7 |AND EAX,1 ;eax 與 00000001b
0041C9AA |INC EBX ;ebx自加1,計數器
0041C9AB |XOR DWORD PTR SS:[EBP-8],EAX 臨時變數2 xor eax
0041C9AE |ADD DWORD PTR SS:[EBP+C],4 ;引數2的地址+4
0041C9B2 |ADD DWORD PTR SS:[EBP+10],4 ;引數3的地址+4
0041C9B6 |CMP BL,20 ;是否經過32次運算
0041C9B9 JB SHORT WinISO1.0041C976 ;小於32次則繼續
0041C9BB XOR EBX,EBX ;清0
0041C9BD MOV EAX,DWORD PTR SS:[EBP+8]
0041C9C0 MOV EDX,DWORD PTR SS:[EBP-4]
0041C9C3 MOV ESI,DWORD PTR DS:[EAX]
0041C9C5 MOV EAX,DWORD PTR SS:[EBP+C]
0041C9C8 MOV EDI,DWORD PTR DS:[EDX]
0041C9CA AND ESI,DWORD PTR DS:[EAX]
0041C9CC MOV EAX,DWORD PTR SS:[EBP+10]
0041C9CF AND EDI,DWORD PTR DS:[EAX]
0041C9D1 PUSH ESI ; /Arg1
0041C9D2 CALL WinISO1.0041C93C ; WinISO1.0041C93C
0041C9D7 POP ECX
0041C9D8 PUSH EAX
0041C9D9 PUSH EDI
0041C9DA CALL WinISO1.0041C93C
0041C9DF POP ECX
0041C9E0 POP EDX
0041C9E1 XOR AL,DL
0041C9E3 MOV EDX,DWORD PTR SS:[EBP-C] ;這裡臨時變數3傳給edx
0041C9E6 ADD DWORD PTR SS:[EBP-C],EDX ;臨時變數3+edx
0041C9E9 AND EAX,0FF
0041C9EE AND EAX,1
0041C9F1 INC EBX
0041C9F2 XOR DWORD PTR SS:[EBP-C],EAX
0041C9F5 ADD DWORD PTR SS:[EBP+C],4
0041C9F9 ADD DWORD PTR SS:[EBP+10],4
0041C9FD CMP BL,20
0041CA00 JB SHORT WinISO1.0041C9BD ;完全與上面演算法一樣,但引數2和3的地址相應+0x80
0041CA02 MOV ECX,DWORD PTR SS:[EBP+8] ;引數1給ecx
0041CA05 MOV EAX,DWORD PTR SS:[EBP-8] ;臨時變數2給eax
0041CA08 MOV DWORD PTR DS:[ECX],EAX ;eax傳到ecx所指地址
0041CA0A MOV EDX,DWORD PTR SS:[EBP-4] ;臨時變數1給edx
0041CA0D MOV ECX,DWORD PTR SS:[EBP-C] ;臨時變數3給ecx
0041CA10 MOV DWORD PTR DS:[EDX],ECX ;ecx傳到edx所指地址
0041CA12 POP EDI
0041CA13 POP ESI
0041CA14 POP EBX
0041CA15 MOV ESP,EBP
0041CA17 POP EBP
0041CA18 RETN
CALL WinISO1.0041C958的引數,第一次引數1指向試煉碼第13位元組,引數2為地址4d18ac,引數3為地址4d19ac,
第二次引數1指向試煉碼第17位元組,引數2為地址4d1aac,引數3為地址4d1bac。
這4處(4d18ac,4d19ac,4d1aac,4d1bac)地址存放了軟體作者內建的4張表。
這個call,第一次將試煉碼13-20位元組加密得到新的8個位元組覆蓋掉13-20位元組所在記憶體。第二次則加密新的17-24位元組,
或者說是第一次加密得到的後4位元組和原21-24位元組,經加密後覆蓋掉17-24位元組。
兩次call 0041C958之後,將這個新得到的12位元組加上由004D18A0開始的內建的12位元組,得到第二次加密結果。
再看一下CALL WinISO1.0041C93C
0041C93C PUSH EBP
0041C93D MOV EBP,ESP
0041C93F MOV EAX,DWORD PTR SS:[EBP+8] ;引數1給eax
0041C942 XOR EDX,EDX ;edx清0
0041C944 TEST EAX,EAX ;eax是否空
0041C946 JE SHORT WinISO1.0041C952 ;是空就結束
0041C948 /INC EDX ;edx加1
0041C949 |MOV ECX,EAX ;eax傳給ecx
0041C94B |DEC ECX ;ecx減1
0041C94C |AND EAX,ECX ;eax 與 ecx
0041C94E |TEST EAX,EAX ;測試eax是否為0
0041C950 JNZ SHORT WinISO1.0041C948 ;不為0繼續
0041C952 MOV EAX,EDX ;edx傳給eax,即函式返回迴圈次數
0041C954 POP EBP
0041C955 RETN
上面這個call實際上計算引數的二進位制值有多少位1,並把該值傳給eax。
下面是比較的call:
004B56B4 PUSH EBP
004B56B5 MOV EBP,ESP
004B56B7 PUSH ESI
004B56B8 PUSH EDI
004B56B9 MOV EDI,DWORD PTR SS:[EBP+10]
004B56BC MOV ECX,DWORD PTR SS:[EBP+8]
004B56BF MOV ESI,DWORD PTR SS:[EBP+C]
004B56C2 /CMP EDI,4
004B56C5 |JL SHORT WinISO1.004B56FB
004B56C7 |MOV AL,BYTE PTR DS:[ECX]
004B56C9 |MOV DL,BYTE PTR DS:[ESI]
004B56CB |CMP DL,AL
004B56CD |JNZ SHORT WinISO1.004B56FB
004B56CF |MOV AL,BYTE PTR DS:[ECX+1]
004B56D2 |MOV DL,BYTE PTR DS:[ESI+1]
004B56D5 |CMP DL,AL
004B56D7 |JNZ SHORT WinISO1.004B56FB
004B56D9 |MOV AL,BYTE PTR DS:[ECX+2]
004B56DC |MOV DL,BYTE PTR DS:[ESI+2]
004B56DF |CMP DL,AL
004B56E1 |JNZ SHORT WinISO1.004B56FB
004B56E3 |MOV AL,BYTE PTR DS:[ECX+3]
004B56E6 |MOV DL,BYTE PTR DS:[ESI+3]
004B56E9 |CMP DL,AL
004B56EB |JNZ SHORT WinISO1.004B56FB
004B56ED |SUB EDI,4
004B56F0 |ADD ECX,4
004B56F3 |ADD ESI,4
004B56F6 |CMP EDI,4
004B56F9 JGE SHORT WinISO1.004B56C2
004B56FB TEST EDI,EDI
004B56FD JNZ SHORT WinISO1.004B5703
004B56FF XOR EAX,EAX
004B5701 JMP SHORT WinISO1.004B571C
004B5703 /MOV AL,BYTE PTR DS:[ECX]
004B5705 |MOV DL,BYTE PTR DS:[ESI]
004B5707 |CMP DL,AL
004B5709 |JNZ SHORT WinISO1.004B5710
004B570B |INC ECX
004B570C |INC ESI
004B570D |DEC EDI
004B570E JNZ SHORT WinISO1.004B5703
004B5710 XOR ECX,ECX
004B5712 MOV CL,AL
004B5714 XOR EAX,EAX
004B5716 MOV AL,DL
004B5718 SUB ECX,EAX
004B571A MOV EAX,ECX
004B571C POP EDI
004B571D POP ESI
004B571E POP EBP
004B571F RETN
第一次驗證是將試煉碼前2位元組經第一次加密得到的12位元組與試煉碼的前12位元組比較,
第二次驗證是將試煉碼後12位元組經第二次加密所得12位元組的前8位元組與試煉碼前8位元組比較(汗,口才不好,說得這麼亂)。
總之這個比較的call演算法很清晰,無需多解釋了。
【思路總結】:
軟體共有兩次加密,我們可以直接利用其中一次而無需求反函式。仔細思考一下,如果先確定後12位元組,則由加密演算法2,
前12位元組也就固定了,要求前2位元組經加密演算法1而得到完全相同的12個位元組可以說是不可能的,因此必須先得到前12位元組。
若要保持註冊碼的隨機性,我們可以隨機產生註冊碼前2位元組,然後由加密演算法1確定3-12位元組。
加密演算法2的最後一步是0041CA99 - 0041CAAD的簡單加法,反函式自然就是減法。
call 0041C958的加密,有兩個自變數,第一次call為13-16位元組和17-20位元組,第二次則為17-20位元組和21-24位元組,
我們仍然可以隨機產生13-16位元組,這樣就相當於只有一個自變數,由13-16位元組可以得到固定的17-20位元組,
再由這17-20位元組可得到固定的21-24位元組。
經過這樣的簡化,call 0041C958似乎還是找不到反函式,因為其中有and計算,最笨的辦法是窮舉,那需要0xFFFFFFFF次的迴圈!
本人嘗試了一下,得到一個註冊碼需半個多小時(還不是最壞情況),這樣的序號產生器是不合格的。
當然最後還是想到了等價的反函式,先看一下call 0041C958的c程式碼(看c比看彙編簡單吧?):
void encrypt2(unsigned long* p, unsigned long* t1, unsigned long* t2) {
unsigned long l1,l2,tmp1,tmp2;
int i;
i = tmp1 = tmp2 = 0;
for (; i < 32; i++) {
l1 = *p;
l2 = *(p+1);
l1 &= *(t1 + i);
l2 &= *(t2 + i);
l1 = getQuantityOfOne(l1);
l2 = getQuantityOfOne(l2);
l2 ^= l1;
tmp1 *= 2;
l2 &= 255;
l2 &= 1;
tmp1 ^= l2;
}
for (; i < 64; i++) {
l1 = *p;
l2 = *(p+1);
l1 &= *(t1 + i);
l2 &= *(t2 + i);
l1 = getQuantityOfOne(l1);
l2 = getQuantityOfOne(l2);
l2 ^= l1;
tmp2 *= 2;
l2 &= 255;
l2 &= 1;
tmp2 ^= l2;
}
*p = tmp1;
*(p+1) = tmp2;
}
引數p第一次指向註冊碼第13-16位元組,第二次指向17-20位元組,t1,t2分別指向加密表。
getQuantityOfOne()函式就是CALL WinISO1.0041C93C,返回引數二進位制中1的數量,這裡程式碼略過了。
其實只要看第一個for迴圈就行了,找到第一個for的反函式,就可以得到自變數l2(另一個自變數l1當然已經簡化掉了)。
仔細考慮可以發現,每次l2的值只需要最後1 bit,並且這1 bit儲存在tmp1的某位當中供以後的比較。
其實要得到l2相當於解方程組了:f(i)(x31,x30,...,x0) = a(i)(31)x31^a(i)(30)x30^...^a(i)(0)x0 = b(i) (i = 0,1,...,31),
其中常數a(31)(31)...a(31)(0),a(30)(31)...a(30)(0),......,a(0)(31)...a(0)(0)以及b(31)...b(0)取值非0即1,
自變數x31...x0取值同樣非0即1,而係數與自變數的乘法就能簡化成&運算。
寫成矩陣形式AX = B,矩陣A可由第2和第4內建表得到,B可由註冊碼前12位元組減去004D18A0開始的12位元組然後與l1運算後得到。
因為內建表是固定的,於是係數矩陣A也固定,因此X相當於B的函式,可以獨立寫一個程式計算出這種關係(X=CB),
這樣在序號產生器程式碼中就可以由常數陣列C直接運算X了,不需每次都算一下C。
給出一組可用註冊碼:
使用者名稱:worldhello
註冊碼:000012C6D4C4D7CCE0FFEAE7000000009CA2C909CC9E7CC5
【後記】:由於這是本人第一次寫這樣的破解文章,因此錯誤在所難免,希望各位大蝦不吝賜教。
相關文章
- 用ollydbg找eBook Edit Pro v3.21的註冊碼2003-02-12
- 用ollyDbg尋找VB程式的註冊核心的一點思路2003-06-20
- LanSee 註冊演算法2015-11-15演算法
- 財智老闆通3.04註冊版---註冊演算法分析2003-03-16演算法
- Instant Source 註冊演算法分析+註冊器原始碼2015-11-15演算法原始碼
- supercleaner註冊演算法分析2015-11-15演算法
- 財智證券結算軟體2.5 破解註冊碼分析!使用ollydbg 破解註冊動畫!高手莫入! (1千字)2001-11-20動畫
- SpeedFlash註冊演算法分析(VB)2015-11-15演算法
- Screen Demo Maker 3.0 註冊演算法分析2003-07-15演算法
- <<Anti-Hack>> 2.0註冊演算法分析2003-06-06演算法
- 註冊碼演算法 (2千字)2001-01-14演算法
- SWF Browser的註冊演算法 (874字)2001-10-26演算法
- Personal Antispy 1.14 註冊演算法分析2015-11-15演算法
- 冰盾濾鏡註冊演算法分析2015-11-15演算法
- 迷你網路電視5.1註冊演算法2003-07-04演算法
- eXeScope
V6.41 的註冊演算法破解2004-05-03演算法
- DLL Show V4.4 註冊演算法分析2015-11-15演算法
- Disk
Chief 1.2 簡單註冊演算法分析2015-11-15演算法
- 註冊碼演算法入門!----菜鳥篇2015-11-15演算法
- 動態註冊和靜態註冊2018-05-21
- 靜態註冊和動態註冊2013-11-27
- CDSpace Power+註冊演算法 (7千字)2001-07-27演算法
- 《棋隱》的註冊演算法 (19千字)2001-08-26演算法
- E族百變桌面6.0註冊演算法分析2015-11-15演算法
- FolderView 1.7
註冊演算法分析 (14千字)2015-11-15View演算法
- 豪情唐詩大全 v1.0 註冊演算法2015-11-15演算法
- 盜文高手(DownFiles) Ver1.3 註冊演算法2015-11-15演算法
- Oracle Listener 動態註冊 與 靜態註冊2013-12-02Oracle
- ffmpeg分析系列之一(註冊該註冊的)2010-11-04
- Oracle listener靜態註冊和動態註冊2010-04-12Oracle
- Oracle Listener 動態註冊與靜態註冊2011-09-21Oracle
- 【監聽】動態註冊和靜態註冊2015-11-30
- oracle的靜態註冊和動態註冊2024-11-11Oracle
- 註冊中心 Eureka 原始碼解析 —— 應用例項註冊發現(一)之註冊2019-03-03原始碼
- 新狐傳真群發2.0註冊演算法分析2003-06-29演算法
- 網路精確時鐘 2.25註冊演算法分析2003-07-30演算法
- 重新貼過註冊演算法分析 (16千字)2001-10-23演算法
- 長沙vod點歌系統(註冊演算法分析)2015-11-15演算法