private Dictionary<int, string> GetManagedThreadNames(ClrHeap heap) { var result = new Dictionary<int, string>(); if (!heap.CanWalkHeap) return result; var threadObjects = from obj in heap.EnumerateObjectAddresses() let type = heap.GetObjectType(obj) where type != null && type.Name == "System.Threading.Thread" select obj; var threadType = heap.GetTypeByName("System.Threading.Thread"); var nameField = threadType.GetFieldByName("m_Name"); var managedIdField = threadType.GetFieldByName("m_ManagedThreadId"); foreach (var threadObject in threadObjects) { string name = (string)nameField.GetValue(threadObject); int id = (int)managedIdField.GetValue(threadObject); result.Add(id, name); } return result; }
private static void DumpRetention(DataTarget dataTarget, ClrInfo clrVersion, ClrRuntime runtime, ClrAppDomain appDomain, ClrHeap heap, string targetType) { var graph = new Graph(); Console.WriteLine("## What's the retention path of the {0} object?", targetType); Console.WriteLine(""); foreach (var ptr in heap.EnumerateObjectAddresses()) { var type = heap.GetObjectType(ptr); if (type == null || type.Name != targetType) { continue; } // Enumerate roots and try to find the current object var stack = new Stack <ulong>(); foreach (var root in heap.EnumerateRoots()) { stack.Clear(); stack.Push(root.Object); if (GetPathToObject(heap, ptr, stack, new HashSet <ulong>())) { // Print retention path var depth = 0; var previousAddress = (ulong)0; foreach (var address in stack) { var t = heap.GetObjectType(address); if (t == null) { continue; } Console.WriteLine("{0} {1} - {2} - {3} bytes", new string('+', depth++), address, t.Name, t.GetSize(address)); graph.AddNode(address.ToString()).LabelText = $"{t.Name} ({address})"; if (previousAddress > 0 && !graph.Edges.Any(e => e.Source == previousAddress.ToString() && e.Target == address.ToString())) { graph.AddEdge(previousAddress.ToString(), address.ToString()); } previousAddress = address; } Console.WriteLine(); } } } Console.ReadLine(); // Render graph var width = 1600; var renderer = new GraphRenderer(graph); renderer.CalculateLayout(); var bitmap = new Bitmap(width, (int)(graph.Height * (width / graph.Width)), PixelFormat.Format32bppRgb); renderer.Render(bitmap); bitmap.Save("test.png"); Process.Start("test.png"); }
private static KeyValuePair <bool, string> Enumerate() { //Attach to target process DataTarget dt = null; try { dt = DataTarget.AttachToProcess(targetPID, 10000, AttachFlag.NonInvasive); } catch (Exception e) { return(new KeyValuePair <bool, string>(false, e.ToString())); } //If no ClrVersions, return if (dt.ClrVersions.Count == 0) { return(new KeyValuePair <bool, string>(false, "[!] No Clr Versions detected")); } #if DEBUG foreach (var ver in dt.ClrVersions) { Console.WriteLine("Clr Runtime Version Found: " + ver.Version.ToString()); } #endif ClrInfo Version = dt.ClrVersions[0]; try { cRun = Version.CreateRuntime(); #if DEBUG Console.WriteLine("[+] Created Runtime"); #endif } catch (Exception e) { #if DEBUG Console.WriteLine("[!] Failed to create runtime"); #endif return(new KeyValuePair <bool, string>(false, e.ToString())); } ClrHeap Heap = cRun.GetHeap(); //if we can't walk the heap, return if (!Heap.CanWalkHeap) { return(new KeyValuePair <bool, string>(false, "[!] Unable to walk the heap")); } Console.WriteLine("[+] Walking the heap...."); string m = WildCardToRegWithQM("System.*"); string m1 = WildCardToRegWithQM("_*"); string m2 = WildCardToRegWithQM("Microsoft.*"); foreach (ulong obj in Heap.EnumerateObjectAddresses()) { //Grab each object, check if it has a simple value, if so, display it ClrType type = Heap.GetObjectType(obj); if (TypeName != null) { if (type == null && type.Name == TypeName || Regex.IsMatch(type.Name, m) || Regex.IsMatch(type.Name, m1) || Regex.IsMatch(type.Name, m2) || type.Name == "Free") { continue; } } else { if (type == null || Regex.IsMatch(type.Name, m) || Regex.IsMatch(type.Name, m1) || Regex.IsMatch(type.Name, m2) || type.Name == "Free") { continue; } } if (!type.IsPrimitive) { #if DEBUG Console.WriteLine("[+] Enumerating type: " + type.Name); #endif //if the type has a simple value, add the type and its value to the results resultOutput.Append("\r\nType: " + type.Name + "\r\n\r\n"); //Enumerate all of the instance fields for the given type if (showFields) { if (type.Fields != null) { GetInstanceFields(type.Fields, obj); } } if (showstaticFields) { if (type.StaticFields != null) { GetStaticFields(type.StaticFields, cRun.AppDomains[0]); } } if (showMethods) { if (type.Methods != null) { GetMethods(type.Methods); } } if (referenceObjects) { resultOutput.Append("\r\nReferencedTypes\r\n\r\n"); List <ulong> referencedObjects = ClrMDHelper.GetReferencedObjects(Heap, obj); foreach (ulong refObj in referencedObjects) { ClrType refObjType = Heap.GetObjectType(refObj); if (refObjType == null || Regex.IsMatch(refObjType.Name, m) || Regex.IsMatch(refObjType.Name, m1) || Regex.IsMatch(refObjType.Name, m2) || refObjType.Name == "Free") { continue; } if (showFields) { if (refObjType.Fields != null) { GetInstanceFields(refObjType.Fields, obj, fieldName); } } if (showstaticFields) { if (refObjType.StaticFields != null) { GetStaticFields(refObjType.StaticFields, cRun.AppDomains[0], fieldName); } } if (showMethods) { if (refObjType.Methods != null) { GetMethods(refObjType.Methods); } } } } } } return(new KeyValuePair <bool, string>(true, "[+] Successfully walked the heap.")); }
public void OptimizedClassHistogram() { using (DataTarget dt = TestTargets.Types.LoadFullDump()) { ClrRuntime runtime = dt.ClrVersions.Single().CreateRuntime(); ClrHeap heap = runtime.Heap; // ensure that the optimized version is faster than the default one Stopwatch timing = new Stopwatch(); var notOptimizedStatistics = new Dictionary <ClrType, TypeEntry>(32768); int notOptimizedObjectCount = 0; // with an optimized version timing.Start(); foreach (var objDetails in heap.EnumerateObjectDetails()) { ClrType type = objDetails.Item3; ulong size = objDetails.Item4; TypeEntry entry; if (!notOptimizedStatistics.TryGetValue(type, out entry)) { entry = new TypeEntry() { TypeName = type.Name, Size = 0 }; notOptimizedStatistics[type] = entry; } entry.Count++; entry.Size += size; notOptimizedObjectCount++; } timing.Stop(); var notOptimizedTime = TimeSpan.FromMilliseconds(timing.ElapsedMilliseconds); // with an non-optimized version var statistics = new Dictionary <ClrType, TypeEntry>(32768); int objectCount = 0; timing.Restart(); foreach (ulong objAddress in heap.EnumerateObjectAddresses()) { ClrType type = heap.GetObjectType(objAddress); ulong size = type.GetSize(objAddress); TypeEntry entry; if (!statistics.TryGetValue(type, out entry)) { entry = new TypeEntry() { TypeName = type.Name, Size = 0 }; statistics[type] = entry; } entry.Count++; entry.Size += size; objectCount++; } timing.Stop(); // check object count Assert.AreEqual(notOptimizedObjectCount, objectCount); // check heap content var types = notOptimizedStatistics.Keys; foreach (var type in types) { var notOptimizedDetails = notOptimizedStatistics[type]; var details = statistics[type]; Assert.AreEqual(notOptimizedDetails.TypeName, details.TypeName); Assert.AreEqual(notOptimizedDetails.Count, details.Count); Assert.AreEqual(notOptimizedDetails.Size, details.Size); } Assert.AreEqual(types.Count, statistics.Count); // checking that optimized is faster could be flaky // Assert.IsTrue(notOptimizedTime > TimeSpan.FromMilliseconds(timing.ElapsedMilliseconds)); } }
// Returns all the info about any Composite Keys stored in memory public static List <CompositeKeyInfo> GetCompositeKeyInfo(Process process) { List <CompositeKeyInfo> keyInfo = new List <CompositeKeyInfo>(); DataTarget dt = null; string databaseLocation = ""; try { dt = DataTarget.AttachToProcess(process.Id, 50000); if (dt.ClrVersions.Count == 0) { string err = "CLR is not loaded. Is it Keepass 1.x, perhaps?"; Logger.WriteLine(err); throw new Exception(err); } if (dt.ClrVersions.Count > 1) { Logger.WriteLine("*** Interesting... there are multiple .NET runtimes loaded in KeePass"); } ClrInfo Version = dt.ClrVersions[0]; ClrRuntime Runtime = Version.CreateRuntime(); ClrHeap Heap = Runtime.GetHeap(); if (!Heap.CanWalkHeap) { string err = "Error: Cannot walk the heap!"; Logger.WriteLine(err); throw new Exception(err); } foreach (ulong obj in Heap.EnumerateObjectAddresses()) { ClrType type = Heap.GetObjectType(obj); if (type == null || type.Name != "KeePassLib.PwDatabase") { continue; } Logger.WriteLine("************ Found a PwDatabase! **********"); List <ulong> referencedObjects = ClrMDHelper.GetReferencedObjects(Heap, obj); // First walk the referenced objects to find the database path foreach (ulong refObj in referencedObjects) { ClrType refObjType = Heap.GetObjectType(refObj); if (refObjType.Name == "KeePassLib.Serialization.IOConnectionInfo") { ClrInstanceField UrlField = refObjType.GetFieldByName("m_strUrl"); ulong UrlFieldAddr = UrlField.GetAddress(refObj); object Url = UrlField.GetValue(UrlFieldAddr, true); databaseLocation = (string)Url; } } if (databaseLocation != "") { Logger.WriteLine("*** PwDatabase location : " + databaseLocation); referencedObjects = ClrMDHelper.GetReferencedObjects(Heap, obj); // now walk the referenced objects looking for a master composite key foreach (ulong refObj in referencedObjects) { ClrType refObjType = Heap.GetObjectType(refObj); if (refObjType.Name == "KeePassLib.Keys.CompositeKey") { Logger.WriteLine("************ Found a CompositeKey! **********"); CompositeKeyInfo CompositeKey = new CompositeKeyInfo(); // Get all objects kept alive by the composite key. // (A shortcut to get references to all Key types) List <ulong> referencedObjects2 = ClrMDHelper.GetReferencedObjects(Heap, refObj); foreach (ulong refObj2 in referencedObjects2) { ClrType refObjType2 = Heap.GetObjectType(refObj2); if (refObjType2.Name == "KeePassLib.Keys.KcpPassword") { KcpPassword KcpPassword = GetKcpPasswordInfo(refObj2, refObjType2, Heap, databaseLocation); if (KcpPassword == null) { continue; } CompositeKey.AddUserKey(KcpPassword); } else if (refObjType2.Name == "KeePassLib.Keys.KcpKeyFile") { KcpKeyFile KcpKeyFile = GetKcpKeyFileInfo(refObj2, refObjType2, Heap, databaseLocation); if (KcpKeyFile == null) { continue; } CompositeKey.AddUserKey(KcpKeyFile); } else if (refObjType2.Name == "KeePassLib.Keys.KcpUserAccount") { KcpUserAccount KcpUserAccount = GetKcpUserAccountInfo(refObj2, refObjType2, Heap, databaseLocation); if (KcpUserAccount == null) { continue; } CompositeKey.AddUserKey(KcpUserAccount); } } if (CompositeKey.UserKeyCount > 0) { keyInfo.Add(CompositeKey); } } } } } Logger.Write("\n"); } catch (Exception e) { Logger.WriteLine(e.Message); throw; } finally { if (dt != null) { dt.Dispose(); } } return(keyInfo); }