346 lines
10 KiB
Nim
346 lines
10 KiB
Nim
import winim/lean
|
|
import ptr_math
|
|
import strformat
|
|
import ../../common/utils
|
|
|
|
#[
|
|
References:
|
|
- https://github.com/frkngksl/NiCOFF/blob/main/BeaconFunctions.nim
|
|
- https://github.com/trustedsec/COFFLoader/blob/main/beacon_compatibility.c
|
|
- https://github.com/Cracked5pider/CoffeeLdr/blob/main/Source/BeaconApi.c
|
|
]#
|
|
|
|
const
|
|
CALLBACK_OUTPUT = 0x0
|
|
CALLBACK_OUTPUT_OEM = 0x1e
|
|
CALLBACK_ERROR = 0x0d
|
|
CALLBACK_OUTPUT_UTF8 = 0x20
|
|
DEFAULT_PROCESS = protect("rundll32.exe")
|
|
|
|
type
|
|
datap* {.bycopy,packed.} = object
|
|
original*: PCHAR
|
|
buffer*: PCHAR
|
|
length*: int
|
|
size*: int
|
|
|
|
formatp* {.bycopy,packed.} = object
|
|
original*: PCHAR
|
|
buffer*: PCHAR
|
|
length*: int
|
|
size*: int
|
|
|
|
# Reference: https://forum.nim-lang.org/t/7352
|
|
type va_list* {.importc: "va_list", header: "<stdarg.h>".} = object
|
|
proc va_start(format: va_list, args: PCHAR) {.stdcall, importc, header: "stdio.h"}
|
|
proc va_end(ap: va_list) {.stdcall, importc, header: "stdio.h"}
|
|
proc vprintf(format: cstring, args: va_list) {.stdcall, importc, header: "stdio.h"}
|
|
proc vsnprintf(buffer: cstring; size: int; fmt: cstring; args: va_list): int {.stdcall, importc, dynlib: "msvcrt".}
|
|
|
|
var beaconCompatibilityOutput: PCHAR = nil
|
|
var beaconCompatibilitySize: int = 0
|
|
var beaconCompatibilityOffset: int = 0
|
|
|
|
#[
|
|
Parsing
|
|
]#
|
|
proc BeaconDataParse(parser: ptr datap, buffer: PCHAR, size: int): void {.stdcall.} =
|
|
if cast[uint64](parser) == 0:
|
|
return
|
|
|
|
parser.original = buffer
|
|
parser.buffer = buffer
|
|
parser.length = size - 4
|
|
parser.size = size - 4
|
|
parser.buffer += 4
|
|
return
|
|
|
|
proc BeaconDataInt(parser: ptr datap): int {.stdcall.}=
|
|
if cast[uint64](parser) == 0:
|
|
return
|
|
|
|
var returnValue: int = 0
|
|
if parser.length < 4:
|
|
return returnValue
|
|
|
|
copyMem(addr returnValue, parser.buffer, 4)
|
|
parser.length -= 4
|
|
parser.buffer += 4
|
|
return returnValue
|
|
|
|
proc BeaconDataShort(parser: ptr datap): int16 {.stdcall.} =
|
|
if cast[uint64](parser) == 0:
|
|
return
|
|
|
|
var returnValue: int16 = 0
|
|
if parser.length < 2:
|
|
return returnValue
|
|
|
|
copyMem(addr returnValue, parser.buffer, 2)
|
|
parser.length -= 2
|
|
parser.buffer += 2
|
|
return returnValue
|
|
|
|
proc BeaconDataLength(parser: ptr datap): int {.stdcall.} =
|
|
if cast[uint64](parser) == 0:
|
|
return
|
|
|
|
return parser.length
|
|
|
|
proc BeaconDataExtract(parser: ptr datap, size: ptr int): PCHAR {.stdcall.} =
|
|
if cast[uint64](parser) == 0:
|
|
return
|
|
|
|
var
|
|
length: int32 = 0
|
|
outData: PCHAR = nil
|
|
|
|
# Length of prefixed binary blob
|
|
if parser.length < 4:
|
|
return NULL
|
|
copyMem(addr length, parser.buffer, 4)
|
|
parser.buffer += 4
|
|
|
|
outData = parser.buffer
|
|
if(outData == NULL):
|
|
return NULL
|
|
parser.length -= 4
|
|
parser.length -= length
|
|
parser.buffer += length
|
|
if(size != NULL and outData != NULL):
|
|
size[] = length
|
|
return outData
|
|
|
|
#[
|
|
Formatting
|
|
]#
|
|
proc BeaconFormatAlloc(format: ptr formatp, maxsz: int): void {.stdcall.} =
|
|
if format == NULL:
|
|
return
|
|
|
|
format.original = cast[PCHAR](alloc(maxsz))
|
|
zeroMem(format.original, maxsz)
|
|
format.buffer = format.original
|
|
format.length = 0
|
|
format.size = maxsz
|
|
|
|
proc BeaconFormatReset(format: ptr formatp): void {.stdcall.} =
|
|
if format == NULL:
|
|
return
|
|
|
|
zeroMem(format.original, format.size)
|
|
format.buffer = format.original
|
|
format.length = format.size
|
|
|
|
proc BeaconFormatFree(format: ptr formatp): void {.stdcall.} =
|
|
if format == NULL:
|
|
return
|
|
|
|
if cast[uint64](format.original) != 0:
|
|
dealloc(format.original)
|
|
format.original = NULL
|
|
|
|
format.buffer = NULL
|
|
format.length = 0
|
|
format.size = 0
|
|
|
|
proc BeaconFormatAppend(format: ptr formatp, text: PCHAR, len: int): void {.stdcall.} =
|
|
if format == NULL or text == NULL:
|
|
return
|
|
|
|
copyMem(format.buffer,text,len)
|
|
format.buffer += len
|
|
format.length += len
|
|
|
|
proc BeaconFormatPrintf(format: ptr formatp, fmt: PCHAR): void {.stdcall, varargs.} =
|
|
if format == NULL or fmt == NULL:
|
|
return
|
|
|
|
var args: va_list
|
|
var length: int = 0
|
|
|
|
va_start(args, fmt)
|
|
length = vsnprintf(NULL, 0, fmt, args)
|
|
va_end(args)
|
|
|
|
if format.length + length > format.size:
|
|
return
|
|
|
|
va_start(args, fmt)
|
|
discard vsnprintf(format.buffer, length, fmt, args)
|
|
va_end(args)
|
|
format.length += length
|
|
format.buffer += length
|
|
|
|
proc BeaconFormatToString(format: ptr formatp, size: ptr int): PCHAR {.stdcall.} =
|
|
if format == NULL or size == NULL:
|
|
return
|
|
|
|
size[] = format.length
|
|
return format.original
|
|
|
|
proc swapEndianess(indata: uint32): uint32 =
|
|
var testInt: uint32 = cast[uint32](0xaabbccdd)
|
|
var outInt: uint32 = indata
|
|
if(cast[PBYTE](addr testInt)[] == 0xdd):
|
|
cast[PBYTE](addr outInt)[] = (cast[PBYTE](addr indata)+3)[]
|
|
(cast[PBYTE](addr outInt)+1)[] = (cast[PBYTE](addr indata)+2)[]
|
|
(cast[PBYTE](addr outInt)+2)[] = (cast[PBYTE](addr indata)+1)[]
|
|
(cast[PBYTE](addr outInt)+3)[] = cast[PBYTE](addr indata)[]
|
|
return outint
|
|
|
|
proc BeaconFormatInt(format: ptr formatp, value: int): void =
|
|
if format == NULL:
|
|
return
|
|
|
|
var indata:uint32 = cast[uint32](value)
|
|
var outdata:uint32 = 0
|
|
if format.length + 4 > format.size:
|
|
return
|
|
outdata = swapEndianess(indata)
|
|
copyMem(format.buffer, addr outdata, 4)
|
|
format.length += 4
|
|
format.buffer += 4
|
|
|
|
#[
|
|
Output functions
|
|
]#
|
|
proc BeaconPrintf(typeArg: int, fmt: PCHAR):void{.stdcall, varargs.} =
|
|
if fmt == NULL:
|
|
return
|
|
|
|
var length: int = 0
|
|
var tempPtr: PCHAR = nil
|
|
var args: va_list
|
|
va_start(args, fmt)
|
|
vprintf(fmt, args)
|
|
va_end(args)
|
|
|
|
va_start(args, fmt)
|
|
length = vsnprintf(NULL, 0, fmt, args)
|
|
va_end(args)
|
|
tempPtr = cast[PCHAR](realloc(beaconCompatibilityOutput,beaconCompatibilitySize + length + 1))
|
|
if tempPtr == nil:
|
|
return
|
|
beaconCompatibilityOutput = tempPtr
|
|
zeroMem(beaconCompatibilityOutput + beaconCompatibilityOffset, length + 1)
|
|
va_start(args, fmt)
|
|
length = vsnprintf(beaconCompatibilityOutput+beaconCompatibilityOffset,length,fmt,args)
|
|
beaconCompatibilitySize += length
|
|
beaconCompatibilityOffset += length
|
|
va_end(args)
|
|
|
|
proc BeaconOutput(typeArg: int, data: PCHAR, len: int): void {.stdcall.} =
|
|
if data == NULL:
|
|
return
|
|
|
|
var tempPtr: PCHAR = nil
|
|
tempPtr = cast[PCHAR](realloc(beaconCompatibilityOutput,beaconCompatibilitySize + len + 1))
|
|
beaconCompatibilityOutput = tempPtr
|
|
if tempPtr == nil:
|
|
return
|
|
zeroMem(beaconCompatibilityOutput + beaconCompatibilityOffset, len + 1)
|
|
copyMem(beaconCompatibilityOutput + beaconCompatibilityOffset, data, len)
|
|
beaconCompatibilitySize += len
|
|
beaconCompatibilityOffset += len
|
|
|
|
#[
|
|
Token functions
|
|
]#
|
|
proc BeaconUseToken(token: HANDLE): BOOL {.stdcall.} =
|
|
SetThreadToken(NULL, token)
|
|
return TRUE
|
|
|
|
# void BeaconRevertToken();
|
|
proc BeaconRevertToken(): void {.stdcall.} =
|
|
RevertToSelf()
|
|
|
|
# BOOL BeaconIsAdmin();
|
|
proc BeaconIsAdmin(): BOOL {.stdcall.}=
|
|
# Not implemented
|
|
return FALSE
|
|
|
|
#[
|
|
Spawn+Inject Functions
|
|
]#
|
|
proc BeaconGetSpawnTo(x86: BOOL, buffer: PCHAR, length: int): void {.stdcall.} =
|
|
if buffer == NULL:
|
|
return
|
|
|
|
var tempBufferPath: string = ""
|
|
if cast[uint64](buffer) == 0:
|
|
return
|
|
|
|
if x86 == TRUE:
|
|
tempBufferPath = fmt"C:\Windows\SysWOW64\{DEFAULT_PROCESS}"
|
|
else:
|
|
tempBufferPath = fmt"C:\Windows\System32\{DEFAULT_PROCESS}"
|
|
|
|
if tempBufferPath.len > length:
|
|
return
|
|
copyMem(buffer, addr tempBufferPath[0], tempBufferPath.len)
|
|
|
|
proc BeaconSpawnTemporaryProcess(x86: BOOL, ignoreToken: BOOL, sInfo: ptr STARTUPINFOA, pInfo: ptr PROCESS_INFORMATION): BOOL {.stdcall.} =
|
|
var bSuccess: BOOL = FALSE
|
|
|
|
if x86 == TRUE:
|
|
bSuccess = CreateProcessA(NULL, fmt"C:\Windows\SysWOW64\{DEFAULT_PROCESS}", NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, NULL, sInfo, pInfo)
|
|
else:
|
|
bSuccess = CreateProcessA(NULL, fmt"C:\Windows\System32\{DEFAULT_PROCESS}", NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, NULL, sInfo, pInfo)
|
|
|
|
return bSuccess
|
|
|
|
proc BeaconInjectProcess(hProc: HANDLE, pid: int, payload: PCHAR, p_len: int, p_offset: int, arg: PCHAR, a_len: int): void {.stdcall.} =
|
|
# Not implemented
|
|
return
|
|
|
|
proc BeaconInjectTemporaryProcess(pInfo: ptr PROCESS_INFORMATION, payload: PCHAR, p_len: int, p_offset: int, arg: PCHAR, a_len: int): void {.stdcall.} =
|
|
# Not implemented
|
|
return
|
|
|
|
proc BeaconCleanupProcess(pInfo: ptr PROCESS_INFORMATION): void {.stdcall.} =
|
|
CloseHandle(pInfo.hThread)
|
|
CloseHandle(pInfo.hProcess)
|
|
|
|
#[
|
|
Utility Functions
|
|
]#
|
|
proc toWideChar(src: PCHAR, dst: PCHAR, max: int): BOOL {.stdcall.} =
|
|
# Not implemented
|
|
return FALSE
|
|
|
|
proc BeaconGetOutputData*(outSize: ptr int): PCHAR {.stdcall.} =
|
|
var outData: PCHAR = beaconCompatibilityOutput
|
|
|
|
if cast[uint64](outSize) != 0:
|
|
outsize[] = beaconCompatibilitySize
|
|
beaconCompatibilityOutput = NULL
|
|
beaconCompatibilitySize = 0
|
|
beaconCompatibilityOffset = 0
|
|
return outData
|
|
|
|
var beaconApiAddresses*: array[23, tuple[name: string, address: PVOID]] = [
|
|
(protect("BeaconDataParse"), BeaconDataParse),
|
|
(protect("BeaconDataInt"), BeaconDataInt),
|
|
(protect("BeaconDataShort"), BeaconDataShort),
|
|
(protect("BeaconDataLength"), BeaconDataLength),
|
|
(protect("BeaconDataExtract"), BeaconDataExtract),
|
|
(protect("BeaconFormatAlloc"), BeaconFormatAlloc),
|
|
(protect("BeaconFormatReset"), BeaconFormatReset),
|
|
(protect("BeaconFormatFree"), BeaconFormatFree),
|
|
(protect("BeaconFormatAppend"), BeaconFormatAppend),
|
|
(protect("BeaconFormatPrintf"), BeaconFormatPrintf),
|
|
(protect("BeaconFormatToString"), BeaconFormatToString),
|
|
(protect("BeaconFormatInt"), BeaconFormatInt),
|
|
(protect("BeaconPrintf"), BeaconPrintf),
|
|
(protect("BeaconOutput"), BeaconOutput),
|
|
(protect("BeaconUseToken"), BeaconUseToken),
|
|
(protect("BeaconRevertToken"), BeaconRevertToken),
|
|
(protect("BeaconIsAdmin"), BeaconIsAdmin),
|
|
(protect("BeaconGetSpawnTo"), BeaconGetSpawnTo),
|
|
(protect("BeaconSpawnTemporaryProcess"), BeaconSpawnTemporaryProcess),
|
|
(protect("BeaconInjectProcess"), BeaconInjectProcess),
|
|
(protect("BeaconInjectTemporaryProcess"), BeaconInjectTemporaryProcess),
|
|
(protect("BeaconCleanupProcess"), BeaconCleanupProcess),
|
|
(protect("toWideChar"), toWideChar)
|
|
] |