在winxp下进程的创建无非是使用System,Winexec,ShellExecute,CreateProcess等库函数和系统API.但是为了实现对进程创建的监视,我们一般都是拦截这些api,这样工作量会很大.而实际上这些函数最终都会调用ntdll.dll所导出的ZwCreateProcessEx函数,由他填入服务索引号,并软中断进入内核模式.只要Hook了该函数就能有效地从用户层监视进程的创建.但是有人会说,在2000和Xp下不是有NtCreateProcess和ZwCreateProcess么,实际上今天晚上我自己动手试了下,上述这两者,首先他们是一个函数,其次,在Xp下创建进程的时候,根本不会使用到他们...
首先看下ZwCreateProcessEx的定义(参考win2k/xp native api refernce):
typedef NTSTATUS (*NTCREATEPROCESSEX)(
OUT PHANDLE ProcessHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
IN HANDLE ParentProcess,
IN BOOLEAN InheritObjectTable,
IN HANDLE SectionHandle OPTIONAL,
IN HANDLE DebugPort OPTIONAL,
IN HANDLE ExceptionPort OPTIONAL,
IN HANDLE Unknown );
我们需要的只是拦截他,目前暂时具体参数的功能就不谈了,具体实现方式就不说了,在前面的<用户层下拦截API的原理与实现>中已经讲得很清楚拉.如果你忘记了,具体见:http://redcoder.blog.sohu.com/2183228.html下面是这次实验的代码,拦截了ZwCreateProcessEx函数:
编译环境:WinXp Sp2 + vc6.0- #include <stdio.h>
- #include <windows.h>
- #define STATUS_SUCCESS 0
- #define HOOKFUCTIONSIZE 10240 //定义拦截函数体的大小,以字节为单位,且以4kb为基本单位
- #define HOOKEDAPIPARAMNUMINBYTE 36 //定义被拦截的api的函数的参数的大小,以字节为单位
- typedef unsigned long NTSTATUS;
- typedef unsigned long SYSTEM_INFORMATION_CLASS;
- typedef struct _RemoteParam{
- LPVOID lpFunAddr;
- LPVOID lpWriteProcessMemory;
- unsigned char szOldCode[12];
- unsigned char szNewCode[12];
- LPVOID lpMessageBox;
- }RemoteParam, * PRemoteParam;
- typedef BOOL (__stdcall * PFN_WRITEPROCESSMEMORY)(HANDLE, LPVOID, LPCVOID, SIZE_T, SIZE_T*);
- typedef int (__stdcall * PFN_MESSAGEBOX)(HWND, LPCTSTR, LPCTSTR, DWORD);
- typedef
- NTSTATUS
- (__stdcall * PFN_ZWCREATEPROCESSEX)(
- PHANDLE,
- ACCESS_MASK,
- LPVOID,
- HANDLE,
- BOOLEAN,
- HANDLE,
- HANDLE,
- HANDLE,
- HANDLE
- );
- VOID HookApi(LPVOID lParam)
- {
- RemoteParam* Rpm = (RemoteParam*)lParam;
- PFN_ZWCREATEPROCESSEX pfnZwCreateprocessEx = (PFN_ZWCREATEPROCESSEX)Rpm->lpFunAddr;
- PFN_WRITEPROCESSMEMORY pfnWriteProcessMemory = (PFN_WRITEPROCESSMEMORY)Rpm->lpWriteProcessMemory;
- PFN_MESSAGEBOX pfnMessageBox = (PFN_MESSAGEBOX)Rpm->lpMessageBox;
- char sztest[8] = {';h';, ';e';, ';l';, ';l';, ';o';, ';.';, ';.';, ';\0';};
-
- PHANDLE ProcessHandle = NULL;
- ACCESS_MASK DesiredAccess = 0;
- LPVOID ObjectAttributes = NULL;
- HANDLE InheritFromProcessHandle = NULL;
- BOOLEAN InheritHandles = TRUE;
- HANDLE SectionHandle = NULL;
- HANDLE DebugPort = NULL;
- HANDLE ExceptionPort = NULL;
- HANDLE reserv = NULL;
-
- NTSTATUS Retvalue = STATUS_SUCCESS; //定义要拦截的api的默认返回植
- DWORD NextIpAddr = 0;
- DWORD dwParamaAddr = 0;
- DWORD temp1 = 0;
-
- __asm
- {
- MOV EAX, [EBP + 12]
- MOV [NextIpAddr], EAX
- MOV EAX, [EBP + 16]
- MOV [ProcessHandle], EAX
- MOV EAX, [EBP + 20]
- MOV [DesiredAccess], EAX
- MOV EAX, [EBP + 24]
- MOV [ObjectAttributes], EAX
- MOV EAX, [EBP + 28]
- MOV [InheritFromProcessHandle], EAX
- MOV EAX, [EBP + 32]
- MOV [temp1], EAX
- MOV EAX, [EBP + 36]
- MOV [SectionHandle], EAX
- MOV EAX, [EBP + 40]
- MOV [DebugPort], EAX
- MOV EAX, [EBP + 44]
- MOV [ExceptionPort], EAX
- MOV EAX, [EBP + 48]
- MOV [reserv], EAX
- }
- InheritHandles = (BOOLEAN)temp1;
- //这里可以做你的事情了,比如我只想弹出一个对话框,其实也可以在让api完成之后再做些东西
- pfnMessageBox(NULL, sztest, sztest, 0);
- pfnWriteProcessMemory((HANDLE)0XFFFFFFFF, Rpm->lpFunAddr, (LPCVOID)Rpm->szOldCode, 12, NULL);
- //让api真正执行,这里换成你要拦截的api
- Retvalue = pfnZwCreateprocessEx(ProcessHandle,
- DesiredAccess,
- ObjectAttributes,
- InheritFromProcessHandle,
- InheritHandles,
- SectionHandle,
- DebugPort,
- ExceptionPort,
- reserv);
-
- //再次恢复对他的拦截
- pfnWriteProcessMemory((HANDLE)0XFFFFFFFF, Rpm->lpFunAddr, (LPCVOID)Rpm->szNewCode, 12, NULL);
-
- DWORD dwStackSize = 12 + HOOKEDAPIPARAMNUMINBYTE;
-
- //这里对拦截函数堆栈的恢复,必须放在最后
- __asm
- {
- POP EDI //注意如果你编译生成的debug版本的程序则需要把这
- POP ESI //三个注释去掉
- POP EBX
- MOV ECX, [dwStackSize]
- MOV EDX, [NextIpAddr]
- MOV EAX, [Retvalue]
- MOV ESP, EBP
- POP EBP
- ADD ESP, ECX //12 + HOOKEDAPIPARAMNUMINBYTE //恢复堆栈
- PUSH EDX
- RET
- }
- }
- //////////////////////////////////////////////////////////////////////////
- //************************************************************************
- //模块名字:AdjustProcessPrivileges(LPCSTR)
- //模块功能:修改调用进程的权限
- //返回数值:成功返回TRUE,失败返回FALSE
- //参数可以为下列值:
- // #define SE_BACKUP_NAME TEXT("SeBackupPrivilege")
- // #define SE_RESTORE_NAME TEXT("SeRestorePrivilege")
- // #define SE_SHUTDOWN_NAME TEXT("SeShutdownPrivilege")
- // #define SE_DEBUG_NAME TEXT("SeDebugPrivilege")
- //////////////////////////////////////////////////////////////////////////
- BOOL AdjustProcessPrivileges(LPCSTR lpPrivilegesName)
- {
- HANDLE hToken;
- TOKEN_PRIVILEGES tkp;
- if(!OpenProcessToken((HANDLE)0XFFFFFFFF,
- TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
- {
- return FALSE;
- }
- if(!LookupPrivilegeValue(NULL, lpPrivilegesName, &tkp.Privileges[0].Luid))
- {
- CloseHandle(hToken);
- return FALSE;
- }
-
- tkp.PrivilegeCount = 1;
- tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
- if(!AdjustTokenPrivileges(hToken, FALSE, &tkp, sizeof(tkp), NULL, NULL))
- {
- CloseHandle(hToken);
- return FALSE;
- }
- CloseHandle(hToken);
- return TRUE;
- }
- int SetHook(DWORD dwPid, LPCTSTR lpApiName, LPCTSTR lpExportDllName, LPVOID lpHookFunAddr)
- {
- if(!AdjustProcessPrivileges(SE_DEBUG_NAME))
- {
- printf("-----AdjustProcessPrivileges error..\n");
- return -1;
- }
- printf("1:AdjustProcessPrivileges ok\n");
-
- //获取要拦截的api的地址
- HMODULE hExportDll = LoadLibrary(lpExportDllName);
- if(hExportDll == NULL)
- {
- printf("-----LoadLibrary error..\n");
- return -1;
- }
-
- LPVOID lpApiAddr = GetProcAddress(hExportDll, lpApiName);
- if(lpApiAddr == NULL)
- {
- printf("-----GetProcAddress %s error..\n", lpApiName);
- FreeLibrary(hExportDll);
- return -1;
- }
-
- //打开进程句柄
- HANDLE hTargetProcess = OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ,
- FALSE, dwPid);
- if(hTargetProcess == NULL)
- {
- printf("-----OpenProcess %d error..\n", dwPid);
- FreeLibrary(hExportDll);
- return -1;
- }
-
- //申请拦截函数内存空间
- LPVOID lpFunAddr = VirtualAllocEx(hTargetProcess, NULL, HOOKFUCTIONSIZE,
- MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
- if(lpFunAddr == NULL)
- {
- printf("-----VirtualAllocEx for remotefuction error..\n");
- FreeLibrary(hExportDll);
- CloseHandle(hTargetProcess);
- return -1;
- }
-
- //申请远程参数空间
- LPVOID lpParamaAddr = VirtualAllocEx(hTargetProcess, NULL, sizeof(RemoteParam),
- MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
- if(lpParamaAddr == NULL)
- {
- printf("-----VirtualAllocEx for remoteparam error..\n");
- FreeLibrary(hExportDll);
- VirtualFreeEx(hTargetProcess, lpFunAddr, 0, MEM_RELEASE);
- CloseHandle(hTargetProcess);
- return -1;
- }
- printf("2:Alloc remote memory for the hook fuction and param ok\n");
-
-
- //设置远程参数,下一步要把参数写入要拦截的远程进程地址空间
- RemoteParam RParam;
- ZeroMemory(&RParam, sizeof(RParam));
-
- unsigned char oldcode[12];
- unsigned char newcode[12];
- DWORD dwError = 0;
- if(!ReadProcessMemory((HANDLE)0XFFFFFFFF,
- lpApiAddr,
- oldcode,
- 12,
- &dwError))
- {
- printf("-----ReadProcessMemory from lpApiName error..\n");
- FreeLibrary(hExportDll);
- VirtualFreeEx(hTargetProcess, lpFunAddr, 0, MEM_RELEASE);
- VirtualFreeEx(hTargetProcess, lpParamaAddr, 0, MEM_RELEASE);
- CloseHandle(hTargetProcess);
- return -1;
- }
- //生成跳转指令,这将覆盖要拦截的api的前十个字节
- int praadd = (int)lpParamaAddr;
- int threadadd = (int)lpFunAddr;
- newcode[4] = praadd>>24;
- newcode[3] = (praadd<<8)>>24;
- newcode[2] = (praadd<<16)>>24;
- newcode[1] = (praadd<<24)>>24;
- newcode[0] = 0x68; //PUSH lpParamaAddr
- int offsetaddr = threadadd - (int)lpApiAddr - 10 ;
- newcode[9] = offsetaddr>>24;
- newcode[8] = (offsetaddr<<8)>>24;
- newcode[7] = (offsetaddr<<16)>>24;
- newcode[6] = (offsetaddr<<24)>>24;
- newcode[5] = 0xE8; //CALL lpFunAddr
- newcode[10] = 0x90;
- newcode[11] = 0x90;
-
- for(int j = 0; j < 12; j++)
- {
- RParam.szOldCode[j] = oldcode[j];
- RParam.szNewCode[j] = newcode[j];
- }
- RParam.lpFunAddr = lpApiAddr;
-
- HMODULE hKernel32 = LoadLibrary("Kernel32.dll");
- if(hKernel32 == NULL)
- {
- printf("-----LoadLibrary Kernel32.dll error..\n");
- FreeLibrary(hExportDll);
- VirtualFreeEx(hTargetProcess, lpFunAddr, 0, MEM_RELEASE);
- VirtualFreeEx(hTargetProcess, lpParamaAddr, 0, MEM_RELEASE);
- CloseHandle(hTargetProcess);
- return -1;
- }
-
- RParam.lpWriteProcessMemory = GetProcAddress(hKernel32, "WriteProcessMemory");
- if(RParam.lpWriteProcessMemory == NULL)
- {
- printf("-----GetProcAddress WriteProcessMemory from Kernel32.dll error..\n");
- FreeLibrary(hExportDll);
- VirtualFreeEx(hTargetProcess, lpFunAddr, 0, MEM_RELEASE);
- VirtualFreeEx(hTargetProcess, lpParamaAddr, 0, MEM_RELEASE);
- CloseHandle(hTargetProcess);
- FreeLibrary(hKernel32);
- return -1;
- }
-
- //以上皆为必须,下面可以为自己的拦截函数中所需要用的一些变量以及系统api放到参数中去
- HMODULE hUser32 = LoadLibrary("User32.dll");
- if(hUser32 == NULL)
- {
- printf("-----LoadLibrary User32.dll error..\n");
- FreeLibrary(hExportDll);
- VirtualFreeEx(hTargetProcess, lpFunAddr, 0, MEM_RELEASE);
- VirtualFreeEx(hTargetProcess, lpParamaAddr, 0, MEM_RELEASE);
- CloseHandle(hTargetProcess);
- FreeLibrary(hKernel32);
- return -1;
- }
-
- RParam.lpMessageBox = GetProcAddress(hUser32, "MessageBoxA");
- if(RParam.lpMessageBox == NULL)
- {
- printf("-----GetProcAddress MessageBoxA from User32.dll error..\n");
- FreeLibrary(hExportDll);
- VirtualFreeEx(hTargetProcess, lpFunAddr, 0, MEM_RELEASE);
- VirtualFreeEx(hTargetProcess, lpParamaAddr, 0, MEM_RELEASE);
- CloseHandle(hTargetProcess);
- FreeLibrary(hKernel32);
- FreeLibrary(hUser32);
- return -1;
- }
-
- FreeLibrary(hUser32);
- printf("3:Generate remoteparam ok\n");
-
- //下面为必须部分
- //把参数写入要拦截的远程进程地址空间
- if(!WriteProcessMemory(hTargetProcess, lpParamaAddr, (LPVOID)&RParam, sizeof(RParam), &dwError))
- {
- printf("-----WriteProcessMemory for remoteparam error..\n");
- FreeLibrary(hExportDll);
- VirtualFreeEx(hTargetProcess, lpFunAddr, 0, MEM_RELEASE);
- VirtualFreeEx(hTargetProcess, lpParamaAddr, 0, MEM_RELEASE);
- CloseHandle(hTargetProcess);
- FreeLibrary(hKernel32);
- return -1;
- }
- printf("4:WriteProcessMemory for remoteparam ok\n");
- //把拦截函数体写入目标进程地址空间
- if(!WriteProcessMemory(hTargetProcess, lpFunAddr, lpHookFunAddr, HOOKFUCTIONSIZE, &dwError))
- {
- printf("-----WriteProcessMemory for remotefuction error..\n");
- FreeLibrary(hExportDll);
- VirtualFreeEx(hTargetProcess, lpFunAddr, 0, MEM_RELEASE);
- VirtualFreeEx(hTargetProcess, lpParamaAddr, 0, MEM_RELEASE);
- CloseHandle(hTargetProcess);
- FreeLibrary(hKernel32);
- return -1;
- }
- printf("5:WriteProcessMemory for remotefuction ok\n");
- //把新的跳转指令写入要拦截的目标进程的要拦截的api的函数的前十字节
- if(!WriteProcessMemory(hTargetProcess, lpApiAddr , (LPVOID)newcode, 12, &dwError))
- {
- printf("-----Modify remote api error..\n");
- FreeLibrary(hExportDll);
- VirtualFreeEx(hTargetProcess, lpFunAddr, 0, MEM_RELEASE);
- VirtualFreeEx(hTargetProcess, lpParamaAddr, 0, MEM_RELEASE);
- CloseHandle(hTargetProcess);
- FreeLibrary(hKernel32);
- return -1;
- }
- printf("6:Modify remote api %s ok\n", lpApiName);
- //show..
- printf("---------------------------------------------------------------------------\n"
- "You hava hooked pid: %d ,and the infomation of this hooking are as follows:\n"
- "API name: %s\n"
- "API addr: 0x%.8x\n"
- "Module name: %s\n"
- "Module addr: 0x%.8x\n"
- "Remote parama addr: 0x%.8x\n"
- "Remote thread addr: 0x%.8x\n"
- "RemoteParam.lpFunAddr: 0x%.8x\n"
- "RemoteParam.lpWriteProcessMemory: 0x%.8x\n"
- "RemoteParam.lpMessageBox: 0x%.8x\n",
- dwPid,
- lpApiName,
- lpApiAddr,
- lpExportDllName,
- hExportDll,
- lpParamaAddr,
- lpFunAddr,
- RParam.lpFunAddr,
- RParam.lpWriteProcessMemory,
- RParam.lpMessageBox);
-
- printf("RemoteParam.szOldCode: ");
- for(int i = 0; i < 12; i++)
- {
- printf("0x%x ", RParam.szOldCode[i]);
- }
- printf("\nRemoteParam.szNewCode: ");
- for(i = 0; i < 12; i++)
- {
- printf("0x%x ", RParam.szNewCode[i]);
- }
- printf("\nThat';s all, good luck ^_^\n");
- Sleep(10000);
-
- //收工,清理资源
- FreeLibrary(hExportDll);
- CloseHandle(hTargetProcess);
- FreeLibrary(hKernel32);
- return 0;
- }
- int main(void)
- {//注意这里第一个参数是你要选择监视的进程的ID,我这里是选的我的explorer.exe
- SetHook(1564, "NtCreateProcessEx", "ntdll.dll", &HookApi);
- return 0;
- }
复制代码 最后当你的文件夹或者其他地方双击鼠标来运行一个程序的时候,首先会弹出一个hello窗口,点ok,该程序才会运行.
|