pk8900 发表于 2017-6-22 00:57

[反汇编练习]160个Crackme之011-Andrénalin.4-详细分析

本帖最后由 pk8900 于 2017-6-22 01:15 编辑

【程序说明】160个Crackme之011-Andrénalin.4,VB 5.0,无壳。
【下载地址:】http://pan.baidu.com/share/link?shareid=541269&uk=4146939145


最近几天学C++学的头晕转向,于是继续进行160个Crackme系列,这个Andrénalin的系列Crackme还真是不好弄,前面几个研究完收获不小,尤其是自己仿写了些代码,反汇编研究,下面就这个Andrénalin.4,给大家详细介绍一下我的分析过程和心得。
Crackme界面如下 :



一些数字键,*、#,<-(退格键),点任意数字键钮,上方文本框中显示字符,同时退格键亮起。右侧有"UNREGISTRIERT"字样,输入正确字符串后,会显示"REGISTRIERT"字样。搜索程序字符串资源,会发现有很多的字串及"REGISTRIERT"



这说明程序采用的是Native Code编码方式,VB编写的应用程序有两种编译方式,一种是Native code方式,另一种是P-code方式,P-code方式程序是搜索不到字符串的。因为P-code方式程序的字节码是运行的时候由msvbvm50.dll和msvbvm60.dll解释执行,所以调试的时候往往会断在msvbvm50.dll和msvbvm60.dll的领空。这个程序爆破起来很容易,因为"REGISTRIERT"字样到处都是,修改之前的跳转,就能达到目的,而我要研究的是程序的算法,所以要进行跟踪,顺着"REGISTRIERT"上找,跟了半天,大致的明白了一点程序的验证流程,但一想到字符串搜索里那若干的REGISTRIERT"和长字符串,就有种不安的感觉,会不会掉到作者挖的坑里了。还是用VB Decompiler Pro反编译看看吧,随便说一下,VB程序反编译,对于分析破解VB程序非常重要,因为VB程序用OD分析,如果代码长,你跟踪变量都会跟丢了。
反编译程序果然发现很多信息:



程序只有一个窗体,但有4个Timer控件,每个控件的周期为1毫秒,而所有的验证代码都在Timer事件中。每个事件中有15段代码,内容大至雷同。



通过对其中一段代码进行分析:
loc_00406CAD: For var_24 = 1 To Len(var_44) Step 1 循环读取字符输入字符
loc_00406CBF:
   loc_00406CC1: If var_F8 = 0 Then GoTo loc_00406DF0 若当前为0跳到验证部分
loc_00406CDB: var_50 = CStr(Left(var_44, 1))   ;取左第一个字母
loc_00406D2D: var_304 = Asc(Mid$(CStr(var_44), CLng(var_24), 1))取当前字母ASC值
loc_00406D72: var_8C = Hex$((var_30C + var_CC))    加上一个数后(经后来分析是一个基数,由输入的数左取固定位转10进制数值得来 变量: var_CC)转为十六进制字符串,
loc_00406D9C: var_34 = var_34 & Hex$((var_30C + var_CC))   累加字符串至变量
以上为大至分析结果,还看不出具体算法,于是用调试器跟踪,因为是时间事件,所以先取消所有断点,输好字符后,再至代码处下断,就会立即断下来。
X32dbg中分析流程:【注:反编译中的var_CC,就是调试器跟踪中的EBP-CC堆栈地址,可以锁定堆栈,把堆栈切换成+??或-??的EBP偏移,方便观察变量的值。】

