├── .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 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/GarbageMan/Bookmarks.xaml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
31 |
32 |
33 |
37 |
41 |
42 |
43 |
44 |
45 |
50 |
55 |
60 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
75 |
76 |
77 |
78 |
79 |
82 |
83 |
84 |
85 |
86 |
90 |
91 |
92 |
93 |
94 |
98 |
99 |
100 |
101 |
102 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
--------------------------------------------------------------------------------
/GarbageMan/Bookmarks.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using System.Windows;
7 | using System.Windows.Controls;
8 | using System.Windows.Data;
9 | using System.Windows.Documents;
10 | using System.Windows.Input;
11 | using System.Windows.Media;
12 | using System.Windows.Media.Imaging;
13 | using System.Windows.Shapes;
14 |
15 | namespace GarbageMan
16 | {
17 | ///
18 | /// Interaction logic for Bookmarks.xaml
19 | ///
20 | public partial class Bookmarks : Window
21 | {
22 | public Bookmarks(List bookmarks)
23 | {
24 | InitializeComponent();
25 | BookmarksDataGrid.DataContext = bookmarks;
26 | }
27 |
28 | private void BookmarkDataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
29 | {
30 | return;
31 | }
32 |
33 | private void BookmarkDataGrid_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
34 | {
35 | var dg = sender as DataGrid;
36 | UIBookmark obj = dg.SelectedItem as UIBookmark;
37 | if (obj != null)
38 | {
39 | ((MainWindow)this.Owner).NavigateToObject(obj.Data);
40 | }
41 | }
42 |
43 | private void BookmarksDataGrid_Unloaded(object sender, RoutedEventArgs e)
44 | {
45 | var grid = (DataGrid)sender;
46 | grid.CommitEdit(DataGridEditingUnit.Row, true);
47 | }
48 |
49 | private void BookmarkContextMenuItem_Address_Click(object sender, RoutedEventArgs e)
50 | {
51 | UIBookmark item = BookmarksDataGrid.SelectedItem as UIBookmark;
52 | if (item != null)
53 | {
54 | Clipboard.SetText($"{item.Data.Address}");
55 | }
56 | }
57 |
58 | private void BookmarkContextMenuItem_Type_Click(object sender, RoutedEventArgs e)
59 | {
60 | UIBookmark item = BookmarksDataGrid.SelectedItem as UIBookmark;
61 | if (item != null)
62 | {
63 | Clipboard.SetText(item.Data.Type);
64 | }
65 | }
66 |
67 | private void BookmarkContextMenuItem_Value_Click(object sender, RoutedEventArgs e)
68 | {
69 | UIBookmark item = BookmarksDataGrid.SelectedItem as UIBookmark;
70 | if (item != null)
71 | {
72 | Clipboard.SetText(item.Data.Value);
73 | }
74 | }
75 | private void BookmarkContextMenuItem_RemoveBookmark_Click(object sender, RoutedEventArgs e)
76 | {
77 | UIBookmark item = BookmarksDataGrid.SelectedItem as UIBookmark;
78 | if (item != null)
79 | {
80 | ((MainWindow)this.Owner).RemoveBookmark(item.Data);
81 | }
82 | }
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/GarbageMan/CrashDump.xaml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/GarbageMan/CrashDump.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using System.Windows;
7 | using System.Windows.Controls;
8 | using System.Windows.Data;
9 | using System.Windows.Documents;
10 | using System.Windows.Input;
11 | using System.Windows.Media;
12 | using System.Windows.Media.Imaging;
13 | using System.Windows.Shapes;
14 | using GMLib;
15 | using System.IO;
16 | using Microsoft.Win32;
17 | using System.ComponentModel;
18 | using System.IO.Pipes;
19 | using System.Text.Json;
20 | using System.Diagnostics;
21 | using System.Threading;
22 |
23 | namespace GarbageMan
24 | {
25 | ///
26 | /// Interaction logic for CrashDump.xaml
27 | ///
28 | public partial class CrashDump : Window
29 | {
30 | public string BasePath { get; set; }
31 | public string DataBasePath { get; set; }
32 | public string RealPath { get; set; }
33 |
34 | private BackgroundWorker _worker = null;
35 | private WorkerArguments _args;
36 | private ManualResetEvent _dumpClosing = new(false);
37 |
38 | void CancelDump()
39 | {
40 | if (_worker != null && _worker.IsBusy)
41 | {
42 | _args.IsStopped = true;
43 | _args.Dumper.Kill();
44 | _dumpClosing.WaitOne();
45 | _worker = null;
46 | }
47 | }
48 |
49 | void CrashDump_Closing(object sender, CancelEventArgs e)
50 | {
51 | CancelDump();
52 | }
53 | public CrashDump(string basePath)
54 | {
55 | BasePath = basePath;
56 | DataBasePath = null;
57 | InitializeComponent();
58 | }
59 | private void CrashDumpCancelButton_Click(object sender, RoutedEventArgs e)
60 | {
61 | CancelDump();
62 | DataBasePath = null;
63 | this.Close();
64 | }
65 |
66 | private void CrashDumpStartButton_Click(object sender, RoutedEventArgs e)
67 | {
68 | // Get all the settings
69 | string path = CrashDumpPathTextBox.Text;
70 |
71 | string initialFlags = "";
72 | if ((bool)CrashDumpInitialBasicCheckBox.IsChecked) initialFlags += "basic refs ";
73 | if ((bool)CrashDumpInitialHeapCheckBox.IsChecked) initialFlags += "heap ";
74 | if ((bool)CrashDumpInitialStackCheckBox.IsChecked) initialFlags += "stack threads ";
75 |
76 | RealPath = System.IO.Path.GetTempFileName();
77 |
78 | if (path == "")
79 | System.Windows.MessageBox.Show("Please pick up proper dump", "CrashDump", MessageBoxButton.OK, MessageBoxImage.Information);
80 | else if (initialFlags == "")
81 | System.Windows.MessageBox.Show("No features selected!", "CrashDump", MessageBoxButton.OK, MessageBoxImage.Information);
82 | else if (CrashDumpDatabaseNameTextBox.Text == "")
83 | System.Windows.MessageBox.Show("Please pick proper filename", "CrashDump", MessageBoxButton.OK, MessageBoxImage.Information);
84 | else
85 | {
86 | string cmdLine = $"--crashdump {path} --dbpath {RealPath} --items {initialFlags} ";
87 |
88 | CrashDumpStatusText.Visibility = Visibility.Visible;
89 | CrashDumpProgressBar.Visibility = Visibility.Visible;
90 |
91 | _worker = new BackgroundWorker();
92 | _worker.DoWork += backgroundWorker_Dump;
93 |
94 | _worker.WorkerReportsProgress = true;
95 | _worker.ProgressChanged += backgroundWorker_ProgressChanged;
96 |
97 | _worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(
98 | (sender, e) =>
99 | {
100 | CrashDumpStatusText.Visibility = Visibility.Hidden;
101 | CrashDumpProgressBar.Visibility = Visibility.Hidden;
102 | if ((bool)e.Result)
103 | {
104 | DataBasePath = CrashDumpDatabaseNameTextBox.Text;
105 | this.Close();
106 | }
107 | else
108 | {
109 | MessageBox.Show($"Cannot create dump", "Dump", MessageBoxButton.OK, MessageBoxImage.Error);
110 | this.Close();
111 | }
112 | });
113 | _args = new WorkerArguments { CommandLine = cmdLine, BasePath = this.BasePath, Done = _dumpClosing };
114 | _worker.RunWorkerAsync(argument: _args);
115 | }
116 | }
117 |
118 | void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
119 | {
120 | CrashDumpStatusText.Text = e.UserState.ToString();
121 | }
122 |
123 | static void backgroundWorker_Dump(object sender, DoWorkEventArgs e)
124 | {
125 | bool success = false;
126 | WorkerArguments args = e.Argument as WorkerArguments;
127 |
128 | // When in doubt, use brute force (we don't know the architecture here):
129 | success = DumpCrashDump(sender, args, true);
130 | if (!success)
131 | success = DumpCrashDump(sender, args, false);
132 |
133 | e.Result = success;
134 | }
135 | static bool DumpCrashDump(object sender, WorkerArguments args, bool Is32bit)
136 | {
137 | bool success = false;
138 |
139 | string arch = Is32bit ? "x86" : "x64";
140 | string exePath = args.BasePath + $"bin\\{arch}\\GM.exe";
141 | var process = new Process
142 | {
143 | StartInfo =
144 | {
145 | FileName = exePath,
146 | CreateNoWindow = true,
147 | UseShellExecute = false
148 | }
149 | };
150 |
151 | args.Dumper = process;
152 |
153 | using (var pipeRead = new AnonymousPipeServerStream(PipeDirection.In,
154 | HandleInheritability.Inheritable))
155 | {
156 | process.StartInfo.Arguments = $"--debug --pipe {pipeRead.GetClientHandleAsString()} ";
157 | process.StartInfo.Arguments += args.CommandLine;
158 | process.Start();
159 |
160 | pipeRead.DisposeLocalCopyOfClientHandle();
161 | using (var sr = new StreamReader(pipeRead))
162 | {
163 | string temp;
164 | int i = 0;
165 | while ((temp = sr.ReadLine()) != null)
166 | {
167 | if (args.IsStopped)
168 | {
169 | break;
170 | }
171 | GMCmdOutput output = JsonSerializer.Deserialize(temp);
172 | (sender as BackgroundWorker).ReportProgress(i++, output.Msg);
173 | if (output.Msg.Contains("ERROR"))
174 | {
175 | process.Close();
176 | return false;
177 | }
178 | if (output.Msg.Contains("SUCCESS"))
179 | {
180 | process.Close();
181 | return true;
182 | }
183 | }
184 | }
185 | }
186 | process.WaitForExit();
187 | process.Close();
188 | args.Done?.Set();
189 | return success;
190 | }
191 | private void CrashDumpDatabasePickerButton_Click(object sender, RoutedEventArgs e)
192 | {
193 | SaveFileDialog saveFileDialog = new SaveFileDialog();
194 | saveFileDialog.Filter = "Database files (*.db)|*.db|All files (*.*)|*.*";
195 | saveFileDialog.FileName = CrashDumpDatabaseNameTextBox.Text;
196 | if (saveFileDialog.ShowDialog() == true)
197 | CrashDumpDatabaseNameTextBox.Text = saveFileDialog.FileName;
198 | }
199 |
200 | private void CrashDumpPathPickerButton_Click(object sender, RoutedEventArgs e)
201 | {
202 | OpenFileDialog openFileDialog = new OpenFileDialog();
203 | openFileDialog.FileName = CrashDumpPathTextBox.Text;
204 | if (openFileDialog.ShowDialog() == true)
205 | CrashDumpPathTextBox.Text = openFileDialog.FileName;
206 | }
207 | }
208 | }
209 |
--------------------------------------------------------------------------------
/GarbageMan/GarbageMan.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | WinExe
5 | net5.0-windows
6 | true
7 | AnyCPU;x86;x64
8 | assets\Recycle.ico
9 | Jarkko Turkulainen
10 | .NET heap analyzer
11 |
12 | MIT
13 | 0.2.4
14 |
15 |
16 |
17 | false
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 | all
46 | runtime; build; native; contentfiles; analyzers; buildtransitive
47 |
48 |
49 |
50 | all
51 | runtime; build; native; contentfiles; analyzers; buildtransitive
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 | True
86 | True
87 | Resources.resx
88 |
89 |
90 |
91 |
92 |
93 | PublicResXFileCodeGenerator
94 | Resources.Designer.cs
95 |
96 |
97 |
98 |
99 |
--------------------------------------------------------------------------------
/GarbageMan/GarbageMan.csproj.user:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Designer
7 |
8 |
9 |
10 |
11 | Code
12 |
13 |
14 | Code
15 |
16 |
17 | Code
18 |
19 |
20 | Code
21 |
22 |
23 | Code
24 |
25 |
26 | Code
27 |
28 |
29 | Code
30 |
31 |
32 | Code
33 |
34 |
35 | Code
36 |
37 |
38 |
39 |
40 | Designer
41 |
42 |
43 | Designer
44 |
45 |
46 | Designer
47 |
48 |
49 | Designer
50 |
51 |
52 | Designer
53 |
54 |
55 | Designer
56 |
57 |
58 | Designer
59 |
60 |
61 | Designer
62 |
63 |
64 | Designer
65 |
66 |
67 | Designer
68 |
69 |
70 |
--------------------------------------------------------------------------------
/GarbageMan/PathViewer.xaml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
22 |
23 |
24 |
28 |
32 |
33 |
34 |
35 |
36 |
37 |
40 |
41 |
42 |
43 |
44 |
47 |
48 |
49 |
50 |
51 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/GarbageMan/PathViewer.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using System.Windows;
7 | using System.Windows.Controls;
8 | using System.Windows.Data;
9 | using System.Windows.Documents;
10 | using System.Windows.Input;
11 | using System.Windows.Media;
12 | using System.Windows.Media.Imaging;
13 | using System.Windows.Shapes;
14 |
15 | namespace GarbageMan
16 | {
17 | ///
18 | /// Interaction logic for PathViewer.xaml
19 | ///
20 | public partial class PathViewer : Window
21 | {
22 | public PathViewer(List list)
23 | {
24 | InitializeComponent();
25 | PathViewerDataGrid.DataContext = list;
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/GarbageMan/PickProcess.xaml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
26 |
27 |
28 |
32 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
--------------------------------------------------------------------------------
/GarbageMan/PickProcess.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using System.Windows;
7 | using System.Windows.Controls;
8 | using System.Windows.Data;
9 | using System.Windows.Documents;
10 | using System.Windows.Input;
11 | using System.Windows.Media;
12 | using System.Windows.Media.Imaging;
13 | using System.Windows.Shapes;
14 | using System.Diagnostics;
15 | using System.Threading;
16 | using System.ComponentModel;
17 | using System.IO;
18 | using System.IO.Pipes;
19 | using GMLib;
20 | using System.Text.Json;
21 | using PInvoke;
22 |
23 | namespace GarbageMan
24 | {
25 |
26 | public partial class PickProcess : Window
27 | {
28 | string BasePath { get; set; }
29 | public PickProcess(string basePath)
30 | {
31 | BasePath = basePath;
32 | InitializeComponent();
33 |
34 | ProcessPickStatusText.Visibility = Visibility.Visible;
35 | ProcessPickProgressBar.Visibility = Visibility.Visible;
36 |
37 | BackgroundWorker worker = new BackgroundWorker();
38 | worker.DoWork += backgroundWorker_GetProcesses;
39 | worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(
40 | (sender, e) => {
41 | ProcessPickStatusText.Visibility = Visibility.Hidden;
42 | ProcessPickProgressBar.Visibility = Visibility.Hidden;
43 | ProcessPickerDataGrid.DataContext = e.Result;
44 | });
45 | worker.RunWorkerAsync(argument: new WorkerArguments { BasePath = this.BasePath });
46 |
47 | }
48 |
49 | static void backgroundWorker_GetProcesses(object sender, DoWorkEventArgs e)
50 | {
51 | WorkerArguments args = e.Argument as WorkerArguments;
52 |
53 | List picked = new();
54 | Dictionary fromGM = new();
55 |
56 | int me = Process.GetCurrentProcess().Id;
57 | foreach (var p in GetProcessList(args, true))
58 | fromGM.Add(p.Pid, p);
59 | foreach (var p in GetProcessList(args, false))
60 | fromGM.Add(p.Pid, p);
61 | foreach (var p in Process.GetProcesses())
62 | {
63 | if (p.Id == me)
64 | continue;
65 | if (fromGM.ContainsKey(p.Id))
66 | picked.Add(fromGM[p.Id]);
67 | else
68 | {
69 | using (var handle = Kernel32.OpenProcess(Kernel32.ProcessAccess.PROCESS_QUERY_LIMITED_INFORMATION | Kernel32.ProcessAccess.PROCESS_VM_READ, false, p.Id))
70 | {
71 | if (!handle.IsInvalid)
72 | {
73 | picked.Add(new UIPickedProcess { Pid = p.Id, Name = p.ProcessName, Runtime = "Native/CoreCLR", Arch = Kernel32.IsWow64Process(handle) ? "x86" : "x64"});
74 | }
75 | }
76 | }
77 | }
78 | e.Result = picked;
79 | }
80 |
81 | static List GetProcessList(WorkerArguments args, bool Is32bit)
82 | {
83 | List picked = new();
84 |
85 | string arch = Is32bit ? "x86" : "x64";
86 | string exePath = args.BasePath + $"bin\\{arch}\\GM.exe";
87 | var process = new Process
88 | {
89 | StartInfo =
90 | {
91 | FileName = exePath,
92 | CreateNoWindow = true,
93 | UseShellExecute = false
94 | }
95 | };
96 |
97 | List cmdLines = new();
98 |
99 | using (var pipeRead = new AnonymousPipeServerStream(PipeDirection.In,
100 | HandleInheritability.Inheritable))
101 | {
102 | process.StartInfo.Arguments = $"--pipe {pipeRead.GetClientHandleAsString()}";
103 | process.StartInfo.Arguments += $" --ps";
104 | process.Start();
105 |
106 | pipeRead.DisposeLocalCopyOfClientHandle();
107 | using (var sr = new StreamReader(pipeRead))
108 | {
109 | string temp;
110 | while ((temp = sr.ReadLine()) != null)
111 | {
112 | GMCmdOutputPList output = JsonSerializer.Deserialize(temp);
113 | cmdLines.Add(output);
114 | }
115 | }
116 | }
117 | process.WaitForExit();
118 | process.Close();
119 |
120 | foreach (GMCmdOutputPList line in cmdLines)
121 | {
122 | if (line.Type == "pslist" && line.PList != null)
123 | {
124 | foreach (var p in line.PList)
125 | picked.Add(new UIPickedProcess { Pid = p.Pid, Name=p.Name, Runtime = p.Runtimes[0], Arch = Is32bit ? "x86" : "x64" });
126 | }
127 | }
128 | return picked;
129 | }
130 |
131 | private void ProcessPickButton_Click(object sender, RoutedEventArgs e)
132 | {
133 | UIPickedProcess p = ProcessPickerDataGrid.SelectedItem as UIPickedProcess;
134 | if (p != null)
135 | {
136 | ((Attach)this.Owner).AttachPidTextBox.Text = $"{p.Pid}";
137 | this.Close();
138 | }
139 | }
140 | private void ProcessPickCancelButton_Click(object sender, RoutedEventArgs e)
141 | {
142 | this.Close();
143 | }
144 |
145 | private void ProcessPickerDataGrid_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
146 | {
147 | var dg = sender as DataGrid;
148 | UIPickedProcess obj = dg.SelectedItem as UIPickedProcess;
149 | if (obj != null)
150 | {
151 | ((Attach)this.Owner).AttachPidTextBox.Text = $"{obj.Pid}";
152 | this.Close();
153 | }
154 | }
155 | }
156 | }
157 |
--------------------------------------------------------------------------------
/GarbageMan/Properties/Resources.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace GarbageMan.Properties {
12 | using System;
13 |
14 |
15 | ///
16 | /// A strongly-typed resource class, for looking up localized strings, etc.
17 | ///
18 | // This class was auto-generated by the StronglyTypedResourceBuilder
19 | // class via a tool like ResGen or Visual Studio.
20 | // To add or remove a member, edit your .ResX file then rerun ResGen
21 | // with the /str option, or rebuild your VS project.
22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
25 | public class Resources {
26 |
27 | private static global::System.Resources.ResourceManager resourceMan;
28 |
29 | private static global::System.Globalization.CultureInfo resourceCulture;
30 |
31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
32 | internal Resources() {
33 | }
34 |
35 | ///
36 | /// Returns the cached ResourceManager instance used by this class.
37 | ///
38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
39 | public static global::System.Resources.ResourceManager ResourceManager {
40 | get {
41 | if (object.ReferenceEquals(resourceMan, null)) {
42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("GarbageMan.Properties.Resources", typeof(Resources).Assembly);
43 | resourceMan = temp;
44 | }
45 | return resourceMan;
46 | }
47 | }
48 |
49 | ///
50 | /// Overrides the current thread's CurrentUICulture property for all
51 | /// resource lookups using this strongly typed resource class.
52 | ///
53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
54 | public static global::System.Globalization.CultureInfo Culture {
55 | get {
56 | return resourceCulture;
57 | }
58 | set {
59 | resourceCulture = value;
60 | }
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/GarbageMan/Properties/Resources.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
--------------------------------------------------------------------------------
/GarbageMan/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "profiles": {
3 | "GarbageMan": {
4 | "commandName": "Project",
5 | "commandLineArgs": "1122"
6 | }
7 | }
8 | }
--------------------------------------------------------------------------------
/GarbageMan/RawSql.xaml:
--------------------------------------------------------------------------------
1 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/GarbageMan/RawSql.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using System.Windows;
7 | using System.Windows.Controls;
8 | using System.Windows.Data;
9 | using System.Windows.Documents;
10 | using System.Windows.Input;
11 | using System.Windows.Media;
12 | using System.Windows.Media.Imaging;
13 | using System.Windows.Shapes;
14 |
15 | namespace GarbageMan
16 | {
17 | ///
18 | /// Interaction logic for RawSql.xaml
19 | ///
20 | public partial class RawSql : Window
21 | {
22 | public RawSql()
23 | {
24 | InitializeComponent();
25 | }
26 |
27 | // XXX: verify at least "LIMIT"
28 | private bool VerifySql()
29 | {
30 | if (!SqlTextBox.Text.ToUpper().Contains(" LIMIT "))
31 | {
32 | MessageBox.Show($"Please put some kind of LIMIT to the query", "GarbageMan", MessageBoxButton.OK, MessageBoxImage.Error);
33 | return false;
34 | }
35 | return true;
36 | }
37 |
38 | private void ExportButton_Click(object sender, RoutedEventArgs e)
39 | {
40 | if (VerifySql())
41 | {
42 | string json = " {\n";
43 | json += " \"Header\": \"MySearch\",\n";
44 | json += " \"Category\": \"MyCategory\",\n";
45 | json += " \"SearchType\": \"Custom\",\n";
46 | json += " \"SearchAll\": \"No\",\n";
47 | json += $" \"SQL\": \"{SqlTextBox.Text.Replace("\\", "\\\\").Replace("\"", "\\\"").Replace("\n", String.Empty).Replace("\r", String.Empty)}\"\n";
48 | json += " }\n";
49 | Clipboard.SetText(json);
50 | }
51 | }
52 |
53 | private void RunButton_Click(object sender, RoutedEventArgs e)
54 | {
55 | using (new WaitCursor())
56 | {
57 | if (VerifySql())
58 | ((MainWindow)this.Owner).SearchRawSql(SqlTextBox.Text);
59 | }
60 | }
61 |
62 | private void CloseButton_Click(object sender, RoutedEventArgs e)
63 | {
64 | this.Close();
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/GarbageMan/RunExecutable.xaml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
--------------------------------------------------------------------------------
/GarbageMan/SmartRefs.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using GMLib;
7 | using Microsoft.EntityFrameworkCore;
8 | using System.Collections;
9 | using Microsoft.Data.Sqlite;
10 |
11 | namespace GarbageMan
12 | {
13 | public class UITraceNode
14 | {
15 | public ulong Address { get; set; }
16 | public string To { get; set; }
17 | public string Type { get; set; }
18 | }
19 |
20 | public class UITraceObject
21 | {
22 | public ulong Address { get; set; }
23 | public int Distance { get; set; }
24 | public UIObjectData Object { get; set; }
25 | public GMObjectData ObjectData { get; set; }
26 | public List Path { get; set; }
27 |
28 | // Return json string on ToString()
29 | public override string ToString()
30 | {
31 | if (Path.Count != 0)
32 | {
33 | string path = "[\n";
34 | for (int i = 0; i < Path.Count; i++)
35 | {
36 | path += " {";
37 | path += $" \"Address\": {Path[i].Address}";
38 | path += $", \"To\": {Path[i].To}, \"Type\": \"{Path[i].Type}\"" + " }";
39 | if (i < (Path.Count - 1))
40 | path += ",";
41 | path += "\n";
42 | }
43 | path += "]\n";
44 | return path;
45 | }
46 | return null;
47 | }
48 | }
49 |
50 | public class ReferenceTracer
51 | {
52 | public int Snapshot { get; set; }
53 | public SqliteConnection db { get; set; }
54 |
55 | private bool VerifyObjectType(GMObjectData obj)
56 | {
57 | bool retVal = false;
58 | if (obj != null)
59 | {
60 | if (obj.Type == "System.Object[]" && obj.Size > 100)
61 | retVal = false;
62 | else if (obj.Type.StartsWith("System.Globalization") || obj.Type.StartsWith("System.Configuration"))
63 | retVal = false;
64 | else
65 | retVal = true;
66 | }
67 | return retVal;
68 | }
69 |
70 | private bool IsPrimitiveValue(string type)
71 | {
72 | bool retVal = false;
73 | switch (type)
74 | {
75 | case "System.String":
76 | case "System.Char[]":
77 | case "System.Byte[]":
78 | case "System.SByte[]":
79 | retVal = true;
80 | break;
81 | default:
82 | break;
83 | }
84 | return retVal;
85 | }
86 | public void Close()
87 | {
88 | db.Dispose();
89 | db.Close();
90 | }
91 |
92 | public void Trace(TracerArguments args)
93 | {
94 | Snapshot = args.Snapshot;
95 |
96 | db = new SqliteConnection($"Filename={args.Database}; Pooling=False;");
97 | db.Open();
98 | /*
99 | string pragmaCommand = "PRAGMA journal_mode = WAL; PRAGMA synchronous = NORMAL;";
100 | SqliteCommand createPragma = new(pragmaCommand, db);
101 | createPragma.ExecuteNonQuery();
102 | */
103 | // Return values
104 | List retList = new();
105 |
106 | HashSet seen = new HashSet() { args.Object.Object.ObjectId };
107 | Stack todo = new Stack();
108 |
109 | // First node
110 | List path = new();
111 | path.Add(new UITraceNode { Address = args.Object.Address, To = "false", Type = args.Object.Type });
112 | todo.Push(new UITraceObject { Object = args.Object, ObjectData = args.Object.Object, Distance = 0, Address = args.Object.Object.ObjectId, Path = path });
113 |
114 | while (todo.Count > 0)
115 | {
116 | if (args.IsStopped)
117 | break;
118 | if (args.IsCanceled)
119 | {
120 | args.Done?.Set();
121 | return;
122 | }
123 |
124 | UITraceObject curr = todo.Pop();
125 |
126 | // Do not follow very long paths
127 | if (curr.Distance > args.TraceDepth)
128 | {
129 | continue;
130 | }
131 | retList.Add(curr);
132 |
133 | // SQL query gets Object rows for all objects referencing to given object or referenced by the object
134 | var cmd = db.CreateCommand();
135 | cmd.CommandText = $"SELECT * FROM Objects WHERE Id = {Snapshot + 1} AND ObjectId IN (";
136 | cmd.CommandText += $"SELECT Address FROM Refs WHERE Id = {Snapshot + 1} AND (Address = {curr.Address} OR Ref = {curr.Address}) ";
137 | cmd.CommandText += $"UNION SELECT Ref FROM Refs WHERE Id = {Snapshot + 1} AND (Address = {curr.Address} OR Ref = {curr.Address})) LIMIT 50";
138 | using (var reader = cmd.ExecuteReader())
139 | {
140 | while (reader.Read())
141 | {
142 | ulong objId = (ulong)reader.GetInt64(1);
143 | if (seen.Add(objId))
144 | {
145 | GMObjectData obj = new GMObjectData
146 | {
147 | Id = Snapshot + 1,
148 | ObjectId = objId,
149 | Address = (ulong)reader.GetInt64(2),
150 | Type = reader.GetString(3),
151 | Size = (ulong)reader.GetInt64(4)
152 | };
153 | if (VerifyObjectType(obj))
154 | {
155 | if (!reader.IsDBNull(5))
156 | obj.Value = reader.GetFieldValue(5);
157 |
158 | List reftopath = new();
159 | reftopath.AddRange(curr.Path);
160 | reftopath.Add(new UITraceNode { Address = obj.Address, To = "true", Type = obj.Type });
161 | todo.Push(new UITraceObject { Address = objId, Distance = curr.Distance + 1, ObjectData = obj, Path = reftopath });
162 | }
163 | }
164 | }
165 | }
166 | }
167 | for (int i = retList.Count - 1; i >= 0; i--)
168 | {
169 | if (retList[i].Distance == 0)
170 | continue;
171 | else
172 | {
173 | // non-primitive types probably not very interesting here
174 | if (!(IsPrimitiveValue(retList[i].ObjectData.Type)))
175 | retList.RemoveAt(i);
176 | else
177 | retList[i].Object = new UIObjectData(retList[i].ObjectData);
178 | }
179 | }
180 | args.Object.Trace = retList.OrderBy(r => r.Distance).ToList();
181 | args.Done?.Set();
182 | }
183 | }
184 | }
185 |
--------------------------------------------------------------------------------
/GarbageMan/Snapshots.xaml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
29 |
30 |
31 |
35 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/GarbageMan/Snapshots.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using System.Windows;
7 | using System.Windows.Controls;
8 | using System.Windows.Data;
9 | using System.Windows.Documents;
10 | using System.Windows.Input;
11 | using System.Windows.Media;
12 | using System.Windows.Media.Imaging;
13 | using System.Windows.Shapes;
14 |
15 | namespace GarbageMan
16 | {
17 | ///
18 | /// Interaction logic for Snapshots.xaml
19 | ///
20 | public partial class Snapshots : Window
21 | {
22 | public Snapshots()
23 | {
24 | InitializeComponent();
25 | }
26 |
27 | private void SnapshotsDataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
28 | {
29 | }
30 |
31 | private void SnapshotsDataGrid_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
32 | {
33 | var dg = sender as DataGrid;
34 | UISnapshot obj = dg.SelectedItem as UISnapshot;
35 | if (obj != null)
36 | {
37 | ((MainWindow)this.Owner).SwitchToSnapshot(obj.Id-1);
38 | this.Close();
39 | }
40 | }
41 | }
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/GarbageMan/Tracer.xaml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
42 |
43 |
44 |
48 |
52 |
53 |
54 |
55 |
56 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
71 |
72 |
73 |
74 |
75 |
78 |
79 |
80 |
81 |
82 |
86 |
87 |
88 |
89 |
90 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
--------------------------------------------------------------------------------
/GarbageMan/Tracer.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using System.Windows;
7 | using System.Windows.Controls;
8 | using System.Windows.Data;
9 | using System.Windows.Documents;
10 | using System.Windows.Input;
11 | using System.Windows.Media;
12 | using System.Windows.Media.Imaging;
13 | using System.Windows.Shapes;
14 | using System.IO;
15 | using Microsoft.Win32;
16 | using System.ComponentModel;
17 | using System.IO.Pipes;
18 | using System.Text.Json;
19 | using System.Diagnostics;
20 | using System.Threading;
21 | using System.Timers;
22 |
23 | namespace GarbageMan
24 | {
25 | public class TracerArguments
26 | {
27 | public UIObjectData Object { get; set; }
28 | public string Database { get; set; }
29 | public int Snapshot { get; set; }
30 | public bool IsCanceled { get; set; }
31 | public bool IsStopped { get; set; }
32 | public int TraceDepth { get; set; }
33 | public ManualResetEvent Done { get; set; }
34 | }
35 | public partial class Tracer : Window
36 | {
37 | public List Trace { get; set; }
38 |
39 | private BackgroundWorker _worker = null;
40 | private static ReferenceTracer _tracer;
41 | private TracerArguments _args;
42 |
43 | private UIObjectData _object;
44 | private string _dbPath;
45 | private int _snapshot;
46 | private bool _ready = false;
47 |
48 | private ManualResetEvent _tracerClosing = new(false);
49 |
50 | private void StopTracer()
51 | {
52 | _args.IsStopped = true;
53 | _tracerClosing.WaitOne(TimeSpan.FromSeconds(5));
54 | _tracer.Close();
55 | }
56 |
57 | void Tracer_Closing(object sender, CancelEventArgs e)
58 | {
59 | if (_worker != null && _worker.IsBusy)
60 | {
61 | StopTracer();
62 | }
63 | }
64 | public Tracer(UIObjectData obj, string dbPath, int snapshot = 0)
65 | {
66 | InitializeComponent();
67 |
68 | _object = obj;
69 | _dbPath = dbPath;
70 | _snapshot = snapshot;
71 |
72 | if (obj.Trace != null && obj.Trace.Count != 0)
73 | {
74 | // Trace data is already available
75 | TracerProgressBar.Visibility = Visibility.Hidden;
76 | Trace = obj.Trace;
77 | TracerDataGrid.DataContext = Trace;
78 | _ready = true;
79 | }
80 | }
81 |
82 | private void backgroundWorker_Timer(object source, ElapsedEventArgs e)
83 | {
84 | _args.IsStopped = true;
85 | _ready = true;
86 | }
87 |
88 | static void backgroundWorker_Trace(object sender, DoWorkEventArgs e)
89 | {
90 | TracerArguments args = e.Argument as TracerArguments;
91 | _tracer = new();
92 | try
93 | {
94 | _tracer.Trace(args);
95 | }
96 | catch
97 | {
98 | _tracer.Close();
99 | throw;
100 | }
101 | }
102 |
103 | private void TracerDataGrid_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
104 | {
105 | var dg = sender as DataGrid;
106 | UITraceObject obj = dg.SelectedItem as UITraceObject;
107 | if (obj != null)
108 | {
109 | ((MainWindow)this.Owner).NavigateToIndex((int)obj.Object.Object.ObjectId);
110 | }
111 | }
112 |
113 | private void TracerContextMenuItem_View_Click(object sender, RoutedEventArgs e)
114 | {
115 | UITraceObject item = TracerDataGrid.SelectedItem as UITraceObject;
116 | if (item != null)
117 | {
118 | PathViewer viewer = new(item.Path);
119 | viewer.Show();
120 | }
121 | }
122 |
123 | private void CommandBindingStart_Executed(object sender, ExecutedRoutedEventArgs e)
124 | {
125 | Start();
126 | }
127 |
128 | private void Start()
129 | {
130 | if (_worker != null && _worker.IsBusy)
131 | return;
132 | if (_ready)
133 | TracerDataGrid.DataContext = null;
134 |
135 | _ready = false;
136 |
137 | _worker = new BackgroundWorker();
138 | _worker.DoWork += backgroundWorker_Trace;
139 | _worker.WorkerReportsProgress = true;
140 | _worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(
141 | (sender, e) =>
142 | {
143 | TracerProgressBar.Visibility = Visibility.Hidden;
144 | Trace = _object.Trace;
145 | if (Trace == null || Trace.Count == 0)
146 | {
147 | TracerDataGrid.DataContext = null;
148 | _ready = true;
149 | _worker = null;
150 | _tracer.Close();
151 | //this.Close();
152 | }
153 | else
154 | {
155 | TracerDataGrid.DataContext = _object.Trace;
156 | _ready = true;
157 | _worker = null;
158 | _tracer.Close();
159 | }
160 | });
161 |
162 | _args = new TracerArguments
163 | {
164 | Object = _object,
165 | Database = _dbPath,
166 | Snapshot = _snapshot,
167 | IsCanceled = false,
168 | IsStopped = false,
169 | TraceDepth = Int32.Parse(DeptTeaxtBox.Text == "" ? "7" : DeptTeaxtBox.Text),
170 | Done = _tracerClosing
171 | };
172 | _worker.RunWorkerAsync(argument: _args);
173 |
174 | System.Timers.Timer timer = new System.Timers.Timer();
175 | timer.Elapsed += new ElapsedEventHandler(backgroundWorker_Timer);
176 | timer.Interval = Int32.Parse(TimeTextBox.Text == "" ? "10" : TimeTextBox.Text);
177 | timer.Interval *= 1000;
178 | timer.AutoReset = false;
179 | timer.Enabled = true;
180 |
181 | TracerProgressBar.Visibility = Visibility.Visible;
182 | }
183 |
184 | private void StopButton_Click(object sender, RoutedEventArgs e)
185 | {
186 | if (_ready == true)
187 | return;
188 | if (_worker != null && _worker.IsBusy)
189 | _args.IsStopped = true;
190 | }
191 |
192 | private void CommandBindingClose_Executed(object sender, ExecutedRoutedEventArgs e)
193 | {
194 | if (_worker != null && _worker.IsBusy)
195 | {
196 | StopTracer();
197 | }
198 | this.Close();
199 | }
200 | }
201 | }
202 |
--------------------------------------------------------------------------------
/GarbageMan/assets/AddBookmark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WithSecureLabs/GarbageMan/1229c2ef89f400e709431977f05dac96961d914e/GarbageMan/assets/AddBookmark.png
--------------------------------------------------------------------------------
/GarbageMan/assets/Analyze.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WithSecureLabs/GarbageMan/1229c2ef89f400e709431977f05dac96961d914e/GarbageMan/assets/Analyze.png
--------------------------------------------------------------------------------
/GarbageMan/assets/Back.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WithSecureLabs/GarbageMan/1229c2ef89f400e709431977f05dac96961d914e/GarbageMan/assets/Back.png
--------------------------------------------------------------------------------
/GarbageMan/assets/CSFile.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WithSecureLabs/GarbageMan/1229c2ef89f400e709431977f05dac96961d914e/GarbageMan/assets/CSFile.png
--------------------------------------------------------------------------------
/GarbageMan/assets/Close.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WithSecureLabs/GarbageMan/1229c2ef89f400e709431977f05dac96961d914e/GarbageMan/assets/Close.png
--------------------------------------------------------------------------------
/GarbageMan/assets/Copy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WithSecureLabs/GarbageMan/1229c2ef89f400e709431977f05dac96961d914e/GarbageMan/assets/Copy.png
--------------------------------------------------------------------------------
/GarbageMan/assets/Execute.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WithSecureLabs/GarbageMan/1229c2ef89f400e709431977f05dac96961d914e/GarbageMan/assets/Execute.png
--------------------------------------------------------------------------------
/GarbageMan/assets/Exit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WithSecureLabs/GarbageMan/1229c2ef89f400e709431977f05dac96961d914e/GarbageMan/assets/Exit.png
--------------------------------------------------------------------------------
/GarbageMan/assets/Home.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WithSecureLabs/GarbageMan/1229c2ef89f400e709431977f05dac96961d914e/GarbageMan/assets/Home.png
--------------------------------------------------------------------------------
/GarbageMan/assets/New.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WithSecureLabs/GarbageMan/1229c2ef89f400e709431977f05dac96961d914e/GarbageMan/assets/New.png
--------------------------------------------------------------------------------
/GarbageMan/assets/Open.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WithSecureLabs/GarbageMan/1229c2ef89f400e709431977f05dac96961d914e/GarbageMan/assets/Open.png
--------------------------------------------------------------------------------
/GarbageMan/assets/Process.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WithSecureLabs/GarbageMan/1229c2ef89f400e709431977f05dac96961d914e/GarbageMan/assets/Process.png
--------------------------------------------------------------------------------
/GarbageMan/assets/Recycle.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WithSecureLabs/GarbageMan/1229c2ef89f400e709431977f05dac96961d914e/GarbageMan/assets/Recycle.ico
--------------------------------------------------------------------------------
/GarbageMan/assets/RemoveBookmark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WithSecureLabs/GarbageMan/1229c2ef89f400e709431977f05dac96961d914e/GarbageMan/assets/RemoveBookmark.png
--------------------------------------------------------------------------------
/GarbageMan/assets/SQL.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WithSecureLabs/GarbageMan/1229c2ef89f400e709431977f05dac96961d914e/GarbageMan/assets/SQL.png
--------------------------------------------------------------------------------
/GarbageMan/assets/Save.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WithSecureLabs/GarbageMan/1229c2ef89f400e709431977f05dac96961d914e/GarbageMan/assets/Save.png
--------------------------------------------------------------------------------
/GarbageMan/assets/Search.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WithSecureLabs/GarbageMan/1229c2ef89f400e709431977f05dac96961d914e/GarbageMan/assets/Search.png
--------------------------------------------------------------------------------
/GarbageMan/assets/SmartRefs.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WithSecureLabs/GarbageMan/1229c2ef89f400e709431977f05dac96961d914e/GarbageMan/assets/SmartRefs.png
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 WithSecure Labs
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # GarbageMan
2 |
3 | ## What is GarbageMan?
4 |
5 | `GarbageMan` is a set of tools designed for .NET heap analysis. These tools offer the following benefits for malware researchers:
6 |
7 | - Ability to extract clear-text payload (PE Images etc.) from .NET heaps quickly.
8 | - Easy analysis of encrypted network protocols, signs of data exfiltration, and similar.
9 | - Ability to overcome malware anti-dumping techniques (`psnotify`)
10 |
11 |
12 | More detailed description, background information and usage instructions can be found in WithSecure Labs tools: https://labs.withsecure.com/tools/garbageman/
13 |
14 | More details about the `psnotify` can be found here: [psnotify/README.md](psnotify).
15 |
16 |
17 | ## How to get it?
18 |
19 | Download the latest release from the "Releases". You will probably need `psnotify` in addition to GarbageMan release.
20 |
21 | For running GarbageMan, you need to install .NET 5.0 desktop runtime for amd64 and x86 (yes, both). On the first run, Windows probably offers download link automatically. Just make sure to install `desktop` runtimes.
22 |
23 | Note that GarbageMan and psnotify were developed and tested only in x64 Windows 10. It won't probably run on any other Windows version.
24 |
25 |
26 | ## How to use it?
27 |
28 | Crash course:
29 |
30 | - Extract the release archive, run GarbageMan.exe
31 | - You can attach to running process, or execute a new process, or open minidump from File menu
32 | - You can also open existing GarbageMan database
33 |
34 | If you need to use `psnotify` for dumping, you need to extract it to `C:\psnotify` (yes, that's fixed for now). Just run `psnotify.exe` and stop it with `Ctrl+C` when done. It will create minidumps in `C:\dumps`. You can later then analyze those dumps with GarbageMan.
35 |
36 | **Note**: If you'd like to specify a working directory for the program to execute from, make sure psnotify isn't running as it will conflict with GarbageMan.
37 |
38 |
39 | ## How to compile the GUI tool
40 |
41 | For compiling a release, you need to install:
42 |
43 | - MS Visual Studio 2019 or 2022 (pick up .NET desktop dev workload)
44 | - .NET 5.0 Runtime (as a part of VS, with VS2022 you need pick it up from "Individual components")
45 |
46 | After installing the VS, run "Developer PowerShell for VS" and then run `build.bat`.
47 |
48 | Please do note that `build.bat` refers to `compress.ps1` which is probably not going to run properly until your policy allows running powershell scripts.
49 |
50 | If everything goes well, this should produce `GarbageMan-X.X.X.zip` where X.X.X is the version of your build, as defined in the GarbageMan project assembly properties. If the PS script fails, the GarbageMan release build should still be available in directory `rel`.
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/build.bat:
--------------------------------------------------------------------------------
1 | rmdir /s /q rel
2 | mkdir rel
3 |
4 | dotnet restore
5 |
6 | msbuild -target:GarbageMan /p:Configuration=Release /p:Platform=x64 GarbageMan.sln
7 | msbuild -target:GM /p:Configuration=Release /p:Platform=x64 GarbageMan.sln
8 | msbuild -target:GM /p:Configuration=Release /p:Platform=x86 GarbageMan.sln
9 |
10 | xcopy GarbageMan\bin\x64\Release\net5.0-windows\* rel\ /E /H
11 | rmdir /s /q rel\runtimes\
12 | mkdir rel\runtimes\win
13 | xcopy GarbageMan\bin\x64\Release\net5.0-windows\runtimes\win rel\runtimes\win\ /E /H
14 | mkdir rel\runtimes\win-x64
15 | xcopy GarbageMan\bin\x64\Release\net5.0-windows\runtimes\win-x64 rel\runtimes\win-x64\ /E /H
16 |
17 | mkdir rel\bin
18 |
19 | mkdir rel\bin\x64
20 | xcopy GM\bin\x64\Release\net5.0\* rel\bin\x64\ /E /H
21 | rmdir /s /q rel\bin\x64\runtimes\
22 | mkdir rel\bin\x64\runtimes\win-x64
23 | xcopy GM\bin\x64\Release\net5.0\runtimes\win-x64 rel\bin\x64\runtimes\win-x64\ /E /H
24 |
25 | mkdir rel\bin\x86
26 | xcopy GM\bin\x86\Release\net5.0\* rel\bin\x86\ /E /H
27 | rmdir /s /q rel\bin\x86\runtimes\
28 | mkdir rel\bin\x86\runtimes\win-x86
29 | xcopy GM\bin\x86\Release\net5.0\runtimes\win-x86 rel\bin\x86\runtimes\win-x86\ /E /H
30 |
31 | copy Search.json rel\
32 |
33 |
34 | powershell -File compress.ps1 -ExecutionPolicy Bypass
--------------------------------------------------------------------------------
/compress.ps1:
--------------------------------------------------------------------------------
1 |
2 | $V=Select-Xml -Path .\GarbageMan\GarbageMan.csproj -XPath '/Project/PropertyGroup/Version' | ForEach-Object { $_.Node.InnerXML }
3 | $G="GarbageMan-"+$V
4 | $Z=$G+".zip"
5 | Rename-Item rel $G
6 | Compress-Archive -Path $G -DestinationPath $Z
7 |
8 |
--------------------------------------------------------------------------------
/psnotify/.gitignore:
--------------------------------------------------------------------------------
1 | /sys/.vs/
2 | /sys/out/
3 | /sys/tmp/
4 | /exe/.vs/
5 | /exe/x64/
6 | /exe/Release/
7 | /exe/Debug/
8 | /exe/packages/
9 | /hook/.vs/
10 | /hook/x64/
11 | /hook/Release/
12 | /hook/Debug/
13 | /inject/.vs/
14 | /inject/x64/
15 | /inject/Release/
16 | /inject/Debug/
17 | /dump/.vs/
18 | /dump/x64/
19 | /dump/Release/
20 | /dump/Debug/
--------------------------------------------------------------------------------
/psnotify/README.md:
--------------------------------------------------------------------------------
1 | # psnotify
2 |
3 | `psnotify` is a POC tool to fight .NET anti-dumping tricks. It does this with two specific techniques:
4 |
5 | - Dump process image to disk on exit
6 | - Prevent user-initiated garbage collection
7 |
8 | The key functionality of `psnotify` is based on registering `PsSetCreateProcessNotifyRoutineEx` with a driver that notifies the user-mode component for any process creation and termination. That's where the name comes from.
9 |
10 | For new processes, the program injects a hook DLL that tries to prevent garbage collection. On process exit, the program dumps its full memory on disk as MS minidump image.
11 |
12 |
13 | ## Installation, running and configuration
14 |
15 | Installation is very simple: just extract the release archive as `C:\psnotify`. The directory is hard-coded in the POC.
16 |
17 | Running is a matter of executing `psnotify.exe`, it will take care of all the service handling. By default, it dumps only .NET processes. This can be changed with command line option `-a`. Hook DLL is injected to all processes, since managed functionality can in theory also appear dynamically.
18 |
19 | **Note**: `psnotify.sys` is signed by test certificate. You need to sign it yourself or put the machine in test sigining mode (`bcdedit /set testsigning on`).
20 |
21 | Minidumps are written to `C:\dumps`. These files are straight out compatible with `GarbageMan`.
22 |
23 | There are two things to configure:
24 | - Whitelisting. Just add program names to `whitelist.txt` for preventing dumping. For example there's GarbageMan and some other common non-interesting programs
25 | - Symbols are needed by the user-mode hook component in `c:\symbols` (more on that below).
26 |
27 |
28 | ## GC hooking and symbols
29 |
30 | This feature is based on inline hooking the garbage collection routine in .NET runtime. Prototype of the routine looks like this:
31 |
32 | ```
33 | static VOID (WINAPI* Collect)(INT c1, INT c2);
34 | ```
35 |
36 | Bypassing garbage collection can be achieved by just inserting return. We use the [Detours](https://github.com/microsoft/Detours) library for inline hooking.
37 |
38 | This routine is not exported symbol, so it needs to be resolved from debug symbol file. If the symbols are not available in `C:\symbols`, hooking cannot be done.
39 |
40 | Hook routine logs some details using debug printing, so you need to first make that visible with [dbgview](https://docs.microsoft.com/en-us/sysinternals/downloads/debugview).
41 |
42 | Failure to install hook looks like this in debug log:
43 | ```
44 | [4564] Hook: C:\Users\turkja\Test.exe: C:\Windows\Microsoft.NET\Framework\v4.0.30319\clr.dll
45 | [4564] Hook: C:\Users\turkja\Test.exe: ERROR: Could not find clr!GCInterface::Collect
46 | ```
47 |
48 | Most simple method for downlowding the symbols is a tool like [PDB-Downlowder](https://github.com/rajkumar-rangaraj/PDB-Downloader). Just take the DLL path from debug log to get the PDB to default location (`C:\symbols`). It might be a good idea to add `PDBDownlader.exe` to `whitelist.txt`, if you use it to get symbols.
49 |
50 | Successful hooking looks like this:
51 | ```
52 | [4032] Hook: C:\Users\turkja\Test.exe: C:\Windows\Microsoft.NET\Framework\v4.0.30319\clr.dll
53 | [4032] Hook: C:\Users\turkja\Test.exe: SUCCESS: Found clr!GCInterface::Collect
54 | ```
55 |
56 | Note that you need to download symbols for each .NET runtime. In practice, this needs to be done 32 -and 64-bit .NET Framework 4.x, .NET 5.0 etc. Failure to install hooks doesn't prevent anything else besides the user-initiated GC. Progams run and gets dumped on disk anyways.
57 |
58 |
59 | ## How to compile
60 |
61 | For compiling user-mode and kernel-mode components, you need to install:
62 |
63 | - MS Visual Studio 2019 or 2022 (with C++ dev workload)
64 | - WDK for Windows 10 (for driver)
65 |
66 | There are separate solution files for user-mode (`exe/psnotify.sln`) and driver (`sys/psnotify.sln`). First can used to compile all user-mode components. Note that you need both 32 and 64-bit builds for `dump`, `hook` and `inject`.
67 |
68 | When compiling the driver, you probably need to deal with driver signing, which is turned off by the solution. The solution file refers to test-signing certificate `test.pfx` which you need to create, or then compile without signature and sign manually.
69 |
70 | Also note that we use ad-hoc altitude value for the driver, you might need to deal with this as well: https://docs.microsoft.com/en-us/windows-hardware/drivers/ifs/load-order-groups-and-altitudes-for-minifilter-drivers
71 |
72 |
73 |
74 |
75 |
76 |
--------------------------------------------------------------------------------
/psnotify/dump/dump.cpp:
--------------------------------------------------------------------------------
1 |
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 |
11 | int main(int argc, char** argv)
12 | {
13 | if (argc < 2)
14 | {
15 | std::cout << "Usage: " << argv[0] << " [-a]\n";
16 | return 1;
17 | }
18 |
19 | // Read in whitelisted processes
20 | std::list whitelisted;
21 | std::wfstream fs_file;
22 | fs_file.open("whitelist.txt", std::ios::in);
23 | if (fs_file.is_open())
24 | {
25 | std::wstring line;
26 | while (std::getline(fs_file, line))
27 | {
28 | whitelisted.push_back(line);
29 | }
30 | fs_file.close();
31 | }
32 |
33 | int pid = atoi(argv[1]);
34 | HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
35 | if (hProcess == NULL)
36 | {
37 | std::cout << "Error: cannot open process\n";
38 | return 1;
39 | }
40 |
41 | // Enumerate loaded modules in the process for detecting .NET runtimes
42 | HMODULE hMods[1024];
43 | DWORD cbNeeded;
44 | unsigned int i;
45 | BOOL bIsDotNet = FALSE;
46 | if (EnumProcessModules(hProcess, hMods, sizeof(hMods), &cbNeeded))
47 | {
48 | for (i = 0; i < (cbNeeded / sizeof(HMODULE)); i++)
49 | {
50 | TCHAR szModName[MAX_PATH];
51 | if (GetModuleFileNameEx(hProcess, hMods[i], szModName,
52 | sizeof(szModName) / sizeof(TCHAR)))
53 | {
54 | // Check if this module indicates .NET
55 | std::wstring modName(szModName);
56 | if ((modName.find(L"clrjit.dll") != std::string::npos) || (modName.find(L"mscorwks.dll") != std::string::npos))
57 | {
58 | bIsDotNet = TRUE;
59 | break;
60 | }
61 | }
62 | }
63 | }
64 | if ((bIsDotNet == FALSE) && (argc < 3))
65 | {
66 | CloseHandle(hProcess);
67 | return 0;
68 | }
69 |
70 | // Create dump directory
71 | std::wstring dirName(L"C:\\dumps");
72 | CreateDirectory(dirName.c_str(), NULL);
73 |
74 | // Get the base name of process executable
75 | std::wstringstream ss;
76 | WCHAR moduleName[MAX_PATH];
77 | if (!GetModuleBaseName(hProcess, NULL, moduleName, MAX_PATH - 1))
78 | {
79 | ss << dirName << L"\\dump." << pid << L".dmp";
80 | }
81 | else
82 | {
83 | ss << dirName << L"\\" << moduleName << L"." << pid << L".dmp";
84 | }
85 |
86 | // Check of this process is whitelisted
87 | for (std::list::iterator it = whitelisted.begin(); it != whitelisted.end(); ++it)
88 | {
89 | if (*it == moduleName)
90 | {
91 | CloseHandle(hProcess);
92 | return 0;
93 | }
94 | }
95 |
96 | // Ready for dump!
97 |
98 | std::wcout << L"Dumping process to " << ss.str().c_str() << std::endl;
99 | HANDLE hFile = CreateFile(ss.str().c_str(), // name of the write
100 | GENERIC_WRITE, // open for writing
101 | 0, // do not share
102 | NULL, // default security
103 | CREATE_ALWAYS, // create always
104 | FILE_ATTRIBUTE_NORMAL, // normal file
105 | NULL); // no attr. template
106 |
107 | if (hFile == NULL)
108 | {
109 | std::cout << "Error: cannot open dump file\n";
110 | CloseHandle(hProcess);
111 | return 1;
112 | }
113 |
114 | BOOL s = MiniDumpWriteDump(
115 | hProcess,
116 | pid,
117 | hFile,
118 | MiniDumpWithFullMemory,
119 | NULL,
120 | NULL,
121 | NULL
122 | );
123 |
124 | if (!s)
125 | {
126 | std::cout << "Error: cannot dump process: " << GetLastError() << std::endl;
127 | CloseHandle(hProcess);
128 | CloseHandle(hFile);
129 | return 1;
130 | }
131 |
132 | CloseHandle(hProcess);
133 | CloseHandle(hFile);
134 | return 0;
135 | }
136 |
--------------------------------------------------------------------------------
/psnotify/dump/dump.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Release
10 | Win32
11 |
12 |
13 | Debug
14 | x64
15 |
16 |
17 | Release
18 | x64
19 |
20 |
21 |
22 | 16.0
23 | Win32Proj
24 | {4b4dbe09-f69e-4499-b9c5-2b10e35b724c}
25 | dump
26 | 10.0
27 |
28 |
29 |
30 | Application
31 | true
32 | v142
33 | Unicode
34 |
35 |
36 | Application
37 | false
38 | v142
39 | true
40 | Unicode
41 |
42 |
43 | Application
44 | true
45 | v142
46 | Unicode
47 |
48 |
49 | Application
50 | false
51 | v142
52 | true
53 | Unicode
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 | true
75 |
76 |
77 | false
78 | dump32
79 |
80 |
81 | true
82 |
83 |
84 | false
85 | dump64
86 |
87 |
88 |
89 | Level3
90 | true
91 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
92 | true
93 |
94 |
95 | Console
96 | true
97 |
98 |
99 |
100 |
101 | Level3
102 | true
103 | true
104 | true
105 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
106 | true
107 | MultiThreaded
108 |
109 |
110 | Console
111 | true
112 | true
113 | true
114 | dbghelp.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
115 |
116 |
117 |
118 |
119 | Level3
120 | true
121 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
122 | true
123 |
124 |
125 | Console
126 | true
127 |
128 |
129 |
130 |
131 | Level3
132 | true
133 | true
134 | true
135 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
136 | true
137 | MultiThreaded
138 |
139 |
140 | Console
141 | true
142 | true
143 | true
144 | dbghelp.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
--------------------------------------------------------------------------------
/psnotify/dump/dump.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
11 |
12 |
13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
15 |
16 |
17 |
18 |
19 | Source Files
20 |
21 |
22 |
--------------------------------------------------------------------------------
/psnotify/dump/dump.vcxproj.user:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/psnotify/exe/psnotify.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.31729.503
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "psnotify", "psnotify.vcxproj", "{A4B11274-8DDC-42CC-9938-6FC88D9C9FDD}"
7 | EndProject
8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "hook", "..\hook\hook.vcxproj", "{6B50913F-92AC-41A6-8395-26F69D851D59}"
9 | EndProject
10 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "inject", "..\inject\inject.vcxproj", "{956CE75C-B9AD-44E5-9FDE-FBFD80C56A16}"
11 | EndProject
12 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dump", "..\dump\dump.vcxproj", "{4B4DBE09-F69E-4499-B9C5-2B10E35B724C}"
13 | EndProject
14 | Global
15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
16 | Debug|x64 = Debug|x64
17 | Debug|x86 = Debug|x86
18 | Release|x64 = Release|x64
19 | Release|x86 = Release|x86
20 | EndGlobalSection
21 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
22 | {A4B11274-8DDC-42CC-9938-6FC88D9C9FDD}.Debug|x64.ActiveCfg = Debug|x64
23 | {A4B11274-8DDC-42CC-9938-6FC88D9C9FDD}.Debug|x64.Build.0 = Debug|x64
24 | {A4B11274-8DDC-42CC-9938-6FC88D9C9FDD}.Debug|x86.ActiveCfg = Debug|Win32
25 | {A4B11274-8DDC-42CC-9938-6FC88D9C9FDD}.Debug|x86.Build.0 = Debug|Win32
26 | {A4B11274-8DDC-42CC-9938-6FC88D9C9FDD}.Release|x64.ActiveCfg = Release|x64
27 | {A4B11274-8DDC-42CC-9938-6FC88D9C9FDD}.Release|x64.Build.0 = Release|x64
28 | {A4B11274-8DDC-42CC-9938-6FC88D9C9FDD}.Release|x86.ActiveCfg = Release|Win32
29 | {A4B11274-8DDC-42CC-9938-6FC88D9C9FDD}.Release|x86.Build.0 = Release|Win32
30 | {6B50913F-92AC-41A6-8395-26F69D851D59}.Debug|x64.ActiveCfg = Debug|x64
31 | {6B50913F-92AC-41A6-8395-26F69D851D59}.Debug|x64.Build.0 = Debug|x64
32 | {6B50913F-92AC-41A6-8395-26F69D851D59}.Debug|x86.ActiveCfg = Debug|Win32
33 | {6B50913F-92AC-41A6-8395-26F69D851D59}.Debug|x86.Build.0 = Debug|Win32
34 | {6B50913F-92AC-41A6-8395-26F69D851D59}.Release|x64.ActiveCfg = Release|x64
35 | {6B50913F-92AC-41A6-8395-26F69D851D59}.Release|x64.Build.0 = Release|x64
36 | {6B50913F-92AC-41A6-8395-26F69D851D59}.Release|x86.ActiveCfg = Release|Win32
37 | {6B50913F-92AC-41A6-8395-26F69D851D59}.Release|x86.Build.0 = Release|Win32
38 | {956CE75C-B9AD-44E5-9FDE-FBFD80C56A16}.Debug|x64.ActiveCfg = Debug|x64
39 | {956CE75C-B9AD-44E5-9FDE-FBFD80C56A16}.Debug|x64.Build.0 = Debug|x64
40 | {956CE75C-B9AD-44E5-9FDE-FBFD80C56A16}.Debug|x86.ActiveCfg = Debug|Win32
41 | {956CE75C-B9AD-44E5-9FDE-FBFD80C56A16}.Debug|x86.Build.0 = Debug|Win32
42 | {956CE75C-B9AD-44E5-9FDE-FBFD80C56A16}.Release|x64.ActiveCfg = Release|x64
43 | {956CE75C-B9AD-44E5-9FDE-FBFD80C56A16}.Release|x64.Build.0 = Release|x64
44 | {956CE75C-B9AD-44E5-9FDE-FBFD80C56A16}.Release|x86.ActiveCfg = Release|Win32
45 | {956CE75C-B9AD-44E5-9FDE-FBFD80C56A16}.Release|x86.Build.0 = Release|Win32
46 | {4B4DBE09-F69E-4499-B9C5-2B10E35B724C}.Debug|x64.ActiveCfg = Debug|x64
47 | {4B4DBE09-F69E-4499-B9C5-2B10E35B724C}.Debug|x64.Build.0 = Debug|x64
48 | {4B4DBE09-F69E-4499-B9C5-2B10E35B724C}.Debug|x86.ActiveCfg = Debug|Win32
49 | {4B4DBE09-F69E-4499-B9C5-2B10E35B724C}.Debug|x86.Build.0 = Debug|Win32
50 | {4B4DBE09-F69E-4499-B9C5-2B10E35B724C}.Release|x64.ActiveCfg = Release|x64
51 | {4B4DBE09-F69E-4499-B9C5-2B10E35B724C}.Release|x64.Build.0 = Release|x64
52 | {4B4DBE09-F69E-4499-B9C5-2B10E35B724C}.Release|x86.ActiveCfg = Release|Win32
53 | {4B4DBE09-F69E-4499-B9C5-2B10E35B724C}.Release|x86.Build.0 = Release|Win32
54 | EndGlobalSection
55 | GlobalSection(SolutionProperties) = preSolution
56 | HideSolutionNode = FALSE
57 | EndGlobalSection
58 | GlobalSection(ExtensibilityGlobals) = postSolution
59 | SolutionGuid = {7C3BC4B6-EC6F-42A6-8647-04430CE54E30}
60 | EndGlobalSection
61 | EndGlobal
62 |
--------------------------------------------------------------------------------
/psnotify/exe/psnotify.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Release
10 | Win32
11 |
12 |
13 | Debug
14 | x64
15 |
16 |
17 | Release
18 | x64
19 |
20 |
21 |
22 | 16.0
23 | Win32Proj
24 | {a4b11274-8ddc-42cc-9938-6fc88d9c9fdd}
25 | psnotify
26 | 10.0
27 |
28 |
29 |
30 | Application
31 | true
32 | v142
33 | Unicode
34 |
35 |
36 | Application
37 | false
38 | v142
39 | true
40 | Unicode
41 |
42 |
43 | Application
44 | true
45 | v142
46 | Unicode
47 |
48 |
49 | Application
50 | false
51 | v142
52 | true
53 | Unicode
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 | true
75 |
76 |
77 | false
78 |
79 |
80 | true
81 |
82 |
83 | false
84 |
85 |
86 |
87 | Level3
88 | true
89 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
90 | true
91 | ..\include
92 | MultiThreadedDebug
93 | false
94 |
95 |
96 | Console
97 | true
98 | FltLib.lib;Dbghelp.lib;%(AdditionalDependencies)
99 |
100 |
101 |
102 |
103 | Level3
104 | true
105 | true
106 | true
107 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
108 | true
109 | ..\include
110 | MultiThreaded
111 | false
112 |
113 |
114 | Console
115 | true
116 | true
117 | true
118 | FltLib.lib;Dbghelp.lib;%(AdditionalDependencies)
119 | RequireAdministrator
120 | false
121 |
122 |
123 |
124 |
125 | Level3
126 | true
127 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
128 | true
129 | ..\include
130 | MultiThreadedDebug
131 |
132 |
133 | Console
134 | true
135 | FltLib.lib;Dbghelp.lib;%(AdditionalDependencies)
136 |
137 |
138 |
139 |
140 | Level3
141 | true
142 | true
143 | true
144 | DETOUR_DEBUG;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
145 | true
146 | ..\include
147 | MultiThreaded
148 |
149 |
150 | Console
151 | true
152 | true
153 | true
154 | FltLib.lib;Dbghelp.lib;%(AdditionalDependencies)
155 | RequireAdministrator
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
--------------------------------------------------------------------------------
/psnotify/exe/psnotify.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
11 |
12 |
13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
15 |
16 |
17 |
18 |
19 | Source Files
20 |
21 |
22 |
--------------------------------------------------------------------------------
/psnotify/exe/psnotify.vcxproj.user:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/psnotify/hook/Source.def:
--------------------------------------------------------------------------------
1 | LIBRARY
2 | EXPORTS
3 |
4 | DetourFinishHelperProcess @1 NONAME
--------------------------------------------------------------------------------
/psnotify/hook/dllmain.cpp:
--------------------------------------------------------------------------------
1 |
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 |
10 | BOOL bHook = TRUE;
11 | BOOL GCHooked = FALSE;
12 | BOOL OldGCHooked = FALSE;
13 |
14 | WCHAR wcModulePath[MAX_PATH];
15 |
16 |
17 | VOID PrintMessage(const WCHAR* msg)
18 | {
19 | std::wstring dbgString(L"Hook: ");
20 | dbgString += wcModulePath;
21 | dbgString += L": ";
22 | dbgString += msg;
23 | OutputDebugString(dbgString.c_str());
24 | }
25 |
26 |
27 |
28 |
29 | BOOL Initialize()
30 | {
31 | GetModuleFileNameW(NULL, wcModulePath, MAX_PATH);
32 |
33 | std::list whitelisted;
34 |
35 | // Read in whitelisted processes
36 | std::wfstream fs_file;
37 |
38 | fs_file.open("C:\\psnotify\\whitelist.txt", std::ios::in);
39 | if (fs_file.is_open())
40 | {
41 | std::wstring line;
42 | while (std::getline(fs_file, line))
43 | {
44 | whitelisted.push_back(line);
45 | }
46 | fs_file.close();
47 | }
48 |
49 | // Check if we should hook this
50 | std::wstring libName(wcModulePath);
51 | for (std::list::iterator it = whitelisted.begin(); it != whitelisted.end(); ++it)
52 | {
53 | if (libName.find(*it) != std::string::npos)
54 | {
55 | PrintMessage(L"whitelisted");
56 | bHook = FALSE;
57 | return FALSE;
58 | }
59 | }
60 | return TRUE;
61 | }
62 |
63 |
64 |
65 | static VOID(WINAPI* TrueCollect)(INT c1, INT c2);
66 |
67 | VOID WINAPI CollectHook(INT c1, INT c2)
68 | {
69 | PrintMessage(L"CollectHook: GCInterface::Collect");
70 | // Just return
71 | return;
72 | }
73 |
74 | static VOID(WINAPI* TrueCollectGeneration)(INT c1, INT c2);
75 |
76 | VOID WINAPI CollectGenerationHook(INT c1, INT c2)
77 | {
78 | PrintMessage(L"CollectGenerationHook: GCInterface::CollectGeneration");
79 | // Just return
80 | return;
81 | }
82 |
83 | BOOL ResolveGCCollectGeneration()
84 | {
85 | HANDLE hProcess;
86 | hProcess = GetCurrentProcess();
87 |
88 | SymSetOptions(SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS | SYMOPT_DEBUG);
89 | if (!SymInitializeW(hProcess, L"c:\\symbols", TRUE))
90 | {
91 | return FALSE;
92 | }
93 |
94 | ULONG64 buffer[(sizeof(SYMBOL_INFOW) +
95 | MAX_SYM_NAME * sizeof(TCHAR) +
96 | sizeof(ULONG64) - 1) /
97 | sizeof(ULONG64)];
98 | PSYMBOL_INFOW pSymbol = (PSYMBOL_INFOW)buffer;
99 |
100 | pSymbol->SizeOfStruct = sizeof(SYMBOL_INFOW);
101 | pSymbol->MaxNameLen = MAX_SYM_NAME;
102 |
103 | std::wstring szSymbolName(L"mscorwks!GCInterface::CollectGeneration");
104 | HMODULE hMod = GetModuleHandleW(L"mscorwks.dll");
105 | if (hMod != NULL)
106 | {
107 | CHAR path[MAX_PATH];
108 | if (GetModuleFileNameA(hMod, path, MAX_PATH))
109 | {
110 | std::wstringstream ss(L"CLR: ");
111 | ss << path;
112 | PrintMessage(ss.str().c_str());
113 | }
114 | if (SymFromNameW(hProcess, szSymbolName.c_str(), pSymbol))
115 | {
116 | PrintMessage(L"SUCCESS: Found mscorwks!GCInterface::CollectGeneration");
117 | TrueCollectGeneration = (VOID(WINAPI*)(INT, INT))pSymbol->Address;
118 | return TRUE;
119 | }
120 | else
121 | {
122 | PrintMessage(L"ERROR: Could not find mscorwks!GCInterface::CollectGeneration");
123 | return FALSE;
124 | }
125 | }
126 | return FALSE;
127 | }
128 |
129 | BOOL ResolveGCCollect()
130 | {
131 | HANDLE hProcess;
132 | hProcess = GetCurrentProcess();
133 |
134 | SymSetOptions(SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS | SYMOPT_DEBUG);
135 | if (!SymInitializeW(hProcess, L"c:\\symbols", TRUE))
136 | {
137 | return FALSE;
138 | }
139 |
140 | ULONG64 buffer[(sizeof(SYMBOL_INFOW) +
141 | MAX_SYM_NAME * sizeof(TCHAR) +
142 | sizeof(ULONG64) - 1) /
143 | sizeof(ULONG64)];
144 | PSYMBOL_INFOW pSymbol = (PSYMBOL_INFOW)buffer;
145 |
146 | pSymbol->SizeOfStruct = sizeof(SYMBOL_INFOW);
147 | pSymbol->MaxNameLen = MAX_SYM_NAME;
148 |
149 | std::wstring szSymbolName(L"clr!GCInterface::Collect");
150 | HMODULE hMod = GetModuleHandleW(L"clr.dll");
151 | if (hMod != NULL)
152 | {
153 | CHAR path[MAX_PATH];
154 | if (GetModuleFileNameA(hMod, path, MAX_PATH))
155 | {
156 | std::wstringstream ss(L"CLR: ");
157 | ss << path;
158 | PrintMessage(ss.str().c_str());
159 | }
160 | if (SymFromNameW(hProcess, szSymbolName.c_str(), pSymbol))
161 | {
162 | PrintMessage(L"SUCCESS: Found clr!GCInterface::Collect");
163 | TrueCollect = (VOID(WINAPI*)(INT, INT))pSymbol->Address;
164 | return TRUE;
165 | }
166 | else
167 | {
168 | PrintMessage(L"ERROR: Could not find clr!GCInterface::Collect");
169 | return FALSE;
170 | }
171 | }
172 |
173 | std::wstring szSymbolNameCore(L"coreclr!GCInterface::Collect");
174 | hMod = GetModuleHandleW(L"coreclr.dll");
175 | if (hMod != NULL)
176 | {
177 | CHAR path[MAX_PATH];
178 | if (GetModuleFileNameA(hMod, path, MAX_PATH))
179 | {
180 | std::wstringstream ss(L"CLR: ");
181 | ss << path;
182 | PrintMessage(ss.str().c_str());
183 | }
184 | if (SymFromNameW(hProcess, szSymbolNameCore.c_str(), pSymbol))
185 | {
186 | PrintMessage(L"SUCCESS: Found coreclr!GCInterface::Collect");
187 | TrueCollect = (VOID(WINAPI*)(INT, INT))pSymbol->Address;
188 | return TRUE;
189 | }
190 | else
191 | {
192 | PrintMessage(L"ERROR: Could not find coreclr!GCInterface::Collect");
193 | }
194 | }
195 | return FALSE;
196 | }
197 |
198 |
199 |
200 | static HMODULE(WINAPI* TrueLoadLibraryExW)(LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags) = LoadLibraryExW;
201 |
202 | HMODULE WINAPI LoadLibraryExWHook(LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags)
203 | {
204 | if (GCHooked != TRUE)
205 | {
206 | std::wstring libName(lpLibFileName ? lpLibFileName : L"");
207 | if (libName.find(L"clrjit.dll") != std::string::npos)
208 | {
209 | if (ResolveGCCollect())
210 | {
211 | DetourRestoreAfterWith();
212 | DetourTransactionBegin();
213 | DetourUpdateThread(GetCurrentThread());
214 | DetourAttach(&(PVOID&)TrueCollect, CollectHook);
215 | DetourTransactionCommit();
216 | GCHooked = TRUE;
217 | }
218 | }
219 | }
220 |
221 | if (OldGCHooked != TRUE)
222 | {
223 | std::wstring libName(lpLibFileName ? lpLibFileName : L"");
224 | if (libName.find(L"mscorwks.dll") != std::string::npos)
225 | {
226 | HMODULE hMod = TrueLoadLibraryExW(lpLibFileName, hFile, dwFlags);
227 | if (ResolveGCCollectGeneration())
228 | {
229 | DetourRestoreAfterWith();
230 | DetourTransactionBegin();
231 | DetourUpdateThread(GetCurrentThread());
232 | DetourAttach(&(PVOID&)TrueCollectGeneration, CollectGenerationHook);
233 | DetourTransactionCommit();
234 | OldGCHooked = TRUE;
235 | }
236 | return hMod;
237 | }
238 | }
239 |
240 | return TrueLoadLibraryExW(lpLibFileName, hFile, dwFlags);
241 | }
242 |
243 |
244 |
245 | BOOL APIENTRY DllMain( HMODULE hModule,
246 | DWORD ul_reason_for_call,
247 | LPVOID lpReserved
248 | )
249 | {
250 | switch (ul_reason_for_call)
251 | {
252 | case DLL_PROCESS_ATTACH:
253 | if (!Initialize())
254 | break;
255 | DetourRestoreAfterWith();
256 | DetourTransactionBegin();
257 | DetourUpdateThread(GetCurrentThread());
258 | DetourAttach(&(PVOID&)TrueLoadLibraryExW, LoadLibraryExWHook);
259 | DetourTransactionCommit();
260 | break;
261 | case DLL_PROCESS_DETACH:
262 | if (!bHook)
263 | break;
264 | DetourTransactionBegin();
265 | DetourUpdateThread(GetCurrentThread());
266 | DetourDetach(&(PVOID&)TrueLoadLibraryExW, LoadLibraryExWHook);
267 | if (GCHooked == TRUE)
268 | DetourDetach(&(PVOID&)TrueCollect, CollectHook);
269 | if (OldGCHooked == TRUE)
270 | DetourDetach(&(PVOID&)TrueCollectGeneration, CollectGenerationHook);
271 | DetourTransactionCommit();
272 | break;
273 | }
274 | return TRUE;
275 | }
276 |
277 |
--------------------------------------------------------------------------------
/psnotify/hook/framework.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
4 | // Windows Header Files
5 | #include
6 |
--------------------------------------------------------------------------------
/psnotify/hook/hook.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
11 |
12 |
13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
15 |
16 |
17 |
18 |
19 | Header Files
20 |
21 |
22 | Header Files
23 |
24 |
25 |
26 |
27 | Source Files
28 |
29 |
30 |
31 |
32 | Source Files
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/psnotify/hook/hook.vcxproj.user:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/psnotify/hook/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/psnotify/hook/pch.cpp:
--------------------------------------------------------------------------------
1 | // pch.cpp: source file corresponding to the pre-compiled header
2 |
3 | #include "pch.h"
4 |
5 | // When you are using pre-compiled headers, this source file is necessary for compilation to succeed.
6 |
--------------------------------------------------------------------------------
/psnotify/hook/pch.h:
--------------------------------------------------------------------------------
1 | // pch.h: This is a precompiled header file.
2 | // Files listed below are compiled only once, improving build performance for future builds.
3 | // This also affects IntelliSense performance, including code completion and many code browsing features.
4 | // However, files listed here are ALL re-compiled if any one of them is updated between builds.
5 | // Do not add files here that you will be updating frequently as this negates the performance advantage.
6 |
7 | #ifndef PCH_H
8 | #define PCH_H
9 |
10 | // add headers that you want to pre-compile here
11 | #include "framework.h"
12 |
13 | #endif //PCH_H
14 |
--------------------------------------------------------------------------------
/psnotify/include/psnotify.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #define FILE_DEVICE_PSNOTIFY 504919
4 | const WCHAR PsNotifyLinkNameKernel[] = L"\\DosDevices\\psnotify";
5 | const WCHAR PsNotifyDeviceName[] = L"\\Device\\psnotify";
6 | const WCHAR PsNotifyLinkNameDos[] = L"\\\\.\\psnotify";
7 | const WCHAR PsNotifyPort[] = L"\\psnotifyPort";
8 |
9 | enum class MessageId : UINT
10 | {
11 | Unset,
12 | OnCreateRequest,
13 | OnCreateResponse,
14 | OnTerminateRequest,
15 | OnTerminateResponse,
16 | };
17 |
18 | struct ProcessNotificationMessageOnProcessCreateRequest
19 | {
20 | DWORD pid = 0;
21 | DWORD parentPid = 0;
22 | WCHAR imagePath[1024];
23 | WCHAR commandLine[1024];
24 | };
25 |
26 | struct ProcessNotificationMessageOnProcessCreateResponse
27 | {
28 | DWORD status = 0;
29 | };
30 |
31 | struct ProcessNotificationMessageOnProcessTerminateRequest
32 | {
33 | DWORD pid = 0;
34 | };
35 |
36 | struct ProcessNotificationMessageOnProcessTerminateResponse
37 | {
38 | DWORD status = 0;
39 | };
40 |
41 |
42 | struct ProcessNotificationMessage
43 | {
44 | MessageId msgId = MessageId::Unset;
45 | union {
46 | ProcessNotificationMessageOnProcessCreateRequest onCreateRequest;
47 | ProcessNotificationMessageOnProcessCreateResponse onCreateResponse;
48 | ProcessNotificationMessageOnProcessTerminateRequest onTerminateRequest;
49 | ProcessNotificationMessageOnProcessTerminateResponse onTerminateResponse;
50 | };
51 | ProcessNotificationMessage() {}
52 | };
53 |
54 |
55 |
--------------------------------------------------------------------------------
/psnotify/inject/detver.h:
--------------------------------------------------------------------------------
1 | //////////////////////////////////////////////////////////////////////////////
2 | //
3 | // Common version parameters.
4 | //
5 | // Microsoft Research Detours Package, Version 4.0.1
6 | //
7 | // Copyright (c) Microsoft Corporation. All rights reserved.
8 | //
9 |
10 | #define _USING_V110_SDK71_ 1
11 | #include "winver.h"
12 | #if 0
13 | #include
14 | #include
15 | #else
16 | #ifndef DETOURS_STRINGIFY
17 | #define DETOURS_STRINGIFY_(x) #x
18 | #define DETOURS_STRINGIFY(x) DETOURS_STRINGIFY_(x)
19 | #endif
20 |
21 | #define VER_FILEFLAGSMASK 0x3fL
22 | #define VER_FILEFLAGS 0x0L
23 | #define VER_FILEOS 0x00040004L
24 | #define VER_FILETYPE 0x00000002L
25 | #define VER_FILESUBTYPE 0x00000000L
26 | #endif
27 | #define VER_DETOURS_BITS DETOURS_STRINGIFY(DETOURS_BITS)
28 |
--------------------------------------------------------------------------------
/psnotify/inject/disolarm.cpp:
--------------------------------------------------------------------------------
1 | #define DETOURS_ARM_OFFLINE_LIBRARY
2 | #include "disasm.cpp"
3 |
--------------------------------------------------------------------------------
/psnotify/inject/disolarm64.cpp:
--------------------------------------------------------------------------------
1 | #define DETOURS_ARM64_OFFLINE_LIBRARY
2 | #include "disasm.cpp"
3 |
--------------------------------------------------------------------------------
/psnotify/inject/disolia64.cpp:
--------------------------------------------------------------------------------
1 | #define DETOURS_IA64_OFFLINE_LIBRARY
2 | #include "disasm.cpp"
3 |
--------------------------------------------------------------------------------
/psnotify/inject/disolx64.cpp:
--------------------------------------------------------------------------------
1 | #define DETOURS_X64_OFFLINE_LIBRARY
2 | #include "disasm.cpp"
3 |
--------------------------------------------------------------------------------
/psnotify/inject/disolx86.cpp:
--------------------------------------------------------------------------------
1 | #define DETOURS_X86_OFFLINE_LIBRARY
2 | #include "disasm.cpp"
3 |
--------------------------------------------------------------------------------
/psnotify/inject/inject.cpp:
--------------------------------------------------------------------------------
1 | // inject.cpp : This file contains the 'main' function. Program execution begins and ends there.
2 | //
3 |
4 | #include
5 | #include
6 | #include "detours.h"
7 |
8 | int main(int argc, char** argv)
9 | {
10 | if (argc < 2)
11 | {
12 | std::cout << "Usage: " << argv[0] << " \n";
13 | return 1;
14 | }
15 |
16 | int pid = atoi(argv[1]);
17 | HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
18 | if (hProcess == NULL)
19 | {
20 | std::cout << "Error: cannot open process\n";
21 | return 1;
22 | }
23 |
24 | #if DETOURS_64BIT
25 | std::string dllPath("C:\\psnotify\\hook64.dll");
26 | #else
27 | std::string dllPath("C:\\psnotify\\hook32.dll");
28 | #endif
29 | LPCSTR sz = dllPath.c_str();
30 |
31 | if (!DetourUpdateProcessWithDll(hProcess, &sz, 1))
32 | {
33 | printf("DetourUpdateProcessWithDll failed (%d).\n", GetLastError());
34 | }
35 | else
36 | {
37 | printf("DetourUpdateProcessWithDll success\n");
38 | }
39 |
40 | CloseHandle(hProcess);
41 | return 0;
42 | }
--------------------------------------------------------------------------------
/psnotify/inject/inject.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Release
10 | Win32
11 |
12 |
13 | Debug
14 | x64
15 |
16 |
17 | Release
18 | x64
19 |
20 |
21 |
22 | 16.0
23 | Win32Proj
24 | {956ce75c-b9ad-44e5-9fde-fbfd80c56a16}
25 | inject
26 | 10.0
27 |
28 |
29 |
30 | Application
31 | true
32 | v142
33 | Unicode
34 |
35 |
36 | Application
37 | false
38 | v142
39 | true
40 | Unicode
41 |
42 |
43 | Application
44 | true
45 | v142
46 | Unicode
47 |
48 |
49 | Application
50 | false
51 | v142
52 | true
53 | Unicode
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 | true
75 |
76 |
77 | false
78 | inject32
79 |
80 |
81 | true
82 |
83 |
84 | false
85 | inject64
86 |
87 |
88 |
89 | Level3
90 | true
91 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
92 | true
93 |
94 |
95 | Console
96 | true
97 |
98 |
99 |
100 |
101 | Level3
102 | true
103 | true
104 | true
105 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
106 | true
107 | MultiThreaded
108 |
109 |
110 | Console
111 | true
112 | true
113 | true
114 |
115 |
116 |
117 |
118 | Level3
119 | true
120 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
121 | true
122 |
123 |
124 | Console
125 | true
126 |
127 |
128 |
129 |
130 | Level3
131 | true
132 | true
133 | true
134 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
135 | true
136 | MultiThreaded
137 |
138 |
139 | Console
140 | true
141 | true
142 | true
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
--------------------------------------------------------------------------------
/psnotify/inject/inject.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
11 |
12 |
13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
15 |
16 |
17 |
18 |
19 | Source Files
20 |
21 |
22 | Source Files
23 |
24 |
25 | Source Files
26 |
27 |
28 | Source Files
29 |
30 |
31 | Source Files
32 |
33 |
34 | Source Files
35 |
36 |
37 | Source Files
38 |
39 |
40 | Source Files
41 |
42 |
43 | Source Files
44 |
45 |
46 | Source Files
47 |
48 |
49 | Source Files
50 |
51 |
52 |
53 |
54 | Source Files
55 |
56 |
57 | Source Files
58 |
59 |
60 |
--------------------------------------------------------------------------------
/psnotify/inject/inject.vcxproj.user:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/psnotify/readme:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WithSecureLabs/GarbageMan/1229c2ef89f400e709431977f05dac96961d914e/psnotify/readme
--------------------------------------------------------------------------------
/psnotify/sys/Retpoline.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | /d2guardretpoline %(AdditionalOptions)
9 |
10 |
11 | /kernel /INTEGRITYCHECK /d2:-guardretpoline /guard:retpoline %(AdditionalOptions)
12 |
13 |
14 | /GuardRetpoline %(AdditionalOptions)
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/psnotify/sys/memobj.cpp:
--------------------------------------------------------------------------------
1 | #include "stdafx.h"
2 | #include "memobj.h"
3 |
4 | #define __DEFAULT_TAG__ 'fnsP'
5 |
6 |
7 | __drv_allocatesMem(Mem)
8 | _When_((PoolType & PagedPool) != 0, _IRQL_requires_max_(APC_LEVEL))
9 | _When_((PoolType & PagedPool) == 0, _IRQL_requires_max_(DISPATCH_LEVEL))
10 | _When_((PoolType & NonPagedPoolMustSucceed) != 0,
11 | __drv_reportError("Must succeed pool allocations are forbidden. "
12 | "Allocation failures cause a system crash"))
13 | _When_((PoolType & (NonPagedPoolMustSucceed | POOL_RAISE_IF_ALLOCATION_FAILURE)) == 0,
14 | _Post_maybenull_ _Must_inspect_result_)
15 | _When_((PoolType & (NonPagedPoolMustSucceed | POOL_RAISE_IF_ALLOCATION_FAILURE)) != 0,
16 | _Post_notnull_)
17 | _Post_writable_byte_size_(NumberOfBytes) void* __cdecl
18 | operator new(size_t NumberOfBytes, POOL_TYPE PoolType)
19 | {
20 | return ::ExAllocatePoolWithTag(PoolType, NumberOfBytes, __DEFAULT_TAG__);
21 | }
22 |
23 | __drv_allocatesMem(Mem)
24 | _When_((PoolType & PagedPool) != 0, _IRQL_requires_max_(APC_LEVEL))
25 | _When_((PoolType & PagedPool) == 0, _IRQL_requires_max_(DISPATCH_LEVEL))
26 | _When_((PoolType & NonPagedPoolMustSucceed) != 0,
27 | __drv_reportError("Must succeed pool allocations are forbidden. "
28 | "Allocation failures cause a system crash"))
29 | _When_((PoolType & (NonPagedPoolMustSucceed | POOL_RAISE_IF_ALLOCATION_FAILURE)) == 0,
30 | _Post_maybenull_ _Must_inspect_result_)
31 | _When_((PoolType & (NonPagedPoolMustSucceed | POOL_RAISE_IF_ALLOCATION_FAILURE)) != 0,
32 | _Post_notnull_)
33 | _Post_writable_byte_size_(NumberOfBytes) void *__cdecl
34 | operator new[](size_t NumberOfBytes, POOL_TYPE PoolType)
35 | {
36 | return ::ExAllocatePoolWithTag(PoolType, NumberOfBytes, __DEFAULT_TAG__);
37 | }
38 |
39 | void __cdecl operator delete(void *ptr, POOL_TYPE PoolType)
40 | {
41 | ::ExFreePoolWithTag(ptr, __DEFAULT_TAG__);
42 | }
43 |
44 | void __cdecl operator delete[](void *ptr, POOL_TYPE PoolType)
45 | {
46 | ::ExFreePoolWithTag(ptr, __DEFAULT_TAG__);
47 | }
48 |
49 | void *__cdecl operator new(size_t ulSize)
50 | {
51 | return ::ExAllocatePoolWithTag(PagedPool, ulSize, __DEFAULT_TAG__);
52 | }
53 |
54 | void __cdecl operator delete(void *ptr)
55 | {
56 | if (!ptr)
57 | return;
58 | return ::ExFreePoolWithTag(ptr, __DEFAULT_TAG__);
59 | }
60 |
61 | void *__cdecl operator new(size_t /*ulSize*/, void *ptr)
62 | {
63 | return ptr;
64 | }
65 |
66 | void __cdecl operator delete(void * /*ptr*/, void * /*ptr2*/)
67 | {
68 | // *(int*)0 = 0;
69 | }
70 |
71 | void *__cdecl operator new[](size_t ulSize)
72 | {
73 | return ::ExAllocatePoolWithTag(PagedPool, ulSize, __DEFAULT_TAG__);
74 | }
75 |
76 | void __cdecl operator delete[](void *ptr)
77 | {
78 | if (!ptr)
79 | return;
80 | return ::ExFreePoolWithTag(ptr, __DEFAULT_TAG__);
81 | }
82 |
83 | void* __cdecl operator new(size_t NumberOfBytes, POOL_TYPE PoolType, ULONG Tag)
84 | {
85 | return ::ExAllocatePoolWithTag(PoolType, NumberOfBytes, Tag);
86 | }
87 |
88 | void* __cdecl operator new[](size_t NumberOfBytes, POOL_TYPE PoolType, ULONG Tag)
89 | {
90 | return ::ExAllocatePoolWithTag(PoolType, NumberOfBytes, Tag);
91 | }
92 |
93 | void __cdecl operator delete(void* ptr, POOL_TYPE PoolType, ULONG Tag)
94 | {
95 | if (ptr)
96 | ::ExFreePool(ptr);
97 | }
98 |
99 | void __cdecl operator delete[](void* ptr, POOL_TYPE PoolType, ULONG Tag)
100 | {
101 | if(ptr)
102 | ::ExFreePool(ptr);
103 | }
104 |
105 | void *__cdecl operator new[](size_t /*ulSize*/, void *ptr)
106 | {
107 | return ptr;
108 | }
109 |
110 | void __cdecl operator delete[](void * /*ptr*/, void * /*ptr2*/)
111 | {
112 | // *(int*)0 = 0;
113 | }
114 |
115 | void __cdecl operator delete(void* ptr, size_t /*sz*/) // C++14
116 | {
117 | if (!ptr)
118 | return;
119 | return ::ExFreePoolWithTag(ptr, __DEFAULT_TAG__);
120 | }
121 |
122 | void __cdecl operator delete[](void* ptr, size_t /*sz*/) // C++14
123 | {
124 | if (!ptr)
125 | return;
126 | return ::ExFreePoolWithTag(ptr, __DEFAULT_TAG__);
127 | }
128 |
--------------------------------------------------------------------------------
/psnotify/sys/memobj.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | __drv_allocatesMem(Mem)
4 | _When_((PoolType & PagedPool) != 0, _IRQL_requires_max_(APC_LEVEL))
5 | _When_((PoolType & PagedPool) == 0, _IRQL_requires_max_(DISPATCH_LEVEL))
6 | _When_((PoolType & NonPagedPoolMustSucceed) != 0,
7 | __drv_reportError("Must succeed pool allocations are forbidden. "
8 | "Allocation failures cause a system crash"))
9 | _When_((PoolType & (NonPagedPoolMustSucceed | POOL_RAISE_IF_ALLOCATION_FAILURE)) == 0,
10 | _Post_maybenull_ _Must_inspect_result_)
11 | _When_((PoolType & (NonPagedPoolMustSucceed | POOL_RAISE_IF_ALLOCATION_FAILURE)) != 0,
12 | _Post_notnull_)
13 | _Post_writable_byte_size_(NumberOfBytes) void *__cdecl
14 | operator new(size_t NumberOfBytes, POOL_TYPE PoolType);
15 |
16 | void __cdecl operator delete(void *ptr, POOL_TYPE PoolType);
17 |
18 | __drv_allocatesMem(Mem)
19 | _When_((PoolType & PagedPool) != 0, _IRQL_requires_max_(APC_LEVEL))
20 | _When_((PoolType & PagedPool) == 0, _IRQL_requires_max_(DISPATCH_LEVEL))
21 | _When_((PoolType & NonPagedPoolMustSucceed) != 0,
22 | __drv_reportError("Must succeed pool allocations are forbidden. "
23 | "Allocation failures cause a system crash"))
24 | _When_((PoolType & (NonPagedPoolMustSucceed | POOL_RAISE_IF_ALLOCATION_FAILURE)) == 0,
25 | _Post_maybenull_ _Must_inspect_result_)
26 | _When_((PoolType & (NonPagedPoolMustSucceed | POOL_RAISE_IF_ALLOCATION_FAILURE)) != 0,
27 | _Post_notnull_)
28 | _Post_writable_byte_size_(NumberOfBytes) void *__cdecl
29 | operator new[](size_t NumberOfBytes, POOL_TYPE PoolType);
30 |
31 | void __cdecl operator delete[](void *ptr, POOL_TYPE PoolType);
32 |
33 |
34 | void* __cdecl operator new(size_t NumberOfBytes, POOL_TYPE PoolType, ULONG Tag);
35 | void* __cdecl operator new[](size_t NumberOfBytes, POOL_TYPE PoolType, ULONG Tag);
36 | void __cdecl operator delete(void* ptr, POOL_TYPE PoolType, ULONG Tag);
37 | void __cdecl operator delete[](void* ptr, POOL_TYPE PoolType, ULONG Tag);
38 |
--------------------------------------------------------------------------------
/psnotify/sys/psnotify.inf:
--------------------------------------------------------------------------------
1 | ;;;
2 | ;;; psnotify
3 | ;;;
4 |
5 | [Version]
6 | Signature = "$Windows NT$"
7 | Class = "AntiVirus"
8 | ClassGuid = {b1d1a169-c54f-4379-81db-bee7d88d7454}
9 | Provider = %ManufacturerName%
10 | DriverVer =
11 | CatalogFile = psnotify.cat
12 | DriverPackageType = FileSystemMinifilter
13 | PnpLockdown=1
14 |
15 | [DestinationDirs]
16 | DefaultDestDir = 12
17 | MiniFilter.DriverFiles = 12
18 |
19 | ;;
20 | ;; Default install sections
21 | ;;
22 |
23 | [DefaultInstall.NTamd64]
24 | OptionDesc = %ServiceDescription%
25 | CopyFiles = MiniFilter.DriverFiles
26 |
27 | [DefaultInstall.NTx86]
28 | OptionDesc = %ServiceDescription%
29 | CopyFiles = MiniFilter.DriverFiles
30 |
31 | [DefaultInstall.NTamd64.Services]
32 | AddService = %ServiceName%,,MiniFilter.Service,MiniFilter.EventLog
33 |
34 | [DefaultInstall.NTx86.Services]
35 | AddService = %ServiceName%,,MiniFilter.Service,MiniFilter.EventLog
36 |
37 | ;;
38 | ;; Default uninstall sections
39 | ;;
40 |
41 | [DefaultUninstall.NTamd64]
42 | DelFiles = MiniFilter.DriverFiles
43 | LegacyUninstall=1
44 |
45 | [DefaultUninstall.NTx86]
46 | DelFiles = MiniFilter.DriverFiles
47 | LegacyUninstall=1
48 |
49 | [DefaultUninstall.NTamd64.Services]
50 | DelService = %ServiceName%,0x204 ;Ensure service is stopped before deleting, ensure event-log entry related 'system' log is deleted
51 |
52 | [DefaultUninstall.NTx86.Services]
53 | DelService = %ServiceName%,0x204 ;Ensure service is stopped before deleting, ensure event-log entry related 'system' log is deleted
54 | ;
55 | ; Services Section
56 | ;
57 |
58 | [MiniFilter.Service]
59 | DisplayName = %DisplayName%
60 | Description = %ServiceDescription%
61 | ServiceBinary = %12%\%DriverName%.sys ;%windir%\system32\drivers\
62 | Dependencies = "FltMgr"
63 | ServiceType = 2 ;SERVICE_FILE_SYSTEM_DRIVER
64 | StartType = 3 ;SERVICE_DEMAND_START
65 | ErrorControl = 1 ;SERVICE_ERROR_NORMAL
66 | LoadOrderGroup = "FSFilter Anti-Virus"
67 | AddReg = MiniFilter.AddRegistry
68 |
69 |
70 | ;
71 | ; Registry Modifications
72 | ;
73 |
74 | [MiniFilter.AddRegistry]
75 | HKR,"Instances","DefaultInstance",0x00000000,%DefaultInstance%
76 | HKR,"Instances\"%Instance1.Name%,"Altitude",0x00000000,%Instance1.Altitude%
77 | HKR,"Instances\"%Instance1.Name%,"Flags",0x00010001,%Instance1.Flags%
78 |
79 | ;
80 | ; Register as event source
81 | ;
82 | [MiniFilter.EventLog]
83 |
84 | [MiniFilter.EventLog.AddRegistry]
85 |
86 |
87 | ;
88 | ; Copy Files
89 | ;
90 |
91 | [MiniFilter.DriverFiles]
92 | %DriverName%.sys
93 |
94 | [SourceDisksFiles]
95 | psnotify.sys = 1,,
96 |
97 | [SourceDisksNames]
98 | 1 = %DiskId1%,,,
99 |
100 | ;;
101 | ;; String Section
102 | ;;
103 |
104 | [Strings]
105 | ManufacturerName = "F-Secure Corporation"
106 | ServiceDescription = "F-Secure PsNotify"
107 | ServiceName = "F-Secure PsNotify"
108 | DisplayName = "F-Secure PsNotify"
109 | DriverName = "psnotify"
110 | DiskId1 = "psnotify Device Installation Disk"
111 |
112 | ;Instances specific information.
113 | DefaultInstance = "F-Secure PsNotify"
114 | Instance1.Name = "F-Secure PsNotify"
115 | Instance1.Altitude = "322001"
116 | Instance1.Flags = 0x0 ; Allow all attachments
117 |
--------------------------------------------------------------------------------
/psnotify/sys/psnotify.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.30204.135
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "psnotif", "psnotify.vcxproj", "{952EBD85-89BA-4A1C-853E-6E9AF310CE7D}"
7 | ProjectSection(ProjectDependencies) = postProject
8 | {E2DA187C-3322-41B4-9CF6-0B9182D5BC96} = {E2DA187C-3322-41B4-9CF6-0B9182D5BC96}
9 | EndProjectSection
10 | EndProject
11 | Global
12 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
13 | Debug|Win32 = Debug|Win32
14 | Debug|x64 = Debug|x64
15 | Release|Win32 = Release|Win32
16 | Release|x64 = Release|x64
17 | EndGlobalSection
18 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
19 | {952EBD85-89BA-4A1C-853E-6E9AF310CE7D}.Debug|Win32.ActiveCfg = Debug_Static|Win32
20 | {952EBD85-89BA-4A1C-853E-6E9AF310CE7D}.Debug|Win32.Build.0 = Debug_Static|Win32
21 | {952EBD85-89BA-4A1C-853E-6E9AF310CE7D}.Debug|Win32.Deploy.0 = Debug_Static|Win32
22 | {952EBD85-89BA-4A1C-853E-6E9AF310CE7D}.Debug|x64.ActiveCfg = Debug_Static|x64
23 | {952EBD85-89BA-4A1C-853E-6E9AF310CE7D}.Debug|x64.Build.0 = Debug_Static|x64
24 | {952EBD85-89BA-4A1C-853E-6E9AF310CE7D}.Debug|x64.Deploy.0 = Debug_Static|x64
25 | {952EBD85-89BA-4A1C-853E-6E9AF310CE7D}.Release|Win32.ActiveCfg = Release_Static|Win32
26 | {952EBD85-89BA-4A1C-853E-6E9AF310CE7D}.Release|Win32.Build.0 = Release_Static|Win32
27 | {952EBD85-89BA-4A1C-853E-6E9AF310CE7D}.Release|Win32.Deploy.0 = Release_Static|Win32
28 | {952EBD85-89BA-4A1C-853E-6E9AF310CE7D}.Release|x64.ActiveCfg = Release_Static|x64
29 | {952EBD85-89BA-4A1C-853E-6E9AF310CE7D}.Release|x64.Build.0 = Release_Static|x64
30 | {952EBD85-89BA-4A1C-853E-6E9AF310CE7D}.Release|x64.Deploy.0 = Release_Static|x64
31 | {E2DA187C-3322-41B4-9CF6-0B9182D5BC96}.Debug|Win32.ActiveCfg = Debug_Static|Win32
32 | {E2DA187C-3322-41B4-9CF6-0B9182D5BC96}.Debug|Win32.Build.0 = Debug_Static|Win32
33 | {E2DA187C-3322-41B4-9CF6-0B9182D5BC96}.Debug|x64.ActiveCfg = Debug_Static|x64
34 | {E2DA187C-3322-41B4-9CF6-0B9182D5BC96}.Debug|x64.Build.0 = Debug_Static|x64
35 | {E2DA187C-3322-41B4-9CF6-0B9182D5BC96}.Release|Win32.ActiveCfg = Release_Static|Win32
36 | {E2DA187C-3322-41B4-9CF6-0B9182D5BC96}.Release|Win32.Build.0 = Release_Static|Win32
37 | {E2DA187C-3322-41B4-9CF6-0B9182D5BC96}.Release|x64.ActiveCfg = Release_Static|x64
38 | {E2DA187C-3322-41B4-9CF6-0B9182D5BC96}.Release|x64.Build.0 = Release_Static|x64
39 | {7CC8D2CF-A0C8-47F7-869E-9F428FFBFB51}.Debug|Win32.ActiveCfg = Debug_Static|Win32
40 | {7CC8D2CF-A0C8-47F7-869E-9F428FFBFB51}.Debug|Win32.Build.0 = Debug_Static|Win32
41 | {7CC8D2CF-A0C8-47F7-869E-9F428FFBFB51}.Debug|x64.ActiveCfg = Debug_Static|x64
42 | {7CC8D2CF-A0C8-47F7-869E-9F428FFBFB51}.Debug|x64.Build.0 = Debug_Static|x64
43 | {7CC8D2CF-A0C8-47F7-869E-9F428FFBFB51}.Release|Win32.ActiveCfg = Release_Static|Win32
44 | {7CC8D2CF-A0C8-47F7-869E-9F428FFBFB51}.Release|Win32.Build.0 = Release_Static|Win32
45 | {7CC8D2CF-A0C8-47F7-869E-9F428FFBFB51}.Release|x64.ActiveCfg = Release_Static|x64
46 | {7CC8D2CF-A0C8-47F7-869E-9F428FFBFB51}.Release|x64.Build.0 = Release_Static|x64
47 | EndGlobalSection
48 | GlobalSection(SolutionProperties) = preSolution
49 | HideSolutionNode = FALSE
50 | EndGlobalSection
51 | GlobalSection(ExtensibilityGlobals) = postSolution
52 | SolutionGuid = {AD2C21C1-BF67-45FA-B241-59B2F0BF60E3}
53 | EndGlobalSection
54 | EndGlobal
55 |
--------------------------------------------------------------------------------
/psnotify/sys/psnotify.vcxproj.user:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Off
5 |
6 |
7 | Off
8 |
9 |
10 | Off
11 |
12 |
13 | Off
14 |
15 |
--------------------------------------------------------------------------------
/psnotify/sys/stdafx.cpp:
--------------------------------------------------------------------------------
1 | #include "stdafx.h"
2 |
--------------------------------------------------------------------------------
/psnotify/sys/stdafx.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 | #include //for IoCreateDeviceSecure
6 | #include
7 |
8 | #include
9 |
--------------------------------------------------------------------------------
/psnotify/sys/ver.h:
--------------------------------------------------------------------------------
1 | #if DBG
2 | #define MODULE_BUILD_CONFIGURATION "(debug)"
3 | #else
4 | #define MODULE_BUILD_CONFIGURATION
5 | #endif
6 |
7 | #if defined(_WIN64)
8 | #define MODULE_BUILD_PLATFORM "64-bit"
9 | #else
10 | #define MODULE_BUILD_PLATFORM "32-bit"
11 | #endif // _WIN64
12 |
13 | #define CLIENT_FILEDESCRIPTION "F-Secure Process Nofify " MODULE_BUILD_PLATFORM " " MODULE_BUILD_CONFIGURATION "\0"
14 | #define CLIENT_INTERNALNAME "psnotify\0"
15 | #define CLIENT_ORIGINALFILENAME "psnotify.sys\0"
16 |
--------------------------------------------------------------------------------
/psnotify/sys/version.h:
--------------------------------------------------------------------------------
1 | #ifndef VERSION_H
2 | #define VERSION_H
3 |
4 | #define MAJOR 11
5 | #define MINOR 10
6 | #define BUILD 249
7 | #define REVISION 4919
8 |
9 | #define PRODUCTMAJOR 11
10 | #define PRODUCTMINOR 10
11 | #define PRODUCTBUILD 249
12 | #define PRODUCTREVISION 4919
13 |
14 | #define PRODUCTVERSIONCHECKSUM "9771583"
15 |
16 | #endif
17 |
--------------------------------------------------------------------------------
/psnotify/sys/version.rc:
--------------------------------------------------------------------------------
1 | // Include this file from binary specific ver.rc, which overrides necessary fields
2 | // typical fields to override:
3 | // - CLIENT_FILEDESCRIPTION
4 | // - CLIENT_INTERNALNAME
5 | // - CLIENT_ORIGINALFILENAME
6 |
7 | #include
8 | #include
9 |
10 | // version.h contains the build version, it is typically generated by the build script
11 | #include "version.h"
12 | #include "ver.h"
13 |
14 | #define CLIENT_COMPANYNAME "F-Secure Process Nofiy\0"
15 | #define CLIENT_PRODUCTNAME "F-Secure Process Nofiy\0"
16 | #define CLIENT_COPYRIGHT "Copyright \251 F-Secure Corporation\0"
17 | #define CLIENT_FILETYPE 0x3L // VFT_DRV
18 |
19 | #define CLIENT_COMMENTS MODULE_BUILD_CONFIGURATION " " MODULE_BUILD_PLATFORM "\0"
20 |
21 | // #include "afxres.h" gives VS_VERSION_INFO
22 | #define VS_VERSION_INFO 1
23 |
24 | #ifdef _WIN32
25 | LANGUAGE 9, 1
26 | #pragma code_page(1252)
27 | #endif //_WIN32
28 |
29 | #ifndef MAJOR
30 | #define MAJOR PRODUCTMAJOR
31 | #endif
32 | #ifndef MINOR
33 | #define MINOR PRODUCTMINOR
34 | #endif
35 | #ifndef BUILD
36 | #define BUILD PRODUCTBUILD
37 | #endif
38 | #ifndef REVISION
39 | #define REVISION PRODUCTREVISION
40 | #endif
41 |
42 | #define STRINGIZE(arg) #arg
43 | #define _S(arg) STRINGIZE(arg)
44 | #define CAT_PRODUCTVERSION(m, n, b, r, c) _S(m) "." _S(n) "." _S(b) "." _S(r) " (" c ")" "\0"
45 | #define CAT_VERSION(m, n, b, r) _S(m) "." _S(n) "." _S(b) "." _S(r) "\0"
46 |
47 | #define PRODUCTVERSIONSTR \
48 | CAT_PRODUCTVERSION(PRODUCTMAJOR, PRODUCTMINOR, PRODUCTBUILD, PRODUCTREVISION, PRODUCTVERSIONCHECKSUM)
49 | #define FILEVERSIONSTR \
50 | CAT_VERSION(MAJOR, MINOR, BUILD, REVISION)
51 |
52 | #define FILEVERSION_TOKEN \
53 | MAJOR,MINOR,BUILD,REVISION
54 | #define PRODUCTVERSION_TOKEN \
55 | PRODUCTMAJOR,PRODUCTMINOR,PRODUCTBUILD,PRODUCTREVISION
56 |
57 | #ifndef CLIENT_FILEOS
58 | #define CLIENT_FILEOS 0x4L // VOS__WINDOWS32
59 | #endif
60 |
61 | #ifndef CLIENT_FILETYPE
62 | #define CLIENT_FILETYPE VFT_DRV
63 | // Possible types: winver.h:
64 | // VFT_UNKNOWN, VFT_APP, VFT_DLL, VFT_DRV, VFT_FONT, VFT_VXD, VFT_STATIC_LIB
65 | #endif
66 |
67 | #ifndef CLIENT_FILESUBTYPE
68 | #define CLIENT_FILESUBTYPE VFT2_DRV_SYSTEM
69 | #endif
70 |
71 | #ifndef CLIENT_FILEDESCRIPTION
72 | #error CLIENT_FILEDESCRIPTION should be defined
73 | #endif
74 |
75 | #ifndef CLIENT_INTERNALNAME
76 | #define CLIENT_INTERNALNAME "\0"
77 | #endif
78 |
79 | #ifndef CLIENT_ORIGINALFILENAME
80 | #define CLIENT_ORIGINALFILENAME "\0"
81 | #endif
82 |
83 | #ifndef CLIENT_COMMENTS
84 | #define CLIENT_COMMENTS "\0"
85 | #endif
86 |
87 | #ifndef LEGAL_TRADEMARKS
88 | #define LEGAL_TRADEMARKS "\0"
89 | #endif
90 |
91 | VS_VERSION_INFO VERSIONINFO
92 | FILEVERSION FILEVERSION_TOKEN
93 | PRODUCTVERSION PRODUCTVERSION_TOKEN
94 | FILEFLAGSMASK 0x3fL
95 | #if DBG
96 | FILEFLAGS 0x1L
97 | #else
98 | FILEFLAGS 0x0L
99 | #endif
100 | FILEOS CLIENT_FILEOS
101 | FILETYPE CLIENT_FILETYPE
102 | FILESUBTYPE CLIENT_FILESUBTYPE
103 | BEGIN
104 | BLOCK "StringFileInfo"
105 | BEGIN
106 | BLOCK "040904b0"
107 | BEGIN
108 | VALUE "Comments", CLIENT_COMMENTS
109 | VALUE "CompanyName", CLIENT_COMPANYNAME
110 | VALUE "FileDescription", CLIENT_FILEDESCRIPTION
111 | VALUE "FileVersion", FILEVERSIONSTR
112 | VALUE "InternalName", CLIENT_INTERNALNAME
113 | VALUE "LegalCopyright", CLIENT_COPYRIGHT
114 | VALUE "LegalTrademarks", LEGAL_TRADEMARKS
115 | VALUE "OriginalFilename", CLIENT_ORIGINALFILENAME
116 | VALUE "PrivateBuild", "\0"
117 | VALUE "ProductName", CLIENT_PRODUCTNAME
118 | VALUE "ProductVersion", PRODUCTVERSIONSTR
119 | VALUE "SpecialBuild", "\0"
120 | END
121 | END
122 | BLOCK "VarFileInfo"
123 | BEGIN
124 | VALUE "Translation", 0x409, 1200
125 | END
126 | END
127 |
--------------------------------------------------------------------------------