TX游戏多开分析

标 题: 【原创】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;
  }

//NtCreateEvent
InlineHook((__pfnNtCreateEvent)(LPVOID)GetProcAddress(hNTDLL,"NtCreateEvent"),
    OnNtCreateEvent,
    (void **)&pfnNtCreateEvent);
回调函数:


Code:
NTSTATUS
NTAPI
OnNtCreateEvent(
  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.dll
BOOL 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:
NTSTATUS
NTAPI
OnNtCreateFile(
    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    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值