Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
tvass83 committed May 5, 2020
1 parent 5bcfe6e commit 4b73a28
Show file tree
Hide file tree
Showing 14 changed files with 668 additions and 0 deletions.
10 changes: 10 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
################################################################################
# This .gitignore file was automatically created by Microsoft(R) Visual Studio.
################################################################################

*.pdb
*.sqlite
/.vs
/packages
/WcfDumper/obj
/WcfDumper/bin
25 changes: 25 additions & 0 deletions WcfDumper.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.29519.87
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WcfDumper", "WcfDumper\WcfDumper.csproj", "{3DEA7A1C-FC22-41DD-B9C7-4593D497A730}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{3DEA7A1C-FC22-41DD-B9C7-4593D497A730}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3DEA7A1C-FC22-41DD-B9C7-4593D497A730}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3DEA7A1C-FC22-41DD-B9C7-4593D497A730}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3DEA7A1C-FC22-41DD-B9C7-4593D497A730}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {2CC9585E-8222-43C4-9BD7-B238083E5893}
EndGlobalSection
EndGlobal
6 changes: 6 additions & 0 deletions WcfDumper/App.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
</startup>
</configuration>
89 changes: 89 additions & 0 deletions WcfDumper/DataModel/DataTargetWrapper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
using Microsoft.Diagnostics.Runtime;
using System;
using System.Collections.Generic;
using WcfDumper.Helpers;

namespace WcfDumper.DataModel
{
public class DataTargetWrapper
{
private string myFile;
private int myPid;

public DataTargetWrapper(string file)
{
myFile = file;
}

public DataTargetWrapper(int pid)
{
myPid = pid;
}

public void Process()
{
bool isTargetx64 = ProcessHelper.NativeMethods.Is64Bit(myPid);

bool archmatch = (isTargetx64 && Environment.Is64BitProcess) ||
(!isTargetx64 && !Environment.Is64BitProcess);

if (!archmatch)
{
Console.WriteLine($"PID: {myPid} - Inconsistent process architecture.");
return;
}

using (DataTarget dataTarget = GetDataTarget())
{
foreach (ClrInfo clrVersionInfo in dataTarget.ClrVersions)
{
ClrInfoCallback?.Invoke(clrVersionInfo);
}

if (dataTarget.ClrVersions.Count == 0)
{
Console.WriteLine($"PID: {myPid} - Not a managed executable.");
return;
}

ClrInfo runtimeInfo = dataTarget.ClrVersions[0];
ClrRuntime runtime = runtimeInfo.CreateRuntime();
ClrHeap heap = runtime.Heap;

if (!heap.CanWalkHeap)
{
ClrHeapIsNotWalkableCallback?.Invoke();
return;
}
foreach (ulong obj in heap.EnumerateObjectAddresses())
{
ClrType type = heap.GetObjectType(obj);

// If heap corruption, continue past this object.
if (type == null)
continue;

if (TypesToDump.Contains(type.Name))
{
ClrObjectOfTypeFoundCallback(heap, obj, type.Name);
}
}
}
}

private DataTarget GetDataTarget()
{
if (myFile != null)
{
return DataTarget.LoadCrashDump(myFile);
}

return DataTarget.AttachToProcess(myPid, 5000, AttachFlag.NonInvasive);
}

public Action<ClrInfo> ClrInfoCallback;
public Action ClrHeapIsNotWalkableCallback;
public Action<ClrHeap, ulong, string> ClrObjectOfTypeFoundCallback;
public HashSet<string> TypesToDump = new HashSet<string>();
}
}
10 changes: 10 additions & 0 deletions WcfDumper/DataModel/OperationDescriptionEntry.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using System.Collections.Generic;

namespace WcfDumper.DataModel
{
public class OperationDescriptionEntry
{
public string OperationName;
public List<string> OperationBehaviors = new List<string>();
}
}
10 changes: 10 additions & 0 deletions WcfDumper/DataModel/ProcessInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace WcfDumper.DataModel
{
public class ProcessInfo
{
public int PID;
public string Name;
public string Path;
public string CmdLine;
}
}
17 changes: 17 additions & 0 deletions WcfDumper/DataModel/ServiceDescriptionEntry.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using System.Collections.Generic;

