本文章最後由 SheepKingCN 於 2013-9-2 04:27 編輯
- 此為本人無聊學習、備份文章用,大神請無視我SheepKingCN
複製代碼TP多开限制分析
| 作者:Tiany
QQ:304400230
花了10多天 研究过XX的多开 研究分析出一些东西 可是也被卡住了 遇到瓶颈 搞的郁闷了 把我分析到的东西和大家分享一下吧
大家都知道一般多开检测 都是一些互斥体 信号量 这些内核对象 当然TX也不例外 他也会对这些对象有检测 当然还有其他的检测 但是关键的代码都被VM了 所以想逆的难度就相当的大(对我而言) 所以我们必须要想些其他的方法
![]()
一般而言这些内核对象为了要个多个进程访问 所以都有Name 因为我们不好断定程序使用了1个或几个内核对象 来对比判断 所以这里我用的方法是 Inline Hook ZwCreateMutex ZwCreateEvent
ZwCreateSection ZwCreateSemaphore .... 这些函数 检测一下 如果Name 不为空的话 我们都让他的名字改变一下 达到每个进程创建的内核对象都变形
这里为什么要HOOK Zw开头的函数 我解释一下 因为CreateMutexA 调用 CreateMutexW 然后调用 ntdll.dll-ZwCreateMutex 函数 继续就到内核 nt!ZwCreateMutexA
(ntdll.dll-ZwCreateMutex 和 ntdll.dll-NtCreateMutex) 的导出地址是一样的
代码:- 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);
複製代碼 回调函数:
代码:- 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;
- }
複製代碼 其他的函数都一样处理
我们看看效果
![]()
搞完这里只是基本工作 我们运行发现还是运行不要了 说明了还有其他地方检测 经过我细心的观察 发现一个内核对象很可疑
![]()
这个Event 并未被处理 他的Name 也不固定 反正重启过也都会变 可是他为什么没有进到我们的回调函数里呢? 这就是TX猥琐之处 他重新加载Ntdll.dll 然后执行创建对象
这个时候我们只能到更深层的 ntdll.KiFastSystemCall 地方去看看他是在那里调用的
(Zw函数都会 调用 ntdll.KiFastSystemCall 来跳转到内核 )
![]()
定位到这里 反复跟踪后 可以了解 他首先 打开 Ntdll.dll 然后读取数据到内存 然后开辟内存空间 来执行 创建内核对象的代码
这里我用的方法就是 Inline Hook CreateFile 函数 判断 如果打开的是 Ntdll.dll 就让他打开我实现处理好HOOK 的 Ntdll.dllTen 文件 让他继续跳到我们的回调函数去 创建内核对象
上代码
代码:- //新建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 回调函数
代码:- 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我 一起研究
上传的图像
|
|