Strings Utility In PowerShell

Sometimes I’m working in environments where I can’t copy in any tools for troubleshooting and sometimes simply analyzing the strings in an .EXE gives many useful clues to how it works. Here is a simple version of strings utility that only relies on PowerShell.

The script: https://github.com/chentiangemalc/PowerShellScripts/blob/master/Extract-Strings.ps1

 <# .SYNOPSIS Extracts strings from a file. .DESCRIPTION Extracts western printable character strings from a binary file, including ASCII strings and UTF16 strings of a minimum length. .PARAMETER Path Specifies the path to the file from which strings will be extracted. .PARAMETER MinStringLength Specifies the minimum length of strings to be extracted. The default value is 5. .PARAMETER HideAsciiStrings Specifies whether to hide ASCII strings. By default, ASCII strings are shown. .PARAMETER HideUnicodeStrings Specifies whether to hide Unicode strings. By default, Unicode strings are shown. .EXAMPLE Extract-Strings -Path "C:\Files\sample.exe" Extracts strings from the file "c:\Files\Sample.exe". Extract-Strings -Path "C:\Files\sample.exe" -HideUnicodeStrings .INPUTS None. .OUTPUTS Extracted strings are written to the pipeline. .NOTES Version: 1.0 Author: chentiangemalc #> [CmdletBinding()] param ( [Parameter(Mandatory=$true)] [ValidateScript({Test-Path $_ -PathType 'Leaf'})] [string]$Path, [int]$MinStringLength = 5, [switch]$HideAsciiStrings, [switch]$HideUnicodeStrings ) $bytes = [System.IO.File]::ReadAllBytes($Path) $currentASCIIstring = [System.Text.StringBuilder]::new() $currentUNICODEstring = [System.Text.StringBuilder]::new() for ($i = 0; $i -lt $bytes.Length; $i++) { if ($i + 1 -lt $bytes.Length) { if (($bytes[$i] -ge 0x20 -and $bytes[$i] -le 0x7E -or $bytes[$i] -eq 0x0D -or $bytes[$i] -eq 0x0A) -and $bytes[$i + 1] -eq 0x00) { [void]$currentUNICODEstring.Append([char]$bytes[$i]) } elseif ($bytes[$i] -eq 0x00 -and $bytes[$i + 1] -eq 0x00) { if ($currentUNICODEstring.Length -ge $minStringLength) { if (!$HideUnicodeStrings) { $currentUNICODEstring.ToString() } } [void]$currentUNICODEstring.Clear() } } if ($bytes[$i] -ge 0x20 -and $bytes[$i] -le 0x7E -or $bytes[$i] -eq 0x0D -or $bytes[$i] -eq 0x0A) { [void]$currentASCIIstring.Append([char]$bytes[$i]) } elseif ($bytes[$i] -eq 0) { if ($currentASCIIstring.Length -ge $minStringLength) { if (!$HideAsciiStrings) { $currentASCIIstring.ToString() } } [void]$currentASCIIstring.Clear() } else { [void]$currentASCIIstring.Clear() [void]$currentUNICODEstring.Clear() } } 
Posted inUncategorized|Leave a comment

Resolve an API Set Function Name to On Disk Module and Function or Offset

