|
0x1: 某反外挂一直在打开文件,我们对ReadFile 下一个断点,很快就命中了
查看下调用者发现是在 tcj 中,读取的大小是PAGE_SIZE * 10
对读入的数据下一个硬件断点
看了栈,实际上TCJ 读完文件,就直接进来了,IDA 分析下这个函数
分析它的子函数可以很容易看到,这就是一个 MD5 的函数
看下 TCJ 循环READFILE 的逻辑
实际上就是循环读取文件内容,每次 PAGE_SIZE * 10 大小,得到最终的MD5 值放到参数中
我们接着看 TCJ得到了文件的MD5 后要继续做了什么,如果成功得到了文件的MD5 ,那么就进入了第二个函数
该函数逻辑如下,其作用是获取整个文件的 murmur哈希值和文件大小
名单最终我们得到了 2 个值
那么,程序已经获取了目标程序的 MD5 值,HASH值,和文件大小。接着
作为参数调用。 IDA 回顾下之前的逻辑,值得一提的是,在以后操作都完成后,释放才会文件句柄
我们接着分析 HandleFileHash,对输入的MD5 参数下一个硬件断点
发现断在了这个地方。回溯往上
第二次中中断发现在比较 MD5 的值
可以得出这段代码是先把 MD5 归类成一个ID ,然后在一个链表中查找相同ID 的数据,这样做的目的是加速搜索
观察它的结构,发现已经存在于数据库中了,看来这个数据库存放的都是 TCJ 扫描过的所有文件的信息。
接着,我们回到上一个地方,发现它查找到对应的数据库后,就会判断数据库中的 + 0×11字段是否匹配,如果匹配就修改8 为当前的时间
这里的英文查找到 MD5 后
而且有趣的的是,不止一个 MD5 数据库,还有一个hash数据库
,
从这 2 个不同的地方,我们就可以知道,有2 搜索方式1. 搜索方式为 md5 的时候,先获取md5 的桶ID ,再(object+ 0x60)的一个数组索引对应桶ID 的链表 下面我们接着看搜索方式为 hash 和大小的时候,
跟 MD5 搜索类似,给hash计算桶INDEX,再算表。不过是另外一个表,以下我简称这2 个表一个为HASH快查表,一个MD5 快查表。这个函数是搜索的对应的表,不过对应的表又指向相同的数据库。
MD5 快查表的一项
HASH查表快的一项
数据库:
既然知道,这里放着的是 TCJ 扫描过后的缓存,那么如果数据库中没有我们的记录,肯定是会插入的,往上继续回溯
如果没有找到对应的数据库,那么就调用 add_cache_list 添加到2 个表中去。
通过调用参数,我们可以确定最终的数据库结构和对应的大小了0×28
分析了这么多,我们写一个程序 DUMP 一下这2 份表吧
[C++] 纯文本查看 复制代码#include #include #pragma pack(1)struct SFileSig{ DWORD murmur_hash; DWORD file_size; DWORD64 time; BYTE level; BYTE id; DWORD md5[4];};#pragma pack()struct SMd5Item{ SMd5Item* p1; SMd5Item* p2; DWORD md5[4]; SFileSig* database;};struct SHashItem{ SHashItem* p1; SHashItem* p2; DWORD murmur_hash; DWORD file_size; SFileSig* database;};struct STableMd5{ DWORD p1; SMd5Item* list;};struct STableHash{ DWORD p1; SHashItem* list;};void DumpDatabase(const SFileSig* sig) { printf("----------------------------\n"); printf("murmur_hash:%08X\n", sig->murmur_hash); printf("file_size:%08X\n", sig->file_size); printf("update-time:%lu\n", sig->time); printf("level:%02X\n", sig->level); printf("id:%02x\n", sig->id); printf("md5:%08X%08X%08X%08X\n", sig->md5[0], sig->md5[1], sig->md5[2], sig->md5[3]); printf("-------------------------\n");}int __stdcall DllMain(_In_ void* _DllHandle, _In_ unsigned long _Reason, _In_opt_ void* _Reserved) { if (_Reason == DLL_PROCESS_ATTACH) { const auto md5_fast_list = reinterpret_cast(0x0C23BC60); for (int index = 0; index < 0x201; index++) { if (md5_fast_list[index].list) { for (auto iter = md5_fast_list[index].list; ; iter = iter->p1) { if (iter->database == nullptr || iter->md5[0] == 0)break; printf("[FastMd5List]md5:%08X%08X%08X%08X\n", iter->md5[0], iter->md5[1], iter->md5[2], iter->md5[3]); DumpDatabase(iter->database); if (iter->p1 == md5_fast_list[index].list) break; } } } const auto hash_fast_list = reinterpret_cast(0x0C23E488); for (int index = 0; index < 0x201; index++) { if (hash_fast_list[index].list) { for (auto iter = hash_fast_list[index].list; ; iter = iter->p1) { if (iter->p1 == hash_fast_list[index].list) break; printf("[FastHashList]hash:%08X ,file size:%08x\n", iter->murmur_hash, iter->file_size); DumpDatabase(iter->database); } } } } return 0;}
那么tcj维护这个大表做什么呢
欲知后事如何
来源:http://www.12558.net
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
|