逆向工程初步160个crackme-------2

有了第一个crackme的经验后,这个crackme用了半个小时就验证成功了。(思路和第一个crackme相似)

动态调试工具:ollydbg (2.10)
文件分析工具:PEID (0.95)
同样我们先来运行一下程序了解一下程序的大致流程,对程序有个大致了解。
在这里插入图片描述让输入用户名和序列号,我们随便输入一个
在这里插入图片描述输入后弹出一个消息框,显示失败提示从新输入的信息。
现在我们对程序有了初步的了解,
思路:我们需要找到在什么位置判断的序列号错误并弹出失败的信息。然后在找到正确的序列号是什么,正确的序列号是在何时产生的以及生成的算法。

在这之前我们先来分析一下文件的信息,利用PEID工具
在这里插入图片描述由信息可知其实VB编写的32位应用程序,现在我们开始对其进行逆向分析。

  1. 打开OD并运行程序,随便输入用户名和序列号点击确定弹出失败的信息在这里插入图片描述
  2. 我们需要从弹出失败的窗口入手,往上寻找判断函数(判断序列号是否正确的函数),因此我们需要设置弹出失败消息框的API断点,因为我对VB不了解也不知道其用的什么函数所以就把所有弹出消息框的函数都设置了断点,其在哪个函数入口停止那就是调用的哪个函数。

设置完断点后再次点击“OK”,程序停在了弹出消息框的函数的入口,看eip和栈中函数调用提示信息可知其调用的是MessageBoxIndirect()函数在这里插入图片描述
3. 然后我们在栈中的返回地址上右击选择反汇编跟踪,然后在call调用处(即调用MessageBoxIndirect()函数的位置)下段点,(运行程序并再次点击OK),程序将在此处停止
在这里插入图片描述
4. 我们知道判断函数肯定是自己编写的,肯定在用户模块所以我们需要一层一层的往上次函数找,(判断函数肯定不在系统模块),所以我们往call前寻找函数头,然后在往上层调用函数走。

注意一般的函数头都为push ebp | mov ebp,esp
,或者是在最近的一个retn指令下,但是不是说其一定在retn指令下面,一个函数可能包含retn指令。本程序就是其函数头并不一定在最近的rent指令下,在这里插入图片描述此处的xor esi,esi并不是函数头部,其实由retn上面的一条指令跳转到这的,继续往上寻找函数入口。
在这里插入图片描述找到push bp,疑似函数头部在其设置断点之后运行程序并再次点击“OK”,程序停在此处,在这里插入图片描述然后查看栈中上层函数的返回地址,重复 步骤3和步骤 4,直到返回到用户区()

  1. 返回到用户区后暂停在调用函数处,此时模块为A!fkayas
    而且在注释区发现失败窗口的提示信息(胜利在像我们招手)
    在这里插入图片描述
    6.继续往前 寻找发现成功的信息,并在成功的信息上方看到一条跳转指令和测试指令,而且跳转指令正好跳转到失败的信息处,所以可以得知此处即为判断序列号的正确的位置。
    在这里插入图片描述
  2. 找到关键位置之后我们就分析此处的代码
    测试指令为test si,si
    那么就找出改变esi值的所有指令,逆向分析指令,因为跳转指令为je,所以要想不跳转则ZF位为1,test si,si中的si不为0
    ,继续往上分析(下面代码倒着分析)
mov  esi,eax      //所以eax为0
neg  esi				//因为CF应为0所以此处esi为0
sbb esi,esi			//因为esi不能为FFFFFFFFH,所以此处CF位应为0
inc esi					//esi不能为0,此处esi不能为FFFFFFFFH
neg esi			   //因为si不为0,所以此处的esi不能为0

又因为EAX是函数_vbaStrCmp(VB程序字符串比较函数)的返回值,所以_vbaStrCmp比较的两个字符串应相等。在函数调用处下断点(再次运行程序点击OK)
在这里插入图片描述
在栈窗口中可以看到两个字符串参数,一个为我们输入的序列号,所以另一个应该为真正的序列号,现在我们要做的就是找到序列号是在哪里产生的,是如何产生的(序列号的算法),

  1. 我们往上发现字符串连接函数,其中一个参数是“AKA-”正好是正确序列号的开头,所以我们在其调用处设段并运行程序,
    在这里插入图片描述运行程序之后程序断到此处,发现其入口参数,其中第二各参数应该是序列号算法得到的,在这里插入图片描述其值为585234那么我么就从函数头部开始看有没有和585234相关的东西,在函数头下断点(再次运行程序并点击OK),F8单步运行并注意观察各个窗口中的注释信息,一旦发现5885234的信息就暂停运行,
    在这里插入图片描述在此处发现5885234的信息,分析前面的代码,动态跟踪此代码块得知
0040240F   .  8B45 E4        mov eax,dword ptr ss:[ebp-0x1C]
00402412   .  50             push eax                                 ; /String
00402413   .  8B1A           mov ebx,dword ptr ds:[edx]               ; |
00402415   .  FF15 E4404000  call dword ptr ds:[<&MSVBVM50.__vbaLenBs>; \__vbaLenBstr
;计算出输入用户名的长度,
;eax返回值为用户名的长度


0040241B   .  8BF8           mov edi,eax
0040241D   .  8B4D E8        mov ecx,dword ptr ss:[ebp-0x18]
00402420   .  69FF FB7C0100  imul edi,edi,0x17CFB
;用户名长度乘以0x17cfb,结果保存到edi中


00402426   .  51             push ecx                                 ; /String
00402427   .  0F80 91020000  jo Afkayas_.004026BE                     ; |
0040242D   .  FF15 F8404000  call dword ptr ds:[<&MSVBVM50.#516>]     ; 
tcAnsiValueBstr
;将用户名第一个字符的ansi码转化为数值存到ax中


00402433   .  0FBFD0         movsx edx,ax
00402436   .  03FA           add edi,edx
;edx=ax
;edi=edi+edx

00402438   .  0F80 80020000  jo Afkayas_.004026BE
0040243E   .  57             push edi
0040243F   .  FF15 E0404000  call dword ptr ds:[<&MSVBVM50.__vbaStrI4>;  MSVBVM50.__vbaStrI4
00402445   .  8BD0           mov edx,eax
;再把edi的值以asiic的形式存到内存中

最后得序列号算法为:(用户名的长度乘以0x17cfb后,加上第一个字符的asiic值得到的数)与"AKA-"连接组合成序列号,注册机就不写了很简单。

原文地址:https://www.cnblogs.com/revercc/p/13287085.html