#include "sfcp.h" #include "sfcfiles.h" #include #define NOEXTAPI #include #undef DECLARE_API #ifdef __cplusplus #define CPPMOD extern "C" #else #define CPPMOD #endif #define DECLARE_API(s) \ CPPMOD VOID \ s( \ HANDLE hCurrentProcess, \ HANDLE hCurrentThread, \ DWORD_PTR dwCurrentPc, \ PWINDBG_EXTENSION_APIS lpExtensionApis, \ LPSTR lpArgumentString \ ) #define INIT_API() { \ ExtensionApis = *lpExtensionApis; \ ExtensionCurrentProcess = hCurrentProcess; \ } #define dprintf (ExtensionApis.lpOutputRoutine) #define GetExpression (ExtensionApis.lpGetExpressionRoutine) #define GetSymbol (ExtensionApis.lpGetSymbolRoutine) #define Disasm (ExtensionApis.lpDisasmRoutine) #define CheckControlC (ExtensionApis.lpCheckControlCRoutine) #define ReadMemory(a,b,c,d) \ ((ExtensionApis.nSize == sizeof(WINDBG_OLD_EXTENSION_APIS)) ? \ ReadProcessMemory( ExtensionCurrentProcess, (LPCVOID)(a), (b), (c), (d) ) \ : ExtensionApis.lpReadProcessMemoryRoutine( (ULONG_PTR)(a), (b), (c), ((DWORD *)d) )) #define WriteMemory(a,b,c,d) \ ((ExtensionApis.nSize == sizeof(WINDBG_OLD_EXTENSION_APIS)) ? \ WriteProcessMemory( ExtensionCurrentProcess, (LPVOID)(a), (LPVOID)(b), (c), (d) ) \ : ExtensionApis.lpWriteProcessMemoryRoutine( (ULONG_PTR)(a), (LPVOID)(b), (c), ((DWORD *)d) )) #define Ioctl (ExtensionApis.lpIoctlRoutine) WINDBG_EXTENSION_APIS ExtensionApis; HANDLE ExtensionCurrentProcess; PWSTR MultiByteToUnicode( IN PCSTR String, IN UINT Codepage ) /*++ Routine Description: Convert a string to unicode. Arguments: String - supplies string to be converted. Codepage - supplies codepage to be used for the conversion. Return Value: NULL if string could not be converted (out of memory or invalid cp) Caller can free buffer with MyFree(). --*/ { UINT BytesIn8BitString; UINT CharsInUnicodeString; PWSTR UnicodeString; BytesIn8BitString = lstrlenA(String) + 1; // // Allocate maximally sized buffer. // If every character is a single-byte character, // then the buffer needs to be twice the size // as the 8bit string. Otherwise it might be smaller, // as some characters are 2 bytes in their unicode and // 8bit representations. // UnicodeString = malloc(BytesIn8BitString * sizeof(WCHAR)); if(UnicodeString == NULL) { return(NULL); } // // Perform the conversion. // CharsInUnicodeString = MultiByteToWideChar( Codepage, MB_PRECOMPOSED, String, BytesIn8BitString, UnicodeString, BytesIn8BitString ); if(CharsInUnicodeString == 0) { free(UnicodeString); return(NULL); } return(UnicodeString); } void dump_SFC_REGISTRY_VALUE( PSFC_REGISTRY_VALUE srv, DWORD_PTR Addr ) { SIZE_T cb; WCHAR buf[512]; dprintf( "SFC_REGISTRY_VALUE at %p\n", Addr ); dprintf( "\tEntry.Flink = 0x%08x\n", srv->Entry.Flink ); dprintf( "\tEntry.Blink = 0x%08x\n", srv->Entry.Blink ); ReadMemory( srv->FileName.Buffer, buf, srv->FileName.Length+sizeof(WCHAR), &cb); dprintf( "\tFileName = %ws\n", buf ); ReadMemory( srv->DirName.Buffer, buf, srv->DirName.Length+sizeof(WCHAR), &cb); dprintf( "\tDirName = %ws\n", buf ); ReadMemory( srv->FullPathName.Buffer, buf, srv->FullPathName.Length+sizeof(WCHAR), &cb); dprintf( "\tFullPathName = %ws\n", buf ); ReadMemory( srv->InfName.Buffer, buf, srv->FileName.Length+sizeof(WCHAR), &cb); dprintf( "\tInfName = %ws\n", srv->InfName ); ReadMemory( srv->SourceFileName.Buffer, buf, srv->SourceFileName.Length+sizeof(WCHAR), &cb); dprintf( "\tSourceFileName = %ws\n", srv->SourceFileName ); dprintf( "\tDirHandle = 0x%08x\n", srv->DirHandle ); //dprintf( "\tFlags = 0x%08x\n", srv->IgnoreNextChange ); } void dump_IMAGE_VALIDATION_DATA( PIMAGE_VALIDATION_DATA ivd ) { dprintf( "DllVersion = 0x%I64x\n", ivd->DllVersion ); dprintf( "DllCheckSum = 0x%08x\n", ivd->DllCheckSum ); dprintf( "SignatureValid = %s\n", ivd->SignatureValid ? "true" : "false" ); dprintf( "FilePresent = %s\n", ivd->FilePresent ? "true" : "false" ); } void dump_COMPLETE_VALIDATION_DATA( PCOMPLETE_VALIDATION_DATA cvd ) { dprintf( "*Original* = 0x%08x\n", &cvd->Original ); dump_IMAGE_VALIDATION_DATA( &cvd->Original ); dprintf( "*Cache* = 0x%08x\n", &cvd->Cache ); dump_IMAGE_VALIDATION_DATA( &cvd->Cache ); dprintf( "*New* = 0x%08x\n", &cvd->New ); dump_IMAGE_VALIDATION_DATA( &cvd->New ); dprintf( "RestoreFromReal = %s\n", cvd->RestoreFromReal ? "true" : "false" ); dprintf( "RestoreFromCache = %s\n", cvd->RestoreFromCache ? "true" : "false" ); dprintf( "RestoreFromMedia = %s\n", cvd->RestoreFromMedia ? "true" : "false" ); dprintf( "NotifyUser = %s\n", cvd->NotifyUser ? "true" : "false" ); dprintf( "BadCacheEntry = %s\n", cvd->BadCacheEntry ? "true" : "false" ); } void dump_RESTORE_QUEUE( PRESTORE_QUEUE rq, DWORD_PTR Addr ) { dprintf( "RESTORE_QUEUE at %p\n", Addr ); dprintf( "FileQueue = %p\n", rq->FileQueue ); dprintf( "QueueCount = %d\n", rq->QueueCount ); dprintf( "RestoreInProgress = %s\n", rq->RestoreInProgress ? "true" : "false" ); dprintf( "RestoreComplete = %s\n", rq->RestoreComplete ? "true" : "false" ); dprintf( "RestoreStatus = %s\n", rq->RestoreStatus ? "true" : "false" ); dprintf( "LastErrorCode = %d (0x%08x)\n", rq->LastErrorCode, rq->LastErrorCode ); dprintf( "WorkerThreadHandle = %d\n", rq->WorkerThreadHandle ); } void dump_VALIDATION_REQUEST_DATA( PVALIDATION_REQUEST_DATA vrd, DWORD_PTR Addr ) { SIZE_T cb; SFC_REGISTRY_VALUE RegVal; dprintf( "**VALIDATION_REQUEST_DATA at address = 0x%p**\n", Addr ); #if DBG if (vrd->Signature != 0x69696969) { dprintf( "**** invalid queue entry, signature does not match\n" ); return; } #endif dprintf( "\tEntry.Flink = 0x%08x\n", vrd->Entry.Flink ); dprintf( "\tEntry.Blink = 0x%08x\n", vrd->Entry.Blink ); dprintf( "\tImageValData = 0x%08x\n", &vrd->ImageValData ); dump_COMPLETE_VALIDATION_DATA( &vrd->ImageValData ); dprintf( "\tRegVal = 0x%08x\n", vrd->RegVal ); ReadMemory( vrd->RegVal, &RegVal, sizeof(SFC_REGISTRY_VALUE), &cb); dump_SFC_REGISTRY_VALUE( &RegVal, (DWORD_PTR)vrd->RegVal ); dprintf( "\tChangeType = %d\n", vrd->ChangeType ); dprintf( "\tCopyCompleted = %s\n", vrd->CopyCompleted ? "true" : "false" ); dprintf( "\tWin32Error = %d (0x%08x)\n", vrd->Win32Error, vrd->Win32Error ); dprintf( "\tFlags = 0x%08x\n", vrd->Flags ); dprintf( "\tRetryCount = 0x%08x\n", vrd->RetryCount ); dprintf( "\tSyncOnly = %s\n", vrd->SyncOnly ? "true" : "false" ); } void dump_PROTECT_FILE_ENTRY( PPROTECT_FILE_ENTRY Entry, DWORD_PTR Addr ) { WCHAR SourceFileBuffer[MAX_PATH]; WCHAR DestFileBuffer[MAX_PATH]; WCHAR InfNameBuffer[MAX_PATH]; SIZE_T cb; if (Entry->SourceFileName) { ReadMemory( Entry->SourceFileName, SourceFileBuffer, sizeof(SourceFileBuffer), &cb); }else { SourceFileBuffer[0] = L'\0'; } if (Entry->FileName) { ReadMemory( Entry->FileName, DestFileBuffer, sizeof(DestFileBuffer), &cb); }else { DestFileBuffer[0] = L'\0'; } if (Entry->InfName) { ReadMemory( Entry->InfName, InfNameBuffer, sizeof(InfNameBuffer), &cb); }else { InfNameBuffer[0] = L'\0'; } dprintf( " PROTECT_FILE_ENTRY at %p\n", Addr ); dprintf( " \tSourceFileName = %S\n" , SourceFileBuffer[0] ? SourceFileBuffer : L"[Same as target name]" ); dprintf( " \tFileName = %S\n" , DestFileBuffer ); dprintf( " \tInfName = %S\n" , InfNameBuffer[0] ? InfNameBuffer : L"[None, default to layout.inf]" ); } BOOL DoesProtFileEntryMatch( PPROTECT_FILE_ENTRY Entry, DWORD_PTR Addr, PCWSTR FileName ) { WCHAR SourceFileBuffer[MAX_PATH]; WCHAR DestFileBuffer[MAX_PATH]; WCHAR InfNameBuffer[MAX_PATH]; DWORD count; PCWSTR p; SIZE_T cb; PCWSTR a[3] = { SourceFileBuffer, DestFileBuffer, InfNameBuffer } ; if (Entry->SourceFileName) { ReadMemory( Entry->SourceFileName, SourceFileBuffer, sizeof(SourceFileBuffer), &cb); }else { SourceFileBuffer[0] = L'\0'; } if (Entry->FileName) { ReadMemory( Entry->FileName, DestFileBuffer, sizeof(DestFileBuffer), &cb); }else { DestFileBuffer[0] = L'\0'; } if (Entry->InfName) { ReadMemory( Entry->InfName, InfNameBuffer, sizeof(InfNameBuffer), &cb); }else { InfNameBuffer[0] = L'\0'; } for (count = 0; count < 3; count++) { p = wcsrchr( a[count], L'\\' ); if (p) { p += 1; if (_wcsicmp(p, FileName)== 0) { return(TRUE); } } } return(FALSE); } BOOL DoesRegEntryMatch( PSFC_REGISTRY_VALUE Entry, DWORD_PTR Addr, PCWSTR FileName ) { WCHAR Buffer[MAX_PATH]; DWORD count; PCWSTR p; SIZE_T cb; PUNICODE_STRING a[5]; a[0] = &Entry->FileName; a[1] = &Entry->DirName; a[2] = &Entry->FullPathName; a[3] = &Entry->InfName; a[4] = &Entry->SourceFileName; for (count = 0; count < 5; count++) { if (a[count]->Buffer) { ReadMemory( a[count]->Buffer, Buffer, sizeof(Buffer), &cb); } p = wcsrchr( Buffer, L'\\' ); if (p) { p += 1; } else { p = Buffer; } if (_wcsicmp(p, FileName)== 0) { return(TRUE); } } return(FALSE); } DECLARE_API( help ) { INIT_API(); dprintf( "WFP debugger extension commands:\n" ); dprintf( "dumpq - dump validation queue\n" ); dprintf( "dumpsettings - dump global WFP settings\n" ); dprintf( "isprotfile [filename] - search for a particular protected file in the list\n" ); dprintf( "isprotfile [list address] [list count address] [filename] - search for a particular protected file in the list\n" ); dprintf( "protfile - list all protected files in list\n" ); dprintf( "protfile - [list address] [list count address] list all protected files in list\n" ); } DECLARE_API( dumpq ) { DWORD_PTR addr; SIZE_T cb; LIST_ENTRY Next; VALIDATION_REQUEST_DATA vrd; INIT_API(); addr = GetExpression( "SfcErrorQueue" ); if (!addr) { dprintf("couldn't get address"); return; } dprintf( "SfcErrorQueue address=0x%p\n", addr ); ReadMemory( addr, &Next, sizeof(Next), &cb); if (Next.Flink == (PVOID)addr) { dprintf( "queue is empty\n" ); return; } do { ReadMemory( Next.Flink, &vrd, sizeof(VALIDATION_REQUEST_DATA), &cb); dump_VALIDATION_REQUEST_DATA( &vrd, (DWORD_PTR)Next.Flink ); Next.Flink = vrd.Entry.Flink; if (Next.Flink != (PVOID)addr) { dprintf( "\n******************************************\n\n" ); } if (CheckControlC() ) { dprintf( "\nInterrupted\n\n" ); break; } } while (Next.Flink != (PVOID)addr); } DECLARE_API( dumpsettings ) { DWORD_PTR addr; SIZE_T cb; DWORD val; INIT_API(); addr = GetExpression( "SFCDisable" ); if (!addr) { dprintf("couldn't get address"); return; } ReadMemory( addr, &val, sizeof(DWORD), &cb); dprintf( "SFCDisable = %d\n", val ); } DECLARE_API( dumpregval ) { DWORD_PTR addr; SIZE_T cb; SFC_REGISTRY_VALUE regval; INIT_API(); while (*lpArgumentString == ' ') { lpArgumentString++; } if (*lpArgumentString) { addr = GetExpression( lpArgumentString ); } else { dprintf("bogus usage\n"); return; } if (!addr) { dprintf("couldn't get address"); return; } ReadMemory( addr, ®val, sizeof(SFC_REGISTRY_VALUE), &cb); dump_SFC_REGISTRY_VALUE( ®val, (DWORD_PTR)addr ); return; } DECLARE_API( dumprq ) { DWORD_PTR addr; SIZE_T cb; RESTORE_QUEUE rq; INIT_API(); while (*lpArgumentString == ' ') { lpArgumentString++; } if (*lpArgumentString) { addr = GetExpression( lpArgumentString ); } else { dprintf("bogus usage\n"); return; } if (!addr) { dprintf("couldn't get address"); return; } ReadMemory( addr, &rq, sizeof(RESTORE_QUEUE), &cb); dump_RESTORE_QUEUE( &rq, addr ); return; } DECLARE_API( dumpvrd ) { DWORD_PTR addr; SIZE_T cb; VALIDATION_REQUEST_DATA vrd; INIT_API(); while (*lpArgumentString == ' ') { lpArgumentString++; } if (*lpArgumentString) { addr = GetExpression( lpArgumentString ); } else { dprintf("bogus usage\n"); return; } if (!addr) { dprintf("couldn't get address"); return; } ReadMemory( addr, &vrd, sizeof(VALIDATION_REQUEST_DATA), &cb); dump_VALIDATION_REQUEST_DATA( &vrd, addr ); return; } DECLARE_API( protfile ) { DWORD_PTR addrNext, addrTotal; SIZE_T cb; PROTECT_FILE_ENTRY Next; ULONG Total; ULONG Current; INIT_API(); while (*lpArgumentString == ' ') { lpArgumentString++; } if (*lpArgumentString) { addrNext = GetExpression( lpArgumentString ); while (*lpArgumentString && (*lpArgumentString != ' ') ) { lpArgumentString++; } while (*lpArgumentString == ' ') { lpArgumentString++; } if (*lpArgumentString) { addrTotal = GetExpression( lpArgumentString ); } else { dprintf("bogus usage\n"); return; } } else { addrNext = GetExpression( "sfc!Tier2Files" ); addrTotal = GetExpression( "sfc!CountTier2Files" ); } if (!addrTotal || !addrNext) { dprintf("couldn't get address"); return; } ReadMemory( addrNext, &Next, sizeof(PROTECT_FILE_ENTRY), &cb); ReadMemory( addrTotal, &Total, sizeof(ULONG), &cb); dprintf( "Tier2Files: address=0x%p Total=%d\n", addrNext, Total ); Current = 0; while (Current < Total) { dump_PROTECT_FILE_ENTRY( &Next, addrNext+(Current*sizeof(PROTECT_FILE_ENTRY)) ); ReadMemory( addrNext+(Current*sizeof(PROTECT_FILE_ENTRY)), &Next, sizeof(PROTECT_FILE_ENTRY), &cb); Current += 1; if ( CheckControlC() ) { dprintf( "\nInterrupted\n\n" ); break; } } } DECLARE_API( isprotfile ) { DWORD_PTR addrNext, addrTotal; PCSTR FileName; SIZE_T cb; PROTECT_FILE_ENTRY Next; ULONG Total; ULONG Current; BOOL FoundMatch = FALSE; PCWSTR FileNameW; INIT_API(); while (*lpArgumentString == ' ') { lpArgumentString++; } if (*lpArgumentString) { FileName = lpArgumentString; addrNext = GetExpression( lpArgumentString ); while (*lpArgumentString && (*lpArgumentString != ' ') ) { lpArgumentString++; } while (*lpArgumentString == ' ') { lpArgumentString++; } if (*lpArgumentString) { addrTotal = GetExpression( lpArgumentString ); } else { addrNext = GetExpression( "sfc!Tier2Files" ); addrTotal = GetExpression( "sfc!CountTier2Files" ); goto doit; } while (*lpArgumentString && (*lpArgumentString != ' ') ) { lpArgumentString++; } while (*lpArgumentString == ' ') { lpArgumentString++; } if (*lpArgumentString) { FileName = lpArgumentString; } else { dprintf("bogus usage\n"); return; } } else { dprintf("bogus usage\n"); return; } doit: if (!addrTotal || !addrNext) { dprintf("couldn't get address"); return; } ReadMemory( addrNext, &Next, sizeof(PROTECT_FILE_ENTRY), &cb); ReadMemory( addrTotal, &Total, sizeof(ULONG), &cb); FileNameW = MultiByteToUnicode( FileName, CP_ACP ); if (!FileNameW) { dprintf("Error: couldn't convert filename to unicode string\n"); return; } Current = 0; while (Current < Total) { if (DoesProtFileEntryMatch( &Next, addrNext+(Current*sizeof(PROTECT_FILE_ENTRY)),FileNameW )) { dump_PROTECT_FILE_ENTRY( &Next, addrNext+(Current*sizeof(PROTECT_FILE_ENTRY)) ); FoundMatch = TRUE; } ReadMemory( addrNext+(Current*sizeof(PROTECT_FILE_ENTRY)), &Next, sizeof(PROTECT_FILE_ENTRY), &cb); Current += 1; if ( CheckControlC() ) { dprintf( "\nInterrupted\n\n" ); break; } } if (!FoundMatch) { dprintf( "Couldn't find %s in list\n", FileName ); } free((PVOID)FileNameW); } DECLARE_API( regvals ) { DWORD_PTR addrNext, addrTotal; SIZE_T cb; SFC_REGISTRY_VALUE Next; ULONG Total; ULONG Current; INIT_API(); addrNext = GetExpression( "sfc!SfcProtectedDllsList" ); addrTotal = GetExpression( "sfc!SfcProtectedDllCount" ); if (!addrNext || ! addrTotal) { dprintf("Error: couldn't resolve sfc!SfcProtectedDllsList and sfc!SfcProtectedDllCount\n"); return; } ReadMemory( addrNext, &Next, sizeof(PROTECT_FILE_ENTRY), &cb); ReadMemory( addrTotal, &Total, sizeof(ULONG), &cb); dprintf( "SfcProtectedDllsList: address=0x%p Total=%d\n", addrNext, Total ); Current = 0; while (Current < Total) { dump_SFC_REGISTRY_VALUE( &Next, addrNext+(Current*sizeof(PROTECT_FILE_ENTRY)) ); ReadMemory( addrNext+(Current*sizeof(SFC_REGISTRY_VALUE)), &Next, sizeof(SFC_REGISTRY_VALUE), &cb); Current += 1; if ( CheckControlC() ) { dprintf( "\nInterrupted\n\n" ); break; } } } DECLARE_API( getregval ) { DWORD_PTR addrNext, addrTotal; PCSTR FileName; SIZE_T cb; SFC_REGISTRY_VALUE Next; ULONG Total; ULONG Current; BOOL FoundMatch = FALSE; PCWSTR FileNameW; INIT_API(); while (*lpArgumentString == ' ') { lpArgumentString++; } if (*lpArgumentString) { FileName = lpArgumentString; } else { dprintf("bogus usage\n"); return; } addrNext = GetExpression( "sfc!SfcProtectedDllsList" ); addrTotal = GetExpression( "sfc!SfcProtectedDllCount" ); if (!addrNext || ! addrTotal) { dprintf("Error: couldn't resolve sfc!SfcProtectedDllsList and sfc!SfcProtectedDllCount\n"); return; } ReadMemory( addrNext, &Next, sizeof(PROTECT_FILE_ENTRY), &cb); ReadMemory( addrTotal, &Total, sizeof(ULONG), &cb); FileNameW = MultiByteToUnicode( FileName, CP_ACP ); if (!FileNameW) { dprintf("Error: couldn't convert filename to unicode string\n"); return; } Current = 0; while (Current < Total) { if (DoesRegEntryMatch( &Next, addrNext+(Current*sizeof(SFC_REGISTRY_VALUE)),FileNameW )) { dump_SFC_REGISTRY_VALUE( &Next, addrNext+(Current*sizeof(PROTECT_FILE_ENTRY)) ); FoundMatch = TRUE; } ReadMemory( addrNext+(Current*sizeof(SFC_REGISTRY_VALUE)), &Next, sizeof(SFC_REGISTRY_VALUE), &cb); Current += 1; if ( CheckControlC() ) { dprintf( "\nInterrupted\n\n" ); break; } } if (!FoundMatch) { dprintf( "Couldn't find %s in list\n", FileName ); } free((PVOID)FileNameW); }