Here is a script I wrote experimenting with resolving API Set function calls to on disk module/function/offset.

 <# .SYNOPSIS This script resolves an API set and API name to a specific module and function name. .DESCRIPTION This script uses the NativeMethods class to call Windows API functions for resolving a given API set and API name to the actual module and function name they correspond to. .PARAMETER ApiSet The API set string to be resolved. For example: "api-ms-win-devices-query-l1-1-0". .PARAMETER Api The API name string to be resolved. For example: "DevGetObjects". .PARAMETER ShowOffset Will show the offset of function instead of function name. Use if symbols don't resolve. .EXAMPLE .\Resolve-ApiSet.ps1 -ApiSet "api-ms-win-devices-query-l1-1-0" -Api "DevGetObjects" This command will resolve the given ApiSet and ApiName to their corresponding module and function name. .\Resolve-ApiSet.ps1 -ApiSet "api-ms-win-devices-query-l1-1-0" -Api "DevGetObjects" -ShowOffSet This command will resolve the given ApiSet and ApiName to their corresponding module and offset (based on the image base address on disk) .NOTES Run as 32-bit PowerShell for 32-bit modules 64-bit PowerShell for 64-bit modules. If names are not resolving you may need to configure Microsoft Symbol Server or place name of your desired Symbol server in 2nd param to SymInitialize #> param( [Parameter(Mandatory=$true)] [string]$ApiSet, [Parameter(Mandatory=$true)] [string]$Api, [switch]$ShowOffset ) Add-Type -TypeDefinition @' using System; using System.Diagnostics; using System.Runtime.InteropServices; using System.Text; public class NativeMethods { [DllImport("dbghelp.dll", CharSet = CharSet.Unicode, SetLastError = true)] private static extern bool SymInitialize(IntPtr hProcess, string UserSearchPath, bool fInvadeProcess); [DllImport("dbghelp.dll", CharSet = CharSet.Unicode, SetLastError = true)] private static extern bool SymFromAddr(IntPtr hProcess, ulong Address, out ulong Displacement, IntPtr Symbol); [DllImport("dbghelp.dll", CharSet = CharSet.Unicode, SetLastError = true)] private static extern bool SymCleanup(IntPtr hProcess); [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] private static extern IntPtr GetCurrentProcess(); [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] private static extern IntPtr LoadLibrary(string lpFileName); [DllImport("kernel32.dll", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)] private static extern IntPtr GetProcAddress(IntPtr hModule, string procName); private const int MAX_SYM_NAME = 2000; [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] private struct SYMBOL_INFO { public uint SizeOfStruct; public uint TypeIndex; public ulong Reserved1; public ulong Reserved2; public uint Index; public uint Size; public ulong ModBase; public uint Flags; public ulong Value; public ulong Address; public uint Register; public uint Scope; public uint Tag; public uint NameLen; public uint MaxNameLen; public char Name; } public static void SymInitialize() { if (!SymInitialize(GetCurrentProcess(), "", true)) { // can only be called once per process instance } } public static string GetSymbolName(IntPtr address) { ulong displacement = 0; byte[] buffer = new byte[Marshal.SizeOf(typeof(SYMBOL_INFO)) + MAX_SYM_NAME * sizeof(char)]; GCHandle bufferHandle = GCHandle.Alloc(buffer, GCHandleType.Pinned); IntPtr symbolPtr = bufferHandle.AddrOfPinnedObject(); SYMBOL_INFO symbol = (SYMBOL_INFO)Marshal.PtrToStructure(symbolPtr, typeof(SYMBOL_INFO)); symbol.SizeOfStruct = (uint)Marshal.SizeOf(typeof(SYMBOL_INFO)); symbol.MaxNameLen = MAX_SYM_NAME; Marshal.StructureToPtr(symbol, symbolPtr, true); if (SymFromAddr(GetCurrentProcess(), (ulong)address, out displacement, symbolPtr)) { symbol = (SYMBOL_INFO)Marshal.PtrToStructure(symbolPtr, typeof(SYMBOL_INFO)); string functionName = Marshal.PtrToStringUni(symbolPtr + 84); return functionName; } else { Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error()); } bufferHandle.Free(); return String.Empty; } [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] public static extern uint GetModuleFileName( IntPtr hModule, [MarshalAs(UnmanagedType.LPTStr)] StringBuilder lpFilename, uint nSize ); public static string GetModuleFileName(IntPtr hModule) { uint bufferSize = 1024; StringBuilder fileNameBuilder = new StringBuilder((int)bufferSize); uint result = GetModuleFileName(hModule, fileNameBuilder, bufferSize); if (result == 0) { throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error()); } else if (result == bufferSize) { throw new InvalidOperationException("The file name is too long. Increase the buffer size and try again."); } return fileNameBuilder.ToString(); } [DllImport("ntdll.dll", CharSet = CharSet.Unicode, SetLastError = true)] public static extern int LdrLoadDll( string DllPath, uint[] DllCharacteristics, ref UNICODE_STRING DllName, out IntPtr DllHandle ); [DllImport("ntdll.dll", SetLastError = true, CallingConvention = CallingConvention.Cdecl)] public static extern int LdrUnloadDll(IntPtr ModuleHandle); [DllImport("ntdll.dll", CharSet = CharSet.Ansi, SetLastError = true)] public static extern int LdrGetProcedureAddress( IntPtr DllHandle, ref ANSI_STRING ProcedureName, uint ProcedureNumber, out IntPtr ProcedureAddress ); [StructLayout(LayoutKind.Sequential)] public struct UNICODE_STRING { public ushort Length; public ushort MaximumLength; [MarshalAs(UnmanagedType.LPWStr)] public string Buffer; } [StructLayout(LayoutKind.Sequential)] public struct ANSI_STRING { public ushort Length; public ushort MaximumLength; [MarshalAs(UnmanagedType.LPStr)] public string Buffer; } public static UNICODE_STRING CreateUnicodeString(string str) { return new UNICODE_STRING { Length = (ushort)(str.Length * 2), MaximumLength = (ushort)((str.Length * 2) + 2), Buffer = str }; } public static ANSI_STRING CreateAnsiString(string str) { return new ANSI_STRING { Length = (ushort)str.Length, MaximumLength = (ushort)(str.Length + 1), Buffer = str }; } } '@ [Uint16]$IMAGE_DOS_SIGNATURE = 0x5A4D [Uint16]$IMAGE_NT_OPTIONAL_HDR32_MAGIC = 0x10b [UInt16]$IMAGE_NT_OPTIONAL_HDR64_MAGIC = 0x20b [UInt16]$IMAGE_ROM_OPTIONAL_HDR_MAGIC = 0x107 [Uint16]$IMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16 [Uint16]$IMAGE_SIZEOF_SHORT_NAME = 8 [Uint16]$IMAGE_SIZEOF_SECTION_HEADER = 40 enum IMAGE_FILE_MACHINE { IMAGE_FILE_RELOCS_STRIPPED = 0x0001 # Relocation info stripped from file. IMAGE_FILE_EXECUTABLE_IMAGE = 0x0002 # File is executable (i.e. no unresolved external references). IMAGE_FILE_LINE_NUMS_STRIPPED = 0x0004 # Line nunbers stripped from file. IMAGE_FILE_LOCAL_SYMS_STRIPPED = 0x0008 # Local symbols stripped from file. IMAGE_FILE_AGGRESIVE_WS_TRIM = 0x0010 # Aggressively trim working set IMAGE_FILE_LARGE_ADDRESS_AWARE = 0x0020 # App can handle >2gb addresses IMAGE_FILE_BYTES_REVERSED_LO = 0x0080 # Bytes of machine word are reversed. IMAGE_FILE_32BIT_MACHINE = 0x0100 # 32 bit word machine. IMAGE_FILE_DEBUG_STRIPPED = 0x0200 # Debugging info stripped from file in .DBG file IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP = 0x0400 # If Image is on removable media, copy and run from the swap file. IMAGE_FILE_NET_RUN_FROM_SWAP = 0x0800 # If Image is on Net, copy and run from the swap file. IMAGE_FILE_SYSTEM = 0x1000 # System File. IMAGE_FILE_DLL = 0x2000 # File is a DLL. IMAGE_FILE_UP_SYSTEM_ONLY = 0x4000 # File should only be run on a UP machine IMAGE_FILE_BYTES_REVERSED_HI = 0x8000 # Bytes of machine word are reversed. IMAGE_FILE_MACHINE_UNKNOWN = 0x0 IMAGE_FILE_MACHINE_TARGET_HOST = 0x0001 # Useful for indicating we want to interact with the host and not a WoW guest. IMAGE_FILE_MACHINE_I386 = 0x014c # Intel 386. IMAGE_FILE_MACHINE_R3000 = 0x0162 # MIPS little-endian, = 0x160 big-endian IMAGE_FILE_MACHINE_R4000 = 0x0166 # MIPS little-endian IMAGE_FILE_MACHINE_R10000 = 0x0168 # MIPS little-endian IMAGE_FILE_MACHINE_WCEMIPSV2 = 0x0169 # MIPS little-endian WCE v2 IMAGE_FILE_MACHINE_ALPHA = 0x0184 # Alpha_AXP IMAGE_FILE_MACHINE_SH3 = 0x01a2 # SH3 little-endian IMAGE_FILE_MACHINE_SH3DSP = 0x01a3 IMAGE_FILE_MACHINE_SH3E = 0x01a4 # SH3E little-endian IMAGE_FILE_MACHINE_SH4 = 0x01a6 # SH4 little-endian IMAGE_FILE_MACHINE_SH5 = 0x01a8 # SH5 IMAGE_FILE_MACHINE_ARM = 0x01c0 # ARM Little-Endian IMAGE_FILE_MACHINE_THUMB = 0x01c2 # ARM Thumb/Thumb-2 Little-Endian IMAGE_FILE_MACHINE_ARMNT = 0x01c4 # ARM Thumb-2 Little-Endian IMAGE_FILE_MACHINE_AM33 = 0x01d3 IMAGE_FILE_MACHINE_POWERPC = 0x01F0 # IBM PowerPC Little-Endian IMAGE_FILE_MACHINE_POWERPCFP = 0x01f1 IMAGE_FILE_MACHINE_IA64 = 0x0200 # Intel 64 IMAGE_FILE_MACHINE_MIPS16 = 0x0266 # MIPS IMAGE_FILE_MACHINE_ALPHA64 = 0x0284 # ALPHA64 IMAGE_FILE_MACHINE_MIPSFPU = 0x0366 # MIPS IMAGE_FILE_MACHINE_MIPSFPU16 = 0x0466 # MIPS IMAGE_FILE_MACHINE_AXP64 = 0x0284 # IMAGE_FILE_MACHINE_ALPHA64 IMAGE_FILE_MACHINE_TRICORE = 0x0520 # Infineon IMAGE_FILE_MACHINE_CEF = 0x0CEF IMAGE_FILE_MACHINE_EBC = 0x0EBC # EFI Byte Code IMAGE_FILE_MACHINE_AMD64 = 0x8664 # AMD64 (K8) IMAGE_FILE_MACHINE_M32R = 0x9041 # M32R little-endian IMAGE_FILE_MACHINE_ARM64 = 0xAA64 # ARM64 Little-Endian IMAGE_FILE_MACHINE_CEE = 0xC0EE } [Flags()] enum IMAGE_SUBSYSTEM { IMAGE_SUBSYSTEM_UNKNOWN = 0 # Unknown subsystem. IMAGE_SUBSYSTEM_NATIVE = 1 # Image doesnt require a subsystem. IMAGE_SUBSYSTEM_WINDOWS_GUI = 2 # Image runs in the Windows GUI subsystem. IMAGE_SUBSYSTEM_WINDOWS_CUI = 3 # Image runs in the Windows character subsystem. IMAGE_SUBSYSTEM_OS2_CUI = 5 # image runs in the OS/2 character subsystem. IMAGE_SUBSYSTEM_POSIX_CUI = 7 # image runs in the Posix character subsystem. IMAGE_SUBSYSTEM_NATIVE_WINDOWS = 8 # image is a native Win9x driver. IMAGE_SUBSYSTEM_WINDOWS_CE_GUI = 9 # Image runs in the Windows CE subsystem. IMAGE_SUBSYSTEM_EFI_APPLICATION = 10 # IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER = 11 # IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER = 12 # IMAGE_SUBSYSTEM_EFI_ROM = 13 IMAGE_SUBSYSTEM_XBOX = 14 IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION = 16 IMAGE_SUBSYSTEM_XBOX_CODE_CATALOG = 17 } [Flags()] enum IMAGE_DLLCHARACTERISTICS { IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA = 0x0020 # Image can handle a high entropy 64-bit virtual address space. IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE = 0x0040 # DLL can move. IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY = 0x0080 # Code Integrity Image IMAGE_DLLCHARACTERISTICS_NX_COMPAT = 0x0100 # Image is NX compatible IMAGE_DLLCHARACTERISTICS_NO_ISOLATION = 0x0200 # Image understands isolation and doesn't want it IMAGE_DLLCHARACTERISTICS_NO_SEH = 0x0400 # Image does not use SEH. No SE handler may reside in this image IMAGE_DLLCHARACTERISTICS_NO_BIND = 0x0800 # Do not bind this image. IMAGE_DLLCHARACTERISTICS_APPCONTAINER = 0x1000 # Image should execute in an AppContainer IMAGE_DLLCHARACTERISTICS_WDM_DRIVER = 0x2000 # Driver uses WDM model IMAGE_DLLCHARACTERISTICS_GUARD_CF = 0x4000 # Image supports Control Flow Guard. IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE = 0x8000 } enum IMAGE_DIRECTORY_ENTRY { IMAGE_DIRECTORY_ENTRY_EXPORT = 0 # Export Directory IMAGE_DIRECTORY_ENTRY_IMPORT = 1 # Import Directory IMAGE_DIRECTORY_ENTRY_RESOURCE = 2 # Resource Directory IMAGE_DIRECTORY_ENTRY_EXCEPTION = 3 # Exception Directory IMAGE_DIRECTORY_ENTRY_SECURITY = 4 # Security Directory IMAGE_DIRECTORY_ENTRY_BASERELOC = 5 # Base Relocation Table IMAGE_DIRECTORY_ENTRY_DEBUG = 6 # Debug Directory # IMAGE_DIRECTORY_ENTRY_COPYRIGHT = 7 # (X86 usage) IMAGE_DIRECTORY_ENTRY_ARCHITECTURE = 7 # Architecture Specific Data IMAGE_DIRECTORY_ENTRY_GLOBALPTR = 8 # RVA of GP IMAGE_DIRECTORY_ENTRY_TLS = 9 # TLS Directory IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG = 10 # Load Configuration Directory IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT = 11 # Bound Import Directory in headers IMAGE_DIRECTORY_ENTRY_IAT = 12 # Import Address Table IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT = 13 # Delay Load Import Descriptors IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR = 14 # COM Runtime descriptor } [Flags()] enum IMAGE_SCN { # IMAGE_SCN_TYPE_REG 0x00000000 # Reserved. # IMAGE_SCN_TYPE_DSECT 0x00000001 # Reserved. # IMAGE_SCN_TYPE_NOLOAD 0x00000002 # Reserved. # IMAGE_SCN_TYPE_GROUP 0x00000004 # Reserved. IMAGE_SCN_TYPE_NO_PAD = 0x00000008 # Reserved. # IMAGE_SCN_TYPE_COPY 0x00000010 # Reserved. IMAGE_SCN_CNT_CODE = 0x00000020 # Section contains code. IMAGE_SCN_CNT_INITIALIZED_DATA = 0x00000040 # Section contains initialized data. IMAGE_SCN_CNT_UNINITIALIZED_DATA = 0x00000080 # Section contains uninitialized data. IMAGE_SCN_LNK_OTHER = 0x00000100 # Reserved. IMAGE_SCN_LNK_INFO = 0x00000200 # Section contains comments or some other type of information. # IMAGE_SCN_TYPE_OVER 0x00000400 # Reserved. IMAGE_SCN_LNK_REMOVE = 0x00000800 # Section contents will not become part of image. IMAGE_SCN_LNK_COMDAT = 0x00001000 # Section contents comdat. # 0x00002000 # Reserved. # IMAGE_SCN_MEM_PROTECTED - Obsolete = 0x00004000 IMAGE_SCN_NO_DEFER_SPEC_EXC = 0x00004000 # Reset speculative exceptions handling bits in the TLB entries for this section. IMAGE_SCN_GPREL = 0x00008000 # Section content can be accessed relative to GP IMAGE_SCN_MEM_FARDATA = 0x00008000 # IMAGE_SCN_MEM_SYSHEAP - Obsolete 0x00010000 IMAGE_SCN_MEM_PURGEABLE = 0x00020000 IMAGE_SCN_MEM_16BIT = 0x00020000 IMAGE_SCN_MEM_LOCKED = 0x00040000 IMAGE_SCN_MEM_PRELOAD = 0x00080000 IMAGE_SCN_ALIGN_1BYTES = 0x00100000 # IMAGE_SCN_ALIGN_2BYTES = 0x00200000 # IMAGE_SCN_ALIGN_4BYTES = 0x00300000 # IMAGE_SCN_ALIGN_8BYTES = 0x00400000 # IMAGE_SCN_ALIGN_16BYTES = 0x00500000 # Default alignment if no others are specified. IMAGE_SCN_ALIGN_32BYTES = 0x00600000 # IMAGE_SCN_ALIGN_64BYTES = 0x00700000 # IMAGE_SCN_ALIGN_128BYTES = 0x00800000 # IMAGE_SCN_ALIGN_256BYTES = 0x00900000 # IMAGE_SCN_ALIGN_512BYTES = 0x00A00000 # IMAGE_SCN_ALIGN_1024BYTES = 0x00B00000 # IMAGE_SCN_ALIGN_2048BYTES = 0x00C00000 # IMAGE_SCN_ALIGN_4096BYTES = 0x00D00000 # IMAGE_SCN_ALIGN_8192BYTES = 0x00E00000 # # Unused 0x00F00000 IMAGE_SCN_ALIGN_MASK = 0x00F00000 IMAGE_SCN_LNK_NRELOC_OVFL = 0x01000000 # Section contains extended relocations. IMAGE_SCN_MEM_DISCARDABLE = 0x02000000 # Section can be discarded. IMAGE_SCN_MEM_NOT_CACHED = 0x04000000 # Section is not cachable. IMAGE_SCN_MEM_NOT_PAGED = 0x08000000 # Section is not pageable. IMAGE_SCN_MEM_SHARED = 0x10000000 # Section is shareable. IMAGE_SCN_MEM_EXECUTE = 0x20000000 # Section is executable. IMAGE_SCN_MEM_READ = 0x40000000 # Section is readable. IMAGE_SCN_MEM_WRITE = 0x80000000 # Section is writeable. # # TLS Characteristic Flags # IMAGE_SCN_SCALE_INDEX = 0x00000001 # Tls index is scaled } Function Convert-EnumToString([Enum]$enum) { $type = [Type]$enum } $IMAGE_DOS_HEADER = New-Object System.Collections.Specialized.OrderedDictionary $IMAGE_DOS_HEADER.Add("e_magic",[Uint16]0) # magic number $IMAGE_DOS_HEADER.Add("e_cblp",[UInt16]0) # Bytes on last page of file $IMAGE_DOS_HEADER.Add("e_cp",[UInt16]0) # Pages in file $IMAGE_DOS_HEADER.Add("e_crlc",[UInt16]0) # Relocations $IMAGE_DOS_HEADER.Add("e_cparhdr",[UInt16]0) # Size of header in paragraphs $IMAGE_DOS_HEADER.Add("e_minalloc",[UInt16]0) # Minimum extra paragraphs needed $IMAGE_DOS_HEADER.Add("e_maxalloc",[UInt16]0) # Maximum extra paragraphs needed $IMAGE_DOS_HEADER.Add("e_ss",[UInt16]0) # Initial (relative) SS value $IMAGE_DOS_HEADER.Add("e_sp",[UInt16]0) # Initial SP value $IMAGE_DOS_HEADER.Add("e_csum",[UInt16]0) # Checksum $IMAGE_DOS_HEADER.Add("e_ip",[UInt16]0) # Initial IP value $IMAGE_DOS_HEADER.Add("e_cs",[UInt16]0) # Initial (relative) CS value $IMAGE_DOS_HEADER.Add("e_lfarlc",[UInt16]0) # File address of relocation table $IMAGE_DOS_HEADER.Add("e_ovno",[UInt16]0) # Overlay number $IMAGE_DOS_HEADER.Add("e_res",(New-Object UInt16[] 4)) # Reserved words $IMAGE_DOS_HEADER.Add("e_oemid",[UInt16]0) # OEM identifier (for e_oeminfo) $IMAGE_DOS_HEADER.Add("e_oeminfo",[UInt16]0) # OEM information,[UInt16]0) e_oemid specific $IMAGE_DOS_HEADER.Add("e_res2[10]",(New-Object UInt16[] 10)) # Reserved words $IMAGE_DOS_HEADER.Add("e_lfanew",[Uint32]0) # File address of new exe header $IMAGE_FILE_HEADER = New-Object System.Collections.Specialized.OrderedDictionary $IMAGE_FILE_HEADER.Add("Machine",[UInt16]0) $IMAGE_FILE_HEADER.Add("NumberOfSections",[UInt16]0) $IMAGE_FILE_HEADER.Add("TimeDateStamp",[UInt32]0) $IMAGE_FILE_HEADER.Add("PointerToSymbolTable",[UInt32]0) $IMAGE_FILE_HEADER.Add("NumberOfSymbols",[UInt32]0) $IMAGE_FILE_HEADER.Add("SizeOfOptionalHeader",[UInt16]0) $IMAGE_FILE_HEADER.Add("Characteristics",[UInt16]0) $IMAGE_OPTIONAL_HEADER = New-Object System.Collections.Specialized.OrderedDictionary $IMAGE_OPTIONAL_HEADER.Add("Magic",[Uint16]0) $IMAGE_OPTIONAL_HEADER.Add("MajorLinkerVersion",[Byte]0) $IMAGE_OPTIONAL_HEADER.Add("MinorLinkerVersion",[Byte]0) $IMAGE_OPTIONAL_HEADER.Add("SizeOfCode",[Uint32]0) $IMAGE_OPTIONAL_HEADER.Add("SizeOfInitializedData",[Uint32]0) $IMAGE_OPTIONAL_HEADER.Add("SizeOfUninitializedData",[Uint32]0) $IMAGE_OPTIONAL_HEADER.Add("AddressOfEntryPoint",[Uint32]0) $IMAGE_OPTIONAL_HEADER.Add("BaseOfCode",[Uint32]0) $IMAGE_OPTIONAL_HEADER.Add("BaseOfData",[Uint32]0) # NT Additional Fields $IMAGE_OPTIONAL_HEADER.Add("ImageBase",[Uint32]0) $IMAGE_OPTIONAL_HEADER.Add("SectionAlignment",[Uint32]0) $IMAGE_OPTIONAL_HEADER.Add("FileAlignment",[Uint32]0) $IMAGE_OPTIONAL_HEADER.Add("MajorOperatingSystemVersion",[Uint16]0) $IMAGE_OPTIONAL_HEADER.Add("MinorOperatingSystemVersion",[Uint16]0) $IMAGE_OPTIONAL_HEADER.Add("MajorImageVersion",[Uint16]0) $IMAGE_OPTIONAL_HEADER.Add("MinorImageVersion",[Uint16]0) $IMAGE_OPTIONAL_HEADER.Add("MajorSubsystemVersion",[Uint16]0) $IMAGE_OPTIONAL_HEADER.Add("MinorSubsystemVersion",[Uint16]0) $IMAGE_OPTIONAL_HEADER.Add("Win32VersionValue",[Uint32]0) $IMAGE_OPTIONAL_HEADER.Add("SizeOfImage",[Uint32]0) $IMAGE_OPTIONAL_HEADER.Add("SizeOfHeaders",[Uint32]0) $IMAGE_OPTIONAL_HEADER.Add("CheckSum",[Uint32]0) $IMAGE_OPTIONAL_HEADER.Add("Subsystem",[Uint16]0) $IMAGE_OPTIONAL_HEADER.Add("DllCharacteristics",[Uint16]0) $IMAGE_OPTIONAL_HEADER.Add("SizeOfStackReserve",[Uint32]0) $IMAGE_OPTIONAL_HEADER.Add("SizeOfStackCommit",[Uint32]0) $IMAGE_OPTIONAL_HEADER.Add("SizeOfHeapReserve",[Uint32]0) $IMAGE_OPTIONAL_HEADER.Add("SizeOfHeapCommit",[Uint32]0) $IMAGE_OPTIONAL_HEADER.Add("LoaderFlags",[Uint32]0) $IMAGE_OPTIONAL_HEADER.Add("NumberOfRvaAndSizes",[Uint32]0) $IMAGE_OPTIONAL_HEADER.Add("DataDirectory",(New-Object System.Collections.Specialized.OrderedDictionary[] $IMAGE_NUMBEROF_DIRECTORY_ENTRIES)) For ($i = 0; $i -lt $IMAGE_OPTIONAL_HEADER["DataDirectory"].Count;$i++) { $IMAGE_OPTIONAL_HEADER["DataDirectory"][$i] = New-Object System.Collections.Specialized.OrderedDictionary $IMAGE_OPTIONAL_HEADER["DataDirectory"][$i].Add("VirtualAddress",[Uint32]0) $IMAGE_OPTIONAL_HEADER["DataDirectory"][$i].Add("Size",[UINt32]0) } $IMAGE_OPTIONAL_HEADER64 = New-Object System.Collections.Specialized.OrderedDictionary $IMAGE_OPTIONAL_HEADER64.Add("Magic",[Uint16]0) $IMAGE_OPTIONAL_HEADER64.Add("MajorLinkerVersion",[Byte]0) $IMAGE_OPTIONAL_HEADER64.Add("MinorLinkerVersion",[Byte]0) $IMAGE_OPTIONAL_HEADER64.Add("SizeOfCode",[Uint32]0) $IMAGE_OPTIONAL_HEADER64.Add("SizeOfInitializedData",[Uint32]0) $IMAGE_OPTIONAL_HEADER64.Add("SizeOfUninitializedData",[Uint32]0) $IMAGE_OPTIONAL_HEADER64.Add("AddressOfEntryPoint",[Uint32]0) $IMAGE_OPTIONAL_HEADER64.Add("BaseOfCode",[Uint32]0) $IMAGE_OPTIONAL_HEADER64.Add("ImageBase",[Uint64]0) $IMAGE_OPTIONAL_HEADER64.Add("SectionAlignment",[Uint32]0) $IMAGE_OPTIONAL_HEADER64.Add("FileAlignment",[Uint32]0) $IMAGE_OPTIONAL_HEADER64.Add("MajorOperatingSystemVersion",[Uint16]0) $IMAGE_OPTIONAL_HEADER64.Add("MinorOperatingSystemVersion",[Uint16]0) $IMAGE_OPTIONAL_HEADER64.Add("MajorImageVersion",[Uint16]0) $IMAGE_OPTIONAL_HEADER64.Add("MinorImageVersion",[Uint16]0) $IMAGE_OPTIONAL_HEADER64.Add("MajorSubsystemVersion",[Uint16]0) $IMAGE_OPTIONAL_HEADER64.Add("MinorSubsystemVersion",[Uint16]0) $IMAGE_OPTIONAL_HEADER64.Add("Win32VersionValue",[Uint32]0) $IMAGE_OPTIONAL_HEADER64.Add("SizeOfImage",[Uint32]0) $IMAGE_OPTIONAL_HEADER64.Add("SizeOfHeaders",[Uint32]0) $IMAGE_OPTIONAL_HEADER64.Add("CheckSum",[Uint32]0) $IMAGE_OPTIONAL_HEADER64.Add("Subsystem",[Uint16]0) $IMAGE_OPTIONAL_HEADER64.Add("DllCharacteristics",[Uint16]0) $IMAGE_OPTIONAL_HEADER64.Add("SizeOfStackReserve",[Uint64]0) $IMAGE_OPTIONAL_HEADER64.Add("SizeOfStackCommit",[Uint64]0) $IMAGE_OPTIONAL_HEADER64.Add("SizeOfHeapReserve",[Uint64]0) $IMAGE_OPTIONAL_HEADER64.Add("SizeOfHeapCommit",[Uint64]0) $IMAGE_OPTIONAL_HEADER64.Add("LoaderFlags",[Uint32]0) $IMAGE_OPTIONAL_HEADER64.Add("NumberOfRvaAndSizes",[Uint32]0) $IMAGE_OPTIONAL_HEADER64.Add("DataDirectory",(New-Object System.Collections.Specialized.OrderedDictionary[] $IMAGE_NUMBEROF_DIRECTORY_ENTRIES)) For ($i = 0; $i -lt $IMAGE_OPTIONAL_HEADER64["DataDirectory"].Count;$i++) { $IMAGE_OPTIONAL_HEADER64["DataDirectory"][$i] = New-Object System.Collections.Specialized.OrderedDictionary $IMAGE_OPTIONAL_HEADER64["DataDirectory"][$i].Add("VirtualAddress",[Uint32]0) $IMAGE_OPTIONAL_HEADER64["DataDirectory"][$i].Add("Size",[UINt32]0) } $IMAGE_SECTION_HEADER = New-Object System.Collections.Specialized.OrderedDictionary $IMAGE_SECTION_HEADER.Add("Name",(New-Object Byte[] $IMAGE_SIZEOF_SHORT_NAME)) $IMAGE_SECTION_HEADER.Add("Misc.PhysicalAddress",[Uint32]0) $IMAGE_SECTION_HEADER.Add("Misc.VirtualSize",[Uint32]0) $IMAGE_SECTION_HEADER.Add("VirtualAddress",[Uint32]0) $IMAGE_SECTION_HEADER.Add("SizeOfRawData",[Uint32]0) $IMAGE_SECTION_HEADER.Add("PointerToRawData",[Uint32]0) $IMAGE_SECTION_HEADER.Add("PointerToRelocations",[Uint32]0) $IMAGE_SECTION_HEADER.Add("PointerToLinenumbers",[Uint32]0) $IMAGE_SECTION_HEADER.Add("NumberOfRelocations",[Uint16]0) $IMAGE_SECTION_HEADER.Add("NumberOfLinenumbers",[Uint16]0) $IMAGE_SECTION_HEADER.Add("Characteristics",[Uint32]0) Function Convert-EnumToString { param($enum,$value) $builder = New-Object System.Text.StringBuilder $names = ($enum.DeclaredFields | Select-Object -Property Name | Where-Object { $_.Name -ne "value__" }).Name ForEach ($name in $names) { if (!($value -ne 0 -and [Enum]::Parse($enum,$name).value__ -eq 0)) { if ((([Enum]::Parse($enum,$name).value__) -band $value) -eq ([Enum]::Parse($enum,$name).value__)) { if ($builder.Length -gt 0) { [void]$builder.Append(" | ") } [void]$builder.Append($name) } } } return $builder.ToString() } Function Read-BinaryFile { param( [System.IO.BinaryReader][ref]$reader, [System.Collections.Specialized.OrderedDictionary][ref]$items) $keys = New-Object String[] $items.Count $items.Keys.CopyTo($keys,0) for ($i = 0;$i -lt $items.Count;$i++) { $item = $keys[$i] if ($items[$item] -is [Array]) { if ($items[$item][0] -is [System.Collections.Specialized.OrderedDictionary]) { ForEach ($subItem in $items[$item]) { Read-BinaryFile -reader ([ref]$reader) -items ([ref]$subItem) } } else { $currentItem = $items[$item][0] For ($j = 0;$j -lt $items[$item].Length;$j++) { switch($currentItem.GetType().Name) { "Byte" { $items[$item][$j] = $reader.ReadByte() } "Uint16" { $items[$item][$j] = $Reader.ReadUint16() } "Uint32" { $items[$item][$j] = $reader.ReadUInt32() } "Uint64" { $items[$item][$j] = $Reader.ReadUInt64() } default { "Unknown Type! $($currentItem.GetType().Name)" } } } } } else { $currentItem = $items[$item] if ($currentItem -is [System.Collections.Specialized.OrderedDictionary]) { Read-BinaryFile -reader ([ref]$reader) -items ([ref]$items[$item]) } else { switch($currentItem.GetType().Name) { "Byte" { $items[$item] = $reader.ReadByte() } "Uint16" { $items[$item] = $reader.ReadUint16() } "Uint32" { $items[$item] = $reader.ReadUint32() } "Uint64" { $items[$item] = $reader.ReadUint64() } default { "Unknown Type! $($currentItem.GetType().Name)" } } } } } } [NativeMethods]::SymInitialize() $apiSetName = [NativeMethods]::CreateUnicodeString($ApiSet) $apiName = [NativeMethods]::CreateAnsiString($Api) [IntPtr]$dllHandle = [IntPtr]::Zero [IntPtr]$procAddress = [IntPtr]::Zero if ([NativeMethods]::LdrLoadDll("",0,[ref]$apiSetName,[ref]$dllHandle) -eq 0) { if ([NativeMethods]::LdrGetProcedureAddress($dllHandle,[ref]$apiName,0,[ref]$procAddress) -eq 0) { if ($procAddress -ne [IntPtr]::Zero) { $filename = [NativeMethods]::GetModuleFileName($dllHandle) if ($ShowOffset) { $FileStream = [System.IO.File]::Open($filename, [System.IO.FileMode]::Open,[System.IO.FileAccess]::Read,[System.IO.FileShare]::Read) $BinaryReader = New-Object System.IO.BinaryReader($FileStream) [void]$BinaryReader.BaseStream.Seek(0,[System.IO.SeekOrigin]::Begin) Read-BinaryFile -reader ([ref]$BinaryReader) -Items ([ref]$IMAGE_DOS_HEADER) if ($IMAGE_DOS_HEADER["e_magic"] -eq $IMAGE_DOS_SIGNATURE) { [void]$BinaryReader.BaseStream.Seek($IMAGE_DOS_HEADER["e_lfanew"] + 24,[System.IO.SeekOrigin]::Begin) $magic = $BinaryReader.ReadInt16() [void]$BinaryReader.BaseStream.Seek($IMAGE_DOS_HEADER["e_lfanew"],[System.IO.SeekOrigin]::Begin) $IMAGE_NT_HEADER = New-Object System.Collections.Specialized.OrderedDictionary $IMAGE_NT_HEADER.Add("Signature",[Uint32]0) $IMAGE_NT_HEADER.Add("FileHeader",$IMAGE_FILE_HEADER) switch ($magic) { $IMAGE_NT_OPTIONAL_HDR32_MAGIC { $IMAGE_NT_HEADER.Add("OptionalHeader",$IMAGE_OPTIONAL_HEADER) } $IMAGE_NT_OPTIONAL_HDR64_MAGIC { $IMAGE_NT_HEADER.Add("OptionalHeader",$IMAGE_OPTIONAL_HEADER64) } $IMAGE_ROM_OPTIONAL_HDR_MAGIC { "ROM File, not supported!" } default { "Unknown PE file type $($magic)!" } } Read-BinaryFile -reader ([ref]$BinaryReader) -Items ([ref]$IMAGE_NT_HEADER) } else { Write-Host "Not a valid PE file!" } $dllCharacteristics = Convert-EnumToString -enum ([IMAGE_DLLCHARACTERISTICS]) -value $IMAGE_NT_HEADER["OptionalHeader"]["DllCharacteristics"] $subSystem = [Enum]::Parse([IMAGE_SUBSYSTEM],$IMAGE_NT_HEADER["OptionalHeader"]["Subsystem"]) $machine = [Enum]::Parse([IMAGE_FILE_MACHINE],$IMAGE_NT_HEADER["FileHeader"]["Machine"]) [UInt64]$originalAddress = ($procAddress.ToInt64() -$dllHandle) + $IMAGE_NT_HEADER.OptionalHeader.ImageBase "$($filename)!0x{0:X}" -f $originalAddress } else { $symbolName = [NativeMethods]::GetSymbolName($procAddress) [Void][NativeMethods]::LdrUnloadDll($dllHandle) "$($filename)!$symbolName" } } } } 
