├── .gitignore ├── GM ├── GM.csproj ├── Program.cs ├── Properties │ └── launchSettings.json └── Recycle.ico ├── GMLib ├── Collector.cs ├── Constants.cs ├── DataBase.cs ├── DataBaseContext.cs ├── GMData.cs ├── GMLib.csproj ├── NativeInterfaces.cs ├── ProcessEnumerator.cs └── Target.cs ├── GarbageMan.sln ├── GarbageMan ├── App.xaml ├── App.xaml.cs ├── AssemblyInfo.cs ├── Attach.xaml ├── Attach.xaml.cs ├── Bookmarks.xaml ├── Bookmarks.xaml.cs ├── CrashDump.xaml ├── CrashDump.xaml.cs ├── EventHandlers.cs ├── GarbageMan.csproj ├── GarbageMan.csproj.user ├── MainWindow.xaml ├── MainWindow.xaml.cs ├── PathViewer.xaml ├── PathViewer.xaml.cs ├── PickProcess.xaml ├── PickProcess.xaml.cs ├── Properties │ ├── Resources.Designer.cs │ ├── Resources.resx │ └── launchSettings.json ├── RawSql.xaml ├── RawSql.xaml.cs ├── RunExecutable.xaml ├── RunExecutable.xaml.cs ├── SmartRefs.cs ├── Snapshots.xaml ├── Snapshots.xaml.cs ├── ThreadContext.cs ├── Tracer.xaml ├── Tracer.xaml.cs ├── UIObjects.cs └── assets │ ├── AddBookmark.png │ ├── Analyze.png │ ├── Back.png │ ├── CSFile.png │ ├── Close.png │ ├── Copy.png │ ├── Execute.png │ ├── Exit.png │ ├── Home.png │ ├── New.png │ ├── Open.png │ ├── Process.png │ ├── Recycle.ico │ ├── RemoveBookmark.png │ ├── SQL.png │ ├── Save.png │ ├── Search.png │ └── SmartRefs.png ├── LICENSE ├── README.md ├── Search.json ├── build.bat ├── compress.ps1 └── psnotify ├── .gitignore ├── README.md ├── dump ├── dump.cpp ├── dump.vcxproj ├── dump.vcxproj.filters └── dump.vcxproj.user ├── exe ├── psnotify.cpp ├── psnotify.sln ├── psnotify.vcxproj ├── psnotify.vcxproj.filters └── psnotify.vcxproj.user ├── hook ├── Source.def ├── dllmain.cpp ├── framework.h ├── hook.vcxproj ├── hook.vcxproj.filters ├── hook.vcxproj.user ├── packages.config ├── pch.cpp └── pch.h ├── include └── psnotify.h ├── inject ├── creatwth.cpp ├── detours.cpp ├── detours.h ├── detver.h ├── disasm.cpp ├── disolarm.cpp ├── disolarm64.cpp ├── disolia64.cpp ├── disolx64.cpp ├── disolx86.cpp ├── image.cpp ├── inject.cpp ├── inject.vcxproj ├── inject.vcxproj.filters ├── inject.vcxproj.user ├── modules.cpp └── uimports.cpp ├── readme └── sys ├── Retpoline.props ├── main.cpp ├── memobj.cpp ├── memobj.h ├── psnotify.inf ├── psnotify.sln ├── psnotify.vcxproj ├── psnotify.vcxproj.user ├── stdafx.cpp ├── stdafx.h ├── ver.h ├── version.h └── version.rc /.gitignore: -------------------------------------------------------------------------------- 1 | GarbageMan/bin 2 | GarbageMan/obj 3 | GM/bin 4 | GM/obj 5 | GMLib/bin 6 | GMLib/obj 7 | rel/ 8 | .vs/ -------------------------------------------------------------------------------- /GM/GM.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | net5.0 6 | AnyCPU;x86;x64 7 | Recycle.ico 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /GM/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "GM": { 4 | "commandName": "Project", 5 | "commandLineArgs": "--pid 20980 --debug " 6 | } 7 | } 8 | } -------------------------------------------------------------------------------- /GM/Recycle.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WithSecureLabs/GarbageMan/1229c2ef89f400e709431977f05dac96961d914e/GM/Recycle.ico -------------------------------------------------------------------------------- /GMLib/Collector.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using System.Collections.Generic; 4 | using System.Diagnostics; 5 | using Microsoft.Diagnostics.Runtime; 6 | using System.IO; 7 | 8 | namespace GMLib 9 | { 10 | 11 | public class DebugEventArgs : EventArgs 12 | { 13 | public string Msg { get; set; } 14 | public DebugEventArgs(string msg) 15 | { 16 | Msg = msg; 17 | } 18 | } 19 | // Collector's job is to organize all the data sources (processes, dumps, snapshots etc) 20 | // as a single, coherent source of events 21 | // XXX: add support for DataTarget.CreateSnapshotAndAttach and use threading for processing targets 22 | public class Collector 23 | { 24 | 25 | private bool Stopped = false; 26 | public uint Flags { get; set; } 27 | public uint InitialFlags { get; set; } 28 | public int Interval { get; set; } 29 | public int Count { get; set; } 30 | public string Path { get; set; } 31 | public string Args { get; set; } 32 | public string WorkingDirectory { get; set; } 33 | public int Delay { get; set; } 34 | public string CrashDump { get; set; } 35 | public int Pid { get; set; } 36 | public List Pids { set; get; } = new(); 37 | public DataBase Db { get; set; } = null; 38 | string DataBasePath { get; set; } 39 | 40 | public event EventHandler DoneEventHandler; 41 | 42 | // Just a proxy from target handlers 43 | public event EventHandler DataEventHandler; 44 | 45 | public event EventHandler DebugEventHandler; 46 | 47 | void DbgMsg(string msg) 48 | { 49 | DebugEventHandler?.Invoke(this, new DebugEventArgs(msg)); 50 | } 51 | 52 | public Collector( 53 | int pid, 54 | string dataBasePath = null, 55 | uint flags = Constants.COLLECT_EVERYTHING, 56 | uint initialFlags = Constants.COLLECT_EVERYTHING, 57 | int dumpInterval = 0, 58 | int dumpCount = 1) 59 | { 60 | Interval = dumpInterval; 61 | Count = dumpCount; 62 | Pid = pid; 63 | Flags = flags; 64 | InitialFlags = initialFlags; 65 | DataBasePath = dataBasePath; 66 | } 67 | 68 | public Collector( 69 | string crashDump, 70 | uint flags = Constants.COLLECT_EVERYTHING, 71 | uint initialFlags = Constants.COLLECT_EVERYTHING, 72 | string dataBasePath = null, 73 | int dumpInterval = 0, 74 | int dumpCount = 1) 75 | { 76 | Interval = dumpInterval; 77 | Count = dumpCount; 78 | CrashDump = crashDump; 79 | Flags = flags; 80 | InitialFlags = initialFlags; 81 | DataBasePath = dataBasePath; 82 | } 83 | 84 | // Added the option to set the working directory for the process 85 | public Collector( 86 | string path, 87 | string args, 88 | string workingDirectory, 89 | int delay = 500, 90 | uint flags = Constants.COLLECT_EVERYTHING, 91 | uint initialFlags = Constants.COLLECT_EVERYTHING, 92 | string dataBasePath = null, 93 | int dumpInterval = 0, 94 | int dumpCount = 1) 95 | { 96 | Path = path; 97 | Args = args; 98 | WorkingDirectory = workingDirectory; 99 | Delay = delay; 100 | Interval = dumpInterval; 101 | Count = dumpCount; 102 | Flags = flags; 103 | InitialFlags = initialFlags; 104 | DataBasePath = dataBasePath; 105 | } 106 | 107 | // XXX: how to handle child processes? 108 | // Maybe some external tool for checking any children when looping over snapshots? 109 | // This loop needs to be completely rewritten for child process support, now it's messy 110 | public int Run() 111 | { 112 | DbgMsg($"Collector started for {Count} snapshots, flags: {InitialFlags:X8}"); 113 | 114 | if (DataBasePath != null) 115 | Db = new(DataBasePath); 116 | 117 | uint flags = InitialFlags; 118 | long time = 0; 119 | int id; 120 | for (id = 1; id < Count+1; id++) 121 | { 122 | GMProcess process = new(); 123 | Target target = null; 124 | if (Pid != 0) 125 | { 126 | DbgMsg($"Attaching to process {Pid}"); 127 | // Add process only once 128 | if (id == 1) 129 | { 130 | process.Pid = Pid; 131 | process.Arch = IntPtr.Size == 8 ? "AMD64" : "X86"; 132 | process.Date = DateTime.Now.ToString(); 133 | process.Path = ""; 134 | } 135 | try 136 | { 137 | target = new Target(DataTarget.AttachToProcess(Pid, suspend: true), time, id, Pid, flags); 138 | } 139 | catch (Exception e) 140 | { 141 | if (id == 1) throw; 142 | else 143 | { 144 | DbgMsg(e.Message); 145 | break; 146 | } 147 | } 148 | } 149 | else if (CrashDump != null) 150 | { 151 | DbgMsg($"Using crash dump file {CrashDump}"); 152 | process.Pid = 0; 153 | process.Path = CrashDump; 154 | process.Arch = IntPtr.Size == 8 ? "AMD64" : "X86"; 155 | process.Date = DateTime.Now.ToString(); 156 | target = new Target(DataTarget.LoadDump(CrashDump), time, id, flags: flags); 157 | } 158 | else if (Path != null) 159 | { 160 | DbgMsg($"Starting process {Path} with arguments: {Args}"); 161 | Process proc = new Process(); 162 | proc.StartInfo.UseShellExecute = false; 163 | proc.StartInfo.FileName = Path; 164 | if (Args != null) 165 | proc.StartInfo.Arguments = Args; 166 | if (WorkingDirectory != null) 167 | proc.StartInfo.WorkingDirectory = WorkingDirectory; 168 | proc.StartInfo.CreateNoWindow = true; 169 | proc.Start(); 170 | Pid = proc.Id; 171 | 172 | process.Pid = Pid; 173 | process.Path = Path; 174 | process.Args = Args; 175 | process.Arch = IntPtr.Size == 8 ? "AMD64" : "X86"; 176 | process.Date = DateTime.Now.ToString(); 177 | Thread.Sleep(Delay); 178 | time += Delay; 179 | target = new Target(DataTarget.AttachToProcess(Pid, suspend: true), time, id, Pid, flags); 180 | } 181 | if (target == null) 182 | { 183 | if (id == 1) 184 | throw new Exception("Cannot find suitable data target"); 185 | else break; 186 | } 187 | 188 | GMSnapshot snapshot = new GMSnapshot 189 | { 190 | Id = id, 191 | Pid = Pid, 192 | Time = time, 193 | PointerSize = target.Dt.DataReader.PointerSize 194 | }; 195 | 196 | target.DataEventHandler += (obj, evt) => 197 | { 198 | // Just push the object to caller if needed 199 | DataEventHandler?.Invoke(obj, evt); 200 | Stopped = evt.Stop; 201 | }; 202 | 203 | target.DebugEventHandler += (obj, evt) => 204 | { 205 | DbgMsg(evt.Msg); 206 | }; 207 | 208 | DbgMsg($"Action: Processing target {id} with pid={target.Pid}..."); 209 | try 210 | { 211 | target.Collect(); 212 | } 213 | catch (Exception e) 214 | { 215 | DbgMsg(e.Message); 216 | // Scan was canceled 217 | if (Stopped) 218 | { 219 | DbgMsg("User stopped data collection."); 220 | } 221 | target.Close(); 222 | // First target failed, throw exception 223 | if (id == 1) 224 | throw; 225 | else break; 226 | } 227 | 228 | if (DataBasePath != null) 229 | DbgMsg("Beginning Database coordination..."); 230 | 231 | // Add the process only once 232 | if (id == 1) 233 | { 234 | DbgMsg("Adding process to database..."); 235 | Db?.AddProcess(process); 236 | } 237 | DbgMsg("Adding snapshot to database..."); 238 | Db?.AddSnapshot(snapshot); 239 | DbgMsg("Adding target to database..."); 240 | Db?.AddTarget(target); 241 | target.Close(); 242 | 243 | if (CrashDump != null) 244 | break; 245 | if (id < Count) 246 | { 247 | DbgMsg($"Wait interval: {Interval}ms"); 248 | Thread.Sleep(Interval); 249 | time += Interval; 250 | } 251 | flags = Flags; 252 | } 253 | 254 | DbgMsg($"Collected data from {id} targets"); 255 | DoneEventHandler?.Invoke(this, null); 256 | return 0; 257 | } 258 | } 259 | } 260 | -------------------------------------------------------------------------------- /GMLib/Constants.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace GMLib 8 | { 9 | static public class Constants 10 | { 11 | public const uint COLLECT_MODULES = 0x00000001; 12 | public const uint COLLECT_RUNTIMES = 0x00000002; 13 | public const uint COLLECT_APPDOMAINS = 0x00000004; 14 | public const uint COLLECT_THREADS = 0x00000010; 15 | public const uint COLLECT_STACK = 0x00000100; 16 | public const uint COLLECT_HEAP = 0x00010000; 17 | public const uint COLLECT_HANDLES = 0x00100000; 18 | public const uint COLLECT_REFS = 0x10000000; 19 | public const uint COLLECT_BASIC_INFO = COLLECT_RUNTIMES | COLLECT_APPDOMAINS | COLLECT_MODULES; 20 | public const uint COLLECT_EVERYTHING = 0xFFFFFFFF; 21 | 22 | public const uint CONTEXT_FLAGS_32 = 0x1003F; 23 | public const uint CONTEXT_FLAGS_64 = 0x1001F; 24 | 25 | public const int MAX_STRING_SIZE = 0x10000; 26 | public const int MAX_BUFFER_SIZE = 0x100000; 27 | public const int MAX_INT_REFCOUNT = 1000; 28 | 29 | public const string CMD_OUTPUT_TYPE_MSG = "msg"; 30 | public const string CMD_OUTPUT_TYPE_PROCESS = "process"; 31 | public const string CMD_OUTPUT_TYPE_PSLIST = "pslist"; 32 | 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /GMLib/DataBaseContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using Microsoft.EntityFrameworkCore; 7 | 8 | 9 | namespace GMLib 10 | { 11 | public class DatabaseContext : DbContext 12 | { 13 | public string dbPath { get; set; } 14 | public DatabaseContext(string path) 15 | { 16 | dbPath = path; 17 | } 18 | 19 | public DatabaseContext(DbContextOptions options) 20 | : base(options) 21 | { 22 | } 23 | 24 | public virtual DbSet AppDomains { get; set; } 25 | public virtual DbSet Frames { get; set; } 26 | public virtual DbSet Handles { get; set; } 27 | public virtual DbSet Modules { get; set; } 28 | public virtual DbSet Objects { get; set; } 29 | public virtual DbSet Processes { get; set; } 30 | public virtual DbSet Refs { get; set; } 31 | public virtual DbSet Runtimes { get; set; } 32 | public virtual DbSet Snapshots { get; set; } 33 | public virtual DbSet Stacks { get; set; } 34 | public virtual DbSet Threads { get; set; } 35 | public virtual DbSet Settings { get; set; } 36 | public virtual DbSet Bookmarks { get; set; } 37 | 38 | 39 | protected override void OnConfiguring(DbContextOptionsBuilder options) 40 | { 41 | options.UseSqlite($"Data Source={dbPath};Pooling=False;"); 42 | //options.UseSqlite($"Data Source={dbPath}"); 43 | } 44 | 45 | protected override void OnModelCreating(ModelBuilder modelBuilder) 46 | { 47 | modelBuilder.Entity(entity => 48 | { 49 | entity.HasKey(e => new { e.Id, e.Aid }); 50 | }); 51 | 52 | modelBuilder.Entity(entity => 53 | { 54 | entity.HasKey(e => new { e.Id, e.StackPtr }); 55 | }); 56 | 57 | modelBuilder.Entity(entity => 58 | { 59 | entity.HasKey(e => new { e.Id, e.Address }); 60 | }); 61 | 62 | // XXX: AppDomain id (Aid) as a key 63 | modelBuilder.Entity(entity => 64 | { 65 | entity.HasKey(e => new { e.Id, e.AsmAddress }); 66 | }); 67 | 68 | modelBuilder.Entity(entity => 69 | { 70 | entity.HasKey(e => new { e.Id, e.ObjectId }); 71 | }); 72 | 73 | modelBuilder.Entity(entity => 74 | { 75 | entity.HasKey(e => new { e.Id, e.ObjectId }); 76 | }); 77 | 78 | modelBuilder.Entity(entity => 79 | { 80 | entity.HasKey(e => new { e.Pid }); 81 | }); 82 | 83 | modelBuilder.Entity(entity => 84 | { 85 | entity.HasKey(e => new { e.Id, e.Address, e.Ref }); 86 | }); 87 | 88 | modelBuilder.Entity(entity => 89 | { 90 | entity.HasKey(e => new { e.Id, e.Version }); 91 | }); 92 | 93 | modelBuilder.Entity(entity => 94 | { 95 | entity.HasKey(e => new { e.Id }); 96 | }); 97 | 98 | modelBuilder.Entity(entity => 99 | { 100 | entity.HasKey(e => new { e.Id }); 101 | }); 102 | 103 | modelBuilder.Entity(entity => 104 | { 105 | entity.HasKey(e => new { e.Id, e.StackPtr }); 106 | }); 107 | 108 | modelBuilder.Entity(entity => 109 | { 110 | entity.HasKey(e => new { e.Id, e.Tid }); 111 | }); 112 | 113 | } 114 | 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /GMLib/GMData.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using Microsoft.Diagnostics.Runtime; 7 | 8 | 9 | namespace GMLib 10 | { 11 | public class GMCmdOutput 12 | { 13 | public string Type { get; set; } 14 | public string Msg { get; set; } 15 | } 16 | 17 | public class GMCmdOutputProcess : GMCmdOutput 18 | { 19 | public GMProcessInfo Process { get; set; } 20 | } 21 | public class GMCmdOutputPList: GMCmdOutput 22 | { 23 | public List PList { get; set; } 24 | } 25 | public class GMProcessInfo 26 | { 27 | public int Pid { get; set; } 28 | public string Name { get; set; } 29 | public List Runtimes { get; set; } 30 | } 31 | public class GMObject 32 | { 33 | public ulong Address { get; set; } 34 | public ulong Size { get; set; } 35 | public ulong Index { get; set; } 36 | 37 | private ClrObject _obj; 38 | 39 | private int _pointerSize; 40 | 41 | private object _value = null; 42 | 43 | public GMObject(ClrObject obj, ulong index, int pointerSize = 8) 44 | { 45 | Index = index; 46 | Address = obj.Address; 47 | Size = obj.Size; 48 | _obj = obj; 49 | _pointerSize = pointerSize; 50 | } 51 | public string Type() 52 | { 53 | return _obj.Type.Name; 54 | } 55 | 56 | public object Value() 57 | { 58 | if (_value == null) 59 | { 60 | try 61 | { 62 | _value = _Value(); 63 | } 64 | catch { } 65 | } 66 | return _value; 67 | } 68 | 69 | private object _Value() 70 | { 71 | object retData = null; 72 | switch (_obj.Type.Name) 73 | { 74 | case "System.String": 75 | retData = _obj.AsString(maxLength: Constants.MAX_STRING_SIZE); 76 | break; 77 | case "System.Char": 78 | case "System.Int16": 79 | case "System.Int32": 80 | case "System.UInt16": 81 | case "System.UInt32": 82 | case "System.Boolean": 83 | retData = _obj.ReadField("m_value"); 84 | break; 85 | // XXX: 32/64 bit systems seem to have this diffent 86 | case "System.IntPtr": 87 | case "System.UIntPtr": 88 | if (_pointerSize == 4) 89 | retData = _obj.ReadField("m_value"); 90 | else 91 | retData = _obj.ReadField("_value"); 92 | break; 93 | // XXX: Convert to string to avoid sqlite "NaN" problem, or maybe check the value? 94 | case "System.Double": 95 | retData = $"{_obj.ReadField("m_value")}"; 96 | break; 97 | case "System.Int64": 98 | case "System.UInt64": 99 | retData = _obj.ReadField("m_value"); 100 | break; 101 | case "System.Char[]": 102 | case "System.Byte[]": 103 | case "System.SByte[]": 104 | case "System.Int16[]": 105 | case "System.Int32[]": 106 | case "System.Int64[]": 107 | case "System.UInt16[]": 108 | case "System.UInt32[]": 109 | case "System.UInt64[]": 110 | retData = _obj.Type.ReadArrayElements(_obj, 0, Math.Min((int)_obj.Size - 12, Constants.MAX_BUFFER_SIZE)); 111 | break; 112 | default: 113 | break; 114 | } 115 | return retData; 116 | } 117 | } 118 | public class GMAppDomain 119 | { 120 | public long Id { get; set; } 121 | public long Aid { get; set; } 122 | public string Name { get; set; } 123 | public ulong Address { get; set; } 124 | } 125 | 126 | public class GMFrame 127 | { 128 | public long Id { get; set; } 129 | public long Tid { get; set; } 130 | public ulong StackPtr { get; set; } 131 | public ulong Ip { get; set; } 132 | public string Frame { get; set; } 133 | } 134 | 135 | public class GMHandle 136 | { 137 | public long Id { get; set; } 138 | public ulong Address { get; set; } 139 | public ulong Object { get; set; } 140 | public string Kind { get; set; } 141 | } 142 | 143 | // XXX: every module belongs to AppDomain, so we need to include Aid here 144 | public class GMModule 145 | { 146 | public long Id { get; set; } 147 | public ulong AsmAddress { get; set; } 148 | public ulong ImgAddress { get; set; } 149 | public string Name { get; set; } 150 | public string AsmName { get; set; } 151 | public bool IsDynamic { get; set; } 152 | public bool IsPe { get; set; } 153 | } 154 | 155 | public class GMObjectData 156 | { 157 | public long Id { get; set; } 158 | public ulong ObjectId { get; set; } 159 | public ulong Address { get; set; } 160 | public string Type { get; set; } 161 | public ulong Size { get; set; } 162 | public byte[] Value { get; set; } 163 | } 164 | 165 | public class GMRuntime 166 | { 167 | public long Id { get; set; } 168 | public string Version { get; set; } 169 | public string Dac { get; set; } 170 | public string Arch { get; set; } 171 | } 172 | 173 | public class GMRef 174 | { 175 | public long Id { get; set; } 176 | public ulong Address { get; set; } 177 | public ulong Ref { get; set; } 178 | } 179 | 180 | public class GMStack 181 | { 182 | public long Id { get; set; } 183 | public long Tid { get; set; } 184 | public ulong StackPtr { get; set; } 185 | public ulong Object { get; set; } 186 | } 187 | 188 | public class GMThread 189 | { 190 | public long Id { get; set; } 191 | public long Tid { get; set; } 192 | public byte[] Context { get; set; } 193 | } 194 | 195 | public class GMSnapshot 196 | { 197 | public long Id { get; set; } 198 | public long Pid { get; set; } 199 | public long Time { get; set; } 200 | public int PointerSize { get; set; } 201 | } 202 | 203 | public class GMProcess 204 | { 205 | public long Pid { get; set; } 206 | public string Arch { get; set; } 207 | public string Date { get; set; } 208 | public string Path { get; set; } 209 | public string Args { get; set; } 210 | 211 | } 212 | 213 | public class GMBookmark 214 | { 215 | public long Id { get; set; } 216 | public ulong ObjectId { get; set; } 217 | public string Notes { get; set; } 218 | } 219 | 220 | public class GMSetting 221 | { 222 | public long Id { get; set; } 223 | public string Setting { get; set; } 224 | } 225 | 226 | } 227 | -------------------------------------------------------------------------------- /GMLib/GMLib.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net5.0 5 | AnyCPU;x86;x64 6 | 7 | 8 | 9 | AnyCPU 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /GMLib/ProcessEnumerator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.Diagnostics; 8 | using PInvoke; 9 | 10 | namespace GMLib 11 | { 12 | public class ProcessEnumerator: IEnumerable 13 | { 14 | public List PList { get; set; } = new(); 15 | public ProcessEnumerator() 16 | { 17 | foreach (var p in Process.GetProcesses()) 18 | { 19 | try 20 | { 21 | using (var handle = Kernel32.OpenProcess(Kernel32.ProcessAccess.PROCESS_QUERY_LIMITED_INFORMATION | Kernel32.ProcessAccess.PROCESS_VM_READ, false, p.Id)) 22 | { 23 | if (!handle.IsInvalid) 24 | { 25 | List runtimes = ClrUtil.GetProcessRuntimes(handle).ToList(); 26 | if (runtimes.Count != 0) 27 | { 28 | PList.Add(new GMProcessInfo { Pid = p.Id, Name = p.ProcessName, Runtimes = runtimes }); 29 | } 30 | } 31 | } 32 | } 33 | // Don't care 34 | catch { } 35 | } 36 | } 37 | public IEnumerator GetEnumerator() 38 | { 39 | return PList.GetEnumerator(); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /GarbageMan.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.31829.152 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GarbageMan", "GarbageMan\GarbageMan.csproj", "{790BD0D1-FA4F-4288-9F13-B2E2FA9CD327}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GMLib", "GMLib\GMLib.csproj", "{AAA68E87-78A3-4995-A3C8-3C8BC2F51D0B}" 9 | EndProject 10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GM", "GM\GM.csproj", "{BEBD1034-4970-4CF8-8BDE-75D369A0CE69}" 11 | EndProject 12 | Global 13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 14 | Debug|Any CPU = Debug|Any CPU 15 | Debug|x64 = Debug|x64 16 | Debug|x86 = Debug|x86 17 | Release|Any CPU = Release|Any CPU 18 | Release|x64 = Release|x64 19 | Release|x86 = Release|x86 20 | EndGlobalSection 21 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 22 | {790BD0D1-FA4F-4288-9F13-B2E2FA9CD327}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 23 | {790BD0D1-FA4F-4288-9F13-B2E2FA9CD327}.Debug|Any CPU.Build.0 = Debug|Any CPU 24 | {790BD0D1-FA4F-4288-9F13-B2E2FA9CD327}.Debug|x64.ActiveCfg = Debug|x64 25 | {790BD0D1-FA4F-4288-9F13-B2E2FA9CD327}.Debug|x64.Build.0 = Debug|x64 26 | {790BD0D1-FA4F-4288-9F13-B2E2FA9CD327}.Debug|x86.ActiveCfg = Debug|x86 27 | {790BD0D1-FA4F-4288-9F13-B2E2FA9CD327}.Debug|x86.Build.0 = Debug|x86 28 | {790BD0D1-FA4F-4288-9F13-B2E2FA9CD327}.Release|Any CPU.ActiveCfg = Release|Any CPU 29 | {790BD0D1-FA4F-4288-9F13-B2E2FA9CD327}.Release|Any CPU.Build.0 = Release|Any CPU 30 | {790BD0D1-FA4F-4288-9F13-B2E2FA9CD327}.Release|x64.ActiveCfg = Release|x64 31 | {790BD0D1-FA4F-4288-9F13-B2E2FA9CD327}.Release|x64.Build.0 = Release|x64 32 | {790BD0D1-FA4F-4288-9F13-B2E2FA9CD327}.Release|x86.ActiveCfg = Release|x86 33 | {790BD0D1-FA4F-4288-9F13-B2E2FA9CD327}.Release|x86.Build.0 = Release|x86 34 | {AAA68E87-78A3-4995-A3C8-3C8BC2F51D0B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 35 | {AAA68E87-78A3-4995-A3C8-3C8BC2F51D0B}.Debug|Any CPU.Build.0 = Debug|Any CPU 36 | {AAA68E87-78A3-4995-A3C8-3C8BC2F51D0B}.Debug|x64.ActiveCfg = Debug|x64 37 | {AAA68E87-78A3-4995-A3C8-3C8BC2F51D0B}.Debug|x64.Build.0 = Debug|x64 38 | {AAA68E87-78A3-4995-A3C8-3C8BC2F51D0B}.Debug|x86.ActiveCfg = Debug|x86 39 | {AAA68E87-78A3-4995-A3C8-3C8BC2F51D0B}.Debug|x86.Build.0 = Debug|x86 40 | {AAA68E87-78A3-4995-A3C8-3C8BC2F51D0B}.Release|Any CPU.ActiveCfg = Release|Any CPU 41 | {AAA68E87-78A3-4995-A3C8-3C8BC2F51D0B}.Release|Any CPU.Build.0 = Release|Any CPU 42 | {AAA68E87-78A3-4995-A3C8-3C8BC2F51D0B}.Release|x64.ActiveCfg = Release|x64 43 | {AAA68E87-78A3-4995-A3C8-3C8BC2F51D0B}.Release|x64.Build.0 = Release|x64 44 | {AAA68E87-78A3-4995-A3C8-3C8BC2F51D0B}.Release|x86.ActiveCfg = Release|x86 45 | {AAA68E87-78A3-4995-A3C8-3C8BC2F51D0B}.Release|x86.Build.0 = Release|x86 46 | {BEBD1034-4970-4CF8-8BDE-75D369A0CE69}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 47 | {BEBD1034-4970-4CF8-8BDE-75D369A0CE69}.Debug|Any CPU.Build.0 = Debug|Any CPU 48 | {BEBD1034-4970-4CF8-8BDE-75D369A0CE69}.Debug|x64.ActiveCfg = Debug|x64 49 | {BEBD1034-4970-4CF8-8BDE-75D369A0CE69}.Debug|x64.Build.0 = Debug|x64 50 | {BEBD1034-4970-4CF8-8BDE-75D369A0CE69}.Debug|x86.ActiveCfg = Debug|x86 51 | {BEBD1034-4970-4CF8-8BDE-75D369A0CE69}.Debug|x86.Build.0 = Debug|x86 52 | {BEBD1034-4970-4CF8-8BDE-75D369A0CE69}.Release|Any CPU.ActiveCfg = Release|Any CPU 53 | {BEBD1034-4970-4CF8-8BDE-75D369A0CE69}.Release|Any CPU.Build.0 = Release|Any CPU 54 | {BEBD1034-4970-4CF8-8BDE-75D369A0CE69}.Release|x64.ActiveCfg = Release|x64 55 | {BEBD1034-4970-4CF8-8BDE-75D369A0CE69}.Release|x64.Build.0 = Release|x64 56 | {BEBD1034-4970-4CF8-8BDE-75D369A0CE69}.Release|x86.ActiveCfg = Release|x86 57 | {BEBD1034-4970-4CF8-8BDE-75D369A0CE69}.Release|x86.Build.0 = Release|x86 58 | EndGlobalSection 59 | GlobalSection(SolutionProperties) = preSolution 60 | HideSolutionNode = FALSE 61 | EndGlobalSection 62 | GlobalSection(ExtensibilityGlobals) = postSolution 63 | SolutionGuid = {9BC7B56C-E583-4470-8239-D4566D5681A8} 64 | EndGlobalSection 65 | EndGlobal 66 | -------------------------------------------------------------------------------- /GarbageMan/App.xaml: -------------------------------------------------------------------------------- 1 |  6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /GarbageMan/App.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Configuration; 4 | using System.Data; 5 | using System.Linq; 6 | using System.Threading.Tasks; 7 | using System.Windows; 8 | using RestoreWindowPlace; 9 | 10 | namespace GarbageMan 11 | { 12 | /// 13 | /// Interaction logic for App.xaml 14 | /// 15 | /// 16 | 17 | public partial class App : Application 18 | { 19 | public WindowPlace WindowPlace { get; } 20 | 21 | public App() 22 | { 23 | this.WindowPlace = new WindowPlace("garbageman.config"); 24 | } 25 | 26 | protected override void OnExit(ExitEventArgs e) 27 | { 28 | base.OnExit(e); 29 | this.WindowPlace.Save(); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /GarbageMan/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | 3 | [assembly: ThemeInfo( 4 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located 5 | //(used if a resource is not found in the page, 6 | // or application resource dictionaries) 7 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located 8 | //(used if a resource is not found in the page, 9 | // app, or any theme specific resource dictionaries) 10 | )] 11 | -------------------------------------------------------------------------------- /GarbageMan/Attach.xaml: -------------------------------------------------------------------------------- 1 |  9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 129 |