这个教程不想谈太多的技术(主要是我对[脱壳破解]还是处在初级爆破阶段),只想和大家分享一些破解过程,有些过程已经有些忘记,大家凑合看吧。
因为自己是程序员,真是非常热爱这个行业,正因为热爱,所以对各方面的技术也都感兴趣,黑客入侵、木马、外挂、破解都干过,主要是当初所谓的成就感和来自别人崇拜的目光吧,但是因为自己主要是平时没事玩一玩,对一些软件自己动手破解后用着舒服一些,也没有加入过任何的组织(主要也是水平确实不够), 所以在几个方面始终都没有步入很深入的层次,最近加入吾爱,主要也是因为破解这个加密狗的原因,同时也是想自己能够在这个领域再提高一些,希望得到大家的指教。
好了,步入正题吧,朋友问我一个软件能否破解去掉狗,因为我对狗实际的破解经验不多,所以我只能说试试看吧,软件名字这里就不说了。
1:运行
拿到一个软件肯定是先运行看看喽(未插加密狗)
报错:
缺少运行环境,从标题上面看可以确定加密狗的厂商,google搜索之(遇到问题我很少会先问别人,基本都是先在网络上搜索,自己在寻找学习的过程也是自己进步的过程,毕竟自己经历了才是最难忘的嘛,过程比结果更重要)。
在搜索后发现,这个狗不简单啊,自己信心受到了一些打击,毕竟看介绍功能非常强大(其实目前我还不知道这个狗是哪种类型)
最终在官网下载了软件和驱动:
http://www.aladdin.com.cn/hasp/support.asp
安装完成后,再运行,哦,检测到调试器?我没调戏它啊,想了一下肯定是因为我开着Visual Studio开发环境。
关掉VS再运行,果然没有提示被调戏,但已经感觉到这个软件有些不简单啊,现在显示找不到狗了,出现找不到加密狗了.
2:简单分析
有了提示对话框,大都都懂的,Debugger工具该上场了,先选择WinDbg吧,结果也不出所料一顿崩溃,算了用OD吧,虚拟机上的WinXP有OD(话说OD在Win8.1 64bits上面支持的非常不好),隐藏调试器,下断点在MessageBoxA(W),运行后进程自动退出,看来对付调戏做足了检测啊,那就直接运行吧,弹出无狗窗口.运行后F12暂停,切换到调用栈:
找到了调用来自哪里了,经过一顿分析,没什么进展,反而随着跟踪和调试,发现水越来越深,大量的花指令,大量的崩溃,深感自己有点力不从心了,还是继续在网上搜索相关的东西吧。
3:深入分析
通过一系列的分析,知道这个狗是 Aladdin HASP SRM,而且有AES-128加密算法的,本地安装有服务程序:hasplms.exe,开放TCP端口:1947(SentinelSRM (hasplm), Aladdin HASP License Manager),狗是网络版,只不过是localhost,客户端通过socket连接到localhost的hasplms去交互,同时对程序进行了查壳,壳为:
Signature: HASP HL Protection V1.X -> Aladdin
Matches: 42
Signature: HASP HL Protection V1.X -> Aladdin
Matches: 39
4:尝试各种方案
1).不带狗脱壳:<失败>
经过一系列尝试,确定不带狗是不可能脱掉的,遂向朋友拿到了USB加密狗(开始主要还是低估了这个狗,以为不带狗就可以脱壳,很傻很天真).
2).带狗脱壳:<失败>
有了加密狗,程序终于可以正确运行了,所以就尝试脱壳,使用"两次内存断点法寻找OEP",对.IDAta和.text分别下断点,还真定位到了,很兴奋(佩服大牛们分享的经验).
Ctrl+A后代码显示为:
经查这是Borland C++的特征码。
那就dump和IAT修复吧,分别是使用PETools和ImportREC,输入OEP地址并且调整IAT的Size到合适的大小,结果居然有近200个不能定位,我的妈呀,这可如何是好,进行了最后一翻挣扎,深感自己功力不够,无法确信自己可以手动修复IAT,即能找到每一个API的真正调用,但要把200个修复完也得把人累个半死啊,如果修复后还有其他检验就不好办了,最终不得不放弃。
3).模拟网络数据包/DeviceIoControl:<失败>
好吧,放弃了脱壳方案,就看看能不能模拟狗吧,因为是网络狗,所以可以先看看网络数据包。使用CommView截localhost:1947的数据包,经过带狗连续多次的分析,发现每次都是不同的,初步判断即使把网络数据包模拟返回估计也无法认证通过,最后简单的写程序测试了一下,确实是这样的,如果没有返回对应的数据包客户端就会出错,估计用HOOK DeviceIoControl也是一样的,再次放弃。
4).MultiKey等驱动级别模拟:<失败>
后来到网上又进行了一翻搜索,发现老外已经开发出很多驱动级别的HASP狗模拟,也找到了很多的配套工具,比如:h5dmp/h4dmp,hasploger,Toro Dongles Monitor,HaspHLDumper等等,经常一翻测试,最终使用h5dmp dump数据了,此时感觉自己终于看到了曙光,就用MultiKey相关的工具安装驱动,进行注册表文件的转换,导入注册表,结果拔掉狗经常无法找到驱动,或者还是失败,无法模拟,以下是注册表文件.
在模拟加密狗部分花费了大量的时间,最终在网上发现这种办法是针对HASP HL,而且是不支持AES-128的,即使后来新的模拟狗驱动支持AES-128,也需要把加密狗每次发送和返回的数据进行记录,建立一个Q-A数据表才可以,但官方说AES-128算法可是上万种啊。
"QTable"=hex:\
42,84,... 84,AD,A4,\
"ATable"=hex:\
82,22,C2 ... 84,AD,A4,\
如果程序总是随机使用某种加密算法,岂不哭死,直到现在才觉得模拟狗应该也走不下去了,号称全球第一的加密狗果然不简单,连国外的大牛们也不能破解其算法,还得制作Q-A数据库,对简单的或许可以,复杂的肯定就不行了吧,此时心灰意冷,感到很无助,耗费了很大的精力,到头来还是一场空,决定暂停破解,毕竟已经熬了几个夜晚和周末了。
5).寻找高人破解:
通过加一些QQ群找到了一些相关的有经验的大牛们,打算向他们讨教,结果没人理,说给钱才可以,我就问了一下多少钱?说是至少1w,因为这个太复杂,破解需要一周的时间,问如何破解,可否复制狗,回答只能爆破,无法复制狗,问了一下朋友可否接受这个价格,朋友说有点贵,如果没办法也可以接受。后继续询问对方,说要先付一半的钱,破解不了可以退一部分。我觉得不太可靠,和对方说我再考虑一下吧,就没有再联系对方。后来自己也考虑了一下,自己之前花费了那么大的心血,如果去找别人收费破解,真的不甘心。
5:最后的战役:
1).希望重现:
经历上述失败后,几天没有再继续,深感自己功力还是不够,就继续搜索相关技术和破解这个狗的相关信息,寻找更多的这个狗的相关工具,最后使用RTVIDTool2成功的将PW1和PW2从内存中dump出来,而且也保存出来.hvc文件,.hvc就是颁发给每个开发商的一个vendor code,里面肯定是有密码,AES Key和很多乱七八糟的信息,有了这个东西,就可以自己写个程序访问加密狗了。
2).程序测试:
使用Sentinel_HASP_SDK里面带的开发工具VendorSuite\toolbox,指定vendor code,果然可以成功的login,encrypt/decrypt数据,但自己还是高兴有点早了,虽然可以访问加密狗,还是不知道如何利用这个去复制和破解,因为据说这个加密狗有两种,一个是Master加密狗,另一个就是客户端的狗,使用Master加密狗才可以复制客户端加密狗的,也就是master才有写狗的权限。
3).确定使用API HOOK方案:
虽然知道了vendor code不能复制狗,但也不是完全没用,应该是说帮上了大忙,也是最后成功的转折点。有了这个就可以做很多的调试分析,跟踪HASP API的调用入口,经过一翻思考后,打算用API HOOK的方式截获相关加密狗的API,查SDK文档有如下几个:
hasp_status_t HASP_CALLCONV hasp_login(hasp_feature_t feature_id, hasp_vendor_code_t vendor_code, hasp_handle_t *handle);
hasp_status_t HASP_CALLCONV hasp_login_scope(hasp_feature_t feature_id, const char *scope, hasp_vendor_code_t vendor_code, hasp_handle_t *handle);
hasp_status_t HASP_CALLCONV hasp_encrypt(hasp_handle_t handle, void *buffer, hasp_size_t length);
hasp_status_t HASP_CALLCONV hasp_decrypt(hasp_handle_t handle, void *buffer, hasp_size_t length);
还有hasp_logout, hasp_read,hasp_write,hasp_get_size,hasp_get_rtc,hasp_get_info等等
4).DUMP解密的代码:
在程序未运行时是无法找到相关的api调用的,毕竟是加密的,寻找代码解压可以先在socket api位置下断点,比如:connect,此时对当前进行了dump,用IDA Pro静态分析,通过API特征码和相关的字符串分析历尽千辛终于找到了hasp_login,hasp_login_scope,hasp_encrypt,hasp_decrypt的位置.
5).API HOOK程序:
主要HOOK了几个API,使用CFF修改IAT静态导入自己的DLL,真是万幸,程序没有做修改校验。这部分可以参考我发的另一个文章,比较详细:
http://www.52pojie.cn/thread-257140-1-1.html
gHooks.Add(_T("KERNEL32.DLL"), "IsDebuggerPresent", my_IsDebuggerPresent);
gHooks.Add(_T("KERNEL32.DLL"), "GetModuleHandleA", my_GetModuleHandleA);
gHooks.Add(_T("KERNEL32.DLL"), "GetModuleHandleW", my_GetModuleHandleW);
gHooks.Add(_T("KERNEL32.DLL"), "Process32FirstW", my_Process32FirstW);
gHooks.Add(_T("KERNEL32.DLL"), "Process32NextW", my_Process32NextW);
gHooks.Add(_T("KERNEL32.DLL"), "CloseHandle", my_CloseHandle);
gHooks.Add(_T("KERNEL32.DLL"), "EnterCriticalSection", my_EnterCriticalSection);
gHooks.Add(_T("KERNEL32.DLL"), "GetProcAddress", my_GetProcAddress);
gHooks.BeginAll();
对Process32NextW的hook是为了跳过对一些进程的检查,之前提到的,如果我开着VS就提示有调试器(没办法,工作要用VC),这样灰常的不爽,所以HOOK之后有如下代码:
[C++] 纯文本查看 复制代码
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 |
|
同时写了HASP API函数:
[C++] 纯文本查看 复制代码
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
|
这是找到的每个API地址,这部分也是大费周折(开发的SDK API和这个程序使用的API版本不同,没办法完全匹配)
[C++] 纯文本查看 复制代码
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
|
6).HOOK时机:
上述已经找到了每个API的地址,但何时进行HOOK,这里通过测试,发现程序在使用GetProcAddress调用某个API后而且沿未调用hasp_login时代码是解密的,因为我要hook某个地址时可以预先判断代码是否匹配,所以最后索性在截获的GetProcAddress中直接调用HookHaspAPI_Begin(),直接某个时刻成功为止:
[C++] 纯文本查看 复制代码
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
|
7).分析截获的数据:
通过数据截获分析,最终发现调用hasp_login_scope成功后,就会反复的调用hasp_decrypt去解密数据,每次去解密的数据大小都是16,输入的数据是随机的,但有2次解密的数据大小是32768,而且输入的数据是固定的内含,当然解密后的数据也是固定的,这是API log.
[ 1688]12:24:20.179 - ApiDebugger Loaded.
[ 1688]12:24:20.211 - Process32Next, Rename "devenv.exe" to "crack.exe"
[ 1688]12:24:20.215 - Process32Next, Rename "devenv.exe" to "crack.exe"
[ 1688]12:24:20.246 - HASP API : hasp_login_scope hooked
[ 1688]12:24:20.246 - HASP API : my_hasp_encrypt hooked
[ 1688]12:24:20.247 - HASP API : my_hasp_decrypt hooked
[ 1688]12:24:20.247 - HASP API : my_hasp_get_info hooked
[ 1688]12:24:20.247 - HASP API : my_hasp_logout hooked
[ 1688]12:24:20.248 - HASP API : Patch Address 0x0052B45B
[ 1688]12:24:20.248 - HASP API : Patch Address 0x00591DFA
[ 1688]12:24:20.250 - HASP API : Call hasp_login_scope(5476)
[ 1688]12:24:20.252 - HASP API : Call hasp_decrypt(0x88888888, 0x0028F998, 16)
[ 1688]12:24:20.255 - D : D67BF973E80CC4AF98D23FB8285FCB4A
[ 1688]12:24:20.256 - HASP API : Call hasp_decrypt(0x88888888, 0x0028F998, 16)
[ 1688]12:24:20.259 - D : 083E3F19B6527EB976CF7D18BBB80890
[ 1688]12:24:20.263 - HASP API : Call hasp_decrypt(0x88888888, 0x003A0000, 32768)
[ 1688]12:24:20.267 - HASP API : Read data from "data.enc1.bin"
[ 1688]12:24:20.270 - HASP API : Call hasp_decrypt(0x88888888, 0x003A0000, 32768)
[ 1688]12:24:20.274 - HASP API : Read data from "data.enc2.bin"
[ 1688]12:24:20.330 - HASP API : Call hasp_decrypt(0x88888888, 0x0028F91C, 16)
[ 1688]12:24:20.333 - D : 3CE5A8C8DCC197E5C426D78A3CBFA846
[ 1688]12:24:21.393 - HASP API : Call hasp_logout()
[ 1688]12:24:21.395 - ApiDebugger Unloaded.
根据这些重要数据进行分析,可以认为:16个字节的数据解密纯粹是为了校验加密狗的合法性,32768的数据解密应该是对主程序的内容解密,因此之前以为不带狗就能去破解是多么的天真,如果不带狗就能破解,这狗还有啥意思?
8).确定判断地址:
现在我可以对hasp_decrypt函数在请求32768长度数据解密时返回固定的数据,但16字节的校验请求怎么办?这又是一个难题,因为你不知道算法,如果你随便返回数据程序就报错.
这部分不细说了,主要是设置参数内存地址的访问断点,最终确定了有2处hasp_decrypt调用后数据验证地址:
[Asm] 纯文本查看 复制代码
01 02 03 04 05 06 07 08 09 10 11 12 13 14 |
|
9).爆破方法:
尝试了2种办法,第一种是,我既然已经知道了返回数据与正确数据的判断位置,完美的做法是,要检查之前,把正确的数据复制到返回的数据地址:
[Asm] 纯文本查看 复制代码
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 |
|
代码写好了,也要选择插入位置,最终在内存找到了大片的90 90 90 90内存,然后在程序运行中动态的将代码写入到这个位置,同时在原代码处做了一个JMP语句.
完成后再运行程序,最终程序完美运行,这时候真的有一种想哭的感觉,心情豁然开朗!
成功破解后,又试了一种简单的方案,直接Patch Code "CMP EAX,EDX" 为 "CMP EAX,EAX/CMP EDX,EDX"也是成功的。所以也就验证了对于随机解密后的数据仅仅是为了加密狗的校验。
10).最终的my_hasp_decrypt函数:
随着一步步的深入,搞明白了,核心API就是hasp_decrypt,最终hook的函数代码为:
[C++] 纯文本查看 复制代码
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
|
最后经过多次验证,100%确信自己真的把这个狗给破解了,过程中经历的艰辛和不眠立马化为无有,都被最后的成功所淹没,这种感觉妙不可言。
对于这个加密狗破解,是自己花费了最大力气的一个(总历时应该有100小时),虽然最终是API HOOK+爆破,代码仅Patch 2个节,但为了这个2个字节确实经历了太多,每个破解思路都失败的时候也想过放弃,庆幸自己最终还是坚持了下来,赢取了胜利.
从这个过程中也发现自己在某些地方还非常的初级,尤其是算法分析上面,只有能深入算法分析,才能到达更高的层次,总是爆破不利于水平的提高,后面有时候会继续对这个加密狗进行研究,争取做到完美脱壳,将来再与大家分享。
PS:谢谢大家能看完,多提建议和意见,也希望熟悉这个加密狗的大牛和大神们也能分享这方面的经验,能够找到一种更简单快速的破解方法。
转:https://blog.csdn.net/niuzaiwenjie/article/details/34111277