Posted inUncategorized|Leave a comment

Get Directory Listing in Console Tree View via PowerShell

Replicating the behavior of classic command line tool tree in PowerShell. By default only displays directories, add -ShowFileNames switch to show filenames as well.

Script is here https://github.com/chentiangemalc/PowerShellScripts/blob/master/Get-TreeView.ps1

Usage:

 ./Get-TreeView -Path C:\scripts ./Get-TreeView -Path C:\scripts -ShowFileNames 
 param ( [string]$Path = (Get-Location), [switch]$ShowFilenames ) $global:dirCount = 0 $global:fileCount = 0 Function Register-AbsolutePath { param($absolute) if (Test-Path -PathType Container $absolute) { $global:dirCount++ } else { $global:fileCount++ } } Function Get-Summary { return "$($global:dirCount) directories, $($global:fileCount) files" } Function Walk-Directory { param($directory, $prefix ="") if ($ShowFilenames) { $filepaths = @(Get-ChildItem -Path $directory | Sort-Object Name | Select-Object -ExpandProperty Name) } else { $filepaths = @(Get-ChildItem -Path $directory -Directory | Sort-Object Name | Select-Object -ExpandProperty Name) } for ($i = 0; $i -lt $filepaths.Length; $i++) { if ($filepaths[$i][0] -eq ".") { continue } $absolute = Join-Path -Path $directory -ChildPath $filepaths[$i] Register-AbsolutePath -absolute $absolute if ($i -eq $filepaths.Length - 1) { Write-Host "$prefix`└── $($filepaths[$i])" if (Test-Path -PathType Container $absolute) { Walk-Directory -directory $absolute -prefix "$prefix " } } else { Write-Host "$prefix`├── $($filepaths[$i])" if (Test-Path -PathType Container $absolute) { Walk-Directory -directory $absolute -prefix "$prefix`│ " } } } } Write-Host $path Walk-Directory -directory $path Write-Host "" Write-Host (Get-Summary) 
Posted inUncategorized|Leave a comment

Visual Basic 6 Runtime Debugging Symbols (PDBs)

An issue you will likely come across if debugging VB6 apps with the inbuilt VB6 runtime built into Windows 8+ is that symbols don’t seem to be available via the Microsoft Symbol Server. This makes VB6 stack traces completely bonkers and a lot of work to interpret.

In Visual Basic 5 and earlier debug symbols were provided as a separate download, long since gone from the Microsoft website, although still can be found archived across the internet in files such as VB5SP3DS.EXE. These however do not contain PDB files but only the legacy DBG format symbols.

For Visual Basic 6 the debug symbols were only provided in the ISO service pack releases, the Service Pack 6 is still available via Visual Studio subscriber downloads as mu_visual_basic_6.0_service_pack_6_x86_a783d802.iso (as of Jan 2023)

Within this ISO the DBG files are available via the language folder at root of the ISO i.e. en\us\Vs6sp6B.exe. Once extracted this contains a file msvbvm60.dbg and the matching msvbvm60.dll in Msvbvm60.cab. IDA Pro reports the DBG file mismatch with the DLL however it seems to match functions and other information correctly as far as I can tell.

However on my machine, if using this DLL from the SP6 ISO, while the debugging info is fine in IDA Pro, in WinDbg it triggers downloading a PDB file which doesn’t seem to match correctly, as the start of many functions don’t match up with the symbols in many cases.

A small selection of VB6 runtime DLLs/PDBs were published to the symbol server, but most versions of the DLL I’ve come across do not have the symbols available on the symbol server.

For best success with WinDbg I found using this DLL and PDB file from Microsoft Symbol server works.

https://msdl.microsoft.com/download/symbols/msvbvm60.dll/4802A186153000/msvbvm60.dll

https://msdl.microsoft.com/download/symbols/MSVBVM60.pdb/47193E361/MSVBVM60.pdb

I wouldn’t recommend replacing the VB6 runtime included with Windows, but you can put this in the same folder as your VB6 EXE when debugging if you need to try and get more useful stack traces. It is missing a lot of patches vs the VB6 runtime included with Windows, so this is only useful if you can reproduce the scenario with this runtime. In addition, this version of the runtime is likely missing the latest security patches.

Here is an example with correct symbols, what you will see when a control is clicked:

 0:000> k # ChildEBP RetAddr 00 0019f410 734d4738 MSVBVM60!_DoClick 01 0019f428 7347ce03 MSVBVM60!PushCtlProc+0x7c 02 0019f450 7347f800 MSVBVM60!CommonGizWndProc+0xae 03 0019f4ac 7347e1e6 MSVBVM60!StdCtlWndProc+0x232 04 0019f4d0 7347dc27 MSVBVM60!_DefWmCommand+0xc7 05 0019f53c 734a20e3 MSVBVM60!VBDefControlProc+0xb47 06 0019f6bc 7347ce03 MSVBVM60!FormCtlProc+0x10bd 07 0019f6e4 7347f800 MSVBVM60!CommonGizWndProc+0xae 08 0019f740 76d17d52 MSVBVM60!StdCtlWndProc+0x232 09 0019f76c 76cf711a USER32!_InternalCallWinProc+0x2a 0a 0019f85c 76cf6822 USER32!UserCallWinProcCheckWow+0x4aa 0b 0019f8c0 76d1e29c USER32!SendMessageWorker+0x842 0c 0019f8e4 76cf5c66 USER32!SendMessageInternal+0x2d 0d 0019f904 76d387bf USER32!SendMessageW+0x46 0e 0019f928 76d384a7 USER32!xxxButtonNotifyParent+0x50 0f 0019f950 76d37969 USER32!xxxBNReleaseCapture+0x140 10 0019f9f4 76d36de2 USER32!ButtonWndProcWorker+0xad9 11 0019fa20 76d17d52 USER32!ButtonWndProcA+0x52 12 0019fa4c 76cf711a USER32!_InternalCallWinProc+0x2a 13 0019fb3c 76d0d162 USER32!UserCallWinProcCheckWow+0x4aa 14 0019fb74 7347d03c USER32!CallWindowProcA+0x82 15 0019fbe0 734d4776 MSVBVM60!VBDefControlProc+0x255 16 0019fc08 7347ce03 MSVBVM60!PushCtlProc+0xbf 17 0019fc30 7347f800 MSVBVM60!CommonGizWndProc+0xae 18 0019fc8c 76d17d52 MSVBVM60!StdCtlWndProc+0x232 19 0019fcb8 76cf711a USER32!_InternalCallWinProc+0x2a 1a 0019fda8 76cf5a48 USER32!UserCallWinProcCheckWow+0x4aa 1b 0019fe24 76d11af0 USER32!DispatchMessageWorker+0x4b8 1c 0019fe2c 7342a6b0 USER32!DispatchMessageA+0x10 1d 0019fe6c 7342a627 MSVBVM60!ThunderMsgLoop+0xfd 1e 0019fe70 ffffffff MSVBVM60!CMsoCMHandler::FPushMessageLoop+0x19 

Without symbols the same stack trace shows as the following meaningless information. A good clue that this is useless information is the huge offsets after the function name:

 0:000> k # ChildEBP RetAddr WARNING: Stack unwind information not available. Following frames may be wrong. 00 0019f428 7347ce03 MSVBVM60!EbLibraryUnload+0xdcb6 01 0019f450 7347f800 MSVBVM60!IID_IVbaHost+0x2e823 02 0019f4ac 7347e1e6 MSVBVM60!IID_IVbaHost+0x31220 03 0019f4d0 7347dc27 MSVBVM60!IID_IVbaHost+0x2fc06 04 0019f53c 734a20e3 MSVBVM60!IID_IVbaHost+0x2f647 05 0019f6bc 7347ce03 MSVBVM60!BASIC_DISPINTERFACE_GetTICount+0x1cd8b 06 0019f6e4 7347f800 MSVBVM60!IID_IVbaHost+0x2e823 07 0019f740 76d17d52 MSVBVM60!IID_IVbaHost+0x31220 08 0019f76c 76cf711a USER32!AddClipboardFormatListener+0x52 09 0019f85c 76cf6822 USER32!CallWindowProcW+0x144a 0a 0019f8c0 76d1e29c USER32!CallWindowProcW+0xb52 0b 0019f8e4 76cf5c66 USER32!SetWindowsHookExAW+0x10c 0c 0019f904 76d387bf USER32!SendMessageW+0x46 0d 0019f928 76d384a7 USER32!LoadCursorFromFileW+0x1eaf 0e 0019f950 76d37969 USER32!LoadCursorFromFileW+0x1b97 0f 0019f9f4 76d36de2 USER32!LoadCursorFromFileW+0x1059 10 0019fa20 76d17d52 USER32!LoadCursorFromFileW+0x4d2 11 0019fa4c 76cf711a USER32!AddClipboardFormatListener+0x52 12 0019fb3c 76d0d162 USER32!CallWindowProcW+0x144a 13 0019fb74 7347d03c USER32!CallWindowProcA+0x82 14 0019fbe0 734d4776 MSVBVM60!IID_IVbaHost+0x2ea5c 15 0019fc08 7347ce03 MSVBVM60!EbLibraryUnload+0xdfaf 16 0019fc30 7347f800 MSVBVM60!IID_IVbaHost+0x2e823 17 0019fc8c 76d17d52 MSVBVM60!IID_IVbaHost+0x31220 18 0019fcb8 76cf711a USER32!AddClipboardFormatListener+0x52 19 0019fda8 76cf5a48 USER32!CallWindowProcW+0x144a 1a 0019fe24 76d11af0 USER32!DispatchMessageW+0x4d8 1b 0019fe2c 7342a6b0 USER32!DispatchMessageA+0x10 1c 0019fe6c 7342a627 MSVBVM60!_vbaStrToAnsi+0x2f1 1d 0019feb0 00000000 MSVBVM60!_vbaStrToAnsi+0x268 
Posted inUncategorized|Leave a comment

DART Setup Wizard Doesn’t Detect Installed ADK

Trying to create a DART recovery image, got the message during the installation from Microsoft Desktop Optimization Pack 2015 running installer from \DaRT\DaRT 10\Installers\en-us\x64\MSDart100.msi

However, the latest Windows ADK + Windows PE ADK component has been installed. Suspected the issue was a specific version is required, but the download link in the setup is a dead link and just takes you to a generic Microsoft page.

We could look for components not found either through Windows Installer logging, or ProcMon, but here want to demonstrate some ways to analyze how the installer is making the checks.

We can check with ORCA how the ADK installation check is occurring.

Opening the installation MSI in Orca we can set a condition that will prevent the DaRTRecoveryImage feature from installing.;

We could just remove the condition, however was curious how the check actually ocurred…

In Custom Action we can see DetectAdk action

In Binary view we can extract this item by clicking the [Binary Data] and Write Binary to Filename to save the item to disk. Typically these will be a DLL or a Script.

As this is a 32-bit DLL we can test calling this custom action with 32-bit PowerShell

 $code = @' using System; using System.Runtime.InteropServices; using System.ComponentModel; namespace NativeMethods { public static class CustomActionRoutines { [DllImport("msi.dll", ExactSpelling=true)] public static extern IntPtr MsiCreateRecord(uint cParams); [DllImport("SetupCommonDLLCmp2.dll", SetLastError = true)] public static extern uint DetectAdk(IntPtr hMsiHandle); [DllImport("msi.dll", ExactSpelling=true)] public static extern uint MsiCloseHandle(IntPtr hAny); } } '@ Add-Type -TypeDefinition $code $msiHandle = [NativeMethods.CustomActionRoutines]::MsiCreateRecord(0) [NativeMethods.CustomActionRoutines]::DetectAdk($msiHandle) [void][NativeMethods.CustomActionRoutines]::MsiCloseHandle($msiHandle) 

When we run this while monitoring with Process Monitor we can see it triggers creating a process with the following command line:

rundll32.exe “C:\WINDOWS\SYSTEM32\SetupCommonDLLCmp2.dll”,zzzzInvokeManagedCustomActionOutOfProc SfxCA_5457953 7 Microsoft.Dart.MuCustomActions!Microsoft.Dart.CustomActions.ADKCustomActions.DetectAdk

We can see this extracts a number of files, which are deleted straight after being created. Using 7-zip was able to extract the files from the DLL so we could analyze them:

