-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcfg_bypass.h
More file actions
107 lines (98 loc) · 4.4 KB
/
cfg_bypass.h
File metadata and controls
107 lines (98 loc) · 4.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
#pragma once
// ============================================================================
// cfg_bypass.h - Control Flow Guard (CFG) whitelisting for injected DLL
//
// Problem:
// Roblox uses Hyperion anti-cheat which REPLACES the standard Windows CFG
// dispatch function with its own bitmap-based validator. When our DLL is
// manually mapped, its code pages are NOT in either the Windows CFG bitmap
// or Hyperion's custom bitmap. Any indirect call TO our DLL's code will
// trigger a CFG violation. Hyperion logs violations (likely leading to bans)
// but still dispatches the call.
//
// Solution (two-pronged):
// 1. Windows CFG: Use SetProcessValidCallTargets / NtSetInformationVirtualMemory
// to register our DLL's pages as valid call targets in the kernel bitmap.
//
// 2. Hyperion CFG: Directly patch Hyperion's custom bitmap to set the valid
// bits for each page of our DLL.
//
// Hyperion's CFG dispatch algorithm (at GuardCFDispatchFunctionPointer):
// bitmap_base = *(QWORD*)(rip_relative_addr);
// byte_index = target_address >> 15;
// bit_index = (target_address >> 12) & 7;
// valid = bitmap_base[byte_index] & (1 << bit_index);
// => Each bit covers one 4KB page. Each byte covers 8 pages (32KB).
// => The bitmap is sparsely committed (only pages for loaded code exist).
//
// Architecture:
// The injector calls WhitelistCfgRegion() from its own process, using the
// target process handle and ReadProcessMemory/WriteProcessMemory to
// manipulate the target's CFG structures.
// ============================================================================
#include "common.h"
#include "pe_image.h"
// ============================================================================
// NtSetInformationVirtualMemory types
// CFG_CALL_TARGET_INFO is in winnt.h (SDK 10+).
// MEMORY_RANGE_ENTRY may or may not be visible depending on include order.
// We guard our definitions to avoid redefinition errors.
// ============================================================================
#ifndef _CFG_BYPASS_MEMORY_RANGE_ENTRY_DEFINED
#define _CFG_BYPASS_MEMORY_RANGE_ENTRY_DEFINED
typedef struct _CFG_MEMORY_RANGE_ENTRY {
PVOID VirtualAddress;
SIZE_T NumberOfBytes;
} CFG_MEMORY_RANGE_ENTRY;
#endif
// VM_INFORMATION structure for VmCfgCallTargetInformation (class 2)
typedef struct _CFG_CALL_TARGET_LIST_INFORMATION {
ULONG NumberOfEntries;
ULONG Reserved;
PULONG NumberOfEntriesProcessed;
PCFG_CALL_TARGET_INFO CallTargetInfo;
PVOID Section; // Optional (for XFG)
ULONGLONG FileOffset; // Optional
} CFG_CALL_TARGET_LIST_INFORMATION, *PCFG_CALL_TARGET_LIST_INFORMATION;
// NtSetInformationVirtualMemory - for programmatic CFG whitelisting
typedef NTSTATUS(NTAPI* fnNtSetInformationVirtualMemory)(
HANDLE ProcessHandle,
ULONG VmInformationClass, // 2 = VmCfgCallTargetInformation
ULONG_PTR NumberOfEntries,
CFG_MEMORY_RANGE_ENTRY* VirtualAddresses,
PVOID VmInformation,
ULONG VmInformationLength
);
// NtReadVirtualMemory - for reading target process memory
typedef NTSTATUS(NTAPI* fnNtReadVirtualMemory)(
HANDLE ProcessHandle,
PVOID BaseAddress,
PVOID Buffer,
SIZE_T BufferSize,
PSIZE_T NumberOfBytesRead
);
// NtWriteVirtualMemory - for writing target process memory
typedef NTSTATUS(NTAPI* fnNtWriteVirtualMemory)(
HANDLE ProcessHandle,
PVOID BaseAddress,
PVOID Buffer,
SIZE_T BufferSize,
PSIZE_T NumberOfBytesWritten
);
// ============================================================================
// Main API
// ============================================================================
// Whitelist a mapped DLL's pages in both the Windows kernel CFG bitmap
// and Hyperion's custom CFG bitmap.
//
// Must be called AFTER mapping the DLL (steps 8-11) but BEFORE executing
// any code in the target (step 12 shellcode).
//
// Parameters:
// process_handle - Handle to the target process (PROCESS_ALL_ACCESS)
// dll_base - Base address where the DLL is mapped in the target
// dll_size - Total size of the mapped DLL (SizeOfImage)
// image - Parsed PE image (for section info, optional - can pass nullptr sections)
//
// Returns true if at least one method succeeded.
bool WhitelistCfgRegion(HANDLE process_handle, void* dll_base, SIZE_T dll_size, PeImage* image = nullptr);