|
加密狗逆向之硬件复制和软件模拟_Rockey4ND
CodeLive @ 2014-10-18
收到风声说再不发原创的帖子就要被清理了,赶紧熬夜写一篇,呵呵~~
本文主要通过对Rockey4ND狗的分析来说明如何逆向加密狗,包括硬件复制和软件模拟,不谈爆破方法。
首先说明可以硬件复制或者软件模拟的狗要具备下面几种条件:
1.有真狗的运行环境,没狗逆向一般只能爆破;
2.硬件复制要知道狗的用户密码和开发密码,软件模拟密码可以不需要;
3.程序只从狗中读取或写入数据;
4.如果程序在狗中写入了算法函数,这个一般会比较难,但如果逆向出函数算法,也可以模拟;
下面就介绍一款使用了Rockey4ND狗的软件的分析过程,软件名字当然不会说了。
Rockey4ND是无驱HID类型狗,这种截获数据方法有多种,可以用USBTrace,hid.dll替换,HOOK CreateFileA等方法, 但直接有效的方法是直接替换狗的API调用.
1.首先下载一份Rockey4ND的开发SDK,通过查看文件很容易知道,这个狗只有一个API,API定义为:
WORD WINAPI Rockey(WORD function, WORD* handle, DWORD* lp1, DWORD* lp2, WORD* p1, WORD* p2, WORD* p3, WORD* p4, BYTE* buffer);
主要功能定义(Rockey4_ND_32.h文件):
- #define RY_FIND 1 // Find Dongle
- #define RY_FIND_NEXT 2 // Find Next Dongle
- #define RY_OPEN 3 // Open Dongle
- #define RY_CLOSE 4 // Close Dongle
- #define RY_READ 5 // Read Dongle
- #define RY_WRITE 6 // Write Dongle
- #define RY_RANDOM 7 // Generate Random Number
- #define RY_SEED 8 // Generate Seed Code
- #define RY_WRITE_USERID 9 // Write User ID
- #define RY_READ_USERID 10 // Read User ID
- #define RY_SET_MOUDLE 11 // Set Module
- #define RY_CHECK_MOUDLE 12 // Check Module
- #define RY_WRITE_ARITHMETIC 13 // Write Arithmetic
- #define RY_CALCULATE1 14 // Calculate 1
- #define RY_CALCULATE2 15 // Calculate 2
- #define RY_CALCULATE3 16 // Calculate 3
- #define RY_DECREASE 17 // Decrease Module Unit
- #define RY_CALLNET 18 // NetRockey4ND arithmetic
- (1) Find Dongle
- Input:
- function = 1
- *p1 = pass1
- *p2 = pass2
- *p3 = pass3
- *p4 = pass4
- Return:
- *lp1 = Rockey4ND HID
- return 0 = Success, else is error code
- (2) Find Next Dongle
- Input:
- function = 2
- *p1 = pass1
- *p2 = pass2
- *p3 = pass3
- *p4 = pass4
- Return:
- *lp1 = Rockey4ND HID
- return 0 = Success, else is error code
- (3) Open Dongle
- Input:
- function = 3
- *p1 = pass1
- *p2 = pass2
- *p3 = pass3
- *p4 = pass4
- *lp1 = Rockey4ND HID
- Return:
- *handle = Opened dongle handle
- return 0 = Success, else is error code
- (4) Close Dongle
- Input:
- function = 4
- *handle = dongle handle
- Return:
- return 0 = Success, else is error code
- (5) Read Dongle
- Input:
- function = 5
- *handle = dongle handle
- *p1 = pos
- *p2 = length
- buffer = pointer of buffer
- Return:
- Fill buffer with read contents
- return 0 = Success, else is error code
- (6) Write Dongle
- Input:
- function = 6
- *handle = dongle handle
- *p1 = pos
- *p2 = length
- buffer = pointer of buffer
- Return:
- return 0 = Success, else is error code
- (7) Generate Random Number
- Input:
- function = 7
- *handle = dongle handle
- Return:
- *p1 = random number
- return 0 = Success, else is error code
- (8) Generate Seed Code
- Input:
- function = 8
- *handle = dongle handle
- *lp2 = seed code
- Return:
- *p1 = seed return code 1
- *p2 = seed return code 2
- *p3 = seed return code 3
- *p4 = seed return code 4
- return 0 = Success, else is error code
- (9) Write User ID
- Input:
- function = 9
- *handle = dongle handle
- *lp1 = User ID
- Return:
- return 0 = Success, else is error code
- (10) Read User ID
- Input:
- function = 10
- *handle = dongle handle
- Return:
- *lp1 = User ID
- return 0 = Success, else is error code
- (11) Set Module
- Input:
- function = 11
- *handle = dongle handle
- *p1 = module number
- *p2 = module content
- *p3 = set whether allow decrease (1 = allow, 0 = no allow)
- Return:
- return 0 = Success, else is error code
- (12) Check Module
- Input:
- function = 12
- *handle = dongle handle
- *p1 = module number
- Return:
- *p2 = 1 means the module is valid, 0 means the module is invalid
- *p3 = 1 means the module can't decrease, 0 means the module can decrease
- return 0 = Success, else is error code
- (13) Write Arithmetic
- Input:
- function = 13
- *handle = dongle handle
- *p1 = pos
- buffer = arithmetic instruction string
- Return:
- return 0 = Success, else is error code
- (14) Calculate 1 (Hide Unit Init Content = HID high 16bit, HID low 16bit, module content, random number)
- Input:
- function = 14
- *handle = dongle handle
- *lp1 = calculate begin pos
- *lp2 = module number
- *p1 = input value 1
- *p2 = input value 2
- *p3 = input value 3
- *p4 = input value 4
- Return:
- *p1 = return code 1
- *p2 = return code 2
- *p3 = return code 3
- *p4 = return code 4
- return 0 = Success, else is error code
- (15) Calculate 2 (Hide Unit Init Content = seed return code 1, seed return code 2, seed return code 3, seed return code 4)
- Input:
- function = 15
- *handle = dongle handle
- *lp1 = calculate begin pos
- *lp2 = seed code
- *p1 = input value 1
- *p2 = input value 2
- *p3 = input value 3
- *p4 = input value 4
- Return:
- *p1 = return code 1
- *p2 = return code 2
- *p3 = return code 3
- *p4 = return code 4
- return 0 = Success, else is error code
- (16) Calculate 3 (Hide Unit Init Content = module content, module+1 content, module+2 content, module+3 content)
- Input:
- function = 16
- *handle = dongle handle
- *lp1 = calculate begin pos
- *lp2 = module begin pos
- *p1 = input value 1
- *p2 = input value 2
- *p3 = input value 3
- *p4 = input value 4
- Return:
- *p1 = return code 1
- *p2 = return code 2
- *p3 = return code 3
- *p4 = return code 4
- return 0 = Success, else is error code
- (17) Decrease Module Unit
- Input:
- function = 17
- *handle = dongle handle
- *p1 = module number
- Return:
- return 0 = Success, else is error code
复制代码 最好先看看SDK中自带的示例程序,对狗的API一般是如何调用的。
2.分析软件,发现软件是直接使用DLL来对狗进行访问的,Rockey4ND的DLL名字是: Rockey4ND.dll,对这种直接使用DLL来调用的程序真是无语,连分析API函数特征都不需要了(如果是静态库方式调用就需要分析API地址)。
3.建立一个DLL工程,实现和狗API一样的函数: Rockey,定义如下:
- WORD WINAPI Rockey(WORD function, WORD* handle, DWORD* lp1, DWORD* lp2, WORD* p1, WORD* p2, WORD* p3, WORD* p4, BYTE* buffer)
- {
- WORD ret = ERR_SUCCESS;
- // ......后面再说
- return ret;
- }
- Makefile内容:
- LIBRARY ApiRockey4
- EXPORTS
- Rockey @ 1
- 这样DLL就导出了和加密狗一样的API, 同时也要把自己的DLL改为Rockey4ND.dll,原Rockey4ND.dll就要换一个名字,比如改为:Rockey4ND.org.dll
复制代码
4.获取原狗DLL的API地址:
- 1)定义API函数,然后声明一个全局变量:
- typedef WORD (WINAPI * api_Rockey)(WORD function, WORD* handle, DWORD* lp1, DWORD* lp2,
- WORD* p1, WORD* p2, WORD* p3, WORD* p4, BYTE* buffer);
- // 这个就是为了保存原API的地址
- api_Rockey g_Rockey = NULL;
- 2)获取原API地址:
- HMODULE hModule = LoadLibraryW(L"Rockey4ND.org.dll");
- if(hModule != NULL)
- {
- // 获取原API函数地址
- g_Rockey = (api_Rockey)GetProcAddress(hModule, "Rockey");
- }
- 在DLL加载的时候运行上面的代码
- BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
- {
- switch (ul_reason_for_call)
- {
- case DLL_PROCESS_ATTACH:
- {
- // 加载原DLL模块
- HMODULE hModule = LoadLibraryW(L"Rockey4ND.org.dll");
- if(hModule != NULL)
- {
- // 获取原API函数地址
- g_Rockey = (api_Rockey)GetProcAddress(hModule, "Rockey");
- }
- }
- break ;
- case DLL_THREAD_ATTACH:
- case DLL_THREAD_DETACH:
- case DLL_PROCESS_DETACH:
- {
- }
- break;
- }
- return TRUE;
- }
复制代码
5.数据截获
- WORD WINAPI Rockey(WORD function, WORD* handle, DWORD* lp1, DWORD* lp2, WORD* p1, WORD* p2, WORD* p3, WORD* p4, BYTE* buffer)
- {
- WORD ret = ERR_SUCCESS;
- // 这里是执行原API调用
- ret = g_Rockey(function, handle, lp1, lp2, p1, p2, p3, p4, buffer);
- // 根据定义,我把对狗进行数据读写的数据转化为字符串,便于记录
- string strBuffer;
- if((function == RY_READ) || (function == RY_WRITE))
- {
- if((p2 != NULL) && ((*p2) > 0))
- {
- // 数据转换成文本
- strBuffer = data2HexString((const char *)buffer, (*p2));
- }
- }
- // 格式所有参数
- string str = formatString("Rockey(function(%d), handle(0x%04X), "
- "lp1(0x%08X), lp2(0x%08X), "
- "0x%04X, 0x%04X, 0x%04X, 0x%04X, "
- "%s), ret = %d\r\n",
- (int)(function), (handle != NULL) ? (int)(*handle) : 0,
- (lp1 != NULL) ? (int)(*lp1) : 0, (lp2 != NULL) ? (int)(*lp2) : 0,
- (p1 != NULL) ? (int)(*p1) : 0, (p2 != NULL) ? (int)(*p2) : 0,
- (p3 != NULL) ? (int)(*p3) : 0, (p4 != NULL) ? (int)(*p4) : 0,
- strBuffer.c_str(), (int)(ret));
- //打印输出或者记录到文件
- logOutput(str);
- return ret;
- }
复制代码
6.把自己的DLL替换后,运行程序,如果程序没问题,所有数据都会被记录:
// 查找狗,ret = 0,表示找到狗,成功.
Rockey(function(1), handle(0x0000), lp1(0x66666666), lp2(0x77777777), 0x1111, 0x2222, 0x3333, 0x4444, ), ret = 0
// 打开狗,ret = 0,打开成功
Rockey(function(3), handle(0x0000), lp1(0x66666666), lp2(0x77777777), 0x1111, 0x2222, 0x3333, 0x4444, ), ret = 0
// 查找下一个,ret = 17, 没有找到更多的狗,失败
Rockey(function(2), handle(0x0000), lp1(0x66666666), lp2(0x77777777), 0x1111, 0x2222, 0x3333, 0x4444, ), ret = 17
// 从位置0x0008,读取0x0010长度的数据,读取到的内容是:A869BA3E70096F3C0D578FE34E5F8FD4
Rockey(function(5), handle(0x0000), lp1(0x66666666), lp2(0x77777777), 0x0008, 0x0010, 0x3333, 0x4444, A869BA3E70096F3C0D578FE34E5F8FD4), ret = 0
通过参数定义可以知道,开发商ID是0x66666666, 加密狗的4个密码也获取到了,基本密码为:0x1111, 0x2222,高级密码:0x3333, 0x4444 (我截获的密码当然不是这个啦)。
然后多运行几次程序,看看每次读取的数据是否都是相同的,如果每次都一样,那真的是要恭喜你了,但如果有调用狗内函数的功能,那就复杂了,这里暂时不讨论算法这种情况。
7.硬件复制方案:
1)既然4个密码都有了,最完美的方案就是硬件复制,从TB上面买空狗;
2)用官方工具可以直接复制,Rockey4ND_Editor.exe,这个在Rockey4ND的SDK中有,就是使用上面稍有复杂;
3)如果觉得工具有点麻烦的话,可以写一个程序,先从原狗中把数据都读出来,然后再把数据写入到新狗中;
8.软件模拟方案:
就是把我们之前记录数据的部分反过来,下面是大概的代码,一些代码不具体解释了:
- WORD WINAPI Rockey(WORD function, WORD* handle, DWORD* lp1, DWORD* lp2, WORD* p1, WORD* p2, WORD* p3, WORD* p4, BYTE* buffer)
- {
- WORD ret = ERR_SUCCESS;
- *handle = NULL;
- switch(function)
- {
- case RY_FIND:
- {
- // 返回开发商ID
- *lp1 = 0x66666666;
- }
- break ;
- case RY_OPEN:
- {
- // 返回句柄
- *handle = 0x8888;
- }
- break ;
- case RY_FIND_NEXT:
- {
- // 没有更多加密狗
- ret = ERR_NOMORE;
- }
- break ;
- case RY_READ:
- {
- // gRockey4Data是原狗的所有数据
- memcpy(buffer, gRockey4Data+(*p1), (*p2));
- }
- break ;
- case RY_WRITE:
- {
- memcpy(gRockey4Data+(*p1), buffer, (*p2));
- }
- break ;
- case RY_RANDOM:
- {
- *p1 = (WORD)(rand()%(0x10000));
- }
- break ;
- case RY_SEED:
- {
- *p1 = (WORD)(rand()%(0x10000));
- *p2 = (WORD)(rand()%(0x10000));
- *p3 = (WORD)(rand()%(0x10000));
- *p4 = (WORD)(rand()%(0x10000));
- }
- break ;
- }
- }
复制代码
硬件复制和软件模拟不需要对原程序进行逆向,软件升级一般也不需要做任何改动,算是完美的方案,本文是通过Rockey4ND来举例说明加密狗的完美分析方法,同样适用于其他加密狗,只要程序仅对狗的数据进行访问,狗内没有算法函数的情况就可以用差不多的方法实现。
本文完,因为时间关系,没有仔细校验错误,有不对的地方还希望大家指正, 谢谢大家。
|
评分
-
参与人数 51 | 威望 +2 |
HB +91 |
THX +31 |
收起
理由
|
猫妖的故事
| |
+ 1 |
|
|
一起学习
| |
+ 2 |
+ 1 |
|
开天辟地
| |
+ 1 |
|
|
花盗睡鼠
| |
+ 2 |
+ 1 |
[吾爱汇编论坛52HB.COM]-学破解防破解,知进攻懂防守! |
29590
| |
+ 1 |
|
|
怀东
| |
+ 2 |
+ 1 |
|
24567
| |
|
+ 1 |
|
Jawon
| |
+ 2 |
|
|
一路走来不容易
| |
+ 1 |
|
|
Soul1999
| |
|
+ 1 |
|
仙仙猫
| |
+ 1 |
|
|
渴望宁静
| |
+ 1 |
|
|
消逝的过去
| |
|
+ 1 |
|
zyyujq
| |
+ 1 |
|
|
l278785481
| |
+ 1 |
|
|
temp
| |
+ 1 |
+ 1 |
|
Pythonic_vi
| |
+ 1 |
|
|
hbyaojing
| |
+ 1 |
|
[吾爱汇编论坛52HB.COM]-感谢楼主热心分享,小小评分不成敬意! |
SmallEXpel
| |
+ 1 |
|
|
落雪玉
| |
+ 1 |
|
[吾爱汇编论坛52HB.COM]-感谢楼主热心分享,小小评分不成敬意! |
流言飞鱼
| |
|
+ 1 |
|
jaunic
| |
|
+ 1 |
|
hnymsh
| |
|
+ 1 |
|
lies
| |
|
+ 1 |
|
cd37ycs
| |
+ 1 |
+ 1 |
[快捷评语]--吃水不忘打井人,给个评分懂感恩! |
HAINING
| |
+ 2 |
+ 1 |
|
zhm
| |
+ 1 |
+ 1 |
[快捷评语]--积极评分,从我做起。感谢分享! |
曰可
| |
+ 1 |
|
[快捷评语] - 评分=感恩!简单却充满爱!感谢您的作品! |
pinsy
| |
+ 1 |
|
分享精神,是最值得尊敬的!苦苦求了你几千年啊 |
ddx123
| |
+ 1 |
|
分享精神,是最值得尊敬的! |
小笙
| |
+ 1 |
|
分享精神,是最值得尊敬的! |
涵涵涵仔
| |
+ 1 |
|
能分享加密狗软件的链接吗?在线等 |
XIAODOUDOU
| |
+ 1 |
+ 1 |
评分=感恩!简单却充满爱!感谢您的作品! |
a122783999
| |
+ 1 |
+ 1 |
祝学破解论坛全体成员2016年开心每一天! |
billbox
| |
+ 1 |
+ 1 |
转的一手好帖!学习了! |
十月
| |
+ 1 |
+ 1 |
评分=感恩!简单却充满爱!感谢您的作品! |
fzip
| |
+ 2 |
+ 1 |
吃水不忘引水人,学习中! |
lou121505
| |
+ 1 |
+ 1 |
你将受到所有人的崇拜! |
若只如初见
| |
+ 1 |
|
支持原创,感谢楼主! |
am873
| |
+ 3 |
+ 1 |
你将受到所有人的崇拜! |
kasher
| |
+ 3 |
+ 1 |
支持原创,感谢楼主! |
fun
| |
+ 1 |
+ 1 |
你将受到所有人的崇拜! |
清晨
| |
+ 3 |
+ 1 |
高级教程,膜拜学习 |
Ylca
| |
+ 1 |
+ 1 |
建议前辈拿个软件实践一下! |
heiheidz
| + 1 |
+ 2 |
|
请注明转载还是原创 |
Crook
| |
+ 3 |
+ 1 |
你将受到所有人的崇拜! |
yypE
| |
+ 3 |
+ 1 |
你将受到所有人的崇拜! |
rain灿
| |
+ 3 |
+ 1 |
厉害。。。 |
小强
| |
+ 8 |
+ 1 |
你将受到所有人的崇拜! |
Cari
| |
|
+ 1 |
我很赞同! |
查看全部评分
|