These DLLs are .NET assemblies, in Microsoft.Dart.MuCustomActions.dll we find with a .NET decompiler a class Microsoft.Dart.CustomActions.ADK.CustomActions with the following code:

 // Type: Microsoft.Dart.CustomActions.ADKCustomActions // MVID: BB93085A-8824-4EAB-996B-D904BBE67B8D using Microsoft.Dart.Commands.Api; using Microsoft.Deployment.WindowsInstaller; namespace Microsoft.Dart.CustomActions { public static class ADKCustomActions { [CustomAction] public static ActionResult DetectAdk(Session session) { if (!WindowsAdk.IsValidAdkPath()) return ActionResult.Failure; session["WINDOWSKITSINSTALLED"] ="1"; return ActionResult.Success; } } } 

This references the following ADK related queries:

 // Type: Microsoft.Dart.Commands.Api.WindowsAdk // MVID: BB93085A-8824-4EAB-996B-D904BBE67B8D using Microsoft.Win32; using System; using System.IO; namespace Microsoft.Dart.Commands.Api { internal static class WindowsAdk { private static string adkPath; private static string bootFilesPathx64; private static string bootFilesPathx86; private static string oscdImagePathx64; private static string oscdImagePathx86; private static string imagePathx64; private static string imagePathx86; private static string optionalComponentPathx64; private static string optionalComponentPathx86; public static string AdkPath { get { if (WindowsAdk.adkPath == null) { string str = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), "Windows Kits\\10\\"); RegistryKey registryKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32).OpenSubKey("SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots"); if (registryKey != null) WindowsAdk.adkPath = registryKey.GetValue("KitsRoot10", (object) null) as string; if (WindowsAdk.adkPath == null) WindowsAdk.adkPath = str; } return WindowsAdk.adkPath; } internal set => WindowsAdk.adkPath = value; } public static bool IsValidAdkPath() => Directory.Exists(WindowsAdk.BootFilesPathx64) && Directory.Exists(WindowsAdk.BootFilesPathx86) && Directory.Exists(WindowsAdk.OscdImagePathx64) && Directory.Exists(WindowsAdk.OscdImagePathx86) && Directory.Exists(WindowsAdk.ImagePathx64) && Directory.Exists(WindowsAdk.ImagePathx86) && Directory.Exists(WindowsAdk.OptionalComponentPathx64) && Directory.Exists(WindowsAdk.OptionalComponentPathx86); public static string BootFilesPathx64 { get { if (WindowsAdk.bootFilesPathx64 == null) WindowsAdk.bootFilesPathx64 = Path.Combine(WindowsAdk.AdkPath, "Assessment and Deployment Kit\\Windows Preinstallation Environment\\amd64\\Media"); return WindowsAdk.bootFilesPathx64; } internal set => WindowsAdk.bootFilesPathx64 = value; } public static string BootFilesPathx86 { get { if (WindowsAdk.bootFilesPathx86 == null) WindowsAdk.bootFilesPathx86 = Path.Combine(WindowsAdk.AdkPath, "Assessment and Deployment Kit\\Windows Preinstallation Environment\\x86\\Media"); return WindowsAdk.bootFilesPathx86; } internal set => WindowsAdk.bootFilesPathx86 = value; } public static string OscdImagePathx64 { get { if (WindowsAdk.oscdImagePathx64 == null) WindowsAdk.oscdImagePathx64 = Path.Combine(WindowsAdk.AdkPath, "Assessment and Deployment Kit\\Deployment Tools\\amd64\\Oscdimg"); return WindowsAdk.oscdImagePathx64; } internal set => WindowsAdk.oscdImagePathx64 = value; } public static string OscdImagePathx86 { get { if (WindowsAdk.oscdImagePathx86 == null) WindowsAdk.oscdImagePathx86 = Path.Combine(WindowsAdk.AdkPath, "Assessment and Deployment Kit\\Deployment Tools\\x86\\Oscdimg"); return WindowsAdk.oscdImagePathx86; } internal set => WindowsAdk.oscdImagePathx86 = value; } public static string ImagePathx64 { get { if (WindowsAdk.imagePathx64 == null) WindowsAdk.imagePathx64 = Path.Combine(WindowsAdk.AdkPath, "Assessment and Deployment Kit\\Windows Preinstallation Environment\\amd64\\en-us"); return WindowsAdk.imagePathx64; } internal set => WindowsAdk.imagePathx64 = value; } public static string ImagePathx86 { get { if (WindowsAdk.imagePathx86 == null) WindowsAdk.imagePathx86 = Path.Combine(WindowsAdk.AdkPath, "Assessment and Deployment Kit\\Windows Preinstallation Environment\\x86\\en-us"); return WindowsAdk.imagePathx86; } internal set => WindowsAdk.imagePathx86 = value; } public static string OptionalComponentPathx64 { get { if (WindowsAdk.optionalComponentPathx64 == null) WindowsAdk.optionalComponentPathx64 = Path.Combine(WindowsAdk.AdkPath, "Assessment and Deployment Kit\\Windows Preinstallation Environment\\amd64\\WinPE_OCs"); return WindowsAdk.optionalComponentPathx64; } internal set => WindowsAdk.optionalComponentPathx64 = value; } public static string OptionalComponentPathx86 { get { if (WindowsAdk.optionalComponentPathx86 == null) WindowsAdk.optionalComponentPathx86 = Path.Combine(WindowsAdk.AdkPath, "Assessment and Deployment Kit\\Windows Preinstallation Environment\\x86\\WinPE_OCs"); return WindowsAdk.optionalComponentPathx86; } internal set => WindowsAdk.optionalComponentPathx86 = value; } public static string GetWinPeOcsPath(Architecture architecture) { switch (architecture) { case Architecture.X86: return WindowsAdk.OptionalComponentPathx86; case Architecture.X64: return WindowsAdk.OptionalComponentPathx64; default: return string.Empty; } } } } 

From reviewing this we can see that all of the following paths must exist for ADK to be detected as “installed”

WindowsAdk.BootFilesPathx64
WindowsAdk.BootFilesPathx86
WindowsAdk.OscdImagePathx64
WindowsAdk.OscdImagePathx86
WindowsAdk.ImagePathx64
WindowsAdk.ImagePathx86
WindowsAdk.OptionalComponentPathx64
WindowsAdk.OptionalComponentPathx86

We could test the logic with this PowerShell code:

 Add-Type -Path "Microsoft.Dart.MuCustomActions.dll" Add-Type -Path "Microsoft.Deployment.WindowsInstaller.dll" [Microsoft.Dart.CustomActions.ADKCustomActions]::DetectAdk($null) 

