Im trying to use the control flow guard api to set a area of memory to be execution valid.
I used these examples for reverence material:
https://github.com/BreakingMalwareResearch/CFGExceptions/blob/master/CFGExceptions/main.cpp
https://github.com/trailofbits/cfg-showcase/blob/master/cfg_valid_targets.cpp#L111
Here is my code:
#include <stdio.h>
#include <Windows.h>
#include <psapi.h>
#include "cfgTest.h"
BOOL GetMemoryAllocationBaseAndRegionSize(PVOID, PVOID*, PSIZE_T);
INT main() {
HANDLE hProcess;
NTSTATUS ntStatus = ERROR_SUCCESS;
STARTUPINFOA startupInfo;
PROCESS_INFORMATION processInformation = { 0 };
CFG_CALL_TARGET_INFO cfgCallTargetInfoList[1];
DWORD dwPid = 0;
SIZE_T stRegionSize = NULL;
PVOID pvAllocationBase = NULL;
// Function pointers
SETPROCESSVALIDCALLTARGETS pSetProcessValidCallTargets = NULL;
PVOID pvAddressToAddCfgExceptionTo = NULL;
//
// Get address of SetProcessValidCallTargets
//
CONST HMODULE hNtdll = LoadLibraryW(L"ntdll.dll");
CONST HMODULE hKernelbase = LoadLibraryW(L"Kernelbase.dll");
if (hKernelbase && hNtdll) {
pSetProcessValidCallTargets = (SETPROCESSVALIDCALLTARGETS)GetProcAddress(hKernelbase, "SetProcessValidCallTargets");
pvAddressToAddCfgExceptionTo = GetProcAddress(hNtdll, "NtSetContextThread");
}
else {
return ERROR_MOD_NOT_FOUND;
}
FreeLibrary(hNtdll);
FreeLibrary(hKernelbase);
// Get memory allocation base and region size by calling VirtualProtect.
if (GetMemoryAllocationBaseAndRegionSize(pvAddressToAddCfgExceptionTo, &pvAllocationBase, &stRegionSize) == FALSE) {
ntStatus = ERROR_UNHANDLED_ERROR;
goto lblCleanup;
}
//
// Add cfg exception
//
cfgCallTargetInfoList[0].Flags = CFG_CALL_TARGET_VALID;
cfgCallTargetInfoList[0].Offset = (ULONG_PTR)pvAddressToAddCfgExceptionTo - (ULONG_PTR)pvAllocationBase;;
if (pSetProcessValidCallTargets(GetCurrentProcess(), pvAllocationBase, stRegionSize, 1, cfgCallTargetInfoList) == FALSE) {
printf("%d", GetLastError());
ntStatus = ERROR_UNHANDLED_ERROR;
goto lblCleanup;
}
lblCleanup:
if (processInformation.hProcess) {
CloseHandle(processInformation.hProcess);
}
if (processInformation.hThread) {
CloseHandle(processInformation.hThread);
}
return ntStatus;
}
BOOL GetMemoryAllocationBaseAndRegionSize(PVOID pvAddress, PVOID* ppvAllocationBase, PSIZE_T pstRegionSize) {
SIZE_T stErr = 0;
MEMORY_BASIC_INFORMATION tMemoryBasicInformation = { 0 };
stErr = VirtualQuery(pvAddress, &tMemoryBasicInformation, sizeof(tMemoryBasicInformation));
if (0 == stErr) {
return FALSE;
}
*ppvAllocationBase = tMemoryBasicInformation.AllocationBase;
*pstRegionSize = tMemoryBasicInformation.RegionSize;
return TRUE;
}
#pragma once
typedef enum _VIRTUAL_MEMORY_INFORMATION_CLASS
{
VmPrefetchInformation,
VmPagePriorityInformation,
VmCfgCallTargetInformation
} VIRTUAL_MEMORY_INFORMATION_CLASS;
typedef struct _MEMORY_RANGE_ENTRY
{
PVOID VirtualAddress;
SIZE_T NumberOfBytes;
} MEMORY_RANGE_ENTRY, * PMEMORY_RANGE_ENTRY;
typedef struct _VM_INFORMATION
{
DWORD dwNumberOfOffsets;
DWORD dwMustBeZero;
PDWORD pdwOutput;
PCFG_CALL_TARGET_INFO ptOffsets;
} VM_INFORMATION, * PVM_INFORMATION;
typedef NTSTATUS(NTAPI* NTSETINFORMATIONVIRTUALMEMORY)(
HANDLE hProcess,
VIRTUAL_MEMORY_INFORMATION_CLASS VmInformationClass,
ULONG_PTR NumberOfEntries,
PMEMORY_RANGE_ENTRY VirtualAddresses,
PVOID VmInformation,
ULONG VmInformationLength
);
typedef BOOL(WINAPI* SETPROCESSVALIDCALLTARGETS)(
HANDLE hProcess,
PVOID VirtualAddress,
SIZE_T RegionSize,
ULONG NumberOfOffsets,
PCFG_CALL_TARGET_INFO OffsetInformation
);
#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
My problem is SetProcessValidCallTargets returns FALSE and GetLastError() tells me its 87 which means an invalid parameter has been passed. But i have no idea what is going wrong. Could anyone see whats going on?