00406EDC | 85 C0               | test eax,eax                               | 循环控制
00406EDE | 0F 84 29 01 00 00   | je 40700D                                  |
00406EE4 | 8D 4D BC            | lea ecx,dword ptr ss:            | ebp-44是输入的字符串,字符串实际为ebp-3c
00406EE7 | 6A 02               | push 2                                     | 2个
00406EE9 | 8D 55 8C            | lea edx,dword ptr ss:            | ebp-74 结果返回地址,字符:ebp-6c
00406EEC | 51                  | push ecx                                 |
00406EED | 52                  | push edx                                 |
00406EEE | FF D3               | call ebx                                 | msvbvm60.rtcLeftCharVar
00406EF0 | 8D 45 8C            | lea eax,dword ptr ss:            | 返回的两个字符
00406EF3 | 8D 4D B0            | lea ecx,dword ptr ss:            | 结果保存地址
00406EF6 | 50                  | push eax                                 |
00406EF7 | 51                  | push ecx                                 |
00406EF8 | FF D6               | call esi                                 | var_50 = CStr(Left(var_44, 2))
00406EFA | 50                  | push eax                                 |
00406EFB | FF 15 D8 10 40 00   | call dword ptr ds:[<&rtcR8ValFromBstr>]    | 字符串转换成浮点数:st0中
00406F01 | DD 9D 34 FF FF FF   | fstp qword ptr ss:               | 数值传给变量ebp-cc *64位*
00406F07 | 8D 55 9C            | lea edx,dword ptr ss:            |
00406F0A | 8D 45 DC            | lea eax,dword ptr ss:            |
00406F0D | 52                  | push edx                                 |
00406F0E | 50                  | push eax                                 |
00406F0F | C7 45 A4 01 00 00 00| mov dword ptr ss:,1                |
00406F16 | C7 45 9C 02 00 00 00| mov dword ptr ss:,2                |
00406F1D | FF 15 AC 10 40 00   | call dword ptr ds:[<&_vbaI4Var>]         |
00406F23 | 8D 4D BC            | lea ecx,dword ptr ss:            |
00406F26 | 50                  | push eax                                 |
00406F27 | 8D 55 B8            | lea edx,dword ptr ss:            |
00406F2A | 51                  | push ecx                                 |
00406F2B | 52                  | push edx                                 |
00406F2C | FF D6               | call esi                                 |
00406F2E | 50                  | push eax                                 |
00406F2F | FF 15 4C 10 40 00   | call dword ptr ds:[<&rtcMidCharBstr>]      | 循环取字符从1开始
00406F35 | 8B D0               | mov edx,eax                              |
00406F37 | 8D 4D B4            | lea ecx,dword ptr ss:            |
00406F3A | FF 15 BC 10 40 00   | call dword ptr ds:[<&_vbaStrMove>]         |
00406F40 | 50                  | push eax                                 |
00406F41 | FF 15 20 10 40 00   | call dword ptr ds:[<&rtcAnsiValueBstr>]    | ASCLL值
00406F47 | 0F BF C0            | movsx eax,ax                               | 存入变量ebp-310中
00406F4A | 89 85 F0 FC FF FF   | mov dword ptr ss:,eax             | var_310 = Asc(Mid$(CStr(var_44), CLng(var_24), 1))
00406F50 | 8D 8D 7C FF FF FF   | lea ecx,dword ptr ss:            |
00406F56 | DB 85 F0 FC FF FF   | fild dword ptr ss:                | 入栈 st0
00406F5C | 51                  | push ecx                                 |
00406F5D | C7 85 7C FF FF FF 05| mov dword ptr ss:,5                |
00406F67 | DD 9D E8 FC FF FF   | fstp qword ptr ss:                | 转化精度,给变量EBP-318
00406F6D | DD 85 E8 FC FF FF   | fld qword ptr ss:               |
00406F73 | DC 85 34 FF FF FF   | fadd qword ptr ss:               | 加ebp-cc前面转化来的数值
00406F79 | DD 5D 84            | fstp qword ptr ss:               | 存入ebp-7c
00406F7C | DF E0               | fnstsw ax                                  | 以下为较验运算,是否出错。
00406F7E | A8 0D               | test al,D                                  |
00406F80 | 0F 85 D6 1D 00 00   | jne 408D5C                                 |
00406F86 | FF 15 94 10 40 00   | call dword ptr ds:[<&rtcHexBstrFromVar>]   | 十六进制转字符:给变量ebp-8c
00406F8C | 89 85 74 FF FF FF   | mov dword ptr ss:,eax            | var_8C = Hex$((var_318 + var_CC))
00406F92 | 8D 55 CC            | lea edx,dword ptr ss:            | 十六进制转的字符串
00406F95 | 8D 85 6C FF FF FF   | lea eax,dword ptr ss:            |
00406F9B | 52                  | push edx                                 |
00406F9C | 8D 8D 5C FF FF FF   | lea ecx,dword ptr ss:            | 累加连接的字符串
00406FA2 | 50                  | push eax                                 |
00406FA3 | 51                  | push ecx                                 |
00406FA4 | C7 85 6C FF FF FF 08| mov dword ptr ss:,8                |
00406FAE | FF 15 84 10 40 00   | call dword ptr ds:[<&_vbaVarCat>]          | 连接字符串
00406FB4 | 8B D0               | mov edx,eax                              |
00406FB6 | 8D 4D CC            | lea ecx,dword ptr ss:            |
00406FB9 | FF D7               | call edi                                 |
00406FBB | 8D 55 B0            | lea edx,dword ptr ss:            |
00406FBE | 8D 45 B4            | lea eax,dword ptr ss:            |
00406FC1 | 52                  | push edx                                 |
00406FC2 | 8D 4D B8            | lea ecx,dword ptr ss:            |
00406FC5 | 50                  | push eax                                 |
00406FC6 | 51                  | push ecx                                 |
00406FC7 | 6A 03               | push 3                                     |
00406FC9 | FF 15 9C 10 40 00   | call dword ptr ds:[<&_vbaFreeStrList>]   |
00406FCF | 8D 95 6C FF FF FF   | lea edx,dword ptr ss:            |
00406FD5 | 8D 85 7C FF FF FF   | lea eax,dword ptr ss:            |
00406FDB | 52                  | push edx                                 |
00406FDC | 8D 4D 8C            | lea ecx,dword ptr ss:            |
00406FDF | 50                  | push eax                                 |
00406FE0 | 8D 55 9C            | lea edx,dword ptr ss:            |
00406FE3 | 51                  | push ecx                                 |
00406FE4 | 52                  | push edx                                 |
00406FE5 | 6A 04               | push 4                                     |
00406FE7 | FF 15 14 10 40 00   | call dword ptr ds:[<&_vbaFreeVarList>]   |
00406FED | 83 C4 24            | add esp,24                                 |
00406FF0 | 8D 85 E8 FE FF FF   | lea eax,dword ptr ss:             |
00406FF6 | 50                  | push eax                                 |
00406FF7 | 8D 8D F8 FE FF FF   | lea ecx,dword ptr ss:             |
00406FFD | 8D 55 DC            | lea edx,dword ptr ss:            |
00407000 | 51                  | push ecx                                 |
00407001 | 52                  | push edx                                 |
00407002 | FF 15 C8 10 40 00   | call dword ptr ds:[<&_vbaVarForNext>]      |
00407008 | E9 CF FE FF FF      | jmp 406EDC                                 |
0040700D | 8D 45 CC            | lea eax,dword ptr ss:            |
00407010 | 8D 8D 4C FF FF FF   | lea ecx,dword ptr ss:            |
00407016 | 50                  | push eax                                 |
00407017 | 51                  | push ecx                                 |
00407018 | C7 85 54 FF FF FF E8| mov dword ptr ss:,401EE8         | 401EE8:L"0817E747D7A7D7C7F82836D74747A7F7E7G7C7D826D817E7B7C"
00407022 | C7 85 4C FF FF FF 08| mov dword ptr ss:,8008             |
0040702C | FF 15 5C 10 40 00   | call dword ptr ds:[<&_vbaVarTstEq>]      | 比较字符串,进行验证

