依然是加密与解密的习题,依旧循着前辈们的轨迹~。只不过这次的crackme用了通用的加密算法。
这个crack比较简单,过程就略过了,直接说下分析的结果吧。
首先在运行之初 窗口初始化之前,会通过GetVersion的返回值计算出一个值。
计算方法如下:
004010AB /$ E8 32090000 CALL <JMP.&kernel32.GetVersion>
004010B0 |. BB 08000000 MOV EBX,8
004010B5 |. F7E3 MUL EBX ; GetVersion返回值乘以8
004010B7 |. 50 PUSH EAX ; /<%X>
004010B8 |. 68 00304000 PUSH kiToKGNm.00403000 ; |Format = "%X"
004010BD |. 68 A8314000 PUSH kiToKGNm.004031A8 ; |s = kiToKGNm.004031A8
004010C2 |. E8 33090000 CALL <JMP.&user32.wsprintfA> ; \wsprintfA
004010C7 |. 83C4 0C ADD ESP,0C
004010CA |. 68 DA314000 PUSH kiToKGNm.004031DA ; ASCII "RUQ4MDA4MzA="
004010CF |. 6A 08 PUSH 8
004010D1 |. 68 A8314000 PUSH kiToKGNm.004031A8 ; ASCII "ED800830"
004010D6 |. E8 C5070000 CALL kiToKGNm.004018A0 ; 对机器码进行base64加密 放在4031DA
004010DB |. 68 A8314000 PUSH kiToKGNm.004031A8 ; /StringToAdd = "ED800830"
004010E0 |. 68 0C324000 PUSH kiToKGNm.0040320C ; |ConcatString = "ED800830RUQ4MDA4MzA="
004010E5 |. E8 FE080000 CALL <JMP.&kernel32.lstrcatA> ; \lstrcatA
004010EA |. 68 DA314000 PUSH kiToKGNm.004031DA ; /StringToAdd = "RUQ4MDA4MzA="
004010EF |. 68 0C324000 PUSH kiToKGNm.0040320C ; |ConcatString = "ED800830RUQ4MDA4MzA="
004010F4 |. E8 EF080000 CALL <JMP.&kernel32.lstrcatA> ; \lstrcatA
004010F9 |. 68 3E324000 PUSH kiToKGNm.0040323E ; ASCII "RUQ4MDA4MzBSVVE0TURBNE=="
004010FE |. 6A 10 PUSH 10
00401100 |. 68 0C324000 PUSH kiToKGNm.0040320C ; ASCII "ED800830RUQ4MDA4MzA="
00401105 |. E8 96070000 CALL kiToKGNm.004018A0 ; 对字符串的前16位再次进行base64加密 存放在40323E
0040110A \. C3 RETN
先将返回值乘以8,然后进行base64加密 然后再将返回值与加密后的字串连接起来,再进行一次base64加密不过这次加密比较特殊,加密完后取前16位的加密结果,再用'='补充到4的倍数。(这点好像与普通的base64有点不同吧?).
http://baike.baidu.com/view/469071.htm(base64参考资料)
大概过程用C描述如下:
int ver = GetVersion();
ver*=8;
wsprintf(str,"%X",ver);
base64_code(str,lstrlen(str),code);
strcat(str,code);
base64_code(str,16,code);
根据这个题目我写了个base64的加密过程,因为只针对这个题目所以写的很简单没有考虑>74位的情况。首先找到base64的表。
00403060 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 50 ABCDEFGHIJKLMNOP
00403070 51 52 53 54 55 56 57 58 59 5A 61 62 63 64 65 66 QRSTUVWXYZabcdef
00403080 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 ghijklmnopqrstuv
00403090 77 78 79 7A 30 31 32 33 34 35 36 37 38 39 2B 2F wxyz0123456789+/
可以看出就是普通的base64的表,没有做过变形。
以下是针对此crackme的base64加密:
char table[128]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
int base64_code(char str[] , int len ,char code[])
{
short a,b,c;
int i,j=0;
if(len<3)
{
return 0;
}
for(i=0;i<len;i+=3)
{
a=str[i];
b=str[i+1];
if(i+1>strlen(str)-1)
b=0;
c=str[i+2];
if(i+2>strlen(str)-1)
c=0;
code[j++]=table[a>>2];
code[j++]=table[((a<<4)+(b>>4))&63];
code[j++]=table[((b<<2)+(c>>6))&63];
code[j++]=table[c&63];
}
if(len%3==1)
{
code[j-2]='=';
code[j-1]='=';
}
if(len%3==2)
code[j-1]='=';
code[j]='\0';
return j;
}
接下来是读入用户名 并且对用户名进行base64加密,并与前面所计算的code进行连接。再对整个连接的字符串进行MD5加密。MD5的3个过程跟进去看了下。初始化,填充都是正常的MD5过程。所以直接拿MD5的源码过来算就好了。
0040110E |. C605 D4324000>MOV BYTE PTR DS:[4032D4],0
00401115 |. 6A 32 PUSH 32 ; /Count = 32 (50.)
00401117 |. 68 70324000 PUSH kiToKGNm.00403270 ; |Buffer = kiToKGNm.00403270
0040111C |. 68 E9030000 PUSH 3E9 ; |ControlID = 3E9 00401121 |. FF75 08 PUSH DWORD PTR SS:[EBP+8] ; |hWnd
00401124 |. E8 E3080000 CALL <JMP.&user32.GetDlgItemTextA> ; \读入用户名
00401129 |. 68 A2324000 PUSH kiToKGNm.004032A2
0040112E |. 50 PUSH EAX
0040112F |. 68 70324000 PUSH kiToKGNm.00403270 ; ASCII "zhangtaopy"
00401134 |. E8 67070000 CALL kiToKGNm.004018A0 ; 用户名 进行base64加密 存放在4032A2
00401139 |. 68 A2324000 PUSH kiToKGNm.004032A2 ; /StringToAdd = "emhhbmd0YW9weQ=="
0040113E |. 68 D4324000 PUSH kiToKGNm.004032D4 ; |ConcatString = "emhhbmd0YW9weQ==RUQ4MDA4MzBSVVE0TURBNE=="
00401143 |. E8 A0080000 CALL <JMP.&kernel32.lstrcatA> ; \lstrcatA
00401148 |. 68 3E324000 PUSH kiToKGNm.0040323E ; /StringToAdd = "RUQ4MDA4MzBSVVE0TURBNE=="
0040114D |. 68 D4324000 PUSH kiToKGNm.004032D4 ; |ConcatString = "emhhbmd0YW9weQ==RUQ4MDA4MzBSVVE0TURBNE=="
00401152 |. E8 91080000 CALL <JMP.&kernel32.lstrcatA> ; \lstrcatA
00401157 |. 68 D4324000 PUSH kiToKGNm.004032D4 ; /String = "emhhbmd0YW9weQ==RUQ4MDA4MzBSVVE0TURBNE=="
0040115C |. E8 93080000 CALL <JMP.&kernel32.lstrlenA> ; \lstrlenA
00401161 |. A3 A0314000 MOV DWORD PTR DS:[4031A0],EAX ; 字符串长度00401166 |. E8 3D060000 CALL kiToKGNm.004017A8 ; MD5初始化
0040116B |. FF35 A0314000 PUSH DWORD PTR DS:[4031A0]
00401171 |. 68 D4324000 PUSH kiToKGNm.004032D4 ; ASCII "emhhbmd0YW9weQ==RUQ4MDA4MzBSVVE0TURBNE=="
00401176 |. E8 6D060000 CALL kiToKGNm.004017E8 ; MD5 填充函数
0040117B |. E8 C8060000 CALL kiToKGNm.00401848 ; MD5计算
最后将算出来的32位MD5码 以双字的形式相加,的出来的结果转化成字符串后,将第5个字符变成'-',就得出注册码了:
00401182 |. 0318 ADD EBX,DWORD PTR DS:[EAX] ;4个双字相加
00401184 |. 0358 04 ADD EBX,DWORD PTR DS:[EAX+4]
00401187 |. 0358 08 ADD EBX,DWORD PTR DS:[EAX+8]
0040118A |. 0358 0C ADD EBX,DWORD PTR DS:[EAX+C]
0040118D |. 53 PUSH EBX ; /<%X>
0040118E |. 68 00304000 PUSH kiToKGNm.00403000 ; |Format = "%X"
00401193 |. 68 38334000 PUSH kiToKGNm.00403338 ; |s
00401198 |. E8 5D080000 CALL <JMP.&user32.wsprintfA> ; \wsprintfA
0040119D |. 83C4 0C ADD ESP,0C ;结果转化成字符串
004011A0 |. C605 3C334000>MOV BYTE PTR DS:[40333C],2D ;第5个字符变为'-'
004011A7 |. 6A 32 PUSH 32 ; /Count = 32 (50.)
004011A9 |. 68 6A334000 PUSH kiToKGNm.0040336A ; |Buffer
004011AE |. 68 EA030000 PUSH 3EA ; |ControlID = 3EA 004011B3 |. FF75 08 PUSH DWORD PTR SS:[EBP+8] ; |hWnd
004011B6 |. E8 51080000 CALL <JMP.&user32.GetDlgItemTextA> ;
004011BB |. 68 6A334000 PUSH kiToKGNm.0040336A ; /String2 = "9B02-52"
004011C0 |. 68 38334000 PUSH kiToKGNm.00403338 ; |String1 = "9B02-52"
004011C5 |. E8 24080000 CALL <JMP.&kernel32.lstrcmpA> ; \lstrcmpA 明码比较
分析完毕~~
2L注册机
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!