TX游戏多开分析

来源:互联网 发布:大数据时代如何赚钱 编辑:程序博客网 时间:2024/04/30 07:32
标 题: 【原创】TX游戏多开分析
作 者: 毁灭
时 间: 2013-04-08,15:06:23
链 接: http://bbs.pediy.com/showthread.php?t=167848

作者:Tiany
QQ:304400230
花了10多天 研究过XX的多开 研究分析出一些东西 可是也被卡住了 遇到瓶颈 搞的郁闷了 把我分析到的东西和大家分享一下吧 

大家都知道一般多开检测 都是一些互斥体 信号量 这些内核对象 当然TX也不例外 他也会对这些对象有检测  当然还有其他的检测 但是关键的代码都被VM了  所以想逆的难度就相当的大(对我而言) 所以我们必须要想些其他的方法 

http://bbs.pediy.com/attachment.php?attachmentid=78010&stc=1&d=1365405158

一般而言这些内核对象为了要个多个进程访问 所以都有Name 因为我们不好断定程序使用了1个或几个内核对象 来对比判断 所以这里我用的方法是 Inline Hook ZwCreateMutex ZwCreateEvent 
ZwCreateSection  ZwCreateSemaphore .... 这些函数 检测一下 如果Name 不为空的话 我们都让他的名字改变一下 达到每个进程创建的内核对象都变形 

这里为什么要HOOK Zw开头的函数 我解释一下  因为CreateMutexA 调用 CreateMutexW 然后调用 ntdll.dll-ZwCreateMutex 函数 继续就到内核 nt!ZwCreateMutexA 
(ntdll.dll-ZwCreateMutex 和 ntdll.dll-NtCreateMutex) 的导出地址是一样的 

Code:
  HMODULE hNTDLL = LoadLibrary("ntdll.dll");  if (!hNTDLL)  {    OutputDebugStringA("[TEN] [DLL] 加载 ntdll.dll 失败\n");    return TRUE;  }//NtCreateEventInlineHook((__pfnNtCreateEvent)(LPVOID)GetProcAddress(hNTDLL,"NtCreateEvent"),    OnNtCreateEvent,    (void **)&pfnNtCreateEvent);
回调函数:


Code:
NTSTATUSNTAPIOnNtCreateEvent(  OUT PHANDLE             EventHandle,  IN ACCESS_MASK          DesiredAccess,  IN POBJECT_ATTRIBUTES   ObjectAttributes OPTIONAL,  IN EVENT_TYPE           EventType,  IN BOOLEAN              InitialState){  NTSTATUS nRet;  if (ObjectAttributes && ObjectAttributes->ObjectName && ObjectAttributes->ObjectName->Buffer)  {    WCHAR lpTemp[MAX_PATH];    ZeroMemory(lpTemp,MAX_PATH);    wsprintfW(lpTemp,L"[Ten] [DLL] %lS%08X",ObjectAttributes->ObjectName->Buffer,GetCurrentProcessId());    OutputDebugStringW(ObjectAttributes->ObjectName->Buffer);    pfnRtlInitUnicodeString(ObjectAttributes->ObjectName,lpTemp);  }  nRet = pfnNtCreateEvent(    EventHandle,    DesiredAccess,    ObjectAttributes,    EventType,    InitialState    );  return nRet;}


其他的函数都一样处理 

我们看看效果

http://bbs.pediy.com/attachment.php?attachmentid=78011&stc=1&d=1365405158



搞完这里只是基本工作 我们运行发现还是运行不要了 说明了还有其他地方检测 经过我细心的观察 发现一个内核对象很可疑 


http://bbs.pediy.com/attachment.php?attachmentid=78012&stc=1&thumb=1&d=1365405158


这个Event 并未被处理  他的Name 也不固定 反正重启过也都会变  可是他为什么没有进到我们的回调函数里呢? 这就是TX猥琐之处  他重新加载Ntdll.dll 然后执行创建对象 

这个时候我们只能到更深层的 ntdll.KiFastSystemCall 地方去看看他是在那里调用的 
(Zw函数都会 调用 ntdll.KiFastSystemCall 来跳转到内核 )


http://bbs.pediy.com/attachment.php?attachmentid=78013&stc=1&thumb=1&d=1365405158

