实现原理:
修改进程环境块中的进程路径以及命令行信息,从而达到进程伪装的效果。所以,实现的关键在于进程环境块的获取。可以通过ntdll.dll中的导出函数NtQueryInformationProcess来获取指定进程的PEB地址。因为该程序进程可能与目标进程并不在同一个进程内。由于进程空间独立性的缘故,所以需要通过调用WIN32 API函数ReadProcessMemory和WriteProcessMemory来读写目标进程内存。
实现过程:
(1).打开指定进程,获取进程句柄
(2).从ntdll.dll中获取NtQueryInformationProcess函数的导出地址
(3).使用NtQueryInformationProcess函数获取指定的进程基本信息 PROCESS_BASIC_INFORMATION,并从中获取指定进程的PEB
(4).使用WriteProcessMemory修改PEB中的路径信息、命令行信息
注意:NtQueryInformationProcess函数没有关联导入库,所以只能动态获取
实现代码:
//************************************ // 函数名:CHideDlg::DisguiseProcess // 返回类型:BOOL // 功能: 修改指定PEB中的路径和命令行信息, 实现进程伪装 // 参数1:DWORD dwProcessId 需要伪装的程序的PID // 参数2:wchar_t *lpwszPath 伪装之后程序的路径 //************************************ BOOL CHideDlg::DisguiseProcess(DWORD dwProcessId, wchar_t *lpwszPath) { // 打开进程获取句柄 HANDLE hProcess = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId); if (NULL == hProcess) { MessageBox(_T("打开进程失败!")); return FALSE; } //定义函数指针变量 typedef_NtQueryInformationProcess NtQueryInformationProcess = NULL; PROCESS_BASIC_INFORMATION pbi = { 0 }; PEB peb = { 0 }; RTL_USER_PROCESS_PARAMETERS Param = { 0 }; USHORT usCmdLen = 0; USHORT usPathLen = 0; // 需要通过 LoadLibrary、GetProcessAddress 从 ntdll.dll 中获取地址 NtQueryInformationProcess = (typedef_NtQueryInformationProcess)::GetProcAddress( ::LoadLibrary(_T("ntdll.dll")), "NtQueryInformationProcess"); if (NULL == NtQueryInformationProcess) { MessageBox(_T("获取NtQueryInformationProcess函数地址失败!")); return FALSE; } // 获取指定进程的基本信息 NTSTATUS status = NtQueryInformationProcess(hProcess, ProcessBasicInformation, &pbi, sizeof(pbi), NULL); if (!NT_SUCCESS(status)) { MessageBox(_T("获取进程的基本信息失败!")); return FALSE; } // 获取指定进程基本信息结构中的PebBaseAddress //::ReadProcessMemory(hProcess, pbi.PebBaseAddress, &peb, sizeof(peb), NULL); // 获取指定进程环境块结构中的ProcessParameters, 注意指针指向的是指定进程空间 //::ReadProcessMemory(hProcess, peb.ProcessParameters, &Param, sizeof(Param), NULL); // 修改指定PEB中的路径信息, 注意指针指向的是指定进程空间 usPathLen = 2 + 2 * ::wcslen(lpwszPath); ::WriteProcessMemory(hProcess, &pbi.PebBaseAddress->ProcessParameters->ImagePathName.Buffer, &lpwszPath, sizeof(PWSTR), NULL); ::WriteProcessMemory(hProcess, &pbi.PebBaseAddress->ProcessParameters->ImagePathName.Length, &usPathLen, sizeof(usPathLen), NULL); ::WriteProcessMemory(hProcess, &pbi.PebBaseAddress->ProcessParameters->ImagePathName.MaximumLength, &usPathLen, sizeof(usPathLen), NULL); // 修改指定PEB中的命令行信息, 注意指针指向的是指定进程空间 //usCmdLen = 2 + 2 * ::wcslen(lpwszPath); ::WriteProcessMemory(hProcess, &pbi.PebBaseAddress->ProcessParameters->CommandLine.Buffer, &lpwszPath,sizeof(PWSTR), NULL); ::WriteProcessMemory(hProcess, &pbi.PebBaseAddress->ProcessParameters->CommandLine.Length, &usPathLen, sizeof(usPathLen), NULL); return TRUE; }