****核心原理读书笔记-API钩取之隐藏进程(一)
简评:
整体看了下代码,其实就是应用层的inline hook, 钩子勾住ntdll.dll里面的ZwQuerySystemInformation函数, xp环境测试成功了,win7测试失败了,不知道怎么回事,有时间再测试一下。为什么要给所有进程进行dll注入?因为除了taskmgr.exe进程外可能会有其他的进程也会枚举进程(比如自己写了一个枚举进程的程序),为了使这些未知的程序也看不到隐藏进程,对所有进程下的ntdll.dll里面的ZwQuerySystemInformation函数进行了hook。
我们通过一个示例来练习在ProcExp.exe和taskmgr.exe中隐藏进程。钩取前后的原理图如下所示。
下面我们先测试一下代码。关于代码的使用很简单,就不再多说了。
我们来分析一下源代码,看看是怎么实现的。
HideProc.cpp
- #include "windows.h"
- #include "stdio.h"
- #include "tlhelp32.h"
- #include "tchar.h"
- typedef void (*PFN_SetProcName)(LPCTSTR szProcName);
- enum {INJECTION_MODE = 0, EJECTION_MODE};
- BOOL SetPrivilege(LPCTSTR lpszPrivilege, BOOL bEnablePrivilege)
- {
- TOKEN_PRIVILEGES tp;
- HANDLE hToken;
- LUID luid;
- if( !OpenProcessToken(GetCurrentProcess(),
- TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
- &hToken) )
- {
- printf("OpenProcessToken error: %u\n", GetLastError());
- return FALSE;
- }
- if( !LookupPrivilegeValue(NULL, // lookup privilege on local system
- lpszPrivilege, // privilege to lookup
- &luid) ) // receives LUID of privilege
- {
- printf("LookupPrivilegeValue error: %u\n", GetLastError() );
- return FALSE;
- }
- tp.PrivilegeCount = 1;
- tp.Privileges[0].Luid = luid;
- if( bEnablePrivilege )
- tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
- else
- tp.Privileges[0].Attributes = 0;
- // Enable the privilege or disable all privileges.
- if( !AdjustTokenPrivileges(hToken,
- FALSE,
- &tp,
- sizeof(TOKEN_PRIVILEGES),
- (PTOKEN_PRIVILEGES) NULL,
- (PDWORD) NULL) )
- {
- printf("AdjustTokenPrivileges error: %u\n", GetLastError() );
- return FALSE;
- }
- if( GetLastError() == ERROR_NOT_ALL_ASSIGNED )
- {
- printf("The token does not have the specified privilege. \n");
- return FALSE;
- }
- return TRUE;
- }
- BOOL InjectDll(DWORD dwPID, LPCTSTR szDllPath)
- {
- HANDLE hProcess, hThread;
- LPVOID pRemoteBuf;
- DWORD dwBufSize = (DWORD)(_tcslen(szDllPath) + 1) * sizeof(TCHAR);
- LPTHREAD_START_ROUTINE pThreadProc;
- if ( !(hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID)) )
- {
- printf("OpenProcess(%d) failed!!!\n", dwPID);
- return FALSE;
- }
- pRemoteBuf = VirtualAllocEx(hProcess, NULL, dwBufSize,
- MEM_COMMIT, PAGE_READWRITE);
- WriteProcessMemory(hProcess, pRemoteBuf,
- (LPVOID)szDllPath, dwBufSize, NULL);
- pThreadProc = (LPTHREAD_START_ROUTINE)
- GetProcAddress(GetModuleHandle(L"kernel32.dll"),
- "LoadLibraryW");
- hThread = CreateRemoteThread(hProcess, NULL, 0,
- pThreadProc, pRemoteBuf, 0, NULL);
- WaitForSingleObject(hThread, INFINITE);
- VirtualFreeEx(hProcess, pRemoteBuf, 0, MEM_RELEASE);
- CloseHandle(hThread);
- CloseHandle(hProcess);
- return TRUE;
- }
- BOOL EjectDll(DWORD dwPID, LPCTSTR szDllPath)
- {
- BOOL bMore = FALSE, bFound = FALSE;
- HANDLE hSnapshot, hProcess, hThread;
- MODULEENTRY32 me = { sizeof(me) };
- LPTHREAD_START_ROUTINE pThreadProc;
- if( INVALID_HANDLE_VALUE ==
- (hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwPID)) )
- return FALSE;
- bMore = Module32First(hSnapshot, &me);
- for( ; bMore ; bMore = Module32Next(hSnapshot, &me) )
- {
- if( !_tcsicmp(me.szModule, szDllPath) ||
- !_tcsicmp(me.szExePath, szDllPath) )
- {
- bFound = TRUE;
- break;
- }
- }
- if( !bFound )
- {
- CloseHandle(hSnapshot);
- return FALSE;
- }
- if( !(hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID)) )
- {
- CloseHandle(hSnapshot);
- return FALSE;
- }
- pThreadProc = (LPTHREAD_START_ROUTINE)
- GetProcAddress(GetModuleHandle(L"kernel32.dll"),
- "FreeLibrary");
- hThread = CreateRemoteThread(hProcess, NULL, 0,
- pThreadProc, me.modBaseAddr, 0, NULL);
- WaitForSingleObject(hThread, INFINITE);
- CloseHandle(hThread);
- CloseHandle(hProcess);
- CloseHandle(hSnapshot);
- return TRUE;
- }
- BOOL InjectAllProcess(int nMode, LPCTSTR szDllPath)
- {
- DWORD dwPID = 0;
- HANDLE hSnapShot = INVALID_HANDLE_VALUE;
- PROCESSENTRY32 pe;
- // Get the snapshot of the system
- pe.dwSize = sizeof( PROCESSENTRY32 );
- hSnapShot = CreateToolhelp32Snapshot( TH32CS_SNAPALL, NULL );
- // find process
- Process32First(hSnapShot, &pe);
- do
- {
- dwPID = pe.th32ProcessID;
- // 鉴于系统安全性的考虑
- // 对于PID小于100的系统进程
- // 不执行DLL注入操作
- if( dwPID < 100 )
- continue;
- if( nMode == INJECTION_MODE )
- InjectDll(dwPID, szDllPath);
- else
- EjectDll(dwPID, szDllPath);
- }
- while( Process32Next(hSnapShot, &pe) );
- CloseHandle(hSnapShot);
- return TRUE;
- }
- int _tmain(int argc, TCHAR* argv[])
- {
- int nMode = INJECTION_MODE;
- HMODULE hLib = NULL;
- PFN_SetProcName SetProcName = NULL;
- if( argc != 4 )
- {
- printf("\n Usage : HideProc.exe <-hide|-show> "\
- "<process name> <dll path>\n\n");
- return 1;
- }
- // change privilege
- SetPrivilege(SE_DEBUG_NAME, TRUE);
- // load library
- hLib = LoadLibrary(argv[3]);
- // set process name to hide
- SetProcName = (PFN_SetProcName)GetProcAddress(hLib, "SetProcName");
- SetProcName(argv[2]);
- // Inject(Eject) Dll to all process
- if( !_tcsicmp(argv[1], L"-show") )
- nMode = EJECTION_MODE;
- InjectAllProcess(nMode, argv[3]);
- // free library
- FreeLibrary(hLib);
- return 0;
- }
首先通过SetPrivilege函数调用AdjustTokenPrivileges提升权限,然后在InjectAllProcess中使用CreateToolhelp32Snapshot获取系统中运行的所有进程的列表,使用Process32First与Process32Next将获得的进程信息存放到PROCESSENTRY32结构体变量pe中,进而获取进程的PID。获取了进程的PID后,要根据所用的命令选项来选择调用InjectDll函数还是EjectDll函数。当某进程的PID小于100时,鉴于系统安全性的考虑,忽略对它的操作。
下面详细讲解Stealth.dll的源代码(stealth.cpp)。
首先看导出函数SetProcName。先创建名为.SHARE的共享内存节区,然后创建g_szProcName缓冲区,最后再由导出函数SetProcName将要隐藏的进程名称保存到g_szProcName中。
- // global variable (in sharing memory)
- #pragma comment(linker, "/SECTION:.SHARE,RWS")
- #pragma data_seg(".SHARE")
- TCHAR g_szProcName[MAX_PATH] = {0,};
- #pragma data_seg()
- // export function
- #ifdef __cplusplus
- extern "C" {
- #endif
- __declspec(dllexport) void SetProcName(LPCTSTR szProcName)
- {
- _tcscpy_s(g_szProcName, szProcName);
- }
- #ifdef __cplusplus
- }
- #endif
- BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
- {
- char szCurProc[MAX_PATH] = {0,};
- char *p = NULL;
- // #1. 异常处理
- // 若当前进程为HookProc.exe则终止,不进行钩取操作
- GetModuleFileNameA(NULL, szCurProc, MAX_PATH);
- p = strrchr(szCurProc, '\\');
- if( (p != NULL) && !_stricmp(p+1, "HideProc.exe") )
- return TRUE;
- switch( fdwReason )
- {
- // #2. API Hooking
- case DLL_PROCESS_ATTACH :
- hook_by_code(DEF_NTDLL, DEF_ZWQUERYSYSTEMINFORMATION,
- (PROC)NewZwQuerySystemInformation, g_pOrgBytes);
- break;
- // #3. API Unhooking
- case DLL_PROCESS_DETACH :
- unhook_by_code(DEF_NTDLL, DEF_ZWQUERYSYSTEMINFORMATION,
- g_pOrgBytes);
- break;
- }
- return TRUE;
- }
- BOOL hook_by_code(LPCSTR szDllName, LPCSTR szFuncName, PROC pfnNew, PBYTE pOrgBytes)
- {
- FARPROC pfnOrg;
- DWORD dwOldProtect, dwAddress;
- BYTE pBuf[5] = {0xE9, 0, };
- PBYTE pByte;
- // 获取要钩取的API地址
- pfnOrg = (FARPROC)GetProcAddress(GetModuleHandleA(szDllName), szFuncName);
- pByte = (PBYTE)pfnOrg;
- // 若已经被钩取则返回FALSE
- if( pByte[0] == 0xE9 )
- return FALSE;
- // 向内存添加写属性
- VirtualProtect((LPVOID)pfnOrg, 5, PAGE_EXECUTE_READWRITE, &dwOldProtect);
- // 备份原有代码(5字节)
- memcpy(pOrgBytes, pfnOrg, 5);
- // 计算JMP地址 (E9 XXXX)
- // => XXXX = pfnNew - pfnOrg - 5
- dwAddress = (DWORD)pfnNew - (DWORD)pfnOrg - 5;
- memcpy(&pBuf[1], &dwAddress, 4);
- // Hook:修改5 byte(JMP XXXX)
- memcpy(pfnOrg, pBuf, 5);
- // 恢复内存属性
- VirtualProtect((LPVOID)pfnOrg, 5, dwOldProtect, &dwOldProtect);
- return TRUE;
- }
- BOOL unhook_by_code(LPCSTR szDllName, LPCSTR szFuncName, PBYTE pOrgBytes)
- {
- FARPROC pFunc;
- DWORD dwOldProtect;
- PBYTE pByte;
- // 获取API地址
- pFunc = GetProcAddress(GetModuleHandleA(szDllName), szFuncName);
- pByte = (PBYTE)pFunc;
- // 若已经脱钩则返回FALSE
- if( pByte[0] != 0xE9 )
- return FALSE;
- // 向内存添加写属性
- VirtualProtect((LPVOID)pFunc, 5, PAGE_EXECUTE_READWRITE, &dwOldProtect);
- // Unhook
- memcpy(pFunc, pOrgBytes, 5);
- // 恢复内存属性
- VirtualProtect((LPVOID)pFunc, 5, dwOldProtect, &dwOldProtect);
- return TRUE;
- }
- NTSTATUS WINAPI NewZwQuerySystemInformation(
- SYSTEM_INFORMATION_CLASS SystemInformationClass,
- PVOID SystemInformation,
- ULONG SystemInformationLength,
- PULONG ReturnLength)
- {
- NTSTATUS status;
- FARPROC pFunc;
- PSYSTEM_PROCESS_INFORMATION pCur, pPrev;
- char szProcName[MAX_PATH] = {0,};
- // 开始前先脱钩
- unhook_by_code(DEF_NTDLL, DEF_ZWQUERYSYSTEMINFORMATION, g_pOrgBytes);
- // 调用原始API
- pFunc = GetProcAddress(GetModuleHandleA(DEF_NTDLL),
- DEF_ZWQUERYSYSTEMINFORMATION);
- status = ((PFZWQUERYSYSTEMINFORMATION)pFunc)
- (SystemInformationClass, SystemInformation,
- SystemInformationLength, ReturnLength);
- if( status != STATUS_SUCCESS )
- goto __NTQUERYSYSTEMINFORMATION_END;
- // 针对SystemProcessInformation类型操作
- if( SystemInformationClass == SystemProcessInformation )
- {
- // SYSTEM_PROCESS_INFORMATION类型转换
- // pCur是单向链表的头
- pCur = (PSYSTEM_PROCESS_INFORMATION)SystemInformation;
- while(TRUE)
- {
- // 比较进程名称
- // g_szProcName为要隐藏的进程名称
- // (=> SetProcName()设置)
- if(pCur->Reserved2[1] != NULL)
- {
- if(!_tcsicmp((PWSTR)pCur->Reserved2[1], g_szProcName))
- {
- // 从链表中删除隐藏进程的节点
- if(pCur->NextEntryOffset == 0)
- pPrev->NextEntryOffset = 0;
- else
- pPrev->NextEntryOffset += pCur->NextEntryOffset;
- }
- else
- pPrev = pCur;
- }
- if(pCur->NextEntryOffset == 0)
- break;
- // 链表的下一项
- pCur = (PSYSTEM_PROCESS_INFORMATION)
- ((ULONG)pCur + pCur->NextEntryOffset);
- }
- }
- __NTQUERYSYSTEMINFORMATION_END:
- // 函数终止前再次执行API钩取操作,为下次调用准备
- hook_by_code(DEF_NTDLL, DEF_ZWQUERYSYSTEMINFORMATION,
- (PROC)NewZwQuerySystemInformation, g_pOrgBytes);
- return status;
- }
- #include "windows.h"
- #include "tchar.h"
- #define STATUS_SUCCESS (0x00000000L)
- typedef LONG NTSTATUS;
- typedef enum _SYSTEM_INFORMATION_CLASS {
- SystemBasicInformation = 0,
- SystemPerformanceInformation = 2,
- SystemTimeOfDayInformation = 3,
- SystemProcessInformation = 5,
- SystemProcessorPerformanceInformation = 8,
- SystemInterruptInformation = 23,
- SystemExceptionInformation = 33,
- SystemRegistryQuotaInformation = 37,
- SystemLookasideInformation = 45
- } SYSTEM_INFORMATION_CLASS;
- typedef struct _SYSTEM_PROCESS_INFORMATION {
- ULONG NextEntryOffset;
- ULONG NumberOfThreads;
- BYTE Reserved1[48];
- PVOID Reserved2[3];
- HANDLE UniqueProcessId;
- PVOID Reserved3;
- ULONG HandleCount;
- BYTE Reserved4[4];
- PVOID Reserved5[11];
- SIZE_T PeakPagefileUsage;
- SIZE_T PrivatePageCount;
- LARGE_INTEGER Reserved6[6];
- } SYSTEM_PROCESS_INFORMATION, *PSYSTEM_PROCESS_INFORMATION;
- typedef NTSTATUS (WINAPI *PFZWQUERYSYSTEMINFORMATION)
- (SYSTEM_INFORMATION_CLASS SystemInformationClass,
- PVOID SystemInformation,
- ULONG SystemInformationLength,
- PULONG ReturnLength);
- #define DEF_NTDLL ("ntdll.dll")
- #define DEF_ZWQUERYSYSTEMINFORMATION ("ZwQuerySystemInformation")
- // global variable (in sharing memory)
- #pragma comment(linker, "/SECTION:.SHARE,RWS")
- #pragma data_seg(".SHARE")
- TCHAR g_szProcName[MAX_PATH] = {0,};
- #pragma data_seg()
- // global variable
- BYTE g_pOrgBytes[5] = {0,};
- BOOL hook_by_code(LPCSTR szDllName, LPCSTR szFuncName, PROC pfnNew, PBYTE pOrgBytes)
- {
- FARPROC pfnOrg;
- DWORD dwOldProtect, dwAddress;
- BYTE pBuf[5] = {0xE9, 0, };
- PBYTE pByte;
- // 获取要钩取的API地址
- pfnOrg = (FARPROC)GetProcAddress(GetModuleHandleA(szDllName), szFuncName);
- pByte = (PBYTE)pfnOrg;
- // 若已经被钩取则返回FALSE
- if( pByte[0] == 0xE9 )
- return FALSE;
- // 向内存添加写属性
- VirtualProtect((LPVOID)pfnOrg, 5, PAGE_EXECUTE_READWRITE, &dwOldProtect);
- // 备份原有代码(5字节)
- memcpy(pOrgBytes, pfnOrg, 5);
- // 计算JMP地址 (E9 XXXX)
- // => XXXX = pfnNew - pfnOrg - 5
- dwAddress = (DWORD)pfnNew - (DWORD)pfnOrg - 5;
- memcpy(&pBuf[1], &dwAddress, 4);
- // Hook
- memcpy(pfnOrg, pBuf, 5);
- // 恢复内存属性
- VirtualProtect((LPVOID)pfnOrg, 5, dwOldProtect, &dwOldProtect);
- return TRUE;
- }
- BOOL unhook_by_code(LPCSTR szDllName, LPCSTR szFuncName, PBYTE pOrgBytes)
- {
- FARPROC pFunc;
- DWORD dwOldProtect;
- PBYTE pByte;
- // 获取API地址
- pFunc = GetProcAddress(GetModuleHandleA(szDllName), szFuncName);
- pByte = (PBYTE)pFunc;
- // 若已经脱钩则返回FALSE
- if( pByte[0] != 0xE9 )
- return FALSE;
- // 向内存添加写属性
- VirtualProtect((LPVOID)pFunc, 5, PAGE_EXECUTE_READWRITE, &dwOldProtect);
- // Unhook
- memcpy(pFunc, pOrgBytes, 5);
- // 恢复内存属性
- VirtualProtect((LPVOID)pFunc, 5, dwOldProtect, &dwOldProtect);
- return TRUE;
- }
- NTSTATUS WINAPI NewZwQuerySystemInformation(
- SYSTEM_INFORMATION_CLASS SystemInformationClass,
- PVOID SystemInformation,
- ULONG SystemInformationLength,
- PULONG ReturnLength)
- {
- NTSTATUS status;
- FARPROC pFunc;
- PSYSTEM_PROCESS_INFORMATION pCur, pPrev;
- char szProcName[MAX_PATH] = {0,};
- // 开始前先脱钩
- unhook_by_code(DEF_NTDLL, DEF_ZWQUERYSYSTEMINFORMATION, g_pOrgBytes);
- // 调用原始API
- pFunc = GetProcAddress(GetModuleHandleA(DEF_NTDLL),
- DEF_ZWQUERYSYSTEMINFORMATION);
- status = ((PFZWQUERYSYSTEMINFORMATION)pFunc)
- (SystemInformationClass, SystemInformation,
- SystemInformationLength, ReturnLength);
- if( status != STATUS_SUCCESS )
- goto __NTQUERYSYSTEMINFORMATION_END;
- // 针对SystemProcessInformation类型操作
- if( SystemInformationClass == SystemProcessInformation )
- {
- // SYSTEM_PROCESS_INFORMATION类型转换
- // pCur是单向链表的头
- pCur = (PSYSTEM_PROCESS_INFORMATION)SystemInformation;
- while(TRUE)
- {
- // 比较进程名称
- // g_szProcName为要隐藏的进程名称
- // (=> SetProcName()设置)
- if(pCur->Reserved2[1] != NULL)
- {
- if(!_tcsicmp((PWSTR)pCur->Reserved2[1], g_szProcName))
- {
- // 从链表中删除隐藏进程的节点
- if(pCur->NextEntryOffset == 0)
- pPrev->NextEntryOffset = 0;
- else
- pPrev->NextEntryOffset += pCur->NextEntryOffset;
- }
- else
- pPrev = pCur;
- }
- if(pCur->NextEntryOffset == 0)
- break;
- // 链表的下一项
- pCur = (PSYSTEM_PROCESS_INFORMATION)
- ((ULONG)pCur + pCur->NextEntryOffset);
- }
- }
- __NTQUERYSYSTEMINFORMATION_END:
- // 函数终止前再次执行API钩取操作,为下次调用准备
- hook_by_code(DEF_NTDLL, DEF_ZWQUERYSYSTEMINFORMATION,
- (PROC)NewZwQuerySystemInformation, g_pOrgBytes);
- return status;
- }
- BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
- {
- char szCurProc[MAX_PATH] = {0,};
- char *p = NULL;
- // #1. 异常处理
- // 若当前进程为HookProc.exe则终止,不进行钩取操作
- GetModuleFileNameA(NULL, szCurProc, MAX_PATH);
- p = strrchr(szCurProc, '\\');
- if( (p != NULL) && !_stricmp(p+1, "HideProc.exe") )
- return TRUE;
- switch( fdwReason )
- {
- // #2. API Hooking
- case DLL_PROCESS_ATTACH :
- hook_by_code(DEF_NTDLL, DEF_ZWQUERYSYSTEMINFORMATION,
- (PROC)NewZwQuerySystemInformation, g_pOrgBytes);
- break;
- // #3. API Unhooking
- case DLL_PROCESS_DETACH :
- unhook_by_code(DEF_NTDLL, DEF_ZWQUERYSYSTEMINFORMATION,
- g_pOrgBytes);
- break;
- }
- return TRUE;
- }
- #ifdef __cplusplus
- extern "C" {
- #endif
- __declspec(dllexport) void SetProcName(LPCTSTR szProcName)
- {
- _tcscpy_s(g_szProcName, szProcName);
- }
- #ifdef __cplusplus
- }
- #endif