namespace WcfDumper.DataModel
{
public class ServiceDescriptionEntry
{
public ServiceDescriptionEntry(int pid)
{
ProcessInfo = new ProcessInfo();
ProcessInfo.PID = pid;
}

public ProcessInfo ProcessInfo;
public List<string> ServiceBehaviors = new List<string>();
public List<ServiceEndpointEntry> ServiceEndpoints = new List<ServiceEndpointEntry>();
}
}
14 changes: 14 additions & 0 deletions WcfDumper/DataModel/ServiceEndpointEntry.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using System.Collections.Generic;

namespace WcfDumper.DataModel
{
public class ServiceEndpointEntry
{
public string Uri;
public string Contract;
public string CallbackContract;
public List<string> EndpointBehaviors = new List<string>();
public List<string> ContractBehaviors = new List<string>();
public List<OperationDescriptionEntry> ContractOperations = new List<OperationDescriptionEntry>();
}
}
73 changes: 73 additions & 0 deletions WcfDumper/Helpers/ClrMdHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
using Microsoft.Diagnostics.Runtime;
using System.Collections.Generic;
using System.Diagnostics;
using WcfDumper.DataModel;

namespace WcfDumper.Helpers
{
public static class ClrMdHelper
{
public static DataTargetWrapper LoadDumpFile(string file)
{
return new DataTargetWrapper(file);
}

public static DataTargetWrapper AttachToLiveProcess(int pid)
{
return new DataTargetWrapper(pid);
}

public static List<ulong> GetLastObjectInHierarchyAsArray(ClrHeap heap, ulong obj, string[] hierarchy, int currentIndex, string arrayTypeToVerify)
{
ulong arrayObj = ClrMdHelper.GetLastObjectInHierarchy(heap, obj, hierarchy, currentIndex);
ClrType arrayType = heap.GetObjectType(arrayObj);

Debug.Assert(arrayType.Name == arrayTypeToVerify);

List<ulong> arrayItems = GetArrayItems(arrayType, arrayObj);
return arrayItems;
}

public static List<ulong> GetArrayItems(ClrType type, ulong items)
{
int length = type.GetArrayLength(items);
var ret = new List<ulong>();

for (int i = 0; i < length; i++)
{
var val = (ulong)type.GetArrayElementValue(items, i);

if (val != 0)
{
ret.Add(val);
}
}

return ret;
}

public static ulong GetLastObjectInHierarchy(ClrHeap heap, ulong heapobject, string[] hierarchy, int currentIndex)
{
ClrType type = heap.GetObjectType(heapobject);
ClrInstanceField field = type.GetFieldByName(hierarchy[currentIndex]);
ulong fieldValue = (ulong)field.GetValue(heapobject, false, false);

currentIndex++;
if (currentIndex == hierarchy.Length)
{
return fieldValue;
}

return GetLastObjectInHierarchy(heap, fieldValue, hierarchy, currentIndex);
}

public static T GetObjectAs<T>(ClrHeap heap, ulong heapobject, string fieldName)
{
ClrType type = heap.GetObjectType(heapobject);
ClrInstanceField field = type.GetFieldByName(fieldName);
T fieldValue = (T)field.GetValue(heapobject);

return fieldValue;
}
}
}
68 changes: 68 additions & 0 deletions WcfDumper/Helpers/ProcessHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
using WcfDumper.DataModel;

namespace WcfDumper.Helpers
{
public static class ProcessHelper
{
public static ProcessInfo GetProcessDetails(int pid)
{
var pi = new ProcessInfo();
pi.PID = pid;

return pi;
}

public static List<int> GetPIDs(string wildcard)
{
var processes = Process.GetProcesses();
var ret = new List<int>();
Regex regex = new Regex(wildcard, RegexOptions.IgnoreCase);

foreach (var process in processes)
{
using (process)
{
if (regex.IsMatch(process.ProcessName))
{
ret.Add(process.Id);
}
}
}

return ret;
}

internal static class NativeMethods
{
public static bool Is64Bit(int pid)
{
if (!Environment.Is64BitOperatingSystem)
{
return false;
}

bool isWow64;

using (var process = Process.GetProcessById(pid))
{
if (!IsWow64Process(process.Handle, out isWow64))
{
throw new Win32Exception();
}
}

return !isWow64;
}

[DllImport("kernel32.dll", SetLastError = true, CallingConvention = CallingConvention.Winapi)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool IsWow64Process([In] IntPtr process, [Out] out bool wow64Process);
}
}
}
Loading

0 comments on commit 4b73a28

Please sign in to comment.