吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 8778|回复: 13
收起左侧

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

[复制链接]
pk8900 发表于 2017-6-22 00:57
本帖最后由 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界面如下 :

Image 001.png

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

Image 002.png

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

Image 003.png

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

Image 004.png

通过对其中一段代码进行分析:
  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偏移,方便观察变量的值。

[Asm] 纯文本查看 复制代码
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-44是输入的字符串,字符串实际为ebp-3c
00406EE7 | 6A 02                 | push 2                                     | 2个
00406EE9 | 8D 55 8C              | lea edx,dword ptr ss:[ebp-74]              | 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:[ebp-74]              | 返回的两个字符
00406EF3 | 8D 4D B0              | lea ecx,dword ptr ss:[ebp-50]              | 结果保存地址
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]                 | 数值传给变量ebp-cc *64位*
00406F07 | 8D 55 9C              | lea edx,dword ptr ss:[ebp-64]              |
00406F0A | 8D 45 DC              | lea eax,dword ptr ss:[ebp-24]              |
00406F0D | 52                    | push edx                                   |
00406F0E | 50                    | push eax                                   |
00406F0F | C7 45 A4 01 00 00 00  | mov dword ptr ss:[ebp-5C],1                |
00406F16 | C7 45 9C 02 00 00 00  | mov dword ptr ss:[ebp-64],2                |
00406F1D | FF 15 AC 10 40 00     | call dword ptr ds:[<&_vbaI4Var>]           |
00406F23 | 8D 4D BC              | lea ecx,dword ptr ss:[ebp-44]              |
00406F26 | 50                    | push eax                                   |
00406F27 | 8D 55 B8              | lea edx,dword ptr ss:[ebp-48]              |
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:[ebp-4C]              |
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:[ebp-310],eax             | var_310 = Asc(Mid$(CStr(var_44), CLng(var_24), 1))
00406F50 | 8D 8D 7C FF FF FF     | lea ecx,dword ptr ss:[ebp-84]              |
00406F56 | DB 85 F0 FC FF FF     | fild dword ptr ss:[ebp-310]                | 入栈 st0
00406F5C | 51                    | push ecx                                   |
00406F5D | C7 85 7C FF FF FF 05  | mov dword ptr ss:[ebp-84],5                |
00406F67 | DD 9D E8 FC FF FF     | fstp qword ptr ss:[ebp-318]                | 转化精度,给变量EBP-318
00406F6D | DD 85 E8 FC FF FF     | fld qword ptr ss:[ebp-318]                 |
00406F73 | DC 85 34 FF FF FF     | fadd qword ptr ss:[ebp-CC]                 | 加ebp-cc  前面转化来的数值
00406F79 | DD 5D 84              | fstp qword ptr ss:[ebp-7C]                 | 存入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:[ebp-8C],eax              | var_8C = Hex$((var_318 + var_CC))
00406F92 | 8D 55 CC              | lea edx,dword ptr ss:[ebp-34]              | 十六进制转的字符串
00406F95 | 8D 85 6C FF FF FF     | lea eax,dword ptr ss:[ebp-94]              |
00406F9B | 52                    | push edx                                   |
00406F9C | 8D 8D 5C FF FF FF     | lea ecx,dword ptr ss:[ebp-A4]              | 累加连接的字符串
00406FA2 | 50                    | push eax                                   |
00406FA3 | 51                    | push ecx                                   |
00406FA4 | C7 85 6C FF FF FF 08  | mov dword ptr ss:[ebp-94],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:[ebp-34]              |
00406FB9 | FF D7                 | call edi                                   |
00406FBB | 8D 55 B0              | lea edx,dword ptr ss:[ebp-50]              |
00406FBE | 8D 45 B4              | lea eax,dword ptr ss:[ebp-4C]              |
00406FC1 | 52                    | push edx                                   |
00406FC2 | 8D 4D B8              | lea ecx,dword ptr ss:[ebp-48]              |
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:[ebp-94]              |
00406FD5 | 8D 85 7C FF FF FF     | lea eax,dword ptr ss:[ebp-84]              |
00406FDB | 52                    | push edx                                   |
00406FDC | 8D 4D 8C              | lea ecx,dword ptr ss:[ebp-74]              |
00406FDF | 50                    | push eax                                   |
00406FE0 | 8D 55 9C              | lea edx,dword ptr ss:[ebp-64]              |
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:[ebp-118]             |
00406FF6 | 50                    | push eax                                   |
00406FF7 | 8D 8D F8 FE FF FF     | lea ecx,dword ptr ss:[ebp-108]             |
00406FFD | 8D 55 DC              | lea edx,dword ptr ss:[ebp-24]              |
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:[ebp-34]              |
00407010 | 8D 8D 4C FF FF FF     | lea ecx,dword ptr ss:[ebp-B4]              |
00407016 | 50                    | push eax                                   |
00407017 | 51                    | push ecx                                   |
00407018 | C7 85 54 FF FF FF E8  | mov dword ptr ss:[ebp-AC],401EE8           | 401EE8:L"0817E747D7A7D7C7F82836D74747A7F7E7G7C7D826D817E7B7C"
00407022 | C7 85 4C FF FF FF 08  | mov dword ptr ss:[ebp-B4],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++试着编了一个算法:

[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[0]);
        b=hexlist.find(s[1]);
        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[x]==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");

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

免费评分

参与人数 6威望 +1 吾爱币 +12 热心值 +6 收起 理由
海天一色001 + 1 + 1 我很赞同!
Sound + 1 + 8 + 1 已经处理,感谢您对吾爱破解论坛的支持!
孤独之悔 + 1 + 1 已答复!
WYWZ + 1 + 1 热心回复!
Glimmer + 1 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
木子木泗 + 1 热心回复!

查看全部评分

本帖被以下淘专辑推荐:

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

luziye233 发表于 2018-4-14 00:23
哦还有还有,我自己在分析算法的时候只能分析出来大致的情况,所以和你的算法感觉有一点小差别。我目前还只进了一个register,发现我们的汇编代码有一些小差别,主要是我这个每个字符加的基数就只是字符串的第一个字符(额怎么说呢,数字版的这个数据吧)。有点郁闷,不知道是我分析错了,还是被软件作者坑了。。。
 楼主| 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
虽然看不懂,但很厉害滴赶脚、
拉风的蚂蚁 发表于 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的时候老是每一步去数据窗口跟随去看有点小昏还浪费时间
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-17 04:47

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表