OffensiveNim Documentation

repository·master·Indexed 25 days ago

https://github.com/byt3bl33d3r/offensivenim

An experimental project for developing implants and offensive security tools using the Nim programming language. It provides guidance on creating lightweight native payloads, calling Windows APIs via FFI, building Windows DLLs with DllMain, cross-compiling from non-Windows platforms using mingw-w64, and optimizing executable size using specific compiler flags.

Tokens
1K
Snippets
3
Records
6
Agent score
35%

What's inside OffensiveNim

  1. Optimize Nim executable size

    master

    To minimize the size of your compiled binaries (e.g., for shellcode or implants), use the following compiler flags:

    • -d:danger: Disables runtime checks.
    • -d:strip: Removes symbol information.
    • --opt:size: Optimizes for size.
    • --passc=-flto --passl=-flto: Enables Link Time Optimization (LTO) via the C compiler and linker.

    Example usage:

    nim c -d:danger -d:strip --opt:size --passc=-flto --passl=-flto source.nim
  2. Cross-compile Windows programs from *nix/MacOS

    master

    To cross-compile Windows executables on non-Windows platforms, ensure mingw-w64 is installed and use the -d=mingw flag during compilation.

    Example command for a 64-bit console application:

    nim c -d=mingw --app=console --cpu=amd64 source.nim
  3. Create Windows DLLs with DllMain

    master

    To create a Windows DLL in Nim, you must use the --nomain flag to prevent the compiler from creating a default entry point. You must manually define a DllMain function using stdcall, exportc, and dynlib pragmas, and you must call NimMain() inside DllMain to initialize Nim's garbage collector.

    Compilation Command:

    nim c -d=mingw --app=lib --nomain --cpu=amd64 mynim.dll

    Implementation Example:

    import winim/lean
    
    proc NimMain() {.cdecl, importc.}
    
    proc DllMain(hinstDLL: HINSTANCE, fdwReason: DWORD, lpvReserved: LPVOID) : BOOL {.stdcall, exportc, dynlib.}
    =
      NimMain()
      
      if fdwReason == DLL_PROCESS_ATTACH:
        MessageBox(0, "Hello, world !", "Nim is Powerful", 0)
    
      return true
  4. Install and Setup OffensiveNim Environment

    master

    To use the examples in this repository, you need to install the Nim compiler and the winim library. For cross-compiling Windows binaries from *nix/MacOS, you must also install the mingw-w64 toolset.

    1. Install Nim

    • MacOS: brew install nim
    • Linux: apt install nim
    • Windows: Use the official installer from the Nim website.

    2. Install Mingw (Required for cross-compilation)

    • MacOS: brew install mingw-w64
    • Linux: apt-get install mingw-w64

    3. Install Winim library

    nimble install winim

    4. Build Examples

    Navigate to the repository directory and run:

    make

    Compiled binaries and DLLs will be located in the bin/ directory.

  5. Common Nim Pitfalls and Troubleshooting

    master

    When developing with Nim for Windows/Offensive purposes, be aware of these specific behaviors:

    • Winim NULL values: When calling WinAPI via the winim library, use the NULL constant defined by winim instead of Nim's built-in nil.
    • File Handles: When opening files on Windows, use f.getOsFileHandle() instead of f.getFileHandle().
    • Compiler Argument Syntax: Nim does not support -arg=value or --arg=value. You must use the colon syntax: -arg:value or --arg:value.
    • Byte Array Initialization: When defining a byte array, you must explicitly identify the first element as a byte type.

    Correct Byte Array Syntax:

    var buf: array[5, byte] = [byte 0xfc, 0x48, 0x81, 0xe4, 0xf0, 0xff]
  6. Call Windows APIs via FFI

    master

    You can call Windows APIs directly using Nim's Foreign Function Interface (FFI). This is similar to P/Invoke in C#. You must define the types and use the appropriate pragmas like stdcall, dynlib, and importc.

    Example of calling MessageBoxA without external libraries:

    type
        HANDLE* = int
        HWND* = HANDLE
        UINT* = int32
        LPCSTR* = cstring
    
    proc MessageBox*(hWnd: HWND, lpText: LPCSTR, lpCaption: LPCSTR, uType: UINT): int32 
      {.discardable, stdcall, dynlib: "user32", importc: "MessageBoxA".}
    
    MessageBox(0, "Hello, world !", "Nim is Powerful", 0)