0

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?

woldgrep
  • 97
  • 2
  • 12
  • error in function `GetMemoryAllocationBaseAndRegionSize` - `BaseAddress` must be used instead `AllocationBase`. error in flags - must be `CFG_CALL_TARGET_CONVERT_EXPORT_SUPPRESSED_TO_VALID | CFG_CALL_TARGET_VALID`. error that you not check - are export supressed in process, before call – RbMm Jun 11 '21 at 13:19
  • @RbMm I think your selution worked. But now im getting error 5 access denied. But thats maybe because im trying to make a func in ntdll cfg valid – woldgrep Jun 11 '21 at 13:55
  • no, because export **not** supressed in process and you not check this – RbMm Jun 11 '21 at 13:56
  • @RbMm Could you please elaborate or rever to docs that talk about this because im not quite following you – woldgrep Jun 11 '21 at 14:03
  • what is unclear ? – RbMm Jun 11 '21 at 14:28

0 Answers0