[反汇编练习] 160个CrackMe之011
[反汇编练习] 160个CrackMe之011.本系列文章的目的是从一个没有任何经验的新手的角度(其实就是我自己),一步步尝试将160个CrackMe全部破解,如果可以,通过任何方式写出一个类似于注册机的东西。其中,文章中按照如下逻辑编排(解决如下问题):1、使用什么环境和工具2、程序分析3、思路分析和破解流程4、注册机的探索----------------------------------提醒各位看客: 如果文章中的逻辑看不明白,那你一定是没有亲手操刀!OD中的跳转提示很强大,只要你跟踪了,不用怎么看代码就理解了!----------------------------------1、工具和环境:WinXP SP3 + 52Pojie六周年纪念版OD + PEID + 汇编金手指。160个CrackMe的打包文件。下载地址: http://pan.baidu.com/s/1xUWOY 密码: jbnq注:1、Win7系统对于模块和程序开启了随机初始地址的功能,会给分析带来很大的负担,所以不建议使用Win7进行分析。2、以上工具都是在52PoJie论坛下的原版程序,NOD32不报毒,个人承诺绝对不会进行任何和木马病毒相关内容。http://images.cnitblog.com/blog/573547/201406/192147191763366.png2、程序分析:想要破解一个程序,必须先了解这个程序。所以,在破解过程中,对最初程序的分析很重要,他可以帮助我们理解作者的目的和意图,特别是对于注册码的处理细节,从而方便我们反向跟踪和推导。和上一节一样,打开CHM,选择第11个Andrénalin.4,保存下来。运行程序,程序界面如下:http://images.cnitblog.com/blog/573547/201406/192147291926858.png3、思路分析和破解流程:随意点击几个数字,发现没有提示。但是我们可以在右侧的Status: UNREGISTRIERT,我们可以大胆地猜测,如果序列号正常,这个文本应该会变为成功一类的提示。没有什么线索,直接放到OD里进行分析。1、使用PEID查下壳,Microsoft Visual Basic 5.0 / 6.0,没有壳。2、打开OD,将exe拖到OD当中,F9运行。3、由于找不到任何线索,我们还是用“最笨的”查找字符串办法,点击E图标,选中Andrénalin.4.exe,右键->Follow Entry,这样我们就进入了主模块。4、在反汇编窗口任意位置,右键->中文搜索引擎->智能搜索,发现了0-9的数字和很多类似0817E747D7AFF7C7F82836D74RR7A7F7E7B7C7D826D81KE7B7C和REGISTRIERT的字符串。5、我们随意选择一个数字,双击进去发现都是类似如下的代码:00404439 . /7D 12 jge short 0040444D0040443B . |68 A0000000 push 0xA0
00404440 . |68 B81D4000 push 00401DB8
00404445 . |56 push esi
00404446 . |50 push eax
00404447 . |FF15 2C104000 call dword ptr ds:[<&MSVBVM60.__vbaHresu>;msvbvm60.__vbaHresultCheckObj
0040444D > \8B55 E8 mov edx,dword ptr ss:
00404450 .8B37 mov esi,dword ptr ds:
00404452 .52 push edx
00404453 .68 1C1E4000 push 00401E1C ;8
00404458 .FF15 28104000 call dword ptr ds:[<&MSVBVM60.__vbaStrCa>;msvbvm60.__vbaStrCat
0040445E .8BD0 mov edx,eax
00404460 .8D4D E4 lea ecx,dword ptr ss:
00404463 .FF15 BC104000 call dword ptr ds:[<&MSVBVM60.__vbaStrMo>;msvbvm60.__vbaStrMove
00404469 .50 push eax
0040446A .57 push edi
0040446B .FF96 A4000000 call dword ptr ds:
00404471 .85C0 test eax,eax
00404473 .DBE2 fclex
00404475 .7D 12 jge short 00404489
上下查找,找不到任何与算法跳转相关的东西。6、字符串0817E747D7AFF7C7F82836D74RR7A7F7E7B7C7D826D81KE7B7C和REGISTRIERT反而更像是注册码相关的东西,只是….这些注册码是不是有些多的太过了!7、选择第一个REGISTRIERT文本,双击进去,向上浏览代码。哇,似乎和之前的三个都一样啊!太好了,我们大概分析一下:00404A5B .^\E9 CFFEFFFF jmp 0040492F
00404A60 >8D55 CC lea edx,dword ptr ss:
00404A63 .8D85 4CFFFFFF lea eax,dword ptr ss:
00404A69 .52 push edx
00404A6A .50 push eax
00404A6B .C785 54FFFFFF>mov dword ptr ss:,00401E50 ;0817E747D7AFF7C7F82836D74RR7A7F7E7B7C7D826D81KE7B7C
00404A75 .C785 4CFFFFFF>mov dword ptr ss:,0x8008 ;// 修改eax指针的内容
00404A7F .FF15 5C104000 call dword ptr ds:[<&MSVBVM60.__vbaVarTs>;msvbvm60.__vbaVarTstEq // 字符串比较
00404A85 .66:85C0 test ax,ax
00404A88 .74 4C je short 00404AD6 ;// 爆破的关键跳转
00404A8A .8B45 08 mov eax,dword ptr ss:
00404A8D .50 push eax
00404A8E .8B08 mov ecx,dword ptr ds:
00404A90 .FF91 38030000 call dword ptr ds:
00404A96 .8D55 AC lea edx,dword ptr ss:
00404A99 .50 push eax
00404A9A .52 push edx
00404A9B .FF15 3C104000 call dword ptr ds:[<&MSVBVM60.__vbaObjSe>;msvbvm60.__vbaObjSet
00404AA1 .8B08 mov ecx,dword ptr ds:
00404AA3 .68 BC1E4000 push 00401EBC ;REGISTRIERT
00404AA8 .50 push eax
00404AA9 .8985 30FFFFFF mov dword ptr ss:,eax
00404AAF .FF51 54 call dword ptr ds:
哈哈, msvbvm60.__vbaVarTstEq 进行字符串比较test ax,ax和je short 00404AD6完成是否跳转的判断,爆破的关键就是这里啦!选中je语句,右键->Binary->Fill with NOPs。回到程序,神马?已经提示成功了!
4、算法探索根据msvbvm60.__vbaVarTstEq进行文本比较,我们很容易想到就是通过一个算法生成饿了一个字符串,然后这个字符串与“0817E747D7AFF7C7F82836D74RR7A7F7E7B7C7D826D81KE7B7C”进行比较,若果相等就成功。我们按照这个思路继续向上分析代码:004048FD .FF15 30104000 call dword ptr ds:[<&MSVBVM60.__vbaLenVa>;msvbvm60.__vbaLenVar
00404903 .50 push eax ;// "12321"
00404904 .8D95 3CFFFFFF lea edx,dword ptr ss:
0040490A .8D85 08FFFFFF lea eax,dword ptr ss:
00404910 .52 push edx ;1
00404911 .8D8D 18FFFFFF lea ecx,dword ptr ss:
00404917 .50 push eax ;// 5
00404918 .8D55 DC lea edx,dword ptr ss: ;UNICODE "0817E747D7A7D7C7F82836D74G47A7F7E7B7C7D826D817E7B7"
0040491B .51 push ecx ;ecx=1
0040491C .52 push edx ;0
0040491D .FF15 38104000 call dword ptr ds:[<&MSVBVM60.__vbaVarFo>;msvbvm60.__vbaVarForInit
00404923 .8B35 80104000 mov esi,dword ptr ds:[<&MSVBVM60.__vbaSt>;msvbvm60.__vbaStrVarVal
00404929 .8B1D B4104000 mov ebx,dword ptr ds:[<&MSVBVM60.#617>];msvbvm60.rtcLeftCharVar
0040492F >85C0 test eax,eax
00404931 .0F84 29010000 je 00404A60
00404937 .8D45 BC lea eax,dword ptr ss:
0040493A .6A 01 push 0x1
0040493C .8D4D 8C lea ecx,dword ptr ss:
0040493F .50 push eax ;// '12321'
00404940 .51 push ecx ;// '1'
00404941 .FFD3 call ebx ;msvbvm60.rtcLeftCharVar
00404943 .8D55 8C lea edx,dword ptr ss:
00404946 .8D45 B0 lea eax,dword ptr ss:
00404949 .52 push edx
0040494A .50 push eax
0040494B .FFD6 call esi ;msvbvm60.__vbaStrVarVal
0040494D .50 push eax
0040494E .FF15 D8104000 call dword ptr ds:[<&MSVBVM60.#581>] ;msvbvm60.rtcR8ValFromBstr
00404954 .DD9D 34FFFFFF fstp qword ptr ss:
0040495A .8D4D 9C lea ecx,dword ptr ss:
0040495D .8D55 DC lea edx,dword ptr ss:
00404960 .51 push ecx
00404961 .52 push edx
00404962 .C745 A4 01000>mov dword ptr ss:,0x1
00404969 .C745 9C 02000>mov dword ptr ss:,0x2
00404970 .FF15 AC104000 call dword ptr ds:[<&MSVBVM60.__vbaI4Var>;msvbvm60.__vbaI4Var
00404976 .50 push eax ;eax=1 2 3 4
00404977 .8D45 BC lea eax,dword ptr ss:
0040497A .8D4D B8 lea ecx,dword ptr ss:
0040497D .50 push eax
0040497E .51 push ecx
0040497F .FFD6 call esi ;msvbvm60.__vbaStrVarVal
00404981 .50 push eax ;// '12321'
00404982 .FF15 4C104000 call dword ptr ds:[<&MSVBVM60.#631>] ;msvbvm60.rtcMidCharBstr
00404988 .8BD0 mov edx,eax
0040498A .8D4D B4 lea ecx,dword ptr ss:
0040498D .FF15 BC104000 call dword ptr ds:[<&MSVBVM60.__vbaStrMo>;msvbvm60.__vbaStrMove
00404993 .50 push eax
00404994 .FF15 20104000 call dword ptr ds:[<&MSVBVM60.#516>] ;msvbvm60.rtcAnsiValueBstr
0040499A .0FBFD0 movsx edx,ax ;// 取字符的ansii,0x31 0x32 0x33 0x32
0040499D .8995 FCFCFFFF mov dword ptr ss:,edx
004049A3 .C785 7CFFFFFF>mov dword ptr ss:,0x5
004049AD .DB85 FCFCFFFF fild dword ptr ss: ;// 转为浮点数,压栈st0
004049B3 .DD9D F4FCFFFF fstp qword ptr ss: ;// 出栈
004049B9 .DD85 F4FCFFFF fld qword ptr ss: ;// 浮点加载数,拉取数据
004049BF .DC85 34FFFFFF fadd qword ptr ss: ;//从堆栈中弹出这二个操作数,然后把计算的“和”压入堆栈,即:ST=ST(1)+ST
004049C5 .DD5D 84 fstp qword ptr ss: ;// 出栈,50.0,51, 52,51
004049C8 .DFE0 fstsw ax ;// ax=0x100
004049CA .A8 0D test al,0xD ;// 不知道为什么是和0xD比较,但是不用咱关心
004049CC .0F85 FA1F0000 jnz 004069CC ;跳到异常处理,正常不跳
004049D2 .8D85 7CFFFFFF lea eax,dword ptr ss:
004049D8 .50 push eax
004049D9 .FF15 94104000 call dword ptr ds:[<&MSVBVM60.#572>] ;msvbvm60.rtcHexBstrFromVar
004049DF .8D4D CC lea ecx,dword ptr ss:
004049E2 .8985 74FFFFFF mov dword ptr ss:,eax
004049E8 .8D95 6CFFFFFF lea edx,dword ptr ss:
004049EE .51 push ecx ;// '0' '032'// 上一次保存的值
004049EF .8D85 5CFFFFFF lea eax,dword ptr ss:
004049F5 .52 push edx ;// '33' = 0x32 + 1// 浮点数的hex值
004049F6 .50 push eax ;// '032'
004049F7 .C785 6CFFFFFF>mov dword ptr ss:,0x8
00404A01 .FF15 84104000 call dword ptr ds:[<&MSVBVM60.__vbaVarCa>;msvbvm60.__vbaVarCat
00404A07 .8BD0 mov edx,eax ;// '0323334'
00404A09 .8D4D CC lea ecx,dword ptr ss:
00404A0C .FFD7 call edi ;msvbvm60.__vbaVarMove // 将结果存到
00404A0E .8D4D B0 lea ecx,dword ptr ss:
00404A11 .8D55 B4 lea edx,dword ptr ss:
00404A14 .51 push ecx
00404A15 .8D45 B8 lea eax,dword ptr ss:
00404A18 .52 push edx
00404A19 .50 push eax
00404A1A .6A 03 push 0x3
00404A1C .FF15 9C104000 call dword ptr ds:[<&MSVBVM60.__vbaFreeS>;msvbvm60.__vbaFreeStrList
00404A22 .8D8D 6CFFFFFF lea ecx,dword ptr ss:
00404A28 .8D95 7CFFFFFF lea edx,dword ptr ss:
00404A2E .51 push ecx
00404A2F .8D45 8C lea eax,dword ptr ss:
00404A32 .52 push edx
00404A33 .8D4D 9C lea ecx,dword ptr ss:
00404A36 .50 push eax
00404A37 .51 push ecx
00404A38 .6A 04 push 0x4
00404A3A .FF15 14104000 call dword ptr ds:[<&MSVBVM60.__vbaFreeV>;msvbvm60.__vbaFreeVarList
00404A40 .83C4 24 add esp,0x24
00404A43 .8D95 08FFFFFF lea edx,dword ptr ss:
00404A49 .52 push edx
00404A4A .8D85 18FFFFFF lea eax,dword ptr ss:
00404A50 .8D4D DC lea ecx,dword ptr ss:
00404A53 .50 push eax
00404A54 .51 push ecx
00404A55 .FF15 C8104000 call dword ptr ds:[<&MSVBVM60.__vbaVarFo>;msvbvm60.__vbaVarForNext
00404A5B .^ E9 CFFEFFFF jmp 0040492F
00404A60 >8D55 CC lea edx,dword ptr ss:
00404A63 .8D85 4CFFFFFF lea eax,dword ptr ss:
00404A69 .52 push edx
00404A6A .50 push eax
00404A6B .C785 54FFFFFF>mov dword ptr ss:,00401E50 ;0817E747D7AFF7C7F82836D74RR7A7F7E7B7C7D826D81KE7B7C
00404A75 .C785 4CFFFFFF>mov dword ptr ss:,0x8008 ;// 修改eax指针的内容
00404A7F .FF15 5C104000 call dword ptr ds:[<&MSVBVM60.__vbaVarTs>;msvbvm60.__vbaVarTstEq // 字符串比较
00404A85 .66:85C0 test ax,ax
00404A88 .74 4C je short 00404AD6 ;// 爆破的关键跳转
00404A8A .8B45 08 mov eax,dword ptr ss:
00404A8D .50 push eax
00404A8E .8B08 mov ecx,dword ptr ds:
00404A90 .FF91 38030000 call dword ptr ds:
00404A96 .8D55 AC lea edx,dword ptr ss:
00404A99 .50 push eax
00404A9A .52 push edx
00404A9B .FF15 3C104000 call dword ptr ds:[<&MSVBVM60.__vbaObjSe>;msvbvm60.__vbaObjSet
00404AA1 .8B08 mov ecx,dword ptr ds:
00404AA3 .68 BC1E4000 push 00401EBC ;REGISTRIERT
具体VB函数请参考前几节的说明,这里只针对算法部分分析。算法其实内容也很简单,就是在代码:00404994 .FF15 20104000 call dword ptr ds:[<&MSVBVM60.#516>] ;msvbvm60.rtcAnsiValueBstr
0040499A .0FBFD0 movsx edx,ax ;// 取字符的ansii,0x31 0x32 0x33 0x32
0040499D .8995 FCFCFFFF mov dword ptr ss:,edx
004049A3 .C785 7CFFFFFF>mov dword ptr ss:,0x5
004049AD .DB85 FCFCFFFF fild dword ptr ss: ;// 转为浮点数,压栈st0
004049B3 .DD9D F4FCFFFF fstp qword ptr ss: ;// 出栈
004049B9 .DD85 F4FCFFFF fld qword ptr ss: ;// 浮点加载数,拉取数据
004049BF .DC85 34FFFFFF fadd qword ptr ss: ;//从堆栈中弹出这二个操作数,然后把计算的“和”压入堆栈,即:ST=ST(1)+ST
004049C5 .DD5D 84 fstp qword ptr ss: ;// 出栈,50.0,51, 52,51
004049C8 .DFE0 fstsw ax ;// ax=0x100
004049CA .A8 0D test al,0xD ;// 不知道为什么是和0xD比较,但是不用咱关心
004049CC .0F85 FA1F0000 jnz 004069CC ;跳到异常处理,正常不跳
004049D2 .8D85 7CFFFFFF lea eax,dword ptr ss:
004049D8 .50 push eax
004049D9 .FF15 94104000 call dword ptr ds:[<&MSVBVM60.#572>] ;msvbvm60.rtcHexBstrFromVar
进行浮点数加法,具体内容是每个字符的ANSII码,加上一个固定的值1,然后格式化为开头为0,然后每个字符加之后的值格式化为2位十六进制文本,最后组合起来的文本与之前的固定文本进行比较,如果成功则注册成功!似乎很简单啊!我们尝试C/CPP反计算序列号:#include "stdafx.h"
#include "iostream"
int hex2int(char cAnsi)
{
int nRet = '*';
if ( cAnsi >= '0' && cAnsi <= '9')
{
nRet = cAnsi - '0';
}else if ( cAnsi >= 'A' && cAnsi<= 'Z' )
{
nRet = cAnsi - 'A' + 10;
}else if ( cAnsi >= 'a' && cAnsi<= 'z' )
{
nRet = cAnsi - 'A' + 10;
}
return nRet;
}
int _tmain(int argc, _TCHAR* argv[])
{
char pCmp[] = "0817E747D7AFF7C7F82836D74RR7A7F7E7B7C7D826D81KE7B7C"; // 第一个一定是0,不做处理
char pKey = {0};
char cHex = {0};
// 转换为整数,然后减一的值作为ANSII码组成字符串
int nLen = strlen(pCmp);
printf("Len: %d\r\n",nLen);
int nCode = 0;
for( int i=0;i<nLen/2;i++ )
{
cHex = pCmp;
cHex = pCmp;
nCode = hex2int(pCmp)*0x10 + hex2int(pCmp);
pKey = nCode - 1; // 1,12,
}
printf("Key:%s\r\n",pKey);
system("pause");
return 0;
}
计算出来一堆乱七八糟的文本,不管了,…..可是我们无法输入进去啊!坑啊!回想之前的步骤,是不是还有很多比较的文本和“REGISTR”字样的文本?好吧,我们也尝试一下….我直接说结果吧!他们的代码几乎就一样的,只是中间加的固定值不太一样,所以,我们多换几个(其实C/CPP中也已经试过了!),试过之后发现,还是无法计算出一个使0-9组成的字符串,真心无语了!到了这里,说实在的,真的没什么办法了!我的算法似乎也找到了,但是为什么不对呢?本着【相信CracMe作者,怀疑自己的态度】,到网上搜索还有没有更好的反汇编VB的程序,答案是:没有!但是,找到了一个可以跟踪VB事件的程序,叫做VB程序调试工具(SmartCheck),抱着试一试的态度,还真看出来了一些门道:
建议感兴趣的自己去下一个看看,一定要再输入完成后停止捕捉事件,然后等待日志完成。拉到最后几个,随意选择一个事件,按照顺序查看,你会很惊奇地发现:比如我输入的注册码为12321,程序进行了如下步骤:1、 取第1个字符‘1’,转换为ANSII为0x31,然后加上12、 取第2个字符‘2’,转换为ANSII为0x32,然后加上13、 取第3个字符‘3’,转换为ANSII为0x33,然后加上14、 取第4个字符‘2’,转换为ANSII为0x32,然后加上15、 取第5个字符‘1’,转换为ANSII为0x31,然后加上16、 取第1个字符‘1’,转换为ANSII为0x31,然后加上127、 取第2个字符‘2’,转换为ANSII为0x32,然后加上128、 取第3个字符‘3’,转换为ANSII为0x33,然后加上12…….然后每个字符都加上 123,再一次每个字符加上1232,再一次每个字符加上12321,结束。我们可以大胆地猜测,每次循环都将我们之前分析的算法使用上,进行字符串比较,然后相等的才是正确的注册码!我实在无语了!多么坑的作者才会做出这么OOXX的程序,反正按照这个思路我是找不到的。暴力遍历的思路是有的,但是一想到一共51个字符,算下来这个注册码应该的长度是25个数字或者*#号,我就有一种蛋蛋的忧伤!ByeBye 不伺候你了!活该被标记了一个大大的问号!
BY 笨笨D幸福
不看算法了,直接看爆破就好了 很厉害的样子 大赞!不错 0817E747D7AFF7C7F82836D74RR7A7F7E7B7C7D826D81KE7B7C有个RR,RR又不是16进制,我感觉没有答案,只有爆破 留着以后学习 唉,说难也难,说简单也简单,没办法定级了{:1_924:} 本帖最后由 Pnmker 于 2015-5-25 22:04 编辑
彬之酷吻 发表于 2014-11-30 16:33
0817E747D7AFF7C7F82836D74RR7A7F7E7B7C7D826D81KE7B7C有个RR,RR又不是16进制,我感觉没有答案,只有爆破
是的,并非所有的字符串都符合16进制数规则的,实际上如果仔细辨认的话只有"0817E747D7A7D7C7F82836D74747A7F7E7B7C7D826D817E7B7C"一个,
阅读相关代码可以知道这个字符串的计算是从输入的序列号的前2位数字做加法的,
因此可以推测2位数字最大为99(0x63), 序列号中输入最大数字为9(0x39),
那么0x63+0x39=9C,
即"0817E747D7A7D7C7F82836D74747A7F7E7B7C7D826D817E7B7C"除去前导0之后,每2个字符构成一个程序循环计算的数字
即81 7E 74 7D 7A 7D 7C 7F 82 83 6D 74 74 7A 7F 7E 7B 7C 7D 82 6D 81 7E 7B 7C
这些16进制数字中最大的为83,最小的为6D, 0x83-0x6D=0x16(十进制22)
出现差值22这么大,不可能全是数字,而且6D所在的位置在序列号一定是‘#’ (0x23)
因此,序列号的前两位代表的数字为0x6D-0x23=0x4A,
那么0x81-0x4A=0x37 ('7'), 0x7E-0x4A=0x34 ('4'), ......,0x7B-0x4A=0x31 ('1'), 0x7C-0x4A=0x32 ('2')依次计算完就可以得出序列号
74*3032589#**0541238#7412
输进去试一下吧,哈哈
不看算法了,直接看爆破就好了 Pnmker 发表于 2015-5-25 22:02
是的,并非所有的字符串都符合16进制数规则的,实际上如果仔细辨认的话只有"0817E747D7A7D7C7F82836D7474 ...
除了"0817E747D7A7D7C7F82836D74747A7F7E7B7C7D826D817E7B7C"可以,不是还有一个
“0817E747D”吗?怎么这个不行呢?
页:
[1]