监控自身进程指定内存块是否被读写(防CE)

  • Post author:
  • Post category:其他


无意当中看到的一种监控读写的方法,写了个DEMO留档

// WsWatch.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <Psapi.h>
#pragma comment(lib, "psapi.lib")
#ifndef PAGE_SIZE
#define PAGE_SIZE 0x1000
#endif
#define NtCurrentProcess() ((HANDLE)-1)
#define PAGE_ALIGN(Va) ((PVOID)((ULONG_PTR)(Va) & ~(PAGE_SIZE - 1)))

#define INITIAL_RECORD_SIZE 1000

bool GetProcessDataFromThread(_In_ DWORD ThreadId, _Out_ DWORD& ProcessId, _Out_writes_z_(MAX_PATH) wchar_t ProcessPath[MAX_PATH])
{
	bool status = false;

	ProcessId = 0;
	ProcessPath[0] = NULL;
	HANDLE Thread = OpenThread(THREAD_QUERY_LIMITED_INFORMATION, FALSE, ThreadId);
	if (Thread)
	{
		ProcessId = GetProcessIdOfThread(Thread);
		if (ProcessId)
		{
			HANDLE Process = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, ProcessId);
			if (Process)
			{
				status = (GetModuleFileNameExW(Process, NULL, ProcessPath, MAX_PATH) != 0);
				CloseHandle(Process);
			}
		}
		CloseHandle(Thread);
	}
	return status;
}


int check_ce()
{
	int status = -1;

	PBYTE AllocatedBuffer = NULL;
	PPSAPI_WS_WATCH_INFORMATION_EX WatchInfoEx = NULL;

	const DWORD CurrentProcessId = GetCurrentProcessId();
	printf("[+] PID: %lu\n", CurrentProcessId);


#if defined(_M_IX86)
	// Can't run on Wow64 (32-bit on 64-bit OS).
	BOOL Wow64Process = FALSE;
	if (IsWow64Process(NtCurrentProcess(), &Wow64Process) && Wow64Process)
	{
		fprintf(stderr, "[-] ERROR: This process cannot be run under Wow64.\n");
		goto Cleanup;
	}
#endif

	// Initiate monitoring of the working set for this process.
	if (!InitializeProcessForWsWatch(NtCurrentProcess()))
	{
		fprintf(stderr, "[-] ERROR: Failed to initialize process for working set watch. InitializeProcessForWsWatch failed with error: %lu.\n", GetLastError());
		goto Cleanup;
	}
	AllocatedBuffer = (PBYTE)VirtualAlloc(NULL, PAGE_SIZE, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
	if (!AllocatedBuffer)
	{
		fprintf(stderr, "[-] ERROR: Failed to allocate %u bytes for page faulting test buffer.\n", PAGE_SIZE);
		goto Cleanup;
	}

	printf("[+] Allocated buffer at 0x%p.\n", AllocatedBuffer);

	DWORD WatchInfoSize = (sizeof(PSAPI_WS_WATCH_INFORMATION_EX) * INITIAL_RECORD_SIZE);
	WatchInfoEx = (PPSAPI_WS_WATCH_INFORMATION_EX)malloc(WatchInfoSize);
	if (!WatchInfoEx)
	{
		fprintf(stderr, "[-] ERROR: Failed to allocate %lu bytes.\n", WatchInfoSize);
		goto Cleanup;
	}

	while (TRUE)
	{
		memset(WatchInfoEx, 0, WatchInfoSize);

		if (!GetWsChangesEx(NtCurrentProcess(), WatchInfoEx, &WatchInfoSize))
		{
			DWORD ErrorCode = GetLastError();

			// This really isn't an error. This just means that no new pages
			// have been mapped into our process' VA since the last time
			// we called GetWsChangesEx.
			if (ErrorCode == ERROR_NO_MORE_ITEMS)
			{
				// Wait a little bit before trying again.
				Sleep(1);
				continue;
			}

			// Any other error code is bad.
			if (ErrorCode != ERROR_INSUFFICIENT_BUFFER)
			{
				fprintf(stderr, "[-] ERROR: GetWsChangesEx failed with error: %lu.\n", ErrorCode);
				goto Cleanup;
			}

			// If we get this far, we need to increase the buffer size. 
			WatchInfoSize *= 2;

			free(WatchInfoEx);
			WatchInfoEx = (PPSAPI_WS_WATCH_INFORMATION_EX)malloc(WatchInfoSize);

			if (!WatchInfoEx)
			{
				fprintf(stderr, "[-] ERROR: Failed to allocate %lu bytes.\n", WatchInfoSize);
				goto Cleanup;
			}

			continue;
		}

		bool bFound = false;
		for (size_t i = 0;; ++i)
		{
			PPSAPI_WS_WATCH_INFORMATION_EX info = &WatchInfoEx[i];


			if (info->BasicInfo.FaultingPc == NULL)
				break;

			PVOID FaultingPageVa = PAGE_ALIGN(info->BasicInfo.FaultingVa);
			if (FaultingPageVa == AllocatedBuffer)
			{
				printf("[+] 0x%p (0x%p) was mapped by 0x%p (TID: %lu).\n", FaultingPageVa, info->BasicInfo.FaultingVa, info->BasicInfo.FaultingPc, (DWORD)info->FaultingThreadId);

				DWORD ProcessId;
				wchar_t ProcessPath[MAX_PATH];

				if (GetProcessDataFromThread((DWORD)info->FaultingThreadId, ProcessId, ProcessPath))
					printf("\t--> %S (PID: %lu).\n", ProcessPath, ProcessId);


				bFound = true;
				break;
			}
		}

		if (bFound)
		{
			status = 1;
			break;
		}
	}

Cleanup:
	// 'free' the 'malloc's.
	if (WatchInfoEx)
	{
		free(WatchInfoEx);
		WatchInfoEx = NULL;
	}

	if (AllocatedBuffer)
	{
		VirtualFree(AllocatedBuffer, 0, MEM_RELEASE);
		AllocatedBuffer = NULL;
	}

	return status;
}

int main()
{
	printf("Base = %llX\r\n",(UINT64)GetModuleHandle("WsWatch.exe"));
	while (1) {
		if (check_ce() > 0) printf("Find CE\r\n");
		Sleep(100);
	}
    return 0;
}



版权声明:本文为yoie01原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。