This reports “Failure” as expected. However it doesn’t clearly show which of the paths missing is triggering the issue. We can break the logic of the check into some pure PowerShell and show as the result per path:

 class WindowsAdk { [string]$adkPath [string]$bootFilesPathx64 [string]$bootFilesPathx86 [string]$oscdImagePathx64 [string]$oscdImagePathx86 [string]$imagePathx64 [string]$imagePathx86 [string]$optionalComponentPathx64 [string]$optionalComponentPathx86 } $WindowsADK = New-Object WindowsADK $WindowsADK.adkPath = [System.IO.Path]::Combine([Environment]::GetFolderPath("ProgramFilesX86"), "Windows Kits\10\") $key = [Microsoft.Win32.RegistryKey]::OpenBaseKey([Microsoft.Win32.RegistryHive]::LocalMachine, [Microsoft.Win32.RegistryView]::Registry32).OpenSubKey("SOFTWARE\Microsoft\\Windows Kits\Installed Roots") if ($key -ne $null) { $WindowsADK.adkPath = $key.GetValue("KitsRoot10") } $windowsADK.bootFilesPathx64 = [System.IO.Path]::Combine($WindowsADK.adkPath, "Assessment and Deployment Kit\Windows Preinstallation Environment\amd64\Media") $windowsADK.bootFilesPathx86 = [System.IO.Path]::Combine($WindowsADK.adkPath, "Assessment and Deployment Kit\Windows Preinstallation Environment\x86\Media") $windowsADK.oscdImagePathx64 = [System.IO.Path]::Combine($WindowsADK.adkPath,"Assessment and Deployment Kit\Deployment Tools\amd64\Oscdimg") $windowsADK.oscdImagePathx86 = [System.IO.Path]::Combine($WindowsADK.adkPath, "Assessment and Deployment Kit\Deployment Tools\x86\Oscdimg") $windowsADK.imagePathx64 = [System.IO.Path]::Combine($WindowsADK.adkPath, "Assessment and Deployment Kit\Windows Preinstallation Environment\amd64\en-us") $windowsADK.imagePathx86 = [System.IO.Path]::Combine($WindowsADK.adkPath, "Assessment and Deployment Kit\Windows Preinstallation Environment\x86\en-us") $windowsADK.optionalComponentPathx64 = [System.IO.Path]::Combine($WindowsADK.adkPath,"Assessment and Deployment Kit\Windows Preinstallation Environment\amd64\WinPE_OCs") $windowsADK.optionalComponentPathx86 = [System.IO.Path]::Combine($WindowsADK.adkPath,"Assessment and Deployment Kit\Windows Preinstallation Environment\x86\WinPE_OCs") "Windows ADK Path : $(Test-Path $WindowsADK.adkPath)" "x64 Boot Files Path : $(Test-Path $WindowsADK.bootFilesPathx64)" "x86 Boot Files Path : $(Test-Path $WindowsADK.bootFilesPathx86)" "x64 OSCD Files Path : $(Test-Path $WindowsADK.oscdImagePathx64)" "x86 OSCD Files Path : $(Test-Path $WindowsADK.oscdImagePathx86)" "x64 Image Path : $(Test-Path $WindowsADK.imagePathx64)" "x86 Image Path : $(Test-Path $WindowsADK.imagePathx86)" "x64 Optional Components Path : $(Test-Path $WindowsADK.optionalComponentPathx64)" "x86 Optional Components Path : $(Test-Path $WindowsADK.optionalComponentPathx86)" 

On my machine this output the following:

So we ran these two commands to fix the missing folders. I didn’t want to create any 32-bit images so expected these missing shouldn’t be a problem:

 mkdir "C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\Windows Preinstallation Environment\x86\Media" mkdir "C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\Windows Preinstallation Environment\x86\WinPE_OCs" mkdir "C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\Windows Preinstallation Environment\x86\en-us" 

Now the installer works, and recovery images are generated fine…

Posted inUncategorized|1 Comment

Merge Multiple PDFs with PowerShell and PDFSharp

First you will need to download PDF Sharp and build with Visual Studio the solution “BuildAll-PdfSharp.sln” and then obtaining the output PdfSharp.dll and placing in same directory as script.

Takes a specified folder of PDFs and combines them into an output file. Modify sourcePath and outputPath as necessary.

 $sourcePath = "<path to folder with PDFs to merge>" $outputPath = "<filename of final PDF>" Add-Type -Path "$($PSScriptRoot)\PdfSharp.dll" $pdfDestination = New-Object PdfSharp.Pdf.PdfDocument $pdfFiles = Get-ChildItem -Path $sourcePath -Filter *.pdf ForEach ($filename in $pdfFiles) { "Adding '$($filename.Fullname)'" $pdfSource = [PdfSharp.Pdf.IO.PdfReader]::Open($filename.Fullname,[PdfSharp.Pdf.IO.PdfDocumentOpenMode]::Import) for ($i = 0; $i -lt $pdfSource.PageCount; $i++) { $pdfDestination.AddPage($pdfSource.Pages[$i]) } $pdfSource.Close() } $pdfDestination.Save($outputPath) 
Posted inUncategorized|Leave a comment

Extract Access Database Password with PowerShell

Previously we looked at removing Office Macro Passwords with PowerShell here.

This script can be used to retrieve the master password (i.e. database design password) for many Microsoft Access Database files (.mdb) Note this does not work with databases that have multiple user/passwords associated with them. Only tested with Access 2003-2007 format. May work with older formats, or there may be some minimal tweaking required.

The script is available here https://github.com/chentiangemalc/PowerShellScripts/blob/master/Get-MdbPassword.ps1

Example usage:

 <# .SYNOPSIS Displays the password of an Access 2003-2007 (MDB) file .DESCRIPTION Decrypts Access Database password. .PARAMETER Path The access database file of which to display the password. .INPUTS None .OUTPUTS None .NOTES Version: 1.0 Author: chentiangemalc Creation Date: 6 Sep 2022 Purpose/Change: Initial script development .EXAMPLE .\Get-MdbPassword.ps1 -Path c:\test\test.mdb #> [CmdletBinding()]Param( [Parameter(Mandatory=$true)] [ValidateScript({ if( -Not ($_ | Test-Path) ){ throw "File or folder does not exist" } if(-Not ($_ | Test-Path -PathType Leaf) ){ throw "The Path argument must be a file. Folder paths are not allowed." } return $true })] [string]$Path) [Byte[]]$global:decoderKey = @( 0xBA,0x6A,0xEC,0x37,0x61,0xD5,0x9C,0xFA,0xFA, 0xCF,0x28,0xE6,0x2F,0x27,0x8A,0x60,0x68,0x05, 0x7B,0x36,0xC9,0xE3,0xDF,0xB1,0x4B,0x65,0x13, 0x43,0xF3,0x3E,0xB1,0x33,0x08,0xF0,0x79,0x5B, 0xAE,0x24,0x7C,0x2A,0x00,0x00,0x00,0x00) Function Decode-Data([Byte[]]$data,[System.Text.Encoding]$Encoding) { switch($Encoding.EncodingName) { "Unicode" { $decodeSize = 40 } default: { throw "Unknown encoding type" } } $dataPosition = 0 [Byte]$key1 = $global:decoderKey[36] -bxor $data[36] [Byte]$key3 = $global:decoderKey[37] -bxor $data[37] [byte]$key4 = 0 for ($counter = 0; $counter -lt $decodeSize;$counter++) { $key4 = $data[$counter] -bxor $global:decoderKey[$counter] $data[$counter]=$key4 if (!($counter % 4)) { $data[$counter] = $key1 -bxor $key4 } if (($counter % 4) -eq 1) { $data[$counter] = $data[$counter] -bxor $key3 } } $outString = $encoding.GetString($data) $outString = $outString.Substring(0,$outString.IndexOf([Char]0)) $outString } $stream = [System.IO.File]::Open($path, [System.IO.FileMode]::Open, [System.IO.FileAccess]::Read, [System.IO.FileShare]::ReadWrite) $reader = New-Object System.IO.BinaryReader($stream) $chunk = $reader.ReadBytes(128) if ($chunk[4] -eq 0x53 -and $chunk[5] -eq 0x74 -and $chunk[6] -eq 0x61 -and $chunk[13] -eq 0x4A -and $chunk[14] -eq 0x65) { [void]$reader.BaseStream.Seek(66, [System.IO.SeekOrigin]::Begin) $chunk = $reader.ReadBytes(128) if ($chunk[90] -eq 0x34 -and $chunk[91] -eq 0x2E -and $chunk[92] -eq 0x30) { Decode-Data -Data $chunk -Encoding ([System.Text.Encoding]::Unicode) } else { # note: Expect ASCII encoding based file to use decode size of 85 # but don't have any example file to test with at the moment throw "Unknown Encoding" } } else { throw "Unexpected data!" } $reader.Close() $stream.Close() 
Posted inUncategorized|Leave a comment

Display Binary Numbers and Struct Data with Printf in WinDbg

Was comparing an application behavior between Windows XP and Windows 10 and needed to check the value of some structs, without symbol information for them. The values I wanted to check were specific bits in the struct passed as the 2nd parameter to a function. In this case, I wanted to display the contents of DCB struct, but in an easy-to-read format when comparing traces. In addition, was working in an environment where it was difficult to copy files in/out so using/writing an extension wasn’t a suitable option.

This is fairly straightforward with WinDbg Preview and the JavaScript capability, and normally have used the SyntheticTypes script to parse simple C headers with the relevant struct https://github.com/microsoft/WinDbg-Samples/tree/master/SyntheticTypes

We can use .formats command but this offers limited if any formatting capability.

0:000> .formats $t0 Evaluate expression: Hex: 7642b9ad Decimal: 1984084397 Octal: 16620534655 Binary: 01110110 01000010 10111001 10101101 Chars: vB.. Time: Mon Nov 15 09:33:17 2032 Float: low 9.87375e+032 high 0 Double: 9.80268e-315

If you can use the JavaScript capability I would use it instead of this approach.

There may be better ways to achieve this with legacy WinDbg and native scripting, but this approach while tedious does work.

One approach can use a combination of boolean and, left shift and right shifts to extract specific bits. For a 32-bit value position “31” would be the first binary digit, and position “0” would have the final digit.

This can be done concisely with a loop, however, in WinDbg this is extremely slow, taking about a minute on my machine to run the loop. Here we will assume the value we want to display in binary is stored in $t0.

0:000> .for (r $t1 = 0x1F; $t1 >= 0 ; r $t1 = $t1-1) { .printf "%d",($t0 & ( 1 << $t1 )) >> $t1 } 01110110010000101011100110101101

A speedier version is:

0:000> .printf "%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d",($t0 & ( 1 << 0x1F)) >> 0x1F,($t0 & ( 1 << 0x1E)) >> 0x1E,($t0 & ( 1 << 0x1D)) >> 0x1D,($t0 & ( 1 << 0x1C)) >> 0x1C,($t0 & ( 1 << 0x1B)) >> 0x1B,($t0 & ( 1 << 0x1A)) >> 0x1A,($t0 & ( 1 << 0x19)) >> 0x19,($t0 & ( 1 << 0x18)) >> 0x18,($t0 & ( 1 << 0x17)) >> 0x17,($t0 & ( 1 << 0x16)) >> 0x16,($t0 & ( 1 << 0x15)) >> 0x15,($t0 & ( 1 << 0x14)) >> 0x14,($t0 & ( 1 << 0x13)) >> 0x13,($t0 & ( 1 << 0x12)) >> 0x12,($t0 & ( 1 << 0x11)) >> 0x11,($t0 & ( 1 << 0x10)) >> 0x10,($t0 & ( 1 << 0xF)) >> 0xF,($t0 & ( 1 << 0xE)) >> 0xE,($t0 & ( 1 << 0xD)) >> 0xD,($t0 & ( 1 << 0xC)) >> 0xC,($t0 & ( 1 << 0xB)) >> 0xB,($t0 & ( 1 << 0xA)) >> 0xA,($t0 & ( 1 << 0x9)) >> 0x9,($t0 & ( 1 << 0x8)) >> 0x8,($t0 & ( 1 << 0x7)) >> 0x7,($t0 & ( 1 << 0x6)) >> 0x6,($t0 & ( 1 << 0x5)) >> 0x5,($t0 & ( 1 << 0x4)) >> 0x4,($t0 & ( 1 << 0x3)) >> 0x3,($t0 & ( 1 << 0x2)) >> 0x2,($t0 & ( 1 << 0x1)) >> 0x1,($t0 & ( 1 << 0x0)) >> 0x0 01110110010000101011100110101101

If we look at our struct debugging on a target that has debugging symbols, we can see some values are not just individual “bits” but take up multiple positions i.e. bits 15-31 for fDummy2

0:000> dx -r1 ((DcbTest!_DCB *)0x4ffb9c) ((DcbTest!_DCB *)0x4ffb9c) : 0x4ffb9c [Type: _DCB *] [+0x000] DCBlength : 0x1c [Type: unsigned long] [+0x004] BaudRate : 0x2580 [Type: unsigned long] [+0x008 ( 0: 0)] fBinary : 0x1 [Type: unsigned long] [+0x008 ( 1: 1)] fParity : 0x0 [Type: unsigned long] [+0x008 ( 2: 2)] fOutxCtsFlow : 0x1 [Type: unsigned long] [+0x008 ( 3: 3)] fOutxDsrFlow : 0x0 [Type: unsigned long] [+0x008 ( 5: 4)] fDtrControl : 0x2 [Type: unsigned long] [+0x008 ( 6: 6)] fDsrSensitivity : 0x1 [Type: unsigned long] [+0x008 ( 7: 7)] fTXContinueOnXoff : 0x0 [Type: unsigned long] [+0x008 ( 8: 8)] fOutX : 0x1 [Type: unsigned long] [+0x008 ( 9: 9)] fInX : 0x0 [Type: unsigned long] [+0x008 (10:10)] fErrorChar : 0x1 [Type: unsigned long] [+0x008 (11:11)] fNull : 0x0 [Type: unsigned long] [+0x008 (13:12)] fRtsControl : 0x3 [Type: unsigned long] [+0x008 (14:14)] fAbortOnError : 0x1 [Type: unsigned long] [+0x008 (31:15)] fDummy2 : 0x19999 [Type: unsigned long] [+0x00c] wReserved : 0xcccc [Type: unsigned short] [+0x00e] XonLim : 0x7b [Type: unsigned short] [+0x010] XoffLim : 0x1c8 [Type: unsigned short] [+0x012] ByteSize : 0x8 [Type: unsigned char] [+0x013] Parity : 0x4 [Type: unsigned char] [+0x014] StopBits : 0x2 [Type: unsigned char] [+0x015] XonChar : 23 [Type: char] [+0x016] XoffChar : 45 '-' [Type: char] [+0x017] ErrorChar : 67 'C' [Type: char] [+0x018] EofChar : 89 'Y' [Type: char] [+0x019] EvtChar : 98 'b' [Type: char] [+0x01a] wReserved1 : 0xcccc [Type: unsigned short]

We can get the binary value by taking those bit positions. In this case, our value is the 2nd parameter in the 32-bit standard calling convention. As we have just hit a breakpoint where the function starts we find the struct base address at poi(@esp+8) and add 8 for the offset where our 32-bit value we are breaking apart begins.

0:000> r $t0= poi(poi(@esp+8)+8) 0:000> .printf "%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d",($t0 & ( 1 << 0x1F)) >> 0x1F,($t0 & ( 1 << 0x1E)) >> 0x1E,($t0 & ( 1 << 0x1D)) >> 0x1D,($t0 & ( 1 << 0x1C)) >> 0x1C,($t0 & ( 1 << 0x1B)) >> 0x1B,($t0 & ( 1 << 0x1A)) >> 0x1A,($t0 & ( 1 << 0x19)) >> 0x19,($t0 & ( 1 << 0x18)) >> 0x18,($t0 & ( 1 << 0x17)) >> 0x17,($t0 & ( 1 << 0x16)) >> 0x16,($t0 & ( 1 << 0x15)) >> 0x15,($t0 & ( 1 << 0x14)) >> 0x14,($t0 & ( 1 << 0x13)) >> 0x13,($t0 & ( 1 << 0x12)) >> 0x12,($t0 & ( 1 << 0x11)) >> 0x11,($t0 & ( 1 << 0x10)) >> 0x10,($t0 & ( 1 << 0xF)) >> 0xF 11001100110011001 

To display it as a number we can add the bits together and use left shifts to convert it back to a value we can display as hex or decimal.

0:000> .printf "0x%X",((($t0 & ( 1 << 0x1F)) >> 1F) << 0x10) + ((($t0 & ( 1 << 0x1E)) >> 1E) << 0xF) + ((($t0 & ( 1 << 0x1D)) >> 1D) << 0xE) + ((($t0 & ( 1 << 0x1C)) >> 1C) << 0xD) + ((($t0 & ( 1 << 0x1B)) >> 1B) << 0xC) + ((($t0 & ( 1 << 0x1A)) >> 1A) << 0xB) + ((($t0 & ( 1 << 0x19)) >> 19) << 0xA) + ((($t0 & ( 1 << 0x18)) >> 18) << 0x9) + ((($t0 & ( 1 << 0x17)) >> 17) << 0x8) + ((($t0 & ( 1 << 0x16)) >> 16) << 0x7) + ((($t0 & ( 1 << 0x15)) >> 15) << 0x6) + ((($t0 & ( 1 << 0x14)) >> 14) << 0x5) + ((($t0 & ( 1 << 0x13)) >> 13) << 0x4) + ((($t0 & ( 1 << 0x12)) >> 12) << 0x3) + ((($t0 & ( 1 << 0x11)) >> 11) << 0x2) + ((($t0 & ( 1 << 0x10)) >> 10) << 0x1) + ((($t0 & ( 1 << 0xF)) >> F) << 0x0) 0x19999

This is fairly tedious to type out so used a simple PowerShell script I can use to generate the value to type in and set the text to the clipboard to paste into WinDbg:

 $bitStart = 31 $bitEnd = 15 $cmd = "" For ($i = $bitStart;$i -ge $bitEnd;$i --) { $cmd+=[String]::Format("(((`$t0 & ( 1 << 0x{0:X})) >> {0:X}) << 0x{1:X})",$i,$i-$bitEnd) if ($i -ne $bitEnd) { $cmd += " + " } } $cmd | Set-Clipboard 

Combining these techniques we can print out our struct now in an easy to read format. (Well the output is easy to read, not the command…)

0:000> r $t0 = poi(poi(@esp+8)+8);.printf "DCBlength=%i\nBaudRate=%i\nfBinary=%d\nfParity=%d\nfOutxCtsFlow=%d\nfOutxDsrFlow=%d\nfDtrControl=%d\nfDsrSensitivity=%d\nfTXContinueOnXoff=%d\nfOutX=%d\nfInX=%d\nfErrorChar=%d\nfNull=%d\nfRtsControl=%d\nfAbortOnError=%d\n",poi(poi(@esp+8)),poi(poi(@esp+8)+4),($t0 & ( 1 << 0x0)) >> 0x0,($t0 & ( 1 << 0x1)) >> 0x1,($t0 & ( 1 << 0x2)) >> 0x2,($t0 & ( 1 << 0x3)) >> 0x3,((($t0 & ( 1 << 0x5)) >> 5) << 0x1) + ((($t0 & ( 1 << 0x4)) >> 4) << 0x0),($t0 & ( 1 << 0x6)) >> 0x6,($t0 & ( 1 << 0x7)) >> 0x7,($t0 & ( 1 << 0x8)) >> 0x8,($t0 & ( 1 << 0x9)) >> 0x9,($t0 & ( 1 << 0xA)) >> 0xA,($t0 & ( 1 << 0xB)) >> 0xB,((($t0 & ( 1 << 0xD)) >> D) << 0x1) + ((($t0 & ( 1 << 0xC)) >> C) << 0x0),($t0 & ( 1 << 0xE)) >> 0xE;r $t0=poi(poi(@esp+8)+0xe);r $t0=poi(poi(@esp+8)+0xe);.printf "XonLim=%i\nXoffLim=%i\n",((($t0 & ( 1 << 0xF)) >> F) << 0xF) + ((($t0 & ( 1 << 0xE)) >> E) << 0xE) + ((($t0 & ( 1 << 0xD)) >> D) << 0xD) + ((($t0 & ( 1 << 0xC)) >> C) << 0xC) + ((($t0 & ( 1 << 0xB)) >> B) << 0xB) + ((($t0 & ( 1 << 0xA)) >> A) << 0xA) + ((($t0 & ( 1 << 0x9)) >> 9) << 0x9) + ((($t0 & ( 1 << 0x8)) >> 8) << 0x8) + ((($t0 & ( 1 << 0x7)) >> 7) << 0x7) + ((($t0 & ( 1 << 0x6)) >> 6) << 0x6) + ((($t0 & ( 1 << 0x5)) >> 5) << 0x5) + ((($t0 & ( 1 << 0x4)) >> 4) << 0x4) + ((($t0 & ( 1 << 0x3)) >> 3) << 0x3) + ((($t0 & ( 1 << 0x2)) >> 2) << 0x2) + ((($t0 & ( 1 << 0x1)) >> 1) << 0x1) + ((($t0 & ( 1 << 0x0)) >> 0) << 0x0),((($t0 & ( 1 << 0x1F)) >> 1F) << 0xF) + ((($t0 & ( 1 << 0x1E)) >> 1E) << 0xE) + ((($t0 & ( 1 << 0x1D)) >> 1D) << 0xD) + ((($t0 & ( 1 << 0x1C)) >> 1C) << 0xC) + ((($t0 & ( 1 << 0x1B)) >> 1B) << 0xB) + ((($t0 & ( 1 << 0x1A)) >> 1A) << 0xA) + ((($t0 & ( 1 << 0x19)) >> 19) << 0x9) + ((($t0 & ( 1 << 0x18)) >> 18) << 0x8) + ((($t0 & ( 1 << 0x17)) >> 17) << 0x7) + ((($t0 & ( 1 << 0x16)) >> 16) << 0x6) + ((($t0 & ( 1 << 0x15)) >> 15) << 0x5) + ((($t0 & ( 1 << 0x14)) >> 14) << 0x4) + ((($t0 & ( 1 << 0x13)) >> 13) << 0x3) + ((($t0 & ( 1 << 0x12)) >> 12) << 0x2) + ((($t0 & ( 1 << 0x11)) >> 11) << 0x1) + ((($t0 & ( 1 << 0x10)) >> 10) << 0x0);r $t0=poi(poi(@esp+8)+0x12);.printf "ByteSize=%d\nParity=%d\nStopBits=%d\nXonChar='%C'\nXoffChar='%C'\nErrorChar='%C'\nEofChar='%C'\nEvtChar='%C'\n",((($t0 & ( 1 << 0x7)) >> 7) << 0x7) + ((($t0 & ( 1 << 0x6)) >> 6) << 0x6) + ((($t0 & ( 1 << 0x5)) >> 5) << 0x5) + ((($t0 & ( 1 << 0x4)) >> 4) << 0x4) + ((($t0 & ( 1 << 0x3)) >> 3) << 0x3) + ((($t0 & ( 1 << 0x2)) >> 2) << 0x2) + ((($t0 & ( 1 << 0x1)) >> 1) << 0x1) + ((($t0 & ( 1 << 0x0)) >> 0) << 0x0),((($t0 & ( 1 << 0xF)) >> F) << 0x7) + ((($t0 & ( 1 << 0xE)) >> E) << 0x6) + ((($t0 & ( 1 << 0xD)) >> D) << 0x5) + ((($t0 & ( 1 << 0xC)) >> C) << 0x4) + ((($t0 & ( 1 << 0xB)) >> B) << 0x3) + ((($t0 & ( 1 << 0xA)) >> A) << 0x2) + ((($t0 & ( 1 << 0x9)) >> 9) << 0x1) + ((($t0 & ( 1 << 0x8)) >> 8) << 0x0),((($t0 & ( 1 << 0x17)) >> 17) << 0x7) + ((($t0 & ( 1 << 0x16)) >> 16) << 0x6) + ((($t0 & ( 1 << 0x15)) >> 15) << 0x5) + ((($t0 & ( 1 << 0x14)) >> 14) << 0x4) + ((($t0 & ( 1 << 0x13)) >> 13) << 0x3) + ((($t0 & ( 1 << 0x12)) >> 12) << 0x2) + ((($t0 & ( 1 << 0x11)) >> 11) << 0x1) + ((($t0 & ( 1 << 0x10)) >> 10) << 0x0),poi(poi(@esp+8)+0x15),poi(poi(@esp+8)+0x16),poi(poi(@esp+8)+0x17),poi(poi(@esp+8)+0x18),poi(poi(@esp+8)+0x19) DCBlength=28 BaudRate=9600 fBinary=1 fParity=0 fOutxCtsFlow=1 fOutxDsrFlow=0 fDtrControl=2 fDsrSensitivity=1 fTXContinueOnXoff=0 fOutX=1 fInX=0 fErrorChar=1 fNull=0 fRtsControl=3 fAbortOnError=1 XonLim=123 XoffLim=456 ByteSize=8 Parity=4 StopBits=2 XonChar='' XoffChar='-' ErrorChar='C' EofChar='Y' EvtChar='b'

We can also split a 32-bit number stored in $t0 into four separate 1 byte values using this approach, allowing us to print an 8-bit value as a number. And provides an alternative in older versions of WinDbg which don’t support %C for ASCII char output.

0:000> r $t0 = poi(poi(@esp+8)+0x15) 0:000> r $t1 = ((($t0 & ( 1 << 0x7)) >> 7) << 0x7) + ((($t0 & ( 1 << 0x6)) >> 6) << 0x6) + ((($t0 & ( 1 << 0x5)) >> 5) << 0x5) + ((($t0 & ( 1 << 0x4)) >> 4) << 0x4) + ((($t0 & ( 1 << 0x3)) >> 3) << 0x3) + ((($t0 & ( 1 << 0x2)) >> 2) << 0x2) + ((($t0 & ( 1 << 0x1)) >> 1) << 0x1) + ((($t0 & ( 1 << 0x0)) >> 0) << 0x0);r $t2 = ((($t0 & ( 1 << 0xF)) >> F) << 0x7) + ((($t0 & ( 1 << 0xE)) >> E) << 0x6) + ((($t0 & ( 1 << 0xD)) >> D) << 0x5) + ((($t0 & ( 1 << 0xC)) >> C) << 0x4) + ((($t0 & ( 1 << 0xB)) >> B) << 0x3) + ((($t0 & ( 1 << 0xA)) >> A) << 0x2) + ((($t0 & ( 1 << 0x9)) >> 9) << 0x1) + ((($t0 & ( 1 << 0x8)) >> 8) << 0x0);r $t3 = ((($t0 & ( 1 << 0x17)) >> 17) << 0x7) + ((($t0 & ( 1 << 0x16)) >> 16) << 0x6) + ((($t0 & ( 1 << 0x15)) >> 15) << 0x5) + ((($t0 & ( 1 << 0x14)) >> 14) << 0x4) + ((($t0 & ( 1 << 0x13)) >> 13) << 0x3) + ((($t0 & ( 1 << 0x12)) >> 12) << 0x2) + ((($t0 & ( 1 << 0x11)) >> 11) << 0x1) + ((($t0 & ( 1 << 0x10)) >> 10) << 0x0);r $t4 = ((($t0 & ( 1 << 0x1F)) >> 1F) << 0x7) + ((($t0 & ( 1 << 0x1E)) >> 1E) << 0x6) + ((($t0 & ( 1 << 0x1D)) >> 1D) << 0x5) + ((($t0 & ( 1 << 0x1C)) >> 1C) << 0x4) + ((($t0 & ( 1 << 0x1B)) >> 1B) << 0x3) + ((($t0 & ( 1 << 0x1A)) >> 1A) << 0x2) + ((($t0 & ( 1 << 0x19)) >> 19) << 0x1) + ((($t0 & ( 1 << 0x18)) >> 18) << 0x0) 0:000> .printf "%i, %i, %i, %i",$t1,$t2,$t3,$t4 23, 45, 67, 89
Posted inUncategorized|Leave a comment

Adding A Pause Between Items in Config.NT / Config.Sys

I wanted to debug startup of a 16-bit DOS driver on 32-bit Windows 10 with NTVDM, however attempts to attach debugger / Time Travel Debugging Trace to NTVDM startup process was triggering access violations and causing NTVDM.exe to crash. Once NTVDM had started I could attach debugger fine, but was missing the driver startup code I wanted to capture.

MS-DOS 6.00 added a feature where F8 could be pressed to run autoexec.bat/config.sys entries one line at a time, but I haven’t found an alternative that works with c:\windows\system32\config.nt in Windows.

In this case using Microsoft Macro Assmbler built this driver with the following commands:

masm wait.asm link wait exe2bin wait.exe wait.sys xcopy wait.sys C:\windows\system32 

The code is here, this can also be used a template for a simple MS-DOS driver.

 ; ******************************************************************* ; * Press Any Key To Continue DRIVER * ; ******************************************************************* cseg segment para public 'code' wait proc far assume cs:cseg,es:cseg,ds:cseg ; ******************************************************************* ; * MAIN PROCEDURE CODE * ; ******************************************************************* begin: ; ******************************************************************* ; * DEVICE HEADER - REQUIRED BY DOS * ; ******************************************************************* next_dev dd -1 ; no other device drivers attribute dw 8000h ; character device strategy dw dev_strategy ; address of 1st dos call interrupt dw dev_interrupt ; address of 2nd dos call dev_name db 'WAIT$ ' ; name of the driver ; ******************************************************************* ; * WORK SPACE FOR THE DEVICE DRIVER * ; ******************************************************************* rh_ofs dw ? ; request header offset rh_seg dw ? ; request header segment msg1 db 'Waiting...' db 0dh,0ah,'$' seconds db 0 counter db 0 crlf  db 0dh,0ah,'$' ; ******************************************************************* ; * THE STRATEGY PROCEDURE * ; ******************************************************************* dev_strategy: ; first call from DOS mov cs:rh_seg,es ; save request header ptr segment mov cs:rh_ofs,bx ; save request header ptr offset ret ; ******************************************************************* ; * THE INTERRUPT PROCEDURE * ; ******************************************************************* dev_interrupt: ; second call from DOS cld ; save machine state on entry push ds push es push ax push bx push cx push dx push di push si ; perform branch based on the command passed in the req header mov al,es:[bx]+2 ; get command code cmp al,0 ; check for 0 jnz exit3 ; no - exit go to error exit rol al,1 ; get offset into table lea di,cmdtab ; get address of command table mov ah,0 ; clear hi order add di,ax ; add offset jmp word ptr[di] ; jump indirect ; command table ; the command code field of the static request ; field contains the function to be performed cmdtab label byte ; dw init ; initialization ; ******************************************************************* ; * LOCAL PROCEDURES * ; ******************************************************************* initial proc near lea dx,msg1 ; initialization mov ah,9 ; message int 21h ; dos call mov al,30 ; number of seconds to wait call sleep ret ; return initial endp ; ******************************************************************* ; * DOS COMMAND PROCESSING * ; ******************************************************************* ;command 0 initialization init: call initial ; display a message lea ax,exit ; get end address (offset) mov es:[bx]+0eh,ax ; store offset address push cs ; get end pop ax ; address (segment) mov es:[bx]+10h,ax ; store in break address jmp exit2 ; ******************************************************************* ; * ERROR EXIT * ; ******************************************************************* ; Set the done flag, error flag, and unknown command error code exit3: mov es:word ptr 3[bx],8103h jmp exit1 ; restore environment ; ******************************************************************* ; * COMMON EXIT * ; ******************************************************************* ; common exits fall thru code ; 2 sets status to done and no error ; 1 restore callers es:bx ; 0 restore machine state and exit exit2: ; set done flag and no error mov es:word ptr 3[bx],0100h exit1: mov bx,cs:rh_ofs ; restore req hdr to bx and es mov es,cs:rh_seg ; as saved by dev_Strategy exit0: pop si ; restore all registers pop di pop dx pop cx pop bx pop ax pop es pop ds ret exit: ; ******************************************************************* ; * END OF PROGRAM * ; ******************************************************************* wait endp sleep proc near wait_for_al_seconds: wait_loop: push ax ; save our counter (al) mov [counter],al loop_top: mov ah,2 int 1ah ; get time mov ah, [seconds] ; retrieve last good value cmp ah, dh ; is it same as last good value? jz loop_top ; yup, ignore it, loop again! mov [seconds], dh ; save seconds ; display counter - can handle range of 0-99 mov al, [counter] ; retrieve counter cbw ; set AH to 0 mov dl, 10 div dl ; Divides AX by 10: quotient in al, remainder in ah add ax, "00" mov dx, ax mov ah, 02h ; Display 1st digit of counter int 21h mov dl, dh int 21h ; Display 2nd digit of counter lea dx,crlf ; display carriage return mov ah,9 int 21h pop ax dec al ; decrease al by one (does not set flags!!) or al,al ; set flags jnz wait_loop ; al=0? nope, around we go again! ret ; sleep endp cseg ends end begin ; that's all folks! 

Now we can add line to C:\Windows\System32\config.nt to load our driver where we want it to pause:

DEVICE=%SystemRoot%\System32\wait.sys

To test all existing ntvdm.exe process must be terminated, as config.sys is only loaded when a new ntvdm.exe instance is created. Now when launching a 16-bit DOS application you will see a count down for 30 seconds when this line of config.nt has been hit:

Posted inUncategorized|1 Comment

Case of the Windows 11 SystemSettings.exe Crash

Collecting user mode dumps with dumptype set to 2 via Windows Error Reporting registry configuration as documented here

Noticed two SystemSettings.exe crashes, both with similar stack traces. The following information was logged in the Windows application event log:

 Faulting application name: SystemSettings.exe, version: 10.0.22000.348, time stamp: 0x27a6d211 Faulting module name: MusUpdateHandlers.dll, version: 10.0.22000.348, time stamp: 0x5aa0c31b Exception code: 0xc0000005 Fault offset: 0x0000000000092185 Faulting process id: 0x53c0 Faulting application start time: 0x01d802f49e9d7598 Faulting application path: C:\Windows\ImmersiveControlPanel\SystemSettings.exe Faulting module path: C:\Windows\System32\MusUpdateHandlers.dll Report Id: 75fce6a5-9ef4-42a1-a895-83bc2a6b6c9b Faulting package full name: windows.immersivecontrolpanel_10.0.6.1000_neutral_neutral_cw5n1h2txyewy Faulting package-relative application ID: microsoft.windows.immersivecontrolpanel 

Normally some quick potential correlation may be found with Reliability Monitor to see if issues started occurring after specific system change, however possibly due to a major update installing it seems all noted crashes/changes/etc made to system on these dates earlier in the month when crash occurred no longer had any information available.

Initial analysis pointed to culprit being a null reference exception in MusUpdateHandlers.dll which is the Modern Update Settings Handler Implementation.

 0:018> !analyze -v ******************************************************************************* * * * Exception Analysis * * * ******************************************************************************* KEY_VALUES_STRING: 1 Key : AV.Dereference Value: NullPtr Key : AV.Fault Value: Read Key : Analysis.CPU.mSec Value: 2827 Key : Analysis.DebugAnalysisManager Value: Create Key : Analysis.Elapsed.mSec Value: 12646 Key : Analysis.Init.CPU.mSec Value: 265 Key : Analysis.Init.Elapsed.mSec Value: 6821 Key : Analysis.Memory.CommitPeak.Mb Value: 285 Key : Timeline.OS.Boot.DeltaSec Value: 201950 Key : Timeline.Process.Start.DeltaSec Value: 201231 Key : WER.OS.Branch Value: co_release Key : WER.OS.Timestamp Value: 2021-06-04T16:28:00Z Key : WER.OS.Version Value: 10.0.22000.1 Key : WER.Process.Version Value: 10.0.22000.348 FILE_IN_CAB: SystemSettings.exe.16748.dmp NTGLOBALFLAG: 400 PROCESS_BAM_CURRENT_THROTTLED: 0 PROCESS_BAM_PREVIOUS_THROTTLED: 0 APPLICATION_VERIFIER_FLAGS: 0 CONTEXT: (.ecxr) rax=00007107f20fec8f rbx=0000004b595ff744 rcx=0000000000000000 rdx=0000004b595ff744 rsi=0000000000000002 rdi=0000000000000001 rip=00007ffe2ebd2185 rsp=0000004b595ff680 rbp=0000004b595ff7d0 r8=0000000000000001 r9=0000000000000001 r10=0000000000009100 r11=0000004b595ff6b0 r12=0000000000000000 r13=0000000000000000 r14=0000000000000000 r15=00007ffe2ec40328 iopl=0 nv up ei pl nz na po nc cs=0033 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010206 MusUpdateHandlers!SystemSettings::Update::CMusOrchModel::GetSeekerUXDisplayRank+0x55: 00007ffe`2ebd2185 488b01 mov rax,qword ptr [rcx] ds:00000000`00000000=???????????????? Resetting default scope EXCEPTION_RECORD: (.exr -1) ExceptionAddress: 00007ffe2ebd2185 (MusUpdateHandlers!SystemSettings::Update::CMusOrchModel::GetSeekerUXDisplayRank+0x0000000000000055) ExceptionCode: c0000005 (Access violation) ExceptionFlags: 00000000 NumberParameters: 2 Parameter[0]: 0000000000000000 Parameter[1]: 0000000000000000 Attempt to read from address 0000000000000000 PROCESS_NAME: SystemSettings.exe READ_ADDRESS: 0000000000000000 ERROR_CODE: (NTSTATUS) 0xc0000005 - The instruction at 0x%p referenced memory at 0x%p. The memory could not be %s. EXCEPTION_CODE_STR: c0000005 EXCEPTION_PARAMETER1: 0000000000000000 EXCEPTION_PARAMETER2: 0000000000000000 STACK_TEXT: 0000004b`595ff680 00007ffe`2eb8a93c : 0000015a`dec14700 0000015a`dec14700 0000015a`dec14700 00000000`00000001 : MusUpdateHandlers!SystemSettings::Update::CMusOrchModel::GetSeekerUXDisplayRank+0x55 0000004b`595ff6d0 00007ffe`2eb6b013 : 0000015a`e0ca8110 0000015a`e0ca8110 0000015a`e0ca8110 00000000`00000000 : MusUpdateHandlers!SystemSettings::Update::CMusSeekerUpdate::InitializeState+0x38c 0000004b`595ff850 00007ffe`2eb6c0ee : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : MusUpdateHandlers!<lambda_547ec51b376960035aba27ef737bbd82>::operator()+0x257 0000004b`595ff960 00007ffe`8ad36c0c : 0000015a`e565e280 00000000`00000000 00000000`00000000 00000000`00000000 : MusUpdateHandlers!std::thread::_Invoke<std::tuple<<lambda_547ec51b376960035aba27ef737bbd82> >,0>+0xe 0000004b`595ff990 00007ffe`8bd454e0 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : ucrtbase!thread_start<unsigned int (__cdecl*)(void *),1>+0x4c 0000004b`595ff9c0 00007ffe`8cfa485b : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : kernel32!BaseThreadInitThunk+0x10 0000004b`595ff9f0 00000000`00000000 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : ntdll!RtlUserThreadStart+0x2b SYMBOL_NAME: MusUpdateHandlers!SystemSettings::Update::CMusOrchModel::GetSeekerUXDisplayRank+55 MODULE_NAME: MusUpdateHandlers IMAGE_NAME: MusUpdateHandlers.dll STACK_COMMAND: ~18s ; .ecxr ; kb FAILURE_BUCKET_ID: NULL_POINTER_READ_c0000005_MusUpdateHandlers.dll!SystemSettings::Update::CMusOrchModel::GetSeekerUXDisplayRank OS_VERSION: 10.0.22000.1 BUILDLAB_STR: co_release OSPLATFORM_TYPE: x64 OSNAME: Windows 10 IMAGE_VERSION: 10.0.22000.348 FAILURE_ID_HASH: {39aeb642-c99a-f672-5c69-96a915aec9c5} Followup: MachineOwner 

The crash seems to be related to a class CMusOrchModel

What is that? Checking all references to the string in IDA pro we find related methods but the symbol names are mangled i.e in a format like ??_E?$_Ref_count_obj2@VCMusOrchModel@Update@SystemSettings@@@std@@UEAAPEAXI@Z so all search results are copied and pasted into an online GCC/MSVC C++ demangler here http://demangler.com/

This shows us function names involved:

 public: virtual void * __ptr64 __cdecl std::_Ref_count_obj2<class SystemSettings::Update::CMusOrchModel>::`vector deleting destructor'(unsigned int) __ptr64 public: virtual void * __ptr64 __cdecl SystemSettings::Update::CMusOrchModel::`scalar deleting destructor'(unsigned int) __ptr64 public: __cdecl SystemSettings::Update::CMusOrchModel::CMusOrchModel(void) __ptr64 public: virtual __cdecl SystemSettings::Update::CMusOrchModel::~CMusOrchModel(void) __ptr64 private: virtual void __cdecl std::_Ref_count_obj2<class SystemSettings::Update::CMusOrchModel>::_Destroy(void) __ptr64 protected: long __cdecl SystemSettings::Update::CMusOrchModel::AcceptAllUpdateEulas(void) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::AddSeekerUpdateToApprovalList(class wil::com_ptr_t<struct IMoUsoUpdate,struct wil::err_returncode_policy>) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::AddSeekerUpdateToApprovalList(class std::shared_ptr<class UxUsoUpdateShim>) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::ApproveAllSeekerUpdatesFromApprovalList(void) __ptr64 protected: long __cdecl SystemSettings::Update::CMusOrchModel::ApproveSeekerFeatureUpdateForInstall(void) __ptr64 protected: long __cdecl SystemSettings::Update::CMusOrchModel::ApproveSeekerQualityUpdateForInstall(void) __ptr64 public: BOOL __cdecl SystemSettings::Update::CMusOrchModel::AreUpdatesPaused(void) __ptr64 public: BOOL __cdecl SystemSettings::Update::CMusOrchModel::AreUpdatesPausedByPolicy(void) __ptr64 public: BOOL __cdecl SystemSettings::Update::CMusOrchModel::AreUsoObjectsInitialized(void) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::CanExtendPauseUpdates(unsigned long,int * __ptr64) __ptr64 public: BOOL __cdecl SystemSettings::Update::CMusOrchModel::CanPauseUpdates(void) __ptr64 protected: long __cdecl SystemSettings::Update::CMusOrchModel::CreateNotifyPropertyChangedThread(enum SystemSettings::Update::UXUpdateReason) __ptr64 protected: long __cdecl SystemSettings::Update::CMusOrchModel::CreateUpdateResultsTaskSchedule(void) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::DecrementPauseUpdates(unsigned long) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::DoesRebootScheduleExist(BOOL * __ptr64) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::ExtendPauseUpdates(unsigned long) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::FixServiceUnavailable(void) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::get_ActiveHours(unsigned short * __ptr64,unsigned short * __ptr64) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::get_ActiveHoursIntervalLimit(unsigned short * __ptr64) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::get_ApplicableUpdates(class std::vector<class wil::com_ptr_t<struct IMoUsoUpdate,struct wil::err_returncode_policy>,class std::allocator<class wil::com_ptr_t<struct IMoUsoUpdate,struct wil::err_returncode_policy> > > & __ptr64) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::get_ApplicableUpdates(class std::vector<class std::shared_ptr<class UxUsoUpdateShim>,class std::allocator<class std::shared_ptr<class UxUsoUpdateShim> > > & __ptr64) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::get_ApplicableUpdatesPayloadInfo(struct PayloadInfo * __ptr64) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::get_ApprovedSeekerUpdates(class std::vector<class wil::com_ptr_t<struct IMoUsoUpdate,struct wil::err_returncode_policy>,class std::allocator<class wil::com_ptr_t<struct IMoUsoUpdate,struct wil::err_returncode_policy> > > & __ptr64) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::get_ApprovedSeekerUpdates(class std::vector<class std::shared_ptr<class UxUsoUpdateShim>,class std::allocator<class std::shared_ptr<class UxUsoUpdateShim> > > & __ptr64) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::get_CanScheduleUpdate(struct PayloadInfo & __ptr64,BOOL * __ptr64) __ptr64 public: enum NormalizedPolicy __cdecl SystemSettings::Update::CMusOrchModel::get_EnforcedAuPolicy(void) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::get_OptInToMu(BOOL * __ptr64) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::get_RebootSchedule(struct _SYSTEMTIME * __ptr64) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::get_SchedulePickerOption(enum SchedulePickerOption * __ptr64) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::get_SeekerUpdates(class std::vector<class wil::com_ptr_t<struct IMoUsoUpdate,struct wil::err_returncode_policy>,class std::allocator<class wil::com_ptr_t<struct IMoUsoUpdate,struct wil::err_returncode_policy> > > & __ptr64) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::get_SeekerUpdates(class std::vector<class std::shared_ptr<class UxUsoUpdateShim>,class std::allocator<class std::shared_ptr<class UxUsoUpdateShim> > > & __ptr64) __ptr64 public: enum UxSettingType __cdecl SystemSettings::Update::CMusOrchModel::get_UpdateUxOption(void) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::get_UserChoiceActiveHoursEnd(BOOL * __ptr64,unsigned long * __ptr64) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::get_UserChoiceActiveHoursStart(BOOL * __ptr64,unsigned long * __ptr64) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::GetApprovedSeekerUpdatesCounts(unsigned long * __ptr64,unsigned long * __ptr64) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::GetAvailableUpdateStatusCounts(unsigned long * __ptr64,unsigned long * __ptr64,unsigned long * __ptr64,unsigned long * __ptr64) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::GetCompatBlockInfo(class std::optional<class std::basic_string<unsigned short,struct std::char_traits<unsigned short>,class std::allocator<unsigned short> > > & __ptr64,class std::optional<class std::vector<class std::basic_string<unsigned short,struct std::char_traits<unsigned short>,class std::allocator<unsigned short> >,class std::allocator<class std::basic_string<unsigned short,struct std::char_traits<unsigned short>,class std::allocator<unsigned short> > > > > & __ptr64,class std::optional<unsigned int> & __ptr64) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::GetDaysSinceRebootRequired(unsigned long * __ptr64) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::GetDefaultRebootScheduleTime(struct _SYSTEMTIME * __ptr64,struct _FILETIME,struct _FILETIME) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::GetDeviceEosStatus(BOOL * __ptr64,BOOL * __ptr64) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::GetDowntimeEstimateInfo(unsigned long * __ptr64,int * __ptr64) __ptr64 public: static class std::shared_ptr<class SystemSettings::Update::CMusOrchModel> __cdecl SystemSettings::Update::CMusOrchModel::GetInstanceShared(void) public: BOOL __cdecl SystemSettings::Update::CMusOrchModel::GetIsSingletonDeinitializing(void) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::GetMaximumAllowedPauseDays(unsigned long * __ptr64) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::GetMgmtDefaultScheduleTime(struct _SYSTEMTIME * __ptr64) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::GetOptionsForUpdateNotificationLevelPolicy(enum UpdateNotificationOption * __ptr64) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::GetOrchModelShimInstance(class std::shared_ptr<class SystemSettings::Update::OrchModelShim> & __ptr64) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::GetPauseUpdatesExpiryTime(struct _FILETIME * __ptr64) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::GetPolicyValue(enum NormalizedPolicy,enum tagUpdatePolicyStatus * __ptr64,struct tagVARIANT * __ptr64) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::GetSeekerFeatureUpdateBuildNumber(class std::optional<unsigned int> & __ptr64) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::GetSeekerUpdatesCounts(unsigned long * __ptr64,unsigned long * __ptr64,unsigned long * __ptr64,unsigned long * __ptr64) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::GetSeekerUpdateTitle(unsigned short * __ptr64 * __ptr64) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::GetSeekerUXDisplayRank(unsigned long * __ptr64) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::GetUpdateHistoryDefinition(class std::vector<class wil::com_ptr_t<struct IUsoUpdateHistoryEntry,struct wil::err_returncode_policy>,class std::allocator<class wil::com_ptr_t<struct IUsoUpdateHistoryEntry,struct wil::err_returncode_policy> > > & __ptr64,struct _FILETIME * __ptr64) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::GetUpdateHistoryDriver(class std::vector<class wil::com_ptr_t<struct IUsoUpdateHistoryEntry,struct wil::err_returncode_policy>,class std::allocator<class wil::com_ptr_t<struct IUsoUpdateHistoryEntry,struct wil::err_returncode_policy> > > & __ptr64,struct _FILETIME * __ptr64) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::GetUpdateHistoryFeature(class std::vector<class wil::com_ptr_t<struct IUsoUpdateHistoryEntry,struct wil::err_returncode_policy>,class std::allocator<class wil::com_ptr_t<struct IUsoUpdateHistoryEntry,struct wil::err_returncode_policy> > > & __ptr64,struct _FILETIME * __ptr64) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::GetUpdateHistoryOther(class std::vector<class wil::com_ptr_t<struct IUsoUpdateHistoryEntry,struct wil::err_returncode_policy>,class std::allocator<class wil::com_ptr_t<struct IUsoUpdateHistoryEntry,struct wil::err_returncode_policy> > > & __ptr64,struct _FILETIME * __ptr64) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::GetUpdateHistoryQuality(class std::vector<class wil::com_ptr_t<struct IUsoUpdateHistoryEntry,struct wil::err_returncode_policy>,class std::allocator<class wil::com_ptr_t<struct IUsoUpdateHistoryEntry,struct wil::err_returncode_policy> > > & __ptr64,struct _FILETIME * __ptr64) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::GetUpdatePayloadSize(enum tagUsoUpdatePayloadType,unsigned __int64 * __ptr64,unsigned __int64 * __ptr64) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::GetUXElementStoreForSurface(enum UXSurface,class UXElementStore * __ptr64) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::GetValidScheduleRange(struct _FILETIME * __ptr64,struct _FILETIME * __ptr64) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::GetValidScheduleRangeWithFallback(struct _FILETIME * __ptr64,struct _FILETIME * __ptr64,BOOL) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::GetWOSCOneSettingsInstance(struct IUxOneSettings * __ptr64 * __ptr64) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::InitializeUpdateHistory(void) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::InvokeAction(struct HWND__ * __ptr64,enum SystemSettings::Update::MusActionType const & __ptr64) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::InvokeReboot(BOOL,unsigned long * __ptr64) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::IsActiveHourIntervalValid(unsigned short,unsigned short,BOOL * __ptr64) __ptr64 public: BOOL __cdecl SystemSettings::Update::CMusOrchModel::IsActiveHoursUXApplicable(void) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::IsAutoApproveSeekerQualityUpdatesEnabled(BOOL * __ptr64) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::IsAutoRestartDeadlinePolicyConfigured(BOOL * __ptr64) __ptr64 public: BOOL __cdecl SystemSettings::Update::CMusOrchModel::IsCTA(void) __ptr64 public: BOOL __cdecl SystemSettings::Update::CMusOrchModel::IsDirectEngagedReboot(void) __ptr64 public: BOOL __cdecl SystemSettings::Update::CMusOrchModel::IsDisableUXAccessPolicyEnabled(void) __ptr64 public: BOOL __cdecl SystemSettings::Update::CMusOrchModel::IsEngagedRebootAllowedByPolicy(void) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::IsEngagedRestartDeadlinePolicyConfigured(BOOL * __ptr64) __ptr64 public: BOOL __cdecl SystemSettings::Update::CMusOrchModel::IsFeatureUpdatePausedByPolicy(void) __ptr64 public: BOOL __cdecl SystemSettings::Update::CMusOrchModel::IsGraceDeadlinePolicyConfigured(void) __ptr64 public: BOOL __cdecl SystemSettings::Update::CMusOrchModel::IsMgmtPolicyValidForSchedulingReboot(void) __ptr64 public: BOOL __cdecl SystemSettings::Update::CMusOrchModel::IsNotifyToRebootPolicyApplicable(void) __ptr64 public: BOOL __cdecl SystemSettings::Update::CMusOrchModel::IsPolicyConfigured(enum NormalizedPolicy) __ptr64 public: BOOL __cdecl SystemSettings::Update::CMusOrchModel::IsPolicyConfiguredAndEnabled(enum NormalizedPolicy) __ptr64 public: BOOL __cdecl SystemSettings::Update::CMusOrchModel::IsPolicyConfiguredToMapToAutomaticReboot(void) __ptr64 public: BOOL __cdecl SystemSettings::Update::CMusOrchModel::IsQualityUpdatePausedByPolicy(void) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::IsRebootRequired(BOOL * __ptr64) __ptr64 public: BOOL __cdecl SystemSettings::Update::CMusOrchModel::IsRestartForced(void) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::IsSeekerFeatureOrQualityUpdatesAvailable(BOOL * __ptr64) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::IsSeekerHighCompatMessageEnabled(BOOL * __ptr64) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::IsSeekerOnDemandUxEnabled(BOOL * __ptr64) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::IsSeekerUpdateInApprovalList(class wil::com_ptr_t<struct IMoUsoUpdate,struct wil::err_returncode_policy>,BOOL * __ptr64) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::IsSeekerUpdateInApprovalList(class std::shared_ptr<class UxUsoUpdateShim>,BOOL * __ptr64) __ptr64 public: BOOL __cdecl SystemSettings::Update::CMusOrchModel::IsSihUpdatePendingReboot(void) __ptr64 public: BOOL __cdecl SystemSettings::Update::CMusOrchModel::IsSmartActiveHoursSuggestionNeeded(void) __ptr64 public: BOOL __cdecl SystemSettings::Update::CMusOrchModel::IsUpdateErrorIgnorable(long) __ptr64 public: BOOL __cdecl SystemSettings::Update::CMusOrchModel::IsUSOAvailable(void) __ptr64 public: BOOL __cdecl SystemSettings::Update::CMusOrchModel::IsUXCampaignApplicable(enum UXSurface) __ptr64 public: BOOL __cdecl SystemSettings::Update::CMusOrchModel::IsWindowsInsiderAttentionNeeded(void) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::LoadDynamicElementById(enum UXSurface,enum UXElementType,unsigned int,struct HSTRING__ * __ptr64 * __ptr64) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::LoadDynamicUXStringById(unsigned int,struct HSTRING__ * __ptr64 * __ptr64) __ptr64 public: static long __cdecl SystemSettings::Update::CMusOrchModel::LocalizeWsxUpdateTitle(class std::basic_string_view<unsigned short,struct std::char_traits<unsigned short> > const & __ptr64,unsigned short * __ptr64 * __ptr64) public: void __cdecl SystemSettings::Update::CMusOrchModel::NotifyInit(class SystemSettings::DataModel::CSingletonHelper<struct SystemSettings::Update::MusNotification>::CCallback * __ptr64) __ptr64 public: void __cdecl SystemSettings::Update::CMusOrchModel::NotifyPropertyChanged(enum SystemSettings::Update::UXUpdateReason) __ptr64 protected: virtual void __cdecl SystemSettings::Update::CMusOrchModel::OnAsyncInitComplete(void) __ptr64 protected: virtual void __cdecl SystemSettings::Update::CMusOrchModel::OnSingletonDeinit(void) __ptr64 protected: virtual long __cdecl SystemSettings::Update::CMusOrchModel::OnSingletonInit(void) __ptr64 protected: void __cdecl SystemSettings::Update::CMusOrchModel::OrchestratorUpdateCallback(char const & __ptr64,enum SystemSettings::Update::UXUpdateReason) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::PauseUpdates(unsigned long) __ptr64 protected: static void __cdecl SystemSettings::Update::CMusOrchModel::RefreshElementStoresCallback(struct _TP_CALLBACK_INSTANCE * __ptr64,void * __ptr64,struct _TP_TIMER * __ptr64) protected: long __cdecl SystemSettings::Update::CMusOrchModel::RefreshSeekerSessionState(BOOL * __ptr64) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::RemoveSeekerUpdateFromApprovalList(class wil::com_ptr_t<struct IMoUsoUpdate,struct wil::err_returncode_policy>) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::RemoveSeekerUpdateFromApprovalList(class std::shared_ptr<class UxUsoUpdateShim>) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::ResumeUpdates(void) __ptr64 private: long __cdecl SystemSettings::Update::CMusOrchModel::RunElevatedInstall(struct HWND__ * __ptr64) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::ScheduleReboot(struct _SYSTEMTIME,enum SchedulePickerOption) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::SendCTAApprovedData(void) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::set_ActiveHoursEnd(unsigned short) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::set_ActiveHoursStart(unsigned short) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::set_DoMicrosoftScan(BOOL) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::set_SchedulePickerOption(enum SchedulePickerOption) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::set_UserChoiceActiveHoursEnd(unsigned long) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::set_UserChoiceActiveHoursStart(unsigned long) __ptr64 protected: void __cdecl SystemSettings::Update::CMusOrchModel::SingletonDeinitialize(void) __ptr64 protected: long __cdecl SystemSettings::Update::CMusOrchModel::SingletonInitialize(void) __ptr64 protected: void __cdecl SystemSettings::Update::CMusOrchModel::StopTracing(void) __ptr64 

The crash seems to have occured in function “GetSeekerUXDisplayRank” which is called by “CMusSeekerUpdate::InitializeState

References to seeker:

 class WRL::Details::ComPtr<class SystemSettings::Update::CMusSeekerOnDemand> __cdecl Microsoft::WRL::Details::V::Make(void) class WRL::Details::ComPtr<class SystemSettings::Update::CMusSeekerUpdate> __cdecl Microsoft::WRL::Details::V::Make(void) private: long __cdecl SystemSettings::Update::CMusSeekerOnDemand::InitiateSeekerUpdateTitle(void) __ptr64 private: long __cdecl SystemSettings::Update::CMusSeekerOnDemand::MoInitiateSeekerUpdateTitle(void) __ptr64 private: long __cdecl SystemSettings::Update::CMusSeekerUpdate::InitiateSeekerUpdateTitle(void) __ptr64 private: long __cdecl SystemSettings::Update::CMusSeekerUpdate::InitiateWhatsNewUrl(void) __ptr64 private: long __cdecl UxUsoShim::GetNonSeekerOrApprovedUpdates(class std::vector<class wil::com_ptr_t<struct IMoUsoUpdate,struct wil::err_returncode_policy>,class std::allocator<class wil::com_ptr_t<struct IMoUsoUpdate,struct wil::err_returncode_policy> > > & __ptr64) __ptr64 protected: long __cdecl SystemSettings::Update::CMusOrchModel::ApproveSeekerFeatureUpdateForInstall(void) __ptr64 protected: long __cdecl SystemSettings::Update::CMusOrchModel::ApproveSeekerQualityUpdateForInstall(void) __ptr64 protected: long __cdecl SystemSettings::Update::CMusOrchModel::RefreshSeekerSessionState(BOOL * __ptr64) __ptr64 protected: virtual long __cdecl SystemSettings::Update::CMusSeekerOnDemand::InitializeState(struct SystemSettings::Update::MusNotification) __ptr64 protected: virtual long __cdecl SystemSettings::Update::CMusSeekerOnDemand::Invoke(struct HWND__ * __ptr64) __ptr64 protected: virtual long __cdecl SystemSettings::Update::CMusSeekerUpdate::InitializeState(struct SystemSettings::Update::MusNotification) __ptr64 protected: virtual long __cdecl SystemSettings::Update::CMusSeekerUpdate::Invoke(struct HWND__ * __ptr64) __ptr64 protected: virtual void __cdecl SystemSettings::Update::CMusSeekerUpdate::RaiseValueChangedEvents(void) __ptr64 public: __cdecl Microsoft::WRL::Details::MakeAllocator<class SystemSettings::Update::CMusSeekerOnDemand>::~MakeAllocator<class SystemSettings::Update::CMusSeekerOnDemand>(void) __ptr64 public: __cdecl SystemSettings::Update::CMusSeekerOnDemand::CMusSeekerOnDemand(void) __ptr64 public: __cdecl SystemSettings::Update::CMusSeekerUpdate::CMusSeekerUpdate(void) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::AddSeekerUpdateToApprovalList(class std::shared_ptr<class UxUsoUpdateShim>) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::AddSeekerUpdateToApprovalList(class wil::com_ptr_t<struct IMoUsoUpdate,struct wil::err_returncode_policy>) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::ApproveAllSeekerUpdatesFromApprovalList(void) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::get_ApprovedSeekerUpdates(class std::vector<class std::shared_ptr<class UxUsoUpdateShim>,class std::allocator<class std::shared_ptr<class UxUsoUpdateShim> > > & __ptr64) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::get_ApprovedSeekerUpdates(class std::vector<class wil::com_ptr_t<struct IMoUsoUpdate,struct wil::err_returncode_policy>,class std::allocator<class wil::com_ptr_t<struct IMoUsoUpdate,struct wil::err_returncode_policy> > > & __ptr64) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::get_SeekerUpdates(class std::vector<class std::shared_ptr<class UxUsoUpdateShim>,class std::allocator<class std::shared_ptr<class UxUsoUpdateShim> > > & __ptr64) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::get_SeekerUpdates(class std::vector<class wil::com_ptr_t<struct IMoUsoUpdate,struct wil::err_returncode_policy>,class std::allocator<class wil::com_ptr_t<struct IMoUsoUpdate,struct wil::err_returncode_policy> > > & __ptr64) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::GetApprovedSeekerUpdatesCounts(unsigned long * __ptr64,unsigned long * __ptr64) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::GetSeekerFeatureUpdateBuildNumber(class std::optional<unsigned int> & __ptr64) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::GetSeekerUpdatesCounts(unsigned long * __ptr64,unsigned long * __ptr64,unsigned long * __ptr64,unsigned long * __ptr64) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::GetSeekerUpdateTitle(unsigned short * __ptr64 * __ptr64) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::GetSeekerUXDisplayRank(unsigned long * __ptr64) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::IsAutoApproveSeekerQualityUpdatesEnabled(BOOL * __ptr64) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::IsSeekerFeatureOrQualityUpdatesAvailable(BOOL * __ptr64) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::IsSeekerHighCompatMessageEnabled(BOOL * __ptr64) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::IsSeekerOnDemandUxEnabled(BOOL * __ptr64) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::IsSeekerUpdateInApprovalList(class std::shared_ptr<class UxUsoUpdateShim>,BOOL * __ptr64) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::IsSeekerUpdateInApprovalList(class wil::com_ptr_t<struct IMoUsoUpdate,struct wil::err_returncode_policy>,BOOL * __ptr64) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::RemoveSeekerUpdateFromApprovalList(class std::shared_ptr<class UxUsoUpdateShim>) __ptr64 public: long __cdecl SystemSettings::Update::CMusOrchModel::RemoveSeekerUpdateFromApprovalList(class wil::com_ptr_t<struct IMoUsoUpdate,struct wil::err_returncode_policy>) __ptr64 public: long __cdecl UxUsoShim::GetApplicableSeekerUpdates(class std::vector<class std::shared_ptr<class UxUsoUpdateShim>,class std::allocator<class std::shared_ptr<class UxUsoUpdateShim> > > & __ptr64) __ptr64 public: long __cdecl UxUsoShim::GetApprovedSeekerUpdates(class std::vector<class std::shared_ptr<class UxUsoUpdateShim>,class std::allocator<class std::shared_ptr<class UxUsoUpdateShim> > > & __ptr64) __ptr64 public: static long __cdecl SystemSettings::Update::CMusSeekerOnDemand::CreateInstance(struct SystemSettings::DataModel::SettingDBItem const * __ptr64,struct SystemSettings::DataModel::ISettingItem * __ptr64 * __ptr64) public: static long __cdecl SystemSettings::Update::CMusSeekerUpdate::CreateInstance(struct SystemSettings::DataModel::SettingDBItem const * __ptr64,struct SystemSettings::DataModel::ISettingItem * __ptr64 * __ptr64) public: static long __cdecl UpdateUtil::GetApprovedSeekerUpdatesCount(class UxUsoShim * __ptr64,unsigned long * __ptr64,unsigned long * __ptr64) public: virtual __cdecl SystemSettings::Update::CMusSeekerOnDemand::~CMusSeekerOnDemand(void) __ptr64 public: virtual __cdecl SystemSettings::Update::CMusSeekerUpdate::~CMusSeekerUpdate(void) __ptr64 public: virtual long __cdecl SystemSettings::Update::CMusSeekerOnDemand::get_Description(struct HSTRING__ * __ptr64 * __ptr64) __ptr64 public: virtual long __cdecl SystemSettings::Update::CMusSeekerOnDemand::get_IsEnabled(unsigned char * __ptr64) __ptr64 public: virtual long __cdecl SystemSettings::Update::CMusSeekerOnDemand::GetProperty(struct HSTRING__ * __ptr64,struct IInspectable * __ptr64 * __ptr64) __ptr64 public: virtual long __cdecl SystemSettings::Update::CMusSeekerUpdate::get_Description(struct HSTRING__ * __ptr64 * __ptr64) __ptr64 public: virtual long __cdecl SystemSettings::Update::CMusSeekerUpdate::get_IsApplicable(unsigned char * __ptr64) __ptr64 public: virtual long __cdecl SystemSettings::Update::CMusSeekerUpdate::GetProperty(struct HSTRING__ * __ptr64,struct IInspectable * __ptr64 * __ptr64) __ptr64 public: virtual long __cdecl SystemSettings::Update::MoOrchModelShim::ApproveSeekerQualityUpdateForInstall(void) __ptr64 public: virtual long __cdecl SystemSettings::Update::MoOrchModelShim::GetApprovedSeekerUpdates(class std::vector<class std::shared_ptr<class UxUsoUpdateShim>,class std::allocator<class std::shared_ptr<class UxUsoUpdateShim> > > & __ptr64) __ptr64 public: virtual long __cdecl SystemSettings::Update::MoOrchModelShim::GetApprovedSeekerUpdates(class std::vector<class wil::com_ptr_t<struct IMoUsoUpdate,struct wil::err_returncode_policy>,class std::allocator<class wil::com_ptr_t<struct IMoUsoUpdate,struct wil::err_returncode_policy> > > & __ptr64) __ptr64 public: virtual long __cdecl SystemSettings::Update::MoOrchModelShim::GetApprovedSeekerUpdatesCount(unsigned long * __ptr64,unsigned long * __ptr64) __ptr64 public: virtual long __cdecl SystemSettings::Update::MoOrchModelShim::GetNonSelectableSeekerUpdates(class std::vector<class wil::com_ptr_t<struct IMoUsoUpdate,struct wil::err_returncode_policy>,class std::allocator<class wil::com_ptr_t<struct IMoUsoUpdate,struct wil::err_returncode_policy> > > & __ptr64) __ptr64 public: virtual long __cdecl SystemSettings::Update::MoOrchModelShim::GetSeekerSession(BOOL * __ptr64,BOOL * __ptr64) __ptr64 public: virtual long __cdecl SystemSettings::Update::MoOrchModelShim::GetSelectableSeekerUpdates(class std::vector<class wil::com_ptr_t<struct IMoUsoUpdate,struct wil::err_returncode_policy>,class std::allocator<class wil::com_ptr_t<struct IMoUsoUpdate,struct wil::err_returncode_policy> > > & __ptr64) __ptr64 public: virtual long __cdecl SystemSettings::Update::MoOrchModelShim::SetSeekerSession(BOOL) __ptr64 public: virtual long __cdecl SystemSettings::Update::OldOrchModelShim::ApproveSeekerQualityUpdateForInstall(void) __ptr64 public: virtual long __cdecl SystemSettings::Update::OldOrchModelShim::GetApprovedSeekerUpdates(class std::vector<class std::shared_ptr<class UxUsoUpdateShim>,class std::allocator<class std::shared_ptr<class UxUsoUpdateShim> > > & __ptr64) __ptr64 public: virtual long __cdecl SystemSettings::Update::OldOrchModelShim::GetApprovedSeekerUpdatesCount(unsigned long * __ptr64,unsigned long * __ptr64) __ptr64 public: virtual long __cdecl SystemSettings::Update::OldOrchModelShim::GetNonSelectableSeekerUpdates(class std::vector<class wil::com_ptr_t<struct IMoUsoUpdate,struct wil::err_returncode_policy>,class std::allocator<class wil::com_ptr_t<struct IMoUsoUpdate,struct wil::err_returncode_policy> > > & __ptr64) __ptr64 public: virtual long __cdecl SystemSettings::Update::OldOrchModelShim::GetSeekerSession(BOOL * __ptr64,BOOL * __ptr64) __ptr64 public: virtual long __cdecl SystemSettings::Update::OldOrchModelShim::GetSelectableSeekerUpdates(class std::vector<class std::shared_ptr<class UxUsoUpdateShim>,class std::allocator<class std::shared_ptr<class UxUsoUpdateShim> > > & __ptr64) __ptr64 public: virtual long __cdecl SystemSettings::Update::OldOrchModelShim::GetSelectableSeekerUpdates(class std::vector<class wil::com_ptr_t<struct IMoUsoUpdate,struct wil::err_returncode_policy>,class std::allocator<class wil::com_ptr_t<struct IMoUsoUpdate,struct wil::err_returncode_policy> > > & __ptr64) __ptr64 public: virtual long __cdecl SystemSettings::Update::OldOrchModelShim::SetSeekerSession(BOOL) __ptr64 public: virtual void * __ptr64 __cdecl SystemSettings::Update::CMusSeekerOnDemand::`vector deleting destructor'(unsigned int) __ptr64 public: virtual void * __ptr64 __cdecl SystemSettings::Update::CMusSeekerUpdate::`vector deleting destructor'(unsigned int) __ptr64 

What is the process for this CMusSeekerUpdate::InitializeState function?

  1. A call to SystemSettings::Update::CMusSettings::InitializeState which checks for pending reboot.

It checks for pending reboot via SystemSettings::Update::CMusOrchModel::IsSihUpdatePendingReboot

I believe SIH in this case is referring to “Server Initiated Healing” which includes C:\Windows\System32\SIHClient.exe from checking C:\Windows\System32\en-US\SIHClient.exe.mui we find the following text:

This daily task launches the SIH client (server-initiated healing) to detect and fix system components that are vital to automatic updating of Windows and Microsoft software installed on the machine. This task can go online, evaluate applicability of healing actions, download necessary payloads to execute the actions, and execute healing actions.
This boot task launches the SIH client to finish executing healing actions to fix the system components vital to automatic updating of Windows and Microsoft software installed on the machine. It is enabled only when the daily SIH client task fails to complete execution of applicable healing actions. This boot task never goes online and does not evaluate applicability of healing actions.

(Note: SIH can also refer to Shell Infrastructure Host which is C:\Windows\System32\SIHost.exe)

IsSihUpdatePendingReboot calls UsoConfiguration::GetConfiguration(L”UsoServicingStack”, etc) which uses an internal function RegistryManager::GetHKLMValueOrDefault to retrieve a key with name UpdateOrchestratorConfigurationRoot

If GetConfiguration does not return a value of 1 IsSihUpdatePendingReboot exits immediately.

Otherwise it continues can calls RegistryManager::HKLMValueExists(L”Sih”, L”\UpdateStaged”, L”StagingTimeStamp”, x);

Finally IsSihUpdatePendingReboot checks SystemSettings::Update::OtaIsPendingExclusiveContent by calling GetUpdateResultsEx in UpdateAPI.dll.

OtaIsPendingExclusiveContent is true when GetUpdateResultsEx is 0 or greater.

Initialize state then calls SystemSettings::Update::CMusOrchModel::IsUSOAvailable

Here USO refers to Update Session Orchestrator (USO) which you can read about here

It checks if USO is available by checking Update Orchestrator Service (USOSvc) is available service and running.

There is then a check for SystemSettings::Update::CMusOrchModel::FixServiceUnavailable which seems to potentially update some telemetry and other stuff.

The total InitializeState function has some logic like this:

 __int64 __fastcall SystemSettings::Update::CMusSettings<SystemSettings::DataModel::CActionSetting>::InitializeState( __int64 a1) { bool IsSihUpdatePendingReboot; // bl char v3; // si IsSihUpdatePendingReboot = SystemSettings::Update::CMusOrchModel::IsSihUpdatePendingReboot(*(SystemSettings::Update::CMusOrchModel **)(a1 + 248)); if ( !SystemSettings::Update::CMusOrchModel::IsUSOAvailable(*(SystemSettings::Update::CMusOrchModel **)(a1 + 248)) || IsSihUpdatePendingReboot ) { v3 = 0; if ( !IsSihUpdatePendingReboot ) SystemSettings::Update::CMusOrchModel::FixServiceUnavailable(*(SystemSettings::Update::CMusOrchModel **)(a1 + 248)); } else { v3 = 1; } EnterCriticalSection((LPCRITICAL_SECTION)(a1 + 312)); *(_BYTE *)(a1 + 264) = v3; if ( a1 != -312 ) LeaveCriticalSection((LPCRITICAL_SECTION)(a1 + 312)); return 0i64; } 

2. Some configuration is checked related to “allow scan map” and “SeekerOnDemandScanOverride

 v7 = (char *)&SystemSettings::Update::CMusSeekerUpdate::sc_rgupeMap; v8 = 0i64; v9 = *(_DWORD *)a2; v10 = &SystemSettings::Update::CMusSeekerUpdate::sc_rgupeMap; v11 = 1; while ( *v10 != v9 ) { v8 = (unsigned int)(v8 + 1); ++v10; if ( (unsigned int)v8 >= 0xA ) goto LABEL_9; } v7 = (char *)&SystemSettings::Update::CMusSeekerUpdate::sc_rgupeMap + 4 * v8; LABEL_9: v12 = (char *)&SystemSettings::Update::CMusSeekerUpdate::sc_rgupeAllowScanMap; v13 = 0i64; v14 = &SystemSettings::Update::CMusSeekerUpdate::sc_rgupeAllowScanMap; while ( *v14 != v9 ) { v13 = (unsigned int)(v13 + 1); ++v14; if ( (unsigned int)v13 >= 0xB ) goto LABEL_14; } v12 = (char *)&SystemSettings::Update::CMusSeekerUpdate::sc_rgupeAllowScanMap + 4 * v13; LABEL_14: v35 = &SystemSettings::Update::CMusSeekerUpdate::sc_rgupeAllowScanMap != (_UNKNOWN *)v12; HKLMValueOr = RegistryManager::GetHKLMValueOrDefault<unsigned long>( L"WindowsUpdateUXRoot", L"\\TestHooks", L"SeekerOnDemandScanOverride", 1); if ( HKLMValueOr < 0 ) { v5 = 6871i64; goto LABEL_3; } if ( !v58[1] ) { v15 = MusUpdateLogging::Provider(); if ( *(_DWORD *)v15 > 4u ) { v51 = (__int64)"Seeker on demand override is set so scan is not allowed immediately"; _tlgWriteTemplate<long (_tlgProvider_t const *,void const *,_GUID const *,_GUID const *,unsigned int,_EVENT_DATA_DESCRIPTOR *),&long _tlgWriteTransfer_EventWriteTransfer(_tlgProvider_t const *,void const *,_GUID const *,_GUID const *,unsigned int,_EVENT_DATA_DESCRIPTOR *),_GUID const *,_GUID const *>::Write<_tlgWrapSz<char>>( (int)v15, (__int64)&v51); } v35 = 0; } 

3. Some functions are called to check if UX access is blocked and if updates are paused i.e.

 IsDisableUXAccessPolicyEnabled = SystemSettings::Update::CMusOrchModel::IsDisableUXAccessPolicyEnabled(*(SystemSettings::Update::CMusOrchModel **)(a1 + 248)); if ( SystemSettings::Update::CMusOrchModel::AreUpdatesPaused(*(SystemSettings::Update::CMusOrchModel **)(a1 + 248)) || (v16 = SystemSettings::Update::CMusOrchModel::AreUpdatesPausedByPolicy(*(SystemSettings::Update::CMusOrchModel **)(a1 + 248)), v33 = 0, v16) ) { v33 = 1; } 

4. Get Seeker Update counts are retrieved

 HKLMValueOr = SystemSettings::Update::CMusOrchModel::GetSeekerUpdatesCounts( *(SystemSettings::Update::CMusOrchModel **)(a1 + 248), &v46[1], &v47, &v44, &v45); if ( HKLMValueOr < 0 ) { v5 = 6894i64; goto LABEL_3; } v17 = v46[1]; v39 = v46[1] != 0; v18 = v47; v34 = v47 != 0; v19 = v45; if ( v44 || (v36 = 0, v45) ) v36 = 1; v56 = 0; v57 = 0; HKLMValueOr = SystemSettings::Update::CMusOrchModel::GetApprovedSeekerUpdatesCounts( *(SystemSettings::Update::CMusOrchModel **)(a1 + 248), &v56, &v57); if ( HKLMValueOr < 0 ) { v5 = 6904i64; goto LABEL_3; } 

5. Configuration is checked if quality updates are auto approved

 if ( v34 ) { HKLMValueOr = SystemSettings::Update::CMusOrchModel::IsAutoApproveSeekerQualityUpdatesEnabled( *(SystemSettings::Update::CMusOrchModel **)(a1 + 248), &v32); if ( HKLMValueOr < 0 ) { v5 = 6933i64; goto LABEL_3; } v23 = v32; } 

6. We to spot where crash occurs, GetSeekerDisplayUXRank

 IsUXCampaignApplicable = 0; HKLMValueOr = SystemSettings::Update::CMusOrchModel::GetSeekerUXDisplayRank( *(SystemSettings::Update::CMusOrchModel **)(a1 + 248), v46); if ( HKLMValueOr < 0 ) { v5 = 6938i64; goto LABEL_3; } v25 = v46[0]; if ( v46[0] != 1 ) IsUXCampaignApplicable = SystemSettings::Update::CMusOrchModel::IsUXCampaignApplicable(*(_QWORD *)(a1 + 248), 1i64); HKLMValueOr = SystemSettings::Update::CMusOrchModel::IsSeekerOnDemandUxEnabled( *(SystemSettings::Update::CMusOrchModel **)(a1 + 248), &v40); if ( HKLMValueOr < 0 ) { v5 = 6948i64; goto LABEL_3; } v32 = 0; v37 = 0; HKLMValueOr = SystemSettings::Update::CMusOrchModel::GetDeviceEosStatus( *(SystemSettings::Update::CMusOrchModel **)(a1 + 248), &v32, &v37); if ( HKLMValueOr < 0 ) { v5 = 6954i64; goto LABEL_3; } HKLMValueOr = SystemSettings::Update::CMusOrchModel::IsSeekerHighCompatMessageEnabled( *(SystemSettings::Update::CMusOrchModel **)(a1 + 248), &v43); if ( HKLMValueOr < 0 ) { v5 = 6957i64; goto LABEL_3; } 

The crash occurs because a function pointer is null when attempting to call _guard_xfg_dispatch_icall_fptr

 __int64 __fastcall SystemSettings::Update::CMusOrchModel::GetSeekerUXDisplayRank( SystemSettings::Update::CMusOrchModel *this, unsigned int *a2) { __int64 v4; // rcx int v5; // eax unsigned int v6; // edi int v7; // [rsp+20h] [rbp-28h] unsigned int v8; // [rsp+30h] [rbp-18h] BYREF wil::details::in1diag3 *retaddr; // [rsp+48h] [rbp+0h] if ( a2 ) { v4 = *((_QWORD *)this + 212); v8 = 1; v5 = _guard_xfg_dispatch_icall_fptr(v4, 90i64, 1i64, &v8); 

This function is an Xtended Flow Guard (XFG) function generated by the compiler, a good introduction to this is here

It seems like the reference to this function has been overwritten with 0s preventing, causing the null reference when attempting to reference a pointer to the targeted function, although I am current unsure as to what actually caused this problem.

Posted inUncategorized|Leave a comment