自学逆向有段时间了,今天来一帖!
直接进入正题:
安装飞信,登录飞信,制造一点聊天记录。
在 C:\Users\%用户名%\Documents\Fetion\"飞信号" 路径下发现了一个文件 V5_History.dat (可以在飞信设置里面点击打开历史记录文件位置直接过去)
看名称就知道啦,飞信数据库文件就是这货。
UE打开观察此文件,一看就知道肯定经过加密的。不做多的解释
<ignore_js_op>
打开飞信主目录,观察飞信目录中的dll。
看dll名称,猜测消息记录处理的dll,飞信主目录内发现目录 Data\History,目录中有个History.dll,猜测这货是处理历史记录的dll
于是打开OD,OD打开Fetion.exe,ALT+E 跟随History.dll,大概喵了几眼,然后CTRL+N查看模块中的名称,
发现一个_FhOpenDB,看名称就知道这是干嘛的了,根据OD显示,此函数出自Fhlib.dll,于是用 eXeScope 查看此dll的导入导出信息
在导入信息中发现导入了ADVAIP.DLL(非常重要!!!!),此DLL是Windows自带的加密算法库,于是打开 IDA Pro,准备开始分心Fhlib.dll.
在Import表里面发现了 CryptCreateHash、CryptHashData、CryptDeriveKey、CryptDestroyHash等很显眼的函数!!
感觉告诉我,这就是解码部分,
于是逆向了这部分代码,完成过后用OD跟踪,确定这几个函数的可变参数内容,哈哈,最重要的生产hash和key的密钥居然是飞信号,立刻打开VS写代码,
一举成功,成功将V5_History.dat解码,用UE打开观察解码后的文件,我艹!!文件签名好熟悉,这不是我常用的 sqlite3 么?而sqlite3是个轻量级小型开源数据库。
接着用数据库可视化查看工具查看数据库内容,聊天记录一览无遗。破解成功。
附上代码!!!
[C++] 纯文本查看 复制代码
01 |
* - 将解密的数据库文件放入系统临时目录 |
02 |
*/ |
03 |
int IS_FetionV5History::DeCryptFetionDB() |
04 |
{ |
05 |
HCRYPTPROV hProv = NULL; |
06 |
HCRYPTHASH hHash = NULL; |
07 |
LPCTSTR lpszPwd = ( LPCTSTR )szFetionNum; //密码,飞信号 |
08 |
HCRYPTKEY hKey = NULL; |
09 |
10 |
CryptAcquireContext(&hProv, 0, "Microsoft Enhanced Cryptographic Provider v1.0" , 1, 0xF0000000); |
11 |
CryptCreateHash(hProv,0x8004,0,0,&hHash); |
12 |
CryptHashData(hHash,( const BYTE *)lpszPwd, strlen (( const char *)lpszPwd),0); |
13 |
CryptDeriveKey(hProv,0x6801,hHash,0,&hKey); |
14 |
CryptDestroyHash(hHash); |
15 |
16 |
/**************************************************************/ |
17 |
HANDLE pInFile,pOutFile; //文件句柄 |
18 |
DWORD dwReadLen = 0x400 ,dwReadSize ,dwWriteSize; //想要读取的数据长度;实际读取文件大小;实际写入数据 |
19 |
20 |
{ //打开源文件 |
21 |
pInFile = ::CreateFile(strEvidencePath.c_str(), GENERIC_READ, 0, NULL, OPEN_EXISTING, |
22 |
FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_READONLY, NULL); //用这个函数比OpenFile好 |
23 |
if ( pInFile == INVALID_HANDLE_VALUE) |
24 |
{ |
25 |
CloseHandle(pInFile); //一定注意在函数退出之前对句柄进行释放。 |
26 |
return -1; |
27 |
} |
28 |
} |
29 |
{ //打开写入文件 |
30 |
pOutFile = ::CreateFile(strDstPath.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, |
31 |
FILE_ATTRIBUTE_NORMAL, NULL); //用这个函数比OpenFile好 |
32 |
if ( pOutFile == INVALID_HANDLE_VALUE) |
33 |
{ |
34 |
CloseHandle(pOutFile); //一定注意在函数退出之前对句柄进行释放。 |
35 |
return -1; |
36 |
} |
37 |
} |
38 |
/**************************************************************/ |
39 |
BYTE szBuf[0x400 + 1] = {0}; //__in__out 输入加密内容,输出解密后内容 |
40 |
41 |
//循环读取文件 |
42 |
do |
43 |
{ |
44 |
ReadFile(pInFile, szBuf, dwReadLen, &dwReadSize, NULL); |
45 |
46 |
if (dwReadLen < dwReadSize) |
47 |
CryptDecrypt(hKey,0,TRUE,0,szBuf,&dwReadLen); |
48 |
else |
49 |
CryptDecrypt(hKey,0,TRUE,0,szBuf,&dwReadSize); |
50 |
//写入文件 |
51 |
WriteFile(pOutFile,szBuf,dwReadSize,&dwWriteSize,NULL); |
52 |
53 |
memset (szBuf,0,0x400 + 1); |
54 |
} while ( dwReadSize == dwReadLen); |
55 |
56 |
CloseHandle(pInFile); |
57 |
CloseHandle(pOutFile); |
58 |
return 0; |
59 |
} //DeCryptFetionDB() |
https://www.0xaa55.com/forum.php?mod=viewthread&tid=1787&extra=page%3D1