定位到这里  反复跟踪后 可以了解 他首先 打开 Ntdll.dll 然后读取数据到内存 然后开辟内存空间 来执行 创建内核对象的代码  

这里我用的方法就是 Inline Hook CreateFile 函数 判断 如果打开的是 Ntdll.dll 就让他打开我实现处理好HOOK 的 Ntdll.dllTen 文件 让他继续跳到我们的回调函数去 创建内核对象

上代码

Code:
//新建Ntdll.dllBOOL CreateNtdll(LPBYTE NewCode,DWORD len){  PBYTE szBuffer = NULL;  BYTE szSearCode[] = {0xB8,0x23,0x00,0x00,0x00,0xBA,0x00,0x03,0xFE,0x7F,0xFF,0x12,0xC2,0x14,0x00};  DWORD dwSize,lpSize;  HANDLE hFile = CreateFileA("C:\\WINDOWS\\system32\\ntdll.dll",          GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,          FILE_ATTRIBUTE_NORMAL,NULL);  if (hFile == INVALID_HANDLE_VALUE)  {    return FALSE;  }  dwSize = GetFileSize(hFile,NULL);  szBuffer = new BYTE[dwSize];  ReadFile(hFile,szBuffer,dwSize,&lpSize,NULL);  CloseHandle(hFile);  //特征码搜索  LPBYTE pCode = SearchFeature(szBuffer,dwSize,szSearCode,sizeof(szSearCode));  if (pCode == NULL)  {    delete szBuffer;    return FALSE;  }  //替换操作  memcpy(pCode,NewCode,len);  hFile = CreateFileA("C:\\WINDOWS\\system32\\ntdll.dllTen",GENERIC_WRITE,FILE_SHARE_WRITE,            NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);  if (hFile == INVALID_HANDLE_VALUE)  {    delete szBuffer;    return FALSE;  }  WriteFile(hFile,szBuffer,dwSize,&lpSize,NULL);  CloseHandle(hFile);  delete szBuffer;  return TRUE;}

CreateFile 回调函数

Code:
NTSTATUSNTAPIOnNtCreateFile(    OUT PHANDLE  FileHandle,    IN ACCESS_MASK  DesiredAccess,    IN POBJECT_ATTRIBUTES  ObjectAttributes,    OUT PIO_STATUS_BLOCK  IoStatusBlock,    IN PLARGE_INTEGER  AllocationSize  OPTIONAL,    IN ULONG  FileAttributes,    IN ULONG  ShareAccess,    IN ULONG  CreateDisposition,    IN ULONG  CreateOptions,    IN PVOID  EaBuffer  OPTIONAL,    IN ULONG  EaLength){  NTSTATUS nRet;  if (ObjectAttributes && ObjectAttributes->ObjectName && ObjectAttributes->ObjectName->Buffer)  {    if (wcsstr(ObjectAttributes->ObjectName->Buffer,L"ntdll.dll"))    {      WCHAR lpTemp[MAX_PATH];      ZeroMemory(lpTemp,MAX_PATH);      wsprintfW(lpTemp,L"%lSTen",ObjectAttributes->ObjectName->Buffer);      pfnRtlInitUnicodeString(ObjectAttributes->ObjectName,lpTemp);      OutputDebugStringW(ObjectAttributes->ObjectName->Buffer);    }  }  nRet = pfnNtCreateFile(    FileHandle,    DesiredAccess,    ObjectAttributes,    IoStatusBlock,    AllocationSize,    FileAttributes,    ShareAccess,    CreateDisposition,    CreateOptions,    EaBuffer,    EaLength    );  return nRet;}

经过以上的处理后  我们可以看到 内核对象很多都已经让我们 更名换姓了 
当然如果不放心 也可以在ZwOpen*****  函数也进行HOOK 让他如果用打开的时候也访问到是我们创建的内核对象 处理的方法一样 可惜的是程序肯定还有其他的检测 我也尝试处理了 CreateToolhelp32Snapshot Process32First Process32Next 进程遍历的函数 也没能绕过 想不出解决的办法  故把分析的东西都公布 如果大家想一起研究或发现什么新的东西 大家可以论坛PM我 一起研究*转载请注明来自看雪论坛@PEdiy.com
Attached Images
2.jpg   3.jpg  4.jpg  1.jpg    
0 0