/// <summary> /// This guy names the section and establishes the codeview data needed for symbol handling /// </summary> /// <param name="sec"></param> /// <returns></returns> public CODEVIEW_HEADER ExtractCVDebug(MemSection sec) { uint SizeData = 0, RawData = 0, PointerToRawData = 0; Extract Ext = sec.Module; long VA = sec.VA.Address; var _va = VA + Ext.DebugDirPos; var block = GetVirtualByte(_va); var TimeDate2 = BitConverter.ToUInt32(block, 4); if (TimeDate2 != Ext.TimeStamp & Vtero.VerboseOutput) { WriteColor(ConsoleColor.Yellow, "Unable to lock on to CV data."); return(null); } SizeData = BitConverter.ToUInt32(block, 16); RawData = BitConverter.ToUInt32(block, 20); PointerToRawData = BitConverter.ToUInt32(block, 24); // Advance to the debug section where we may find the code view info _va = VA + RawData; var b2 = GetVirtualByte(_va); var bytes2 = new byte[16]; var s2 = b2[0]; Array.ConstrainedCopy(b2, 4, bytes2, 0, 16); var gid2 = new Guid(bytes2); // after GUID var age2 = b2[20]; // char* at end var str2 = Encoding.Default.GetString(b2, 24, 32).Trim(); var cv2 = new CODEVIEW_HEADER { VSize = (int)Ext.SizeOfImage, TimeDateStamp = TimeDate2, byteGuid = bytes2, Age = age2, aGuid = gid2, Sig = s2, PdbName = str2 }; if (str2.Contains(".") && str2.Contains(".pdb")) { sec.Name = str2.Substring(0, str2.IndexOf(".pdb") + 4).ToLower(); } else { sec.Name = str2.ToLower(); } sec.DebugDetails = cv2; return(cv2); }
/// <summary> /// Prefer symbol loading. /// </summary> /// <param name="dp"></param> /// <param name="ext"></param> /// <param name="cv_data"></param> /// <param name="SymbolCache"></param> /// <returns></returns> public bool GetKernelDebuggerData(DetectedProc dp, Extract ext, CODEVIEW_HEADER cv_data, string SymbolCache) { DebugHelp.SYMBOL_INFO symInfo = new DebugHelp.SYMBOL_INFO(); bool rv = false; bool GotData = false; // Locate and extract some data points symInfo.SizeOfStruct = 0x58; symInfo.MaxNameLen = 1024; rv = DebugHelp.SymFromName(hCurrentProcess, "KdpDataBlockEncoded", ref symInfo); if(!rv) { WriteLine($"Symbol Find : {new Win32Exception(Marshal.GetLastWin32Error()).Message }."); return rv; } KernelProc = dp; // at this point we should return true if it's encoded or not rv = true; return rv; #if FALSE I'm leaving this in for now just to show the use of DecodePointer if needed since it could be uswed in a scenerio where symbols fail var KdpDataBlockEncoded = dp.GetByteValue(symInfo.Address); // Convention is to use *Address for addresses or the simple name is the value it is assumed to be a pointer dp.SymbolStore["KdDebuggerDataBlockAddress"] = GetSymAddress(dp, "KdDebuggerDataBlock"); if (KdpDataBlockEncoded == 0) WriteColor(ConsoleColor.Green, $"Kernel KdDebuggerDataBlock @ {dp.SymbolStore["KdDebuggerDataBlockAddress"]:X16} not encoded."); else { #if FALSE_NOT_NEEDED_IF_WE_USE_SYMBOLS var KdDebuggerDataBlock = dp.VGetBlockLong(dp.KdDebuggerDataBlockAddress, ref GotData); if (!GotData) WriteColor(ConsoleColor.Red, "Unable to read debuggerdatablock array"); // Windbg tells us the diff for loaded modules is 0x48 and active proc is 0x50 var EncLoadedModuleList = KdDebuggerDataBlock[9]; var EncActiveProcessList = KdDebuggerDataBlock[0xA]; var PsLoadedModuleList = (long) DecodePointer((ulong) dp.KdDebuggerDataBlockAddress, (ulong)dp.KiWaitAlways, (ulong)dp.KiWaitNever,(ulong) EncLoadedModuleList); var PsActiveProcessHead = (long) DecodePointer((ulong) dp.KdDebuggerDataBlockAddress, (ulong)dp.KiWaitAlways, (ulong)dp.KiWaitNever, (ulong) EncActiveProcessList); WriteColor(ConsoleColor.Cyan, $"Decoded LoadedModuleList {PsLoadedModuleList}, ActiveProcessList {PsActiveProcessHead}"); #endif } return rv; #endif }
public bool TryLoadSymbols(CODEVIEW_HEADER cv_data, long BaseVA, string SymPath) { ulong KernRange = 0xffff000000000000; // sign extend BaseVA for kernel ranges if ((BaseVA & 0xf00000000000) != 0) BaseVA |= (long)KernRange; DebugHelp.SymSetOptions(DebugHelp.SymOptions.SYMOPT_DEBUG); bool symStatus = DebugHelp.SymInitialize(hCurrentProcess, SymPath, false); if(!symStatus) WriteLine($"symbol status {symStatus}: {new Win32Exception(Marshal.GetLastWin32Error()).Message }"); StringBuilder sbx = new StringBuilder(1024); int three = 0; var flags = DebugHelp.SSRVOPT_GUIDPTR; symStatus = DebugHelp.SymFindFileInPathW(hCurrentProcess, null, cv_data.PdbName, ref cv_data.aGuid, cv_data.Age, three, flags, sbx, IntPtr.Zero, IntPtr.Zero); // try twice, just in case if (!symStatus) symStatus = DebugHelp.SymFindFileInPathW(hCurrentProcess, null, cv_data.PdbName, ref cv_data.aGuid, cv_data.Age, three, flags, sbx, IntPtr.Zero, IntPtr.Zero); if (symStatus) WriteColor(ConsoleColor.Cyan, $"Symbols found: {sbx.ToString()}"); if (!symStatus) { WriteLine($"Symbol returned {symStatus}: {new Win32Exception(Marshal.GetLastWin32Error()).Message }, attempting less precise request."); flags = DebugHelp.SSRVOPT_DWORDPTR; var refBytes = BitConverter.GetBytes(cv_data.TimeDateStamp); GCHandle pinnedArray = GCHandle.Alloc(refBytes, GCHandleType.Pinned); IntPtr pointer = pinnedArray.AddrOfPinnedObject(); symStatus = DebugHelp.SymFindFileInPath(hCurrentProcess, null, cv_data.PdbName, pointer, cv_data.VSize, three, flags, sbx, IntPtr.Zero, IntPtr.Zero); pinnedArray.Free(); if (!symStatus) WriteColor(ConsoleColor.Red, $"Find Symbols returned value: {symStatus}:[{sbx.ToString()}]"); } if (symStatus) { var symLoaded = DebugHelp.SymLoadModuleEx(hCurrentProcess, IntPtr.Zero, sbx.ToString(), null, BaseVA, cv_data.VSize, IntPtr.Zero, 0); if (symLoaded == 0) WriteColor(ConsoleColor.Red, $"Load Failed: [{new Win32Exception(Marshal.GetLastWin32Error()).Message }]"); cv_data.PDBFullPath = sbx.ToString(); } return symStatus; }
// TODO: MOVE below to DetectedProc class public CODEVIEW_HEADER ExtractCVDebug(DetectedProc dp, MemSection sec) { uint SizeData=0, RawData=0, PointerToRawData=0; Extract Ext = sec.Module; long VA = sec.VA.Address; if (dp.MemAccess == null) dp.MemAccess = new Mem(MemAccess); var _va = VA + Ext.DebugDirPos; var block = dp.VGetBlock(_va); var TimeDate2 = BitConverter.ToUInt32(block, ((int) Ext.DebugDirPos & 0xfff) + 4); if(TimeDate2 != Ext.TimeStamp & Vtero.VerboseOutput) { WriteColor(ConsoleColor.Yellow, "Unable to lock on to CV data."); return null; } if(Vtero.VerboseOutput) WriteColor(ConsoleColor.Green, $"Locked on to CV Debug info. Time2 = {TimeDate2:X} Time1 = {Ext.TimeStamp:X}"); var max_offset = (int)(_va & 0xfff) + 28; if (max_offset > 0x1000) { if (Vtero.VerboseOutput) WriteColor(ConsoleColor.Yellow, "CV block seems too straddle into next block (too large)"); return null; } SizeData = BitConverter.ToUInt32(block, (int)(_va & 0xfff) + 16); RawData = BitConverter.ToUInt32(block, (int)(_va & 0xfff) + 20); PointerToRawData = BitConverter.ToUInt32(block, (int)(_va & 0xfff) + 24); _va = VA + RawData; var bytes = new byte[16]; block = dp.VGetBlock(_va); // first 4 bytes var sig = block[((int)_va & 0xfff)]; Array.ConstrainedCopy(block, (((int) _va & 0xfff) + 4), bytes, 0, 16); var gid = new Guid(bytes); // after GUID var age = block[((int)_va & 0xfff) + 20]; // char* at end var str = Encoding.Default.GetString(block, (((int)_va & 0xfff) + 24), 32).Trim(); if (Vtero.VerboseOutput) { WriteLine($"Size = {SizeData} \t Raw = {RawData} \t Pointer {PointerToRawData}"); WriteLine($"Str {str} : GUID : {gid} : AGE {age}"); } var cv = new CODEVIEW_HEADER { VSize = (int) Ext.SizeOfImage, TimeDateStamp = TimeDate2, byteGuid = bytes, Age = age, aGuid = gid, Sig = sig, PdbName = str }; sec.DebugDetails = cv; return cv; }