通过OD的跟踪分析,已明子软件的算法,具体算法为:从左取用户输入的字符串N位(1-8位),转为十进制数值。用的就是VB中的Val函数,转字符转 10进度数字,*、#则中断,如:VAL(“789”)--- 789 ;VAL(“078*#89”)---- 78这个值是基数,加上第一个字符的ASC值,两值之和,转为16进制字符,依此类推:第2个字符ASC 加78,转十六进制字符追加后面,直到输入的全部字符,就会得到一个长的十六进制字符串,这里没弄明白的是最前面的字符“0”,在vbaVarCat调用中没发现读取,但在生成后最前加了一个“0”字符,面只有第一次才加。
知道了算法,接下来就是研究做个注册机,分析了一下程序里的字符串,只有这一组:
2 (左取字符为2个)0817E747D7A7D7C7F82836D74747A7F7E7B7C7D826D817E7B7C
全是由十六进制字符,于是用刚学一半的C++试着编了一个算法:

#include <iostream>
#include <sstream>

using namespace std;

string kb="0123456789*#";
int kb_dec[]={48,49,50,51,52,53,54,55,56,57,42,35};
int kb_hex[]={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
string hexlist="0123456789ABCDEF";
int key_num=2;
string key="0817E747D7A7D7C7F82836D74747A7F7E7B7C7D826D817E7B7C";

int hexstr_to_dec(const string s) //转16进制两位字符到十进制数
      {
      int a,b;
      a=hexlist.find(s);
      b=hexlist.find(s);
      return a*16+b;
      }
void main()   
      {
      int key_value;
      int base_value;
      string psword;
      char p;
      string key_str=key.substr(1,2);//取Key的二、三位
      key_value=hexstr_to_dec(key_str);
      
      for(int x=1;x<=9;x++)                //确定公共值base_value               
      {
                for(int y=0;y<=9;y++)
                  {
                        if (y+x*10+kb_dec==key_value)
                        {
                        base_value=x*10+y;
                        break;
                        }
                        }
      }
      cout<<"公共值:"<<base_value<<endl;
      for(int x=1;x<key.length();x+=2)          /*计算 注册码 部分*/
                {
                key_str=key.substr(x,2);
                key_value=hexstr_to_dec(key_str);
                p=(char)(key_value-base_value);
                psword=psword+p;
                }
      cout<<"password:"<<psword<<endl;
      system("pause");

至此分析完成,我还用C++写了一个更长的程序,不用穷举的方法计算取1-8位时验证计算,因为刚学的原因,程序最终还是不完善,程序乱的没法贴上来。
【想法】:VB Decompiler分析得不错,可惜没写过OD或X64DBG的插件,等有时间找点资料学一学,把VB Decompiler分析内容加到调试器里,分析起来就方便多了。

luziye233 发表于 2018-4-14 00:23

哦还有还有,我自己在分析算法的时候只能分析出来大致的情况:rggrg,所以和你的算法感觉有一点小差别。我目前还只进了一个register,发现我们的汇编代码有一些小差别,主要是我这个每个字符加的基数就只是字符串的第一个字符(额怎么说呢,数字版的这个数据吧:rggrg)。有点郁闷,不知道是我分析错了,还是被软件作者坑了。。。

pk8900 发表于 2018-4-14 08:10

luziye233 发表于 2018-4-14 00:23
哦还有还有,我自己在分析算法的时候只能分析出来大致的情况,所以和你的算法感觉有一点小差别。我目 ...

不要郁闷,VB的程序就是不好弄,因为VB程序数据结构在内存中的特殊性,所以调试起来很不好弄,在VB Decompiler Pro中找到关键位置,然后OD跟踪,会省些时间。

jun57663796 发表于 2017-6-22 01:38

完全像看天书

ryan515 发表于 2017-6-22 06:29

虽然看不懂,但很厉害滴赶脚、{:301_977:}

拉风的蚂蚁 发表于 2017-6-22 09:21

感觉很厉害的样子,留个爪慢慢看

lyxi841213 发表于 2017-6-22 09:37

呵呵看不懂

孤独之悔 发表于 2017-6-22 16:11


感谢 大佬

HONGYC 发表于 2017-6-23 10:40

初学 能达到这种程度已经很不错了 我学的时候傻傻分不清,加油!

世间自在王佛 发表于 2017-6-23 19:15

不明觉厉

jingcard 发表于 2018-2-2 20:05

学习一下。。。。。。。。。

luziye233 发表于 2018-4-14 00:04

请问od或者其他反编译器有没有什么能很好的查看地址的方法,用of的时候老是每一步去数据窗口跟随去看有点小昏还浪费时间
页: [1] 2
查看完整版本: [反汇编练习]160个Crackme之011-Andrénalin.4-详细分析