├── .editorconfig
├── .gitignore
├── Directory.Build.props
├── DotNetPlugin.Impl
├── DotNetPlugin.Impl.csproj
├── ILRepack.targets
├── NativeBindings
│ ├── SDK
│ │ ├── Bridge.Dbg.cs
│ │ ├── Bridge.Gui.cs
│ │ ├── Bridge.cs
│ │ └── TitanEngine.cs
│ ├── Script
│ │ ├── Argument.cs
│ │ ├── Disassembly.cs
│ │ ├── Gui.cs
│ │ ├── Module.cs
│ │ ├── Pattern.cs
│ │ └── Register.cs
│ └── Win32
│ │ ├── Constants.cs
│ │ ├── Functions.Kernel32.cs
│ │ ├── Functions.Psapi.cs
│ │ └── Types.cs
├── Plugin.Commands.cs
├── Plugin.EventCallbacks.cs
├── Plugin.ExpressionFunctions.cs
├── Plugin.Menus.cs
├── Plugin.cs
├── Properties
│ ├── Resources.Designer.cs
│ └── Resources.resx
└── Resources
│ └── abouticon.png
├── DotNetPlugin.RemotingHelper
├── AppDomainInitializer.cs
└── DotNetPlugin.RemotingHelper.csproj
├── DotNetPlugin.Stub
├── Commands.cs
├── DotNetPlugin.Stub.csproj
├── EventCallbacks.cs
├── ExpressionFunctions.cs
├── IPlugin.cs
├── IPluginSession.cs
├── Menus.cs
├── NativeBindings
│ ├── BlittableBoolean.cs
│ ├── Extensions.cs
│ ├── SDK
│ │ ├── Bridge.cs
│ │ ├── PLog.cs
│ │ └── Plugins.cs
│ ├── StructRef.cs
│ ├── Utf8StringRef.cs
│ └── Win32
│ │ ├── Types.DebugEvents.cs
│ │ ├── Types.WinGdi.cs
│ │ ├── Types.cs
│ │ └── Win32Window.cs
├── PluginBase.cs
├── PluginMain.cs
├── PluginSession.cs
└── PluginSessionProxy.cs
├── DotNetPluginCS.sln
└── README.md
/.editorconfig:
--------------------------------------------------------------------------------
1 | ; Top-most EditorConfig file
2 | root = true
3 |
4 | ; Windows-style newlines
5 | [*]
6 | end_of_line = CRLF
7 |
8 | ; Tab indentation
9 | [*.cs]
10 | indent_style = space
11 | tab_width = 4
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.rsuser
8 | *.suo
9 | *.user
10 | *.userosscache
11 | *.sln.docstates
12 |
13 | # User-specific files (MonoDevelop/Xamarin Studio)
14 | *.userprefs
15 |
16 | # Mono auto generated files
17 | mono_crash.*
18 |
19 | # Build results
20 | [Dd]ebug/
21 | [Dd]ebugPublic/
22 | [Rr]elease/
23 | [Rr]eleases/
24 | x64/
25 | x86/
26 | [Ww][Ii][Nn]32/
27 | [Aa][Rr][Mm]/
28 | [Aa][Rr][Mm]64/
29 | bld/
30 | [Bb]in/
31 | [Oo]bj/
32 | [Ll]og/
33 | [Ll]ogs/
34 |
35 | # Visual Studio 2015/2017 cache/options directory
36 | .vs/
37 | # Uncomment if you have tasks that create the project's static files in wwwroot
38 | #wwwroot/
39 |
40 | # Visual Studio 2017 auto generated files
41 | Generated\ Files/
42 |
43 | # MSTest test Results
44 | [Tt]est[Rr]esult*/
45 | [Bb]uild[Ll]og.*
46 |
47 | # NUnit
48 | *.VisualState.xml
49 | TestResult.xml
50 | nunit-*.xml
51 |
52 | # Build Results of an ATL Project
53 | [Dd]ebugPS/
54 | [Rr]eleasePS/
55 | dlldata.c
56 |
57 | # Benchmark Results
58 | BenchmarkDotNet.Artifacts/
59 |
60 | # .NET Core
61 | project.lock.json
62 | project.fragment.lock.json
63 | artifacts/
64 |
65 | # ASP.NET Scaffolding
66 | ScaffoldingReadMe.txt
67 |
68 | # StyleCop
69 | StyleCopReport.xml
70 |
71 | # Files built by Visual Studio
72 | *_i.c
73 | *_p.c
74 | *_h.h
75 | *.ilk
76 | *.meta
77 | *.obj
78 | *.iobj
79 | *.pch
80 | *.pdb
81 | *.ipdb
82 | *.pgc
83 | *.pgd
84 | *.rsp
85 | *.sbr
86 | *.tlb
87 | *.tli
88 | *.tlh
89 | *.tmp
90 | *.tmp_proj
91 | *_wpftmp.csproj
92 | *.log
93 | *.tlog
94 | *.vspscc
95 | *.vssscc
96 | .builds
97 | *.pidb
98 | *.svclog
99 | *.scc
100 |
101 | # Chutzpah Test files
102 | _Chutzpah*
103 |
104 | # Visual C++ cache files
105 | ipch/
106 | *.aps
107 | *.ncb
108 | *.opendb
109 | *.opensdf
110 | *.sdf
111 | *.cachefile
112 | *.VC.db
113 | *.VC.VC.opendb
114 |
115 | # Visual Studio profiler
116 | *.psess
117 | *.vsp
118 | *.vspx
119 | *.sap
120 |
121 | # Visual Studio Trace Files
122 | *.e2e
123 |
124 | # TFS 2012 Local Workspace
125 | $tf/
126 |
127 | # Guidance Automation Toolkit
128 | *.gpState
129 |
130 | # ReSharper is a .NET coding add-in
131 | _ReSharper*/
132 | *.[Rr]e[Ss]harper
133 | *.DotSettings.user
134 |
135 | # TeamCity is a build add-in
136 | _TeamCity*
137 |
138 | # DotCover is a Code Coverage Tool
139 | *.dotCover
140 |
141 | # AxoCover is a Code Coverage Tool
142 | .axoCover/*
143 | !.axoCover/settings.json
144 |
145 | # Coverlet is a free, cross platform Code Coverage Tool
146 | coverage*.json
147 | coverage*.xml
148 | coverage*.info
149 |
150 | # Visual Studio code coverage results
151 | *.coverage
152 | *.coveragexml
153 |
154 | # NCrunch
155 | _NCrunch_*
156 | .*crunch*.local.xml
157 | nCrunchTemp_*
158 |
159 | # MightyMoose
160 | *.mm.*
161 | AutoTest.Net/
162 |
163 | # Web workbench (sass)
164 | .sass-cache/
165 |
166 | # Installshield output folder
167 | [Ee]xpress/
168 |
169 | # DocProject is a documentation generator add-in
170 | DocProject/buildhelp/
171 | DocProject/Help/*.HxT
172 | DocProject/Help/*.HxC
173 | DocProject/Help/*.hhc
174 | DocProject/Help/*.hhk
175 | DocProject/Help/*.hhp
176 | DocProject/Help/Html2
177 | DocProject/Help/html
178 |
179 | # Click-Once directory
180 | publish/
181 |
182 | # Publish Web Output
183 | *.[Pp]ublish.xml
184 | *.azurePubxml
185 | # Note: Comment the next line if you want to checkin your web deploy settings,
186 | # but database connection strings (with potential passwords) will be unencrypted
187 | *.pubxml
188 | *.publishproj
189 |
190 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
191 | # checkin your Azure Web App publish settings, but sensitive information contained
192 | # in these scripts will be unencrypted
193 | PublishScripts/
194 |
195 | # NuGet Packages
196 | *.nupkg
197 | # NuGet Symbol Packages
198 | *.snupkg
199 | # The packages folder can be ignored because of Package Restore
200 | **/[Pp]ackages/*
201 | # except build/, which is used as an MSBuild target.
202 | !**/[Pp]ackages/build/
203 | # Uncomment if necessary however generally it will be regenerated when needed
204 | #!**/[Pp]ackages/repositories.config
205 | # NuGet v3's project.json files produces more ignorable files
206 | *.nuget.props
207 | *.nuget.targets
208 |
209 | # Nuget personal access tokens and Credentials
210 | # nuget.config
211 |
212 | # Microsoft Azure Build Output
213 | csx/
214 | *.build.csdef
215 |
216 | # Microsoft Azure Emulator
217 | ecf/
218 | rcf/
219 |
220 | # Windows Store app package directories and files
221 | AppPackages/
222 | BundleArtifacts/
223 | Package.StoreAssociation.xml
224 | _pkginfo.txt
225 | *.appx
226 | *.appxbundle
227 | *.appxupload
228 |
229 | # Visual Studio cache files
230 | # files ending in .cache can be ignored
231 | *.[Cc]ache
232 | # but keep track of directories ending in .cache
233 | !?*.[Cc]ache/
234 |
235 | # Others
236 | ClientBin/
237 | ~$*
238 | *~
239 | *.dbmdl
240 | *.dbproj.schemaview
241 | *.jfm
242 | *.pfx
243 | *.publishsettings
244 | orleans.codegen.cs
245 |
246 | # Including strong name files can present a security risk
247 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
248 | #*.snk
249 |
250 | # Since there are multiple workflows, uncomment next line to ignore bower_components
251 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
252 | #bower_components/
253 |
254 | # RIA/Silverlight projects
255 | Generated_Code/
256 |
257 | # Backup & report files from converting an old project file
258 | # to a newer Visual Studio version. Backup files are not needed,
259 | # because we have git ;-)
260 | _UpgradeReport_Files/
261 | Backup*/
262 | UpgradeLog*.XML
263 | UpgradeLog*.htm
264 | ServiceFabricBackup/
265 | *.rptproj.bak
266 |
267 | # SQL Server files
268 | *.mdf
269 | *.ldf
270 | *.ndf
271 |
272 | # Business Intelligence projects
273 | *.rdl.data
274 | *.bim.layout
275 | *.bim_*.settings
276 | *.rptproj.rsuser
277 | *- [Bb]ackup.rdl
278 | *- [Bb]ackup ([0-9]).rdl
279 | *- [Bb]ackup ([0-9][0-9]).rdl
280 |
281 | # Microsoft Fakes
282 | FakesAssemblies/
283 |
284 | # GhostDoc plugin setting file
285 | *.GhostDoc.xml
286 |
287 | # Node.js Tools for Visual Studio
288 | .ntvs_analysis.dat
289 | node_modules/
290 |
291 | # Visual Studio 6 build log
292 | *.plg
293 |
294 | # Visual Studio 6 workspace options file
295 | *.opt
296 |
297 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
298 | *.vbw
299 |
300 | # Visual Studio LightSwitch build output
301 | **/*.HTMLClient/GeneratedArtifacts
302 | **/*.DesktopClient/GeneratedArtifacts
303 | **/*.DesktopClient/ModelManifest.xml
304 | **/*.Server/GeneratedArtifacts
305 | **/*.Server/ModelManifest.xml
306 | _Pvt_Extensions
307 |
308 | # Paket dependency manager
309 | .paket/paket.exe
310 | paket-files/
311 |
312 | # FAKE - F# Make
313 | .fake/
314 |
315 | # CodeRush personal settings
316 | .cr/personal
317 |
318 | # Python Tools for Visual Studio (PTVS)
319 | __pycache__/
320 | *.pyc
321 |
322 | # Cake - Uncomment if you are using it
323 | # tools/**
324 | # !tools/packages.config
325 |
326 | # Tabs Studio
327 | *.tss
328 |
329 | # Telerik's JustMock configuration file
330 | *.jmconfig
331 |
332 | # BizTalk build output
333 | *.btp.cs
334 | *.btm.cs
335 | *.odx.cs
336 | *.xsd.cs
337 |
338 | # OpenCover UI analysis results
339 | OpenCover/
340 |
341 | # Azure Stream Analytics local run output
342 | ASALocalRun/
343 |
344 | # MSBuild Binary and Structured Log
345 | *.binlog
346 |
347 | # NVidia Nsight GPU debugger configuration file
348 | *.nvuser
349 |
350 | # MFractors (Xamarin productivity tool) working folder
351 | .mfractor/
352 |
353 | # Local History for Visual Studio
354 | .localhistory/
355 |
356 | # BeatPulse healthcheck temp database
357 | healthchecksdb
358 |
359 | # Backup folder for Package Reference Convert tool in Visual Studio 2017
360 | MigrationBackup/
361 |
362 | # Ionide (cross platform F# VS Code tools) working folder
363 | .ionide/
364 |
365 | # Fody - auto-generated XML schema
366 | FodyWeavers.xsd
367 |
368 | # VS Code files for those working on multiple tools
369 | .vscode/*
370 | !.vscode/settings.json
371 | !.vscode/tasks.json
372 | !.vscode/launch.json
373 | !.vscode/extensions.json
374 | *.code-workspace
375 |
376 | # Local History for Visual Studio Code
377 | .history/
378 |
379 | # Windows Installer files from build outputs
380 | *.cab
381 | *.msi
382 | *.msix
383 | *.msm
384 | *.msp
385 |
386 | # JetBrains Rider
387 | .idea/
388 | *.sln.iml
389 |
390 | !DotNetPlugin.Impl/NativeBindings/Win32/
391 | !DotNetPlugin.Stub/NativeBindings/Win32/
--------------------------------------------------------------------------------
/Directory.Build.props:
--------------------------------------------------------------------------------
1 |
2 |
3 | x64dbgDotNetPlugin
4 | DotNetPlugin
5 |
6 | DotNetPlugin
7 | ..\bin\$(Platform)\$(Configuration)\
8 |
9 | 9
10 |
11 |
12 |
13 | true
14 |
15 |
16 |
--------------------------------------------------------------------------------
/DotNetPlugin.Impl/DotNetPlugin.Impl.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | $(PluginAssemblyName).Impl
4 | $(PluginRootNamespace)
5 | net472
6 | x86;x64
7 | $(PluginOutputPath)
8 | false
9 | full
10 | true
11 | true
12 | $(PluginName)
13 |
14 |
15 |
16 | X86;$(DefineConstants)
17 | .dp32
18 |
19 |
20 | AMD64;$(DefineConstants)
21 | .dp64
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 | build
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 | True
49 | True
50 | Resources.resx
51 |
52 |
53 |
54 |
55 |
56 | ResXFileCodeGenerator
57 | Resources.Designer.cs
58 |
59 |
60 |
61 |
71 |
72 |
73 |
74 | $([System.Text.RegularExpressions.Regex]::Replace($(TargetName), '\.Impl$', ''))
75 | .dll
76 | $(TargetDir)$(StubAssemblyName)$(StubAssemblyExt)
77 | $(StubAssemblyPath)
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
--------------------------------------------------------------------------------
/DotNetPlugin.Impl/ILRepack.targets:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/DotNetPlugin.Impl/NativeBindings/SDK/Bridge.Dbg.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.InteropServices;
3 |
4 | namespace DotNetPlugin.NativeBindings.SDK
5 | {
6 | // https://github.com/x64dbg/x64dbg/blob/development/src/bridge/bridgemain.h
7 | partial class Bridge
8 | {
9 | [DllImport(dll, CallingConvention = cdecl, ExactSpelling = true)]
10 | public static extern bool DbgCmdExec([MarshalAs(UnmanagedType.LPUTF8Str)] string cmd);
11 |
12 | [DllImport(dll, CallingConvention = cdecl, ExactSpelling = true)]
13 | public static extern bool DbgCmdExecDirect([MarshalAs(UnmanagedType.LPUTF8Str)] string cmd);
14 |
15 | [DllImport(dll, CallingConvention = cdecl, ExactSpelling = true)]
16 | public static extern void DbgDisasmFastAt(nuint addr, ref BASIC_INSTRUCTION_INFO basicinfo);
17 |
18 | [DllImport(dll, CallingConvention = cdecl, ExactSpelling = true)]
19 | public static extern nuint DbgGetBranchDestination(nuint addr);
20 |
21 | [DllImport(dll, CallingConvention = cdecl, ExactSpelling = true)]
22 | private static extern bool DbgGetCommentAt(nuint addr, IntPtr text);
23 |
24 | public static unsafe bool DbgGetCommentAt(nuint addr, out string text)
25 | {
26 | var textBufferPtr = stackalloc byte[MAX_COMMENT_SIZE];
27 | var success = DbgGetCommentAt(addr, new IntPtr(textBufferPtr));
28 | text = success ? new IntPtr(textBufferPtr).MarshalToStringUTF8(MAX_COMMENT_SIZE) : default;
29 | return success;
30 | }
31 |
32 | [DllImport(dll, CallingConvention = cdecl, ExactSpelling = true)]
33 | private static extern bool DbgGetLabelAt(nuint addr, SEGMENTREG segment, IntPtr text);
34 |
35 | public static unsafe bool DbgGetLabelAt(nuint addr, SEGMENTREG segment, out string text)
36 | {
37 | var textBufferPtr = stackalloc byte[MAX_LABEL_SIZE];
38 | var success = DbgGetLabelAt(addr, segment, new IntPtr(textBufferPtr));
39 | text = success ? new IntPtr(textBufferPtr).MarshalToStringUTF8(MAX_LABEL_SIZE) : default;
40 | return success;
41 | }
42 |
43 | [DllImport(dll, CallingConvention = cdecl, ExactSpelling = true)]
44 | private static extern bool DbgGetModuleAt(nuint addr, IntPtr text);
45 |
46 | public static unsafe bool DbgGetModuleAt(nuint addr, out string text)
47 | {
48 | var textBufferPtr = stackalloc byte[MAX_MODULE_SIZE];
49 | var success = DbgGetModuleAt(addr, new IntPtr(textBufferPtr));
50 | text = success ? new IntPtr(textBufferPtr).MarshalToStringUTF8(MAX_MODULE_SIZE) : default;
51 | return success;
52 | }
53 |
54 | [DllImport(dll, CallingConvention = cdecl, ExactSpelling = true)]
55 | public static extern bool DbgIsDebugging();
56 |
57 | [DllImport(dll, CallingConvention = cdecl, ExactSpelling = true)]
58 | public static extern nuint DbgModBaseFromName([MarshalAs(UnmanagedType.LPUTF8Str)] string name);
59 |
60 | [DllImport(dll, CallingConvention = cdecl, ExactSpelling = true)]
61 | public static extern nuint DbgValFromString([MarshalAs(UnmanagedType.LPUTF8Str)] string @string);
62 |
63 | [DllImport(dll, CallingConvention = cdecl, ExactSpelling = true)]
64 | public static extern bool DbgValToString([MarshalAs(UnmanagedType.LPUTF8Str)] string @string, nuint value);
65 |
66 | [DllImport(dll, CallingConvention = cdecl, ExactSpelling = true)]
67 | public static extern void DbgDisasmAt(nuint addr, ref DISASM_INSTR instr);
68 |
69 | [DllImport(dll, CallingConvention = cdecl, ExactSpelling = true)]
70 | public static extern nuint DbgMemFindBaseAddr(nuint addr, out nuint size);
71 |
72 | [DllImport(dll, CallingConvention = cdecl, ExactSpelling = true)]
73 | public static extern bool DbgSetCommentAt(nuint addr, [MarshalAs(UnmanagedType.LPUTF8Str)] string text);
74 |
75 | [DllImport(dll, CallingConvention = cdecl, ExactSpelling = true)]
76 | public static extern bool DbgSetLabelAt(nuint addr, [MarshalAs(UnmanagedType.LPUTF8Str)] string text);
77 |
78 | [DllImport(dll, CallingConvention = cdecl, ExactSpelling = true)]
79 | public static extern bool DbgSetAutoCommentAt(nuint addr, [MarshalAs(UnmanagedType.LPUTF8Str)] string text);
80 |
81 | [DllImport(dll, CallingConvention = cdecl, ExactSpelling = true)]
82 | public static extern bool DbgSetAutoLabelAt(nuint addr, [MarshalAs(UnmanagedType.LPUTF8Str)] string text);
83 |
84 | [DllImport(dll, CallingConvention = cdecl, ExactSpelling = true)]
85 | public static extern void DbgClearAutoCommentRange(nuint start, nuint end);
86 |
87 | [DllImport(dll, CallingConvention = cdecl, ExactSpelling = true)]
88 | public static extern void DbgClearAutoLabelRange(nuint start, nuint end);
89 |
90 | [DllImport(dll, CallingConvention = cdecl, ExactSpelling = true)]
91 | public static extern void DbgClearCommentRange(nuint start, nuint end);
92 |
93 | [DllImport(dll, CallingConvention = cdecl, ExactSpelling = true)]
94 | public static extern void DbgClearLabelRange(nuint start, nuint end);
95 |
96 | [DllImport(dll, CallingConvention = cdecl, ExactSpelling = true)]
97 | private static extern bool DbgMemRead(nuint va, IntPtr dest, nuint size);
98 |
99 | public static unsafe bool DbgMemRead(nuint va, T[] buffer, nuint size) where T : unmanaged
100 | {
101 | if (buffer is null || size > (nuint)buffer.Length) return false;
102 |
103 | fixed (T* ptr = buffer)
104 | {
105 | return DbgMemRead(va, (IntPtr)ptr, size);
106 | }
107 | }
108 |
109 | public static unsafe bool DbgMemRead(nuint va, ref T dest, nuint size) where T : struct
110 | {
111 | if (size > (nuint)Marshal.SizeOf(dest)) return false;
112 |
113 | var handle = GCHandle.Alloc(dest, GCHandleType.Pinned);
114 | try
115 | {
116 | var success = DbgMemRead(va, handle.AddrOfPinnedObject(), size);
117 | dest = success ? Marshal.PtrToStructure(handle.AddrOfPinnedObject()) : default;
118 | return success;
119 | }
120 | finally
121 | {
122 | handle.Free();
123 | }
124 | }
125 |
126 | [DllImport(dll, CallingConvention = cdecl, ExactSpelling = true)]
127 | public static extern bool DbgXrefGet(nuint addr, ref XREF_INFO info);
128 |
129 | [DllImport(dll, CallingConvention = cdecl, ExactSpelling = true)]
130 | public static extern bool DbgLoopAdd(nuint start, nuint end);
131 |
132 | [DllImport(dll, CallingConvention = cdecl, ExactSpelling = true)]
133 | public static extern bool DbgLoopGet(int depth, nuint addr, out nuint start, out nuint end);
134 |
135 | [DllImport(dll, CallingConvention = cdecl, ExactSpelling = true)]
136 | public static extern bool DbgLoopDel(int depth, nuint addr);
137 |
138 | public enum SEGMENTREG
139 | {
140 | SEG_DEFAULT,
141 | SEG_ES,
142 | SEG_DS,
143 | SEG_FS,
144 | SEG_GS,
145 | SEG_CS,
146 | SEG_SS
147 | }
148 |
149 | public enum DISASM_INSTRTYPE
150 | {
151 | instr_normal,
152 | instr_branch,
153 | instr_stack
154 | }
155 |
156 | public enum DISASM_ARGTYPE
157 | {
158 | arg_normal,
159 | arg_memory
160 | }
161 |
162 | public enum XREFTYPE
163 | {
164 | XREF_NONE,
165 | XREF_DATA,
166 | XREF_JMP,
167 | XREF_CALL
168 | }
169 |
170 | #region Definitions for BASIC_INSTRUCTION_INFO.type
171 | public const uint TYPE_VALUE = 1;
172 | public const uint TYPE_MEMORY = 2;
173 | public const uint TYPE_ADDR = 4;
174 | #endregion
175 |
176 | public enum MEMORY_SIZE
177 | {
178 | size_byte = 1,
179 | size_word = 2,
180 | size_dword = 4,
181 | size_qword = 8,
182 | size_xmmword = 16,
183 | size_ymmword = 32
184 | }
185 |
186 | [Serializable]
187 | public struct VALUE_INFO
188 | {
189 | public nuint value;
190 | public MEMORY_SIZE size;
191 | }
192 |
193 | [Serializable]
194 | public unsafe struct MEMORY_INFO
195 | {
196 | public nuint value; //displacement / addrvalue (rip-relative)
197 | public MEMORY_SIZE size; //byte/word/dword/qword
198 |
199 | private fixed byte mnemonicBytes[MAX_MNEMONIC_SIZE];
200 | public string mnemonic
201 | {
202 | get
203 | {
204 | fixed (byte* ptr = mnemonicBytes)
205 | return new IntPtr(ptr).MarshalToStringUTF8(MAX_MNEMONIC_SIZE);
206 | }
207 | }
208 | }
209 |
210 | [Serializable]
211 | public unsafe struct BASIC_INSTRUCTION_INFO
212 | {
213 | public uint type; //value|memory|addr
214 | public VALUE_INFO value; //immediat
215 | public MEMORY_INFO memory;
216 | public nuint addr; //addrvalue (jumps + calls)
217 | public BlittableBoolean branch; //jumps/calls
218 | public BlittableBoolean call; //instruction is a call
219 |
220 | public int size;
221 |
222 | private fixed byte instructionBytes[MAX_MNEMONIC_SIZE * 4];
223 | public string instruction
224 | {
225 | get
226 | {
227 | fixed (byte* ptr = instructionBytes)
228 | return new IntPtr(ptr).MarshalToStringUTF8(MAX_MNEMONIC_SIZE * 4);
229 | }
230 | set
231 | {
232 | fixed (byte* ptr = instructionBytes)
233 | value.MarshalToPtrUTF8(new IntPtr(ptr), MAX_MNEMONIC_SIZE * 4);
234 | }
235 | }
236 | }
237 |
238 | [Serializable]
239 | public unsafe struct DISASM_ARG
240 | {
241 | public DISASM_ARGTYPE type;
242 | public SEGMENTREG segment;
243 | private fixed byte _mnemonic[MAX_MNEMONIC_SIZE];
244 | public string mnemonic
245 | {
246 | get
247 | {
248 | fixed (byte* ptr = _mnemonic)
249 | return new IntPtr(ptr).MarshalToStringUTF8(MAX_MNEMONIC_SIZE);
250 | }
251 | }
252 | public nuint constant;
253 | public nuint value;
254 | public nuint memvalue;
255 | }
256 |
257 | [Serializable]
258 | public unsafe struct DISASM_INSTR
259 | {
260 | private fixed byte _instruction[MAX_MNEMONIC_SIZE];
261 | public string instruction
262 | {
263 | get
264 | {
265 | fixed (byte* ptr = _instruction)
266 | return new IntPtr(ptr).MarshalToStringUTF8(MAX_MNEMONIC_SIZE);
267 | }
268 | }
269 | public DISASM_INSTRTYPE type;
270 | public int argcount;
271 | public int instr_size;
272 |
273 | public DISASM_ARG arg0; // Maps to arg[0]
274 | public DISASM_ARG arg1; // Maps to arg[1]
275 | public DISASM_ARG arg2; // Maps to arg[2]
276 | }
277 |
278 | [Serializable]
279 | public unsafe struct XREF_INFO
280 | {
281 | public nuint refcount;
282 |
283 | private XREF_RECORD* _references;
284 | public XREF_RECORD[] references
285 | {
286 | get
287 | {
288 | if (_references == null || refcount == UIntPtr.Zero)
289 | return new XREF_RECORD[0];
290 |
291 | var result = new XREF_RECORD[(int)refcount];
292 | for (int i = 0; i < (int)refcount; i++)
293 | {
294 | result[i] = _references[i];
295 | }
296 |
297 | return result;
298 | }
299 | }
300 | }
301 |
302 | [Serializable]
303 | public unsafe struct XREF_RECORD
304 | {
305 | public nuint addr;
306 | public XREFTYPE type;
307 | }
308 | }
309 | }
310 |
--------------------------------------------------------------------------------
/DotNetPlugin.Impl/NativeBindings/SDK/Bridge.Gui.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.InteropServices;
3 |
4 | namespace DotNetPlugin.NativeBindings.SDK
5 | {
6 | // https://github.com/x64dbg/x64dbg/blob/development/src/bridge/bridgemain.h
7 | partial class Bridge
8 | {
9 | public const int GUI_MAX_LINE_SIZE = 65536;
10 |
11 | [DllImport(dll, CallingConvention = cdecl, ExactSpelling = true)]
12 | private static extern bool GuiGetLineWindow([MarshalAs(UnmanagedType.LPUTF8Str)] string title, IntPtr text);
13 |
14 | public static unsafe bool GuiGetLineWindow([MarshalAs(UnmanagedType.LPUTF8Str)] string title, out string text)
15 | {
16 | // alternatively we could implement a custom marshaler (ICustomMarshaler) but that wont't work for ref/out parameters for some reason...
17 | var textBuffer = Marshal.AllocHGlobal(GUI_MAX_LINE_SIZE);
18 | try
19 | {
20 | var success = GuiGetLineWindow(title, textBuffer);
21 | text = success ? textBuffer.MarshalToStringUTF8(GUI_MAX_LINE_SIZE) : default;
22 | return success;
23 | }
24 | finally { Marshal.FreeHGlobal(textBuffer); }
25 | }
26 |
27 | [DllImport(dll, CallingConvention = cdecl, ExactSpelling = true)]
28 | public static extern void GuiAddStatusBarMessage([MarshalAs(UnmanagedType.LPUTF8Str)] string msg);
29 |
30 | [DllImport(dll, CallingConvention = cdecl, ExactSpelling = true)]
31 | public static extern void GuiLogClear();
32 |
33 | [DllImport(dll, CallingConvention = cdecl, ExactSpelling = true)]
34 | public static extern void GuiAddLogMessage([MarshalAs(UnmanagedType.LPUTF8Str)] string msg);
35 |
36 | [DllImport(dll, CallingConvention = cdecl, ExactSpelling = true)]
37 | public static extern void GuiUpdateDisassemblyView();
38 |
39 | [DllImport(dll, CallingConvention = cdecl, ExactSpelling = true)]
40 | private static extern bool GuiGetDisassembly(nuint addr, IntPtr text);
41 |
42 | public static unsafe bool GuiGetDisassembly(nuint addr, out string text)
43 | {
44 | var textBuffer = Marshal.AllocHGlobal(GUI_MAX_LINE_SIZE);
45 | try
46 | {
47 | var success = GuiGetDisassembly(addr, textBuffer);
48 | text = success ? textBuffer.MarshalToStringUTF8(GUI_MAX_LINE_SIZE) : default;
49 | return success;
50 | }
51 | finally
52 | {
53 | Marshal.FreeHGlobal(textBuffer);
54 | }
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/DotNetPlugin.Impl/NativeBindings/SDK/Bridge.cs:
--------------------------------------------------------------------------------
1 | namespace DotNetPlugin.NativeBindings.SDK
2 | {
3 | // https://github.com/x64dbg/x64dbg/blob/development/src/bridge/bridgemain.h
4 | public sealed partial class Bridge : BridgeBase
5 | {
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/DotNetPlugin.Impl/NativeBindings/SDK/TitanEngine.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.InteropServices;
3 |
4 | namespace DotNetPlugin.NativeBindings.SDK
5 | {
6 | // https://github.com/x64dbg/TitanEngine/blob/x64dbg/SDK/C/TitanEngine.h
7 | public static class TitanEngine
8 | {
9 | public const int UE_STRUCT_PE32STRUCT = 1;
10 | public const int UE_STRUCT_PE64STRUCT = 2;
11 | public const int UE_STRUCT_PESTRUCT = 3;
12 | public const int UE_STRUCT_IMPORTENUMDATA = 4;
13 | public const int UE_STRUCT_THREAD_ITEM_DATA = 5;
14 | public const int UE_STRUCT_LIBRARY_ITEM_DATA = 6;
15 | public const int UE_STRUCT_LIBRARY_ITEM_DATAW = 7;
16 | public const int UE_STRUCT_PROCESS_ITEM_DATA = 8;
17 | public const int UE_STRUCT_HANDLERARRAY = 9;
18 | public const int UE_STRUCT_PLUGININFORMATION = 10;
19 | public const int UE_STRUCT_HOOK_ENTRY = 11;
20 | public const int UE_STRUCT_FILE_STATUS_INFO = 12;
21 | public const int UE_STRUCT_FILE_FIX_INFO = 13;
22 | public const int UE_STRUCT_X87FPUREGISTER = 14;
23 | public const int UE_STRUCT_X87FPU = 15;
24 | public const int UE_STRUCT_TITAN_ENGINE_CONTEXT = 16;
25 | public const int UE_ACCESS_READ = 0;
26 | public const int UE_ACCESS_WRITE = 1;
27 | public const int UE_ACCESS_ALL = 2;
28 | public const int UE_HIDE_PEBONLY = 0;
29 | public const int UE_HIDE_BASIC = 1;
30 | public const int UE_PLUGIN_CALL_REASON_PREDEBUG = 1;
31 | public const int UE_PLUGIN_CALL_REASON_EXCEPTION = 2;
32 | public const int UE_PLUGIN_CALL_REASON_POSTDEBUG = 3;
33 | public const int UE_PLUGIN_CALL_REASON_UNHANDLEDEXCEPTION = 4;
34 | public const int TEE_HOOK_NRM_JUMP = 1;
35 | public const int TEE_HOOK_NRM_CALL = 3;
36 | public const int TEE_HOOK_IAT = 5;
37 | public const int UE_ENGINE_ALOW_MODULE_LOADING = 1;
38 | public const int UE_ENGINE_AUTOFIX_FORWARDERS = 2;
39 | public const int UE_ENGINE_PASS_ALL_EXCEPTIONS = 3;
40 | public const int UE_ENGINE_NO_CONSOLE_WINDOW = 4;
41 | public const int UE_ENGINE_BACKUP_FOR_CRITICAL_FUNCTIONS = 5;
42 | public const int UE_ENGINE_CALL_PLUGIN_CALLBACK = 6;
43 | public const int UE_ENGINE_RESET_CUSTOM_HANDLER = 7;
44 | public const int UE_ENGINE_CALL_PLUGIN_DEBUG_CALLBACK = 8;
45 | public const int UE_ENGINE_SET_DEBUG_PRIVILEGE = 9;
46 | public const int UE_OPTION_REMOVEALL = 1;
47 | public const int UE_OPTION_DISABLEALL = 2;
48 | public const int UE_OPTION_REMOVEALLDISABLED = 3;
49 | public const int UE_OPTION_REMOVEALLENABLED = 4;
50 | public const int UE_STATIC_DECRYPTOR_XOR = 1;
51 | public const int UE_STATIC_DECRYPTOR_SUB = 2;
52 | public const int UE_STATIC_DECRYPTOR_ADD = 3;
53 | public const int UE_STATIC_DECRYPTOR_FOREWARD = 1;
54 | public const int UE_STATIC_DECRYPTOR_BACKWARD = 2;
55 | public const int UE_STATIC_KEY_SIZE_1 = 1;
56 | public const int UE_STATIC_KEY_SIZE_2 = 2;
57 | public const int UE_STATIC_KEY_SIZE_4 = 4;
58 | public const int UE_STATIC_KEY_SIZE_8 = 8;
59 | public const int UE_STATIC_APLIB = 1;
60 | public const int UE_STATIC_APLIB_DEPACK = 2;
61 | public const int UE_STATIC_LZMA = 3;
62 | public const int UE_STATIC_HASH_MD5 = 1;
63 | public const int UE_STATIC_HASH_SHA1 = 2;
64 | public const int UE_STATIC_HASH_CRC32 = 3;
65 | public const int UE_RESOURCE_LANGUAGE_ANY = -1;
66 | public const int UE_PE_OFFSET = 0;
67 | public const int UE_IMAGEBASE = 1;
68 | public const int UE_OEP = 2;
69 | public const int UE_SIZEOFIMAGE = 3;
70 | public const int UE_SIZEOFHEADERS = 4;
71 | public const int UE_SIZEOFOPTIONALHEADER = 5;
72 | public const int UE_SECTIONALIGNMENT = 6;
73 | public const int UE_IMPORTTABLEADDRESS = 7;
74 | public const int UE_IMPORTTABLESIZE = 8;
75 | public const int UE_RESOURCETABLEADDRESS = 9;
76 | public const int UE_RESOURCETABLESIZE = 10;
77 | public const int UE_EXPORTTABLEADDRESS = 11;
78 | public const int UE_EXPORTTABLESIZE = 12;
79 | public const int UE_TLSTABLEADDRESS = 13;
80 | public const int UE_TLSTABLESIZE = 14;
81 | public const int UE_RELOCATIONTABLEADDRESS = 15;
82 | public const int UE_RELOCATIONTABLESIZE = 16;
83 | public const int UE_TIMEDATESTAMP = 17;
84 | public const int UE_SECTIONNUMBER = 18;
85 | public const int UE_CHECKSUM = 19;
86 | public const int UE_SUBSYSTEM = 20;
87 | public const int UE_CHARACTERISTICS = 21;
88 | public const int UE_NUMBEROFRVAANDSIZES = 22;
89 | public const int UE_BASEOFCODE = 23;
90 | public const int UE_BASEOFDATA = 24;
91 | public const int UE_SECTIONNAME = 40;
92 | public const int UE_SECTIONVIRTUALOFFSET = 41;
93 | public const int UE_SECTIONVIRTUALSIZE = 42;
94 | public const int UE_SECTIONRAWOFFSET = 43;
95 | public const int UE_SECTIONRAWSIZE = 44;
96 | public const int UE_SECTIONFLAGS = 45;
97 | public const int UE_VANOTFOUND = -2;
98 | public const int UE_CH_BREAKPOINT = 1;
99 | public const int UE_CH_SINGLESTEP = 2;
100 | public const int UE_CH_ACCESSVIOLATION = 3;
101 | public const int UE_CH_ILLEGALINSTRUCTION = 4;
102 | public const int UE_CH_NONCONTINUABLEEXCEPTION = 5;
103 | public const int UE_CH_ARRAYBOUNDSEXCEPTION = 6;
104 | public const int UE_CH_FLOATDENORMALOPERAND = 7;
105 | public const int UE_CH_FLOATDEVIDEBYZERO = 8;
106 | public const int UE_CH_INTEGERDEVIDEBYZERO = 9;
107 | public const int UE_CH_INTEGEROVERFLOW = 10;
108 | public const int UE_CH_PRIVILEGEDINSTRUCTION = 11;
109 | public const int UE_CH_PAGEGUARD = 12;
110 | public const int UE_CH_EVERYTHINGELSE = 13;
111 | public const int UE_CH_CREATETHREAD = 14;
112 | public const int UE_CH_EXITTHREAD = 15;
113 | public const int UE_CH_CREATEPROCESS = 16;
114 | public const int UE_CH_EXITPROCESS = 17;
115 | public const int UE_CH_LOADDLL = 18;
116 | public const int UE_CH_UNLOADDLL = 19;
117 | public const int UE_CH_OUTPUTDEBUGSTRING = 20;
118 | public const int UE_CH_AFTEREXCEPTIONPROCESSING = 21;
119 | public const int UE_CH_SYSTEMBREAKPOINT = 23;
120 | public const int UE_CH_UNHANDLEDEXCEPTION = 24;
121 | public const int UE_CH_RIPEVENT = 25;
122 | public const int UE_CH_DEBUGEVENT = 26;
123 | public const int UE_OPTION_HANDLER_RETURN_HANDLECOUNT = 1;
124 | public const int UE_OPTION_HANDLER_RETURN_ACCESS = 2;
125 | public const int UE_OPTION_HANDLER_RETURN_FLAGS = 3;
126 | public const int UE_OPTION_HANDLER_RETURN_TYPENAME = 4;
127 | public const int UE_BREAKPOINT_INT3 = 1;
128 | public const int UE_BREAKPOINT_LONG_INT3 = 2;
129 | public const int UE_BREAKPOINT_UD2 = 3;
130 | public const int UE_BPXREMOVED = 0;
131 | public const int UE_BPXACTIVE = 1;
132 | public const int UE_BPXINACTIVE = 2;
133 | public const int UE_BREAKPOINT = 0;
134 | public const int UE_SINGLESHOOT = 1;
135 | public const int UE_HARDWARE = 2;
136 | public const int UE_MEMORY = 3;
137 | public const int UE_MEMORY_READ = 4;
138 | public const int UE_MEMORY_WRITE = 5;
139 | public const int UE_MEMORY_EXECUTE = 6;
140 | public const int UE_BREAKPOINT_TYPE_INT3 = 268435456;
141 | public const int UE_BREAKPOINT_TYPE_LONG_INT3 = 536870912;
142 | public const int UE_BREAKPOINT_TYPE_UD2 = 805306368;
143 | public const int UE_HARDWARE_EXECUTE = 4;
144 | public const int UE_HARDWARE_WRITE = 5;
145 | public const int UE_HARDWARE_READWRITE = 6;
146 | public const int UE_HARDWARE_SIZE_1 = 7;
147 | public const int UE_HARDWARE_SIZE_2 = 8;
148 | public const int UE_HARDWARE_SIZE_4 = 9;
149 | public const int UE_HARDWARE_SIZE_8 = 10;
150 | public const int UE_ON_LIB_LOAD = 1;
151 | public const int UE_ON_LIB_UNLOAD = 2;
152 | public const int UE_ON_LIB_ALL = 3;
153 | public const int UE_APISTART = 0;
154 | public const int UE_APIEND = 1;
155 | public const int UE_PLATFORM_x86 = 1;
156 | public const int UE_PLATFORM_x64 = 2;
157 | public const int UE_PLATFORM_ALL = 3;
158 | public const int UE_FUNCTION_STDCALL = 1;
159 | public const int UE_FUNCTION_CCALL = 2;
160 | public const int UE_FUNCTION_FASTCALL = 3;
161 | public const int UE_FUNCTION_STDCALL_RET = 4;
162 | public const int UE_FUNCTION_CCALL_RET = 5;
163 | public const int UE_FUNCTION_FASTCALL_RET = 6;
164 | public const int UE_FUNCTION_STDCALL_CALL = 7;
165 | public const int UE_FUNCTION_CCALL_CALL = 8;
166 | public const int UE_FUNCTION_FASTCALL_CALL = 9;
167 | public const int UE_PARAMETER_BYTE = 0;
168 | public const int UE_PARAMETER_WORD = 1;
169 | public const int UE_PARAMETER_DWORD = 2;
170 | public const int UE_PARAMETER_QWORD = 3;
171 | public const int UE_PARAMETER_PTR_BYTE = 4;
172 | public const int UE_PARAMETER_PTR_WORD = 5;
173 | public const int UE_PARAMETER_PTR_DWORD = 6;
174 | public const int UE_PARAMETER_PTR_QWORD = 7;
175 | public const int UE_PARAMETER_STRING = 8;
176 | public const int UE_PARAMETER_UNICODE = 9;
177 | public const int UE_EAX = 1;
178 | public const int UE_EBX = 2;
179 | public const int UE_ECX = 3;
180 | public const int UE_EDX = 4;
181 | public const int UE_EDI = 5;
182 | public const int UE_ESI = 6;
183 | public const int UE_EBP = 7;
184 | public const int UE_ESP = 8;
185 | public const int UE_EIP = 9;
186 | public const int UE_EFLAGS = 10;
187 | public const int UE_DR0 = 11;
188 | public const int UE_DR1 = 12;
189 | public const int UE_DR2 = 13;
190 | public const int UE_DR3 = 14;
191 | public const int UE_DR6 = 15;
192 | public const int UE_DR7 = 16;
193 | public const int UE_RAX = 17;
194 | public const int UE_RBX = 18;
195 | public const int UE_RCX = 19;
196 | public const int UE_RDX = 20;
197 | public const int UE_RDI = 21;
198 | public const int UE_RSI = 22;
199 | public const int UE_RBP = 23;
200 | public const int UE_RSP = 24;
201 | public const int UE_RIP = 25;
202 | public const int UE_RFLAGS = 26;
203 | public const int UE_R8 = 27;
204 | public const int UE_R9 = 28;
205 | public const int UE_R10 = 29;
206 | public const int UE_R11 = 30;
207 | public const int UE_R12 = 31;
208 | public const int UE_R13 = 32;
209 | public const int UE_R14 = 33;
210 | public const int UE_R15 = 34;
211 | public const int UE_CIP = 35;
212 | public const int UE_CSP = 36;
213 |
214 | [DllImport("TitanEngine.dll", CallingConvention = CallingConvention.Cdecl)]
215 | public static extern UIntPtr GetContextData(uint IndexOfRegister);
216 |
217 | [DllImport("TitanEngine.dll", CallingConvention = CallingConvention.Cdecl)]
218 | public static extern IntPtr TitanGetProcessInformation();
219 |
220 | [DllImport("TitanEngine.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Auto)]
221 | public static extern bool DumpProcess(IntPtr hProcess, IntPtr ImageBase, string szDumpFileName, UIntPtr EntryPoint);
222 |
223 | [DllImport("TitanEngine.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Auto)]
224 | public static extern bool StaticFileLoad(string szFileName, uint DesiredAccess, bool SimulateLoad, IntPtr FileHandle, ref uint LoadedSize, IntPtr FileMap, IntPtr FileMapVA);
225 | }
226 | }
227 |
--------------------------------------------------------------------------------
/DotNetPlugin.Impl/NativeBindings/Script/Argument.cs:
--------------------------------------------------------------------------------
1 | using DotNetPlugin.NativeBindings.SDK;
2 | using System;
3 | using System.Runtime.InteropServices;
4 |
5 | namespace DotNetPlugin.NativeBindings.Script
6 | {
7 | public static class Argument
8 | {
9 | [Serializable]
10 | public unsafe struct ArgumentInfo
11 | {
12 | private fixed byte _mod[BridgeBase.MAX_MODULE_SIZE];
13 | public string mod
14 | {
15 | get
16 | {
17 | fixed (byte* ptr = _mod)
18 | return new IntPtr(ptr).MarshalToStringUTF8(Bridge.MAX_MODULE_SIZE);
19 | }
20 | set
21 | {
22 | fixed (byte* ptr = _mod)
23 | value.MarshalToPtrUTF8(new IntPtr(ptr), Bridge.MAX_MODULE_SIZE * 4);
24 | }
25 | }
26 |
27 | nuint rvaStart;
28 | nuint rvaEnd;
29 | bool manual;
30 | nuint instructioncount;
31 | };
32 |
33 | #if AMD64
34 | private const string dll = "x64dbg.dll";
35 |
36 | private const string Script_Argument_DeleteRangeEP = "?DeleteRange@Argument@Script@@YAX_K0_N@Z";
37 | #else
38 | private const string dll = "x32dbg.dll";
39 |
40 | private const string Script_Argument_DeleteRangeEP = "?DeleteRange@Argument@Script@@YAXKK_N@Z";
41 | #endif
42 | private const CallingConvention cdecl = CallingConvention.Cdecl;
43 |
44 | [DllImport(dll, CallingConvention = cdecl, EntryPoint = Script_Argument_DeleteRangeEP, ExactSpelling = true)]
45 | private static extern void Script_Argument_DeleteRange(nuint start, nuint end, bool deleteManual = false);
46 |
47 | public static void DeleteRange(nuint start, nuint end, bool deleteManual = false) =>
48 | Script_Argument_DeleteRange(start, end, deleteManual);
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/DotNetPlugin.Impl/NativeBindings/Script/Disassembly.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.InteropServices;
2 |
3 | namespace DotNetPlugin.NativeBindings.Script
4 | {
5 | public static partial class Gui
6 | {
7 | public static class Disassembly
8 | {
9 | #if AMD64
10 | private const string dll = "x64dbg.dll";
11 |
12 | private const string Script_Gui_Disassembly_SelectionGetStartEP = "?SelectionGetStart@Disassembly@Gui@Script@@YA_KXZ";
13 | private const string Script_Gui_Disassembly_SelectionGetEndEP = "?SelectionGetEnd@Disassembly@Gui@Script@@YA_KXZ";
14 | #else
15 | private const string dll = "x32dbg.dll";
16 |
17 | private const string Script_Gui_Disassembly_SelectionGetStartEP = "?SelectionGetStart@Disassembly@Gui@Script@@YAKXZ";
18 | private const string Script_Gui_Disassembly_SelectionGetEndEP = "?SelectionGetEnd@Disassembly@Gui@Script@@YAKXZ";
19 | #endif
20 | private const CallingConvention cdecl = CallingConvention.Cdecl;
21 |
22 | [DllImport(dll, CallingConvention = cdecl, EntryPoint = Script_Gui_Disassembly_SelectionGetStartEP, ExactSpelling = true)]
23 | private static extern nuint Script_Gui_Disassembly_SelectionGetStart();
24 |
25 | public static nuint SelectionGetStart() => Script_Gui_Disassembly_SelectionGetStart();
26 |
27 | [DllImport(dll, CallingConvention = cdecl, EntryPoint = Script_Gui_Disassembly_SelectionGetEndEP, ExactSpelling = true)]
28 | private static extern nuint Script_Gui_Disassembly_SelectionGetEnd();
29 |
30 | public static nuint SelectionGetEnd() => Script_Gui_Disassembly_SelectionGetEnd();
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/DotNetPlugin.Impl/NativeBindings/Script/Gui.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.InteropServices;
2 |
3 | namespace DotNetPlugin.NativeBindings.Script
4 | {
5 | public static partial class Gui
6 | {
7 | public enum Window
8 | {
9 | DisassemblyWindow,
10 | DumpWindow,
11 | StackWindow,
12 | GraphWindow,
13 | MemMapWindow,
14 | SymModWindow
15 | };
16 |
17 | #if AMD64
18 | private const string dll = "x64dbg.dll";
19 |
20 | private const string Script_Gui_SelectionGetStartEP = "?SelectionGetStart@Gui@Script@@YA_KW4Window@12@@Z";
21 | private const string Script_Gui_SelectionGetEndEP = "?SelectionGetEnd@Gui@Script@@YA_KW4Window@12@@Z";
22 | #else
23 | private const string dll = "x32dbg.dll";
24 |
25 | private const string Script_Gui_SelectionGetStartEP = "?SelectionGetStart@Gui@Script@@YAKW4Window@12@@Z";
26 | private const string Script_Gui_SelectionGetEndEP = "?SelectionGetEnd@Gui@Script@@YAKW4Window@12@@Z";
27 | #endif
28 | private const CallingConvention cdecl = CallingConvention.Cdecl;
29 |
30 | [DllImport(dll, CallingConvention = cdecl, EntryPoint = Script_Gui_SelectionGetStartEP, ExactSpelling = true)]
31 | private static extern nuint Script_Gui_SelectionGetStart(Window window);
32 |
33 | public static nuint SelectionGetStart(Window window) => Script_Gui_SelectionGetStart(window);
34 |
35 | [DllImport(dll, CallingConvention = cdecl, EntryPoint = Script_Gui_SelectionGetEndEP, ExactSpelling = true)]
36 | private static extern nuint Script_Gui_SelectionGetEnd(Window window);
37 |
38 | public static nuint SelectionGetEnd(Window window) => Script_Gui_SelectionGetEnd(window);
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/DotNetPlugin.Impl/NativeBindings/Script/Module.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.InteropServices;
3 | using DotNetPlugin.NativeBindings.SDK;
4 | using DotNetPlugin.NativeBindings.Win32;
5 |
6 | namespace DotNetPlugin.NativeBindings.Script
7 | {
8 | // https://github.com/x64dbg/x64dbg/blob/development/src/dbg/_scriptapi_module.h
9 | public static class Module
10 | {
11 | [Serializable]
12 | public unsafe struct ModuleInfo
13 | {
14 | public nuint @base;
15 | public nuint size;
16 | public nuint entry;
17 | public int sectionCount;
18 |
19 | private fixed byte nameBytes[Bridge.MAX_MODULE_SIZE];
20 | public string name
21 | {
22 | get
23 | {
24 | fixed (byte* ptr = nameBytes)
25 | return new IntPtr(ptr).MarshalToStringUTF8(Bridge.MAX_MODULE_SIZE);
26 | }
27 | }
28 |
29 | private fixed byte pathBytes[Win32Constants.MAX_PATH];
30 | public string path
31 | {
32 | get
33 | {
34 | fixed (byte* ptr = pathBytes)
35 | return new IntPtr(ptr).MarshalToStringUTF8(Win32Constants.MAX_PATH);
36 | }
37 | }
38 | }
39 |
40 | [Serializable]
41 | public unsafe struct ModuleSectionInfo
42 | {
43 | public nuint addr;
44 | public nuint size;
45 |
46 | private fixed byte nameBytes[Bridge.MAX_SECTION_SIZE * 5];
47 | public string name
48 | {
49 | get
50 | {
51 | fixed (byte* ptr = nameBytes)
52 | return new IntPtr(ptr).MarshalToStringUTF8(Bridge.MAX_SECTION_SIZE * 5);
53 | }
54 | }
55 | }
56 |
57 | #if AMD64
58 | private const string dll = "x64dbg.dll";
59 |
60 | private const string Script_Module_GetListEP = "?GetList@Module@Script@@YA_NPEAUListInfo@@@Z";
61 | private const string Script_Module_SectionListFromAddrEP = "?SectionListFromAddr@Module@Script@@YA_N_KPEAUListInfo@@@Z";
62 | private const string Script_Module_InfoFromAddrEP = "?InfoFromAddr@Module@Script@@YA_N_KPEAUModuleInfo@12@@Z";
63 | private const string Script_Module_NameFromAddrEP = "?NameFromAddr@Module@Script@@YA_N_KPEAD@Z";
64 | private const string Script_Module_BaseFromAddrEP = "?BaseFromAddr@Module@Script@@YA_K_K@Z";
65 | private const string Script_Module_EntryFromAddrEP = "?EntryFromAddr@Module@Script@@YA_K_K@Z";
66 | private const string Script_Module_SectionFromNameEP = "?SectionFromName@Module@Script@@YA_NPEBDHPEAUModuleSectionInfo@12@@Z";
67 | private const string Script_Module_GetMainModuleInfoEP = "?GetMainModuleInfo@Module@Script@@YA_NPEAUModuleInfo@12@@Z";
68 | private const string Script_Module_GetMainModuleNameEP = "?GetMainModuleName@Module@Script@@YA_NPEAD@Z";
69 | #else
70 | private const string dll = "x32dbg.dll";
71 |
72 | private const string Script_Module_GetListEP = "?GetList@Module@Script@@YA_NPAUListInfo@@@Z";
73 | private const string Script_Module_SectionListFromAddrEP = "?SectionListFromAddr@Module@Script@@YA_NKPAUListInfo@@@Z";
74 | private const string Script_Module_InfoFromAddrEP = "?InfoFromAddr@Module@Script@@YA_NKPAUModuleInfo@12@@Z";
75 | private const string Script_Module_NameFromAddrEP = "?NameFromAddr@Module@Script@@YA_NKPAD@Z";
76 | private const string Script_Module_BaseFromAddrEP = "?BaseFromAddr@Module@Script@@YAKK@Z";
77 | private const string Script_Module_EntryFromAddrEP = "?EntryFromAddr@Module@Script@@YAKK@Z";
78 | private const string Script_Module_SectionFromNameEP = "?SectionFromName@Module@Script@@YA_NPBDHPAUModuleSectionInfo@12@@Z";
79 | private const string Script_Module_GetMainModuleInfoEP = "?GetMainModuleInfo@Module@Script@@YA_NPAUModuleInfo@12@@Z";
80 | private const string Script_Module_GetMainModuleNameEP = "?GetMainModuleName@Module@Script@@YA_NPAD@Z";
81 | #endif
82 | private const CallingConvention cdecl = CallingConvention.Cdecl;
83 |
84 | [DllImport(dll, CallingConvention = cdecl, EntryPoint = Script_Module_GetListEP, ExactSpelling = true)]
85 | private static extern bool Script_Module_GetList(ref Bridge.ListInfo listInfo);
86 |
87 | public static ModuleInfo[] GetList()
88 | {
89 | var listInfo = new Bridge.ListInfo();
90 | return listInfo.ToArray(Script_Module_GetList(ref listInfo));
91 | }
92 |
93 | [DllImport(dll, CallingConvention = cdecl, EntryPoint = Script_Module_SectionListFromAddrEP, ExactSpelling = true)]
94 | private static extern bool Script_Module_SectionListFromAddr(nuint addr, ref Bridge.ListInfo listInfo);
95 |
96 | public static ModuleSectionInfo[] SectionListFromAddr(nuint addr)
97 | {
98 | var listInfo = new Bridge.ListInfo();
99 | return listInfo.ToArray(Script_Module_SectionListFromAddr(addr, ref listInfo));
100 | }
101 |
102 | [DllImport(dll, CallingConvention = cdecl, EntryPoint = Script_Module_InfoFromAddrEP, ExactSpelling = true)]
103 | private static extern bool Script_Module_InfoFromAddr(nuint addr, ref ModuleInfo info);
104 |
105 | public static bool InfoFromAddr(nuint addr, ref ModuleInfo info)
106 | {
107 | return Script_Module_InfoFromAddr(addr, ref info);
108 | }
109 |
110 | [DllImport(dll, CallingConvention = cdecl, EntryPoint = Script_Module_NameFromAddrEP, ExactSpelling = true)]
111 | private static extern bool Script_Module_NameFromAddr(nuint addr, IntPtr name);
112 |
113 | public static bool NameFromAddr(nuint addr, out string name)
114 | {
115 | var nameBuffer = Marshal.AllocHGlobal(Bridge.MAX_MODULE_SIZE);
116 | try
117 | {
118 | var success = Script_Module_NameFromAddr(addr, nameBuffer);
119 | name = success ? nameBuffer.MarshalToStringUTF8(Bridge.MAX_MODULE_SIZE) : default;
120 | return success;
121 | }
122 | finally
123 | {
124 | Marshal.FreeHGlobal(nameBuffer);
125 | }
126 | }
127 |
128 | [DllImport(dll, CallingConvention = cdecl, EntryPoint = Script_Module_BaseFromAddrEP, ExactSpelling = true)]
129 | private static extern nuint Script_Module_BaseFromAddr(nuint addr);
130 |
131 | public static nuint BaseFromAddr(nuint addr) => Script_Module_BaseFromAddr(addr);
132 |
133 | [DllImport(dll, CallingConvention = cdecl, EntryPoint = Script_Module_EntryFromAddrEP, ExactSpelling = true)]
134 | private static extern nuint Script_Module_EntryFromAddr(nuint addr);
135 |
136 | public static nuint EntryFromAddr(nuint addr) => Script_Module_EntryFromAddr(addr);
137 |
138 | [DllImport(dll, CallingConvention = cdecl, EntryPoint = Script_Module_SectionFromNameEP, ExactSpelling = true)]
139 | private static extern bool Script_Module_SectionFromName(
140 | [MarshalAs(UnmanagedType.LPUTF8Str)] string name,
141 | int number,
142 | ref ModuleSectionInfo section);
143 |
144 | public static bool SectionFromName(string name, int number, ref ModuleSectionInfo section) =>
145 | Script_Module_SectionFromName(name, number, ref section);
146 |
147 | [DllImport(dll, CallingConvention = cdecl, EntryPoint = Script_Module_GetMainModuleInfoEP, ExactSpelling = true)]
148 | private static extern bool Script_Module_GetMainModuleInfo(ref ModuleInfo info);
149 |
150 | public static bool GetMainModuleInfo(ref ModuleInfo info) => Script_Module_GetMainModuleInfo(ref info);
151 |
152 | [DllImport(dll, CallingConvention = cdecl, EntryPoint = Script_Module_GetMainModuleNameEP, ExactSpelling = true)]
153 | private static extern bool Script_Module_GetMainModuleName(IntPtr name);
154 |
155 | public static bool GetMainModuleName(out string name)
156 | {
157 | var nameBuffer = Marshal.AllocHGlobal(Bridge.MAX_MODULE_SIZE);
158 | try
159 | {
160 | var success = Script_Module_GetMainModuleName(nameBuffer);
161 | name = success ? nameBuffer.MarshalToStringUTF8(Bridge.MAX_MODULE_SIZE) : default;
162 | return success;
163 | }
164 | finally
165 | {
166 | Marshal.FreeHGlobal(nameBuffer);
167 | }
168 | }
169 | }
170 | }
171 |
--------------------------------------------------------------------------------
/DotNetPlugin.Impl/NativeBindings/Script/Pattern.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.InteropServices;
2 |
3 | namespace DotNetPlugin.NativeBindings.Script
4 | {
5 | public static class Pattern
6 | {
7 | #if AMD64
8 | private const string dll = "x64dbg.dll";
9 |
10 | private const string Script_Pattern_FindMemEP = "?FindMem@Pattern@Script@@YA_K_K0PEBD@Z";
11 | #else
12 | private const string dll = "x32dbg.dll";
13 |
14 | private const string Script_Pattern_FindMemEP = "?FindMem@Pattern@Script@@YAKKKPBD@Z";
15 | #endif
16 | private const CallingConvention cdecl = CallingConvention.Cdecl;
17 |
18 | [DllImport(dll, CallingConvention = cdecl, EntryPoint = Script_Pattern_FindMemEP, ExactSpelling = true)]
19 | private static extern nuint Script_Pattern_FindMem(nuint start, nuint size, [MarshalAs(UnmanagedType.LPUTF8Str)] string pattern);
20 |
21 | public static nuint FindMem(nuint start, nuint size, string pattern) => Script_Pattern_FindMem(start, size, pattern);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/DotNetPlugin.Impl/NativeBindings/Script/Register.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.InteropServices;
3 |
4 | namespace DotNetPlugin.NativeBindings.Script
5 | {
6 | public static class Register
7 | {
8 | #if AMD64
9 | private const string dll = "x64dbg.dll";
10 |
11 | private const string ScriptRegisterGetCIP = "?GetCIP@Register@Script@@YA_KXZ";
12 | private const string ScriptRegisterGetCSP = "?GetCSP@Register@Script@@YA_KXZ";
13 | #else
14 | private const string dll = "x32dbg.dll";
15 |
16 | private const string ScriptRegisterGetCIP = "?GetCIP@Register@Script@@YAKXZ";
17 | private const string ScriptRegisterGetCSP = "?GetCSP@Register@Script@@YAKXZ";
18 | #endif
19 | private const CallingConvention cdecl = CallingConvention.Cdecl;
20 |
21 | [DllImport(dll, CallingConvention = cdecl, EntryPoint = ScriptRegisterGetCIP, ExactSpelling = true)]
22 | public static extern UIntPtr GetCIP();
23 |
24 | [DllImport(dll, CallingConvention = cdecl, EntryPoint = ScriptRegisterGetCSP, ExactSpelling = true)]
25 | public static extern UIntPtr GetCSP();
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/DotNetPlugin.Impl/NativeBindings/Win32/Constants.cs:
--------------------------------------------------------------------------------
1 | namespace DotNetPlugin.NativeBindings.Win32
2 | {
3 | public static class Win32Constants
4 | {
5 | public const int MAX_PATH = 260;
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/DotNetPlugin.Impl/NativeBindings/Win32/Functions.Kernel32.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.InteropServices;
3 |
4 | namespace DotNetPlugin.NativeBindings.Win32
5 | {
6 | public static class Kernel32
7 | {
8 | [DllImport("kernel32.dll", EntryPoint = "RtlZeroMemory", ExactSpelling = true)]
9 | public static extern void ZeroMemory(IntPtr dst, nuint length);
10 |
11 | [DllImport("kernel32.dll", SetLastError = true)]
12 | public static extern bool ContinueDebugEvent(int dwProcessId, int dwThreadId, ContinueStatus dwContinueStatus);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/DotNetPlugin.Impl/NativeBindings/Win32/Functions.Psapi.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.InteropServices;
3 | using System.Text;
4 |
5 | namespace DotNetPlugin.NativeBindings.Win32
6 | {
7 | public static class Psapi
8 | {
9 | [DllImport("psapi.dll", CharSet = CharSet.Auto)]
10 | public static extern uint GetModuleBaseName(IntPtr hProcess, IntPtr hModule, StringBuilder lpBaseName, uint nSize);
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/DotNetPlugin.Impl/NativeBindings/Win32/Types.cs:
--------------------------------------------------------------------------------
1 | namespace DotNetPlugin.NativeBindings.Win32
2 | {
3 | #pragma warning disable 0649
4 |
5 | public enum ContinueStatus : uint
6 | {
7 | DBG_CONTINUE = 0x00010002,
8 | DBG_EXCEPTION_NOT_HANDLED = 0x80010001,
9 | DBG_REPLY_LATER = 0x40010001
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/DotNetPlugin.Impl/Plugin.Commands.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading;
3 | using System.Windows.Forms;
4 | using DotNetPlugin.NativeBindings;
5 | using DotNetPlugin.NativeBindings.Script;
6 | using DotNetPlugin.NativeBindings.SDK;
7 | using Microsoft.VisualBasic;
8 | using Microsoft.VisualBasic.CompilerServices;
9 |
10 | namespace DotNetPlugin
11 | {
12 | partial class Plugin
13 | {
14 | [Command("DotNetpluginTestCommand")]
15 | public static void cbNetTestCommand(string[] args)
16 | {
17 | Console.WriteLine(".Net test command!");
18 | string empty = string.Empty;
19 | string Left = Interaction.InputBox("Enter value pls", "NetTest", "", -1, -1);
20 | if (Left == null | Operators.CompareString(Left, "", false) == 0)
21 | Console.WriteLine("cancel pressed!");
22 | else
23 | Console.WriteLine($"line: {Left}");
24 | }
25 |
26 | [Command("DotNetDumpProcess", DebugOnly = true)]
27 | public static bool cbDumpProcessCommand(string[] args)
28 | {
29 | var addr = args.Length >= 2 ? Bridge.DbgValFromString(args[1]) : Bridge.DbgValFromString("cip");
30 | Console.WriteLine($"addr: {addr.ToPtrString()}");
31 | var modinfo = new Module.ModuleInfo();
32 | if (!Module.InfoFromAddr(addr, ref modinfo))
33 | {
34 | Console.Error.WriteLine($"Module.InfoFromAddr failed...");
35 | return false;
36 | }
37 | Console.WriteLine($"InfoFromAddr success, base: {modinfo.@base.ToPtrString()}");
38 | var hProcess = Bridge.DbgValFromString("$hProcess");
39 | var saveFileDialog = new SaveFileDialog
40 | {
41 | Filter = "Executables (*.dll,*.exe)|*.exe|All Files (*.*)|*.*",
42 | RestoreDirectory = true,
43 | FileName = modinfo.name
44 | };
45 | using (saveFileDialog)
46 | {
47 | var result = DialogResult.Cancel;
48 | var t = new Thread(() => result = saveFileDialog.ShowDialog());
49 | t.SetApartmentState(ApartmentState.STA);
50 | t.Start();
51 | t.Join();
52 | if (result == DialogResult.OK)
53 | {
54 | string fileName = saveFileDialog.FileName;
55 | if (!TitanEngine.DumpProcess((nint)hProcess, (nint)modinfo.@base, fileName, addr))
56 | {
57 | Console.Error.WriteLine($"DumpProcess failed...");
58 | return false;
59 | }
60 | Console.WriteLine($"Dumping done!");
61 | }
62 | }
63 | return true;
64 | }
65 |
66 | [Command("DotNetModuleEnum", DebugOnly = true)]
67 | public static void cbModuleEnum(string[] args)
68 | {
69 | foreach (var mod in Module.GetList())
70 | {
71 | Console.WriteLine($"{mod.@base.ToPtrString()} {mod.name}");
72 | foreach (var section in Module.SectionListFromAddr(mod.@base))
73 | Console.WriteLine($" {section.addr.ToPtrString()} \"{section.name}\"");
74 | }
75 | }
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/DotNetPlugin.Impl/Plugin.EventCallbacks.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using DotNetPlugin.NativeBindings;
3 | using DotNetPlugin.NativeBindings.SDK;
4 |
5 | namespace DotNetPlugin
6 | {
7 | partial class Plugin
8 | {
9 | [EventCallback(Plugins.CBTYPE.CB_INITDEBUG)]
10 | public static void OnInitDebug(ref Plugins.PLUG_CB_INITDEBUG info)
11 | {
12 | var szFileName = info.szFileName;
13 | LogInfo($"DotNet test debugging of file {szFileName} started!");
14 | }
15 |
16 | [EventCallback(Plugins.CBTYPE.CB_STOPDEBUG)]
17 | public static void OnStopDebug(ref Plugins.PLUG_CB_STOPDEBUG info)
18 | {
19 | LogInfo($"DotNet test debugging stopped!");
20 | }
21 |
22 | [EventCallback(Plugins.CBTYPE.CB_CREATEPROCESS)]
23 | public static void OnCreateProcess(IntPtr infoPtr)
24 | {
25 | // info can also be cast manually
26 | var info = infoPtr.ToStructUnsafe();
27 |
28 | var CreateProcessInfo = info.CreateProcessInfo;
29 | var modInfo = info.modInfo;
30 | string DebugFileName = info.DebugFileName;
31 | var fdProcessInfo = info.fdProcessInfo;
32 | LogInfo($"Create process {info.DebugFileName}");
33 | }
34 |
35 | [EventCallback(Plugins.CBTYPE.CB_LOADDLL)]
36 | public static void OnLoadDll(ref Plugins.PLUG_CB_LOADDLL info)
37 | {
38 | var LoadDll = info.LoadDll;
39 | var modInfo = info.modInfo;
40 | string modname = info.modname;
41 | LogInfo($"Load DLL {modname}");
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/DotNetPlugin.Impl/Plugin.ExpressionFunctions.cs:
--------------------------------------------------------------------------------
1 | namespace DotNetPlugin
2 | {
3 | partial class Plugin
4 | {
5 | [ExpressionFunction]
6 | public static nuint DotNetAdd(nuint a, nuint b)
7 | {
8 | return a + b;
9 | }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/DotNetPlugin.Impl/Plugin.Menus.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Windows.Forms;
3 | using DotNetPlugin.NativeBindings.SDK;
4 | using DotNetPlugin.Properties;
5 |
6 | namespace DotNetPlugin
7 | {
8 | partial class Plugin
9 | {
10 | protected override void SetupMenu(Menus menus)
11 | {
12 | menus.Main
13 | .AddAndConfigureItem("&About...", OnAboutMenuItem).SetIcon(Resources.AboutIcon).Parent
14 | .AddAndConfigureItem("&DotNetDumpProcess", OnDumpMenuItem).SetHotKey("CTRL+F12").Parent
15 | .AddAndConfigureSubMenu("sub menu")
16 | .AddItem("sub menu entry1", menuItem => Console.WriteLine($"hEntry={menuItem.Id}"))
17 | .AddSeparator()
18 | .AddItem("sub menu entry2", menuItem => Console.WriteLine($"hEntry={menuItem.Id}"));
19 | }
20 |
21 | public void OnAboutMenuItem(MenuItem menuItem)
22 | {
23 | MessageBox.Show(HostWindow, "DotNet Plugin For x64dbg\nCoded By ", "Info", MessageBoxButtons.OK, MessageBoxIcon.Information);
24 | }
25 |
26 | public static void OnDumpMenuItem(MenuItem menuItem)
27 | {
28 | if (!Bridge.DbgIsDebugging())
29 | {
30 | Console.WriteLine("You need to be debugging to use this Command");
31 | return;
32 | }
33 | Bridge.DbgCmdExec("DotNetDumpProcess");
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/DotNetPlugin.Impl/Plugin.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading.Tasks;
3 | using DotNetPlugin.NativeBindings;
4 | using DotNetPlugin.NativeBindings.SDK;
5 |
6 | namespace DotNetPlugin
7 | {
8 | ///
9 | /// Implementation of your x64dbg plugin.
10 | ///
11 | ///
12 | /// If you change the namespace or name of this class, don't forget to reflect the change in too!
13 | ///
14 | public partial class Plugin : PluginBase
15 | {
16 | public override bool Init()
17 | {
18 | Console.SetOut(PLogTextWriter.Default);
19 | Console.SetError(PLogTextWriter.Default);
20 |
21 | LogInfo($"PluginHandle: {PluginHandle}");
22 |
23 | // You can listen to debugger events in two ways:
24 | // 1. by declaring dll exports in the Stub project (see PluginMain), then adding the corresponding methods to the IPlugin interface,
25 | // finally implementing them as required to propagate the call to the Plugin class or
26 | // 2. by registering callbacks using the EventCallback attribute (see Plugin.EventCallbacks.cs).
27 |
28 | // Please note that Option 1 goes through remoting in Debug builds (where Impl assembly unloading is enabled),
29 | // so it may be somewhat slower than Option 2. Release builds don't use remoting, just direct calls, so in that case there should be no significant difference.
30 |
31 | // Commands and function expressions are discovered and registered automatically. See Plugin.Commands.cs and Plugin.ExpressionFunctions.cs.
32 |
33 | // Menus can be registered by overriding the SetupMenu method. See Plugin.Menus.cs.
34 |
35 | return true;
36 | }
37 |
38 | public override void Setup(ref Plugins.PLUG_SETUPSTRUCT setupStruct)
39 | {
40 | // Do additional UI setup (apart from menus) here.
41 | }
42 |
43 | public override Task StopAsync()
44 | {
45 | // Do additional cleanup here.
46 |
47 | return Task.FromResult(true);
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/DotNetPlugin.Impl/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 DotNetPlugin.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", "17.0.0.0")]
23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
25 | internal 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 | internal 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("DotNetPlugin.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 | internal static global::System.Globalization.CultureInfo Culture {
55 | get {
56 | return resourceCulture;
57 | }
58 | set {
59 | resourceCulture = value;
60 | }
61 | }
62 |
63 | ///
64 | /// Looks up a localized resource of type System.Drawing.Bitmap.
65 | ///
66 | internal static System.Drawing.Bitmap AboutIcon {
67 | get {
68 | object obj = ResourceManager.GetObject("AboutIcon", resourceCulture);
69 | return ((System.Drawing.Bitmap)(obj));
70 | }
71 | }
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/DotNetPlugin.Impl/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 |
121 |
122 | ..\resources\abouticon.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
123 |
124 |
--------------------------------------------------------------------------------
/DotNetPlugin.Impl/Resources/abouticon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mrexodia/DotNetPluginCS/d1f367318d2d29d2c7c2c66e7a8d062eeebc6874/DotNetPlugin.Impl/Resources/abouticon.png
--------------------------------------------------------------------------------
/DotNetPlugin.RemotingHelper/AppDomainInitializer.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Reflection;
4 |
5 | namespace DotNetPlugin
6 | {
7 | ///
8 | /// A helper class which enables the Stub assembly to be resolved in a separate app domain.
9 | ///
10 | ///
11 | /// It's inevitable to place this class into a separate assembly because of an issue of the remoting activator:
12 | /// if this type resided in the Stub assembly, the activator would want to load that assembly in the app domain upon initialization,
13 | /// which would fail because the activator looks for a dll but x64dbg plugins must have a custom extension (dp32/dp64)...
14 | ///
15 | public static class AppDomainInitializer
16 | {
17 | private const string DllExtension =
18 | #if AMD64
19 | ".dp64";
20 | #else
21 | ".dp32";
22 | #endif
23 |
24 | public static void Initialize(string[] args)
25 | {
26 | AppDomain.CurrentDomain.AssemblyResolve += (s, e) =>
27 | {
28 | var assemblyName = new AssemblyName(e.Name);
29 | var pluginAssemblyName = typeof(AppDomainInitializer).Assembly.GetName().Name;
30 |
31 | if (pluginAssemblyName.StartsWith(assemblyName.Name, StringComparison.OrdinalIgnoreCase) &&
32 | pluginAssemblyName.Substring(assemblyName.Name.Length).Equals(".RemotingHelper", StringComparison.OrdinalIgnoreCase))
33 | {
34 | var location = typeof(AppDomainInitializer).Assembly.Location;
35 | var pluginBasePath = Path.GetDirectoryName(location);
36 | var dllPath = Path.Combine(pluginBasePath, assemblyName.Name + DllExtension);
37 |
38 | return Assembly.LoadFile(dllPath);
39 | }
40 |
41 | return null;
42 | };
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/DotNetPlugin.RemotingHelper/DotNetPlugin.RemotingHelper.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | $(PluginAssemblyName).RemotingHelper
4 | DotNetPlugin
5 | net472
6 | x86;x64
7 | false
8 | full
9 | true
10 | $(PluginName)
11 |
12 |
13 |
14 | X86;$(DefineConstants)
15 |
16 |
17 | AMD64;$(DefineConstants)
18 |
19 |
20 |
--------------------------------------------------------------------------------
/DotNetPlugin.Stub/Commands.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Reflection;
5 | using System.Threading;
6 | using DotNetPlugin.NativeBindings.SDK;
7 |
8 | namespace DotNetPlugin
9 | {
10 | ///
11 | /// Attribute for automatically registering commands in x64Dbg.
12 | ///
13 | [AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = false)]
14 | public class CommandAttribute : Attribute
15 | {
16 | public string Name { get; }
17 |
18 | public bool DebugOnly { get; set; }
19 |
20 | public CommandAttribute() { }
21 |
22 | public CommandAttribute(string name)
23 | {
24 | Name = name;
25 | }
26 | }
27 |
28 | internal static class Commands
29 | {
30 | private static Plugins.CBPLUGINCOMMAND BuildCallback(PluginBase plugin, MethodInfo method, bool reportsSuccess)
31 | {
32 | object firstArg = method.IsStatic ? null : plugin;
33 |
34 | if (reportsSuccess)
35 | {
36 | return (Plugins.CBPLUGINCOMMAND)Delegate.CreateDelegate(typeof(Plugins.CBPLUGINCOMMAND), firstArg, method, throwOnBindFailure: true);
37 | }
38 | else
39 | {
40 | var callback = (Action)Delegate.CreateDelegate(typeof(Action), firstArg, method, throwOnBindFailure: true);
41 | return args =>
42 | {
43 | callback(args);
44 | return true;
45 | };
46 | }
47 | }
48 |
49 | public static IDisposable Initialize(PluginBase plugin, MethodInfo[] pluginMethods)
50 | {
51 | // command names are case-insensitive
52 | var registeredNames = new HashSet(StringComparer.OrdinalIgnoreCase);
53 |
54 | var methods = pluginMethods
55 | .SelectMany(method => method.GetCustomAttributes().Select(attribute => (method, attribute)));
56 |
57 | foreach (var (method, attribute) in methods)
58 | {
59 | var name = attribute.Name ?? method.Name;
60 |
61 | var reportsSuccess = method.ReturnType == typeof(bool);
62 | if (!reportsSuccess && method.ReturnType != typeof(void))
63 | {
64 | PluginBase.LogError($"Registration of command '{name}' is skipped. Method '{method.Name}' has an invalid return type.");
65 | continue;
66 | }
67 |
68 | var methodParams = method.GetParameters();
69 |
70 | if (methodParams.Length != 1 || methodParams[0].ParameterType != typeof(string[]))
71 | {
72 | PluginBase.LogError($"Registration of command '{name}' is skipped. Method '{method.Name}' has an invalid signature.");
73 | continue;
74 | }
75 |
76 | if (registeredNames.Contains(name) ||
77 | !Plugins._plugin_registercommand(plugin.PluginHandle, name, BuildCallback(plugin, method, reportsSuccess), attribute.DebugOnly))
78 | {
79 | PluginBase.LogError($"Registration of command '{name}' failed.");
80 | continue;
81 | }
82 |
83 | registeredNames.Add(name);
84 | }
85 |
86 | return new Registrations(plugin, registeredNames);
87 | }
88 |
89 | private sealed class Registrations : IDisposable
90 | {
91 | private PluginBase _plugin;
92 | private HashSet _registeredNames;
93 |
94 | public Registrations(PluginBase plugin, HashSet registeredNames)
95 | {
96 | _plugin = plugin;
97 | _registeredNames = registeredNames;
98 | }
99 |
100 | public void Dispose()
101 | {
102 | var plugin = Interlocked.Exchange(ref _plugin, null);
103 |
104 | if (plugin != null)
105 | {
106 | foreach (var name in _registeredNames)
107 | {
108 | if (!Plugins._plugin_unregistercommand(plugin.PluginHandle, name))
109 | PluginBase.LogError($"Unregistration of command '{name}' failed.");
110 | }
111 |
112 | _registeredNames = null;
113 | }
114 | }
115 | }
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/DotNetPlugin.Stub/DotNetPlugin.Stub.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | $(PluginAssemblyName)
4 | $(PluginRootNamespace)
5 | net472
6 | x86;x64
7 | false
8 | full
9 | true
10 | true
11 | $(PluginName)
12 |
13 |
14 |
15 | X86;$(DefineConstants)
16 | .dp32
17 |
18 |
19 | AMD64;$(DefineConstants)
20 | .dp64
21 |
22 |
23 |
24 |
25 |
26 | ALLOW_UNLOADING;$(DefineConstants)
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 | build.meta
44 | $(IntermediateOutputPath)$(BuildMetadataFileName)
45 | $([System.IO.Path]::GetFullPath($(PluginOutputPath)))$(TargetName).Impl$(TargetExt)
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 | $(BuildMetadataFileName)
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 | build
66 |
67 |
68 |
--------------------------------------------------------------------------------
/DotNetPlugin.Stub/EventCallbacks.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Linq.Expressions;
5 | using System.Reflection;
6 | using System.Runtime.CompilerServices;
7 | using System.Threading;
8 | using DotNetPlugin.NativeBindings;
9 | using DotNetPlugin.NativeBindings.SDK;
10 |
11 | namespace DotNetPlugin
12 | {
13 | ///
14 | /// Attribute for automatically registering event callbacks in x64Dbg.
15 | ///
16 | [AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = false)]
17 | public class EventCallbackAttribute : Attribute
18 | {
19 | public Plugins.CBTYPE EventType { get; }
20 |
21 | public EventCallbackAttribute(Plugins.CBTYPE eventType)
22 | {
23 | EventType = eventType;
24 | }
25 | }
26 |
27 | internal static class EventCallbacks
28 | {
29 | private delegate void Callback(ref T info) where T : unmanaged;
30 |
31 | private delegate void InvokeCallbackDelegate(Callback callback, IntPtr callbackInfo) where T : unmanaged;
32 |
33 | private static readonly MethodInfo s_invokeCallbackMethodDefinition =
34 | new InvokeCallbackDelegate(InvokeCallback).Method.GetGenericMethodDefinition();
35 |
36 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
37 | private static void InvokeCallback(Callback callback, IntPtr callbackInfo) where T : unmanaged =>
38 | callback(ref callbackInfo.ToStructUnsafe());
39 |
40 | private static Plugins.CBPLUGIN BuildCallback(PluginBase plugin, MethodInfo method, Type eventInfoType)
41 | {
42 | object firstArg = method.IsStatic ? null : plugin;
43 |
44 | if (eventInfoType.IsByRef)
45 | {
46 | // ref return is not possible with expression trees (https://github.com/dotnet/csharplang/discussions/158),
47 | // so method can't be called directly, only via an indirection (InvokeCallback)
48 |
49 | eventInfoType = eventInfoType.GetElementType();
50 |
51 | var eventTypeParam = Expression.Parameter(typeof(Plugins.CBTYPE));
52 | var eventInfoParam = Expression.Parameter(typeof(IntPtr));
53 |
54 | var callbackType = typeof(Callback<>).MakeGenericType(eventInfoType);
55 | var callback = Delegate.CreateDelegate(callbackType, firstArg, method, throwOnBindFailure: true);
56 |
57 | var callArgs = new Expression[]
58 | {
59 | Expression.Constant(callback, callbackType),
60 | eventInfoParam
61 | };
62 |
63 | method = s_invokeCallbackMethodDefinition.MakeGenericMethod(eventInfoType);
64 | var call = method.IsStatic ? Expression.Call(method, callArgs) : Expression.Call(Expression.Constant(plugin), method, callArgs);
65 |
66 | var lambda = Expression.Lambda(call, eventTypeParam, eventInfoParam);
67 |
68 | return lambda.Compile();
69 | }
70 | else
71 | {
72 | var callback = (Action)Delegate.CreateDelegate(typeof(Action), firstArg, method, throwOnBindFailure: true);
73 | return (_, info) => callback(info);
74 | }
75 | }
76 |
77 | private static bool IsValidCallbackInfoType(Plugins.CBTYPE eventType, Type eventInfoType) => eventType switch
78 | {
79 | Plugins.CBTYPE.CB_INITDEBUG => eventInfoType == typeof(Plugins.PLUG_CB_INITDEBUG),
80 | Plugins.CBTYPE.CB_STOPDEBUG => eventInfoType == typeof(Plugins.PLUG_CB_STOPDEBUG),
81 | Plugins.CBTYPE.CB_CREATEPROCESS => eventInfoType == typeof(Plugins.PLUG_CB_CREATEPROCESS),
82 | Plugins.CBTYPE.CB_EXITPROCESS => eventInfoType == typeof(Plugins.PLUG_CB_EXITPROCESS),
83 | Plugins.CBTYPE.CB_CREATETHREAD => eventInfoType == typeof(Plugins.PLUG_CB_CREATETHREAD),
84 | Plugins.CBTYPE.CB_EXITTHREAD => eventInfoType == typeof(Plugins.PLUG_CB_EXITTHREAD),
85 | Plugins.CBTYPE.CB_SYSTEMBREAKPOINT => eventInfoType == typeof(Plugins.PLUG_CB_SYSTEMBREAKPOINT),
86 | Plugins.CBTYPE.CB_LOADDLL => eventInfoType == typeof(Plugins.PLUG_CB_LOADDLL),
87 | Plugins.CBTYPE.CB_UNLOADDLL => eventInfoType == typeof(Plugins.PLUG_CB_UNLOADDLL),
88 | Plugins.CBTYPE.CB_OUTPUTDEBUGSTRING => eventInfoType == typeof(Plugins.PLUG_CB_OUTPUTDEBUGSTRING),
89 | Plugins.CBTYPE.CB_EXCEPTION => eventInfoType == typeof(Plugins.PLUG_CB_EXCEPTION),
90 | Plugins.CBTYPE.CB_BREAKPOINT => eventInfoType == typeof(Plugins.PLUG_CB_BREAKPOINT),
91 | Plugins.CBTYPE.CB_PAUSEDEBUG => eventInfoType == typeof(Plugins.PLUG_CB_PAUSEDEBUG),
92 | Plugins.CBTYPE.CB_RESUMEDEBUG => eventInfoType == typeof(Plugins.PLUG_CB_RESUMEDEBUG),
93 | Plugins.CBTYPE.CB_STEPPED => eventInfoType == typeof(Plugins.PLUG_CB_STEPPED),
94 | Plugins.CBTYPE.CB_ATTACH => eventInfoType == typeof(Plugins.PLUG_CB_ATTACH),
95 | Plugins.CBTYPE.CB_DETACH => eventInfoType == typeof(Plugins.PLUG_CB_DETACH),
96 | Plugins.CBTYPE.CB_DEBUGEVENT => eventInfoType == typeof(Plugins.PLUG_CB_DEBUGEVENT),
97 | Plugins.CBTYPE.CB_MENUENTRY => eventInfoType == typeof(Plugins.PLUG_CB_MENUENTRY),
98 | Plugins.CBTYPE.CB_WINEVENT => eventInfoType == typeof(Plugins.PLUG_CB_WINEVENT),
99 | Plugins.CBTYPE.CB_WINEVENTGLOBAL => eventInfoType == typeof(Plugins.PLUG_CB_WINEVENTGLOBAL),
100 | Plugins.CBTYPE.CB_LOADDB => eventInfoType == typeof(Plugins.PLUG_CB_LOADSAVEDB),
101 | Plugins.CBTYPE.CB_SAVEDB => eventInfoType == typeof(Plugins.PLUG_CB_LOADSAVEDB),
102 | Plugins.CBTYPE.CB_FILTERSYMBOL => eventInfoType == typeof(Plugins.PLUG_CB_FILTERSYMBOL),
103 | Plugins.CBTYPE.CB_TRACEEXECUTE => eventInfoType == typeof(Plugins.PLUG_CB_TRACEEXECUTE),
104 | Plugins.CBTYPE.CB_SELCHANGED => eventInfoType == typeof(Plugins.PLUG_CB_SELCHANGED),
105 | Plugins.CBTYPE.CB_ANALYZE => eventInfoType == typeof(Plugins.PLUG_CB_ANALYZE),
106 | Plugins.CBTYPE.CB_ADDRINFO => eventInfoType == typeof(Plugins.PLUG_CB_ADDRINFO),
107 | Plugins.CBTYPE.CB_VALFROMSTRING => eventInfoType == typeof(Plugins.PLUG_CB_VALFROMSTRING),
108 | Plugins.CBTYPE.CB_VALTOSTRING => eventInfoType == typeof(Plugins.PLUG_CB_VALTOSTRING),
109 | Plugins.CBTYPE.CB_MENUPREPARE => eventInfoType == typeof(Plugins.PLUG_CB_MENUPREPARE),
110 | Plugins.CBTYPE.CB_STOPPINGDEBUG => eventInfoType == typeof(Plugins.PLUG_CB_STOPDEBUG),
111 | _ => false
112 | };
113 |
114 | public static IDisposable Initialize(PluginBase plugin, MethodInfo[] pluginMethods)
115 | {
116 | var registeredEventTypes = new HashSet();
117 |
118 | var methods = pluginMethods
119 | .SelectMany(method => method.GetCustomAttributes().Select(attribute => (method, attribute)));
120 |
121 | foreach (var (method, attribute) in methods)
122 | {
123 | var eventType = attribute.EventType;
124 |
125 | if (method.ReturnType != typeof(void))
126 | {
127 | PluginBase.LogError($"Registration of event callback {eventType} is skipped. Method '{method.Name}' has an invalid return type.");
128 | continue;
129 | }
130 |
131 | var methodParams = method.GetParameters();
132 | ParameterInfo eventInfoParam;
133 | Type eventInfoType;
134 | if (methodParams.Length != 1 ||
135 | (eventInfoType = (eventInfoParam = methodParams[0]).ParameterType) != typeof(IntPtr) &&
136 | !(eventInfoType.IsByRef && !eventInfoParam.IsIn && !eventInfoParam.IsOut && IsValidCallbackInfoType(eventType, eventInfoType.GetElementType())))
137 | {
138 | PluginBase.LogError($"Registration of event callback {eventType} is skipped. Method '{method.Name}' has an invalid signature.");
139 | continue;
140 | }
141 |
142 | if (registeredEventTypes.Contains(eventType))
143 | {
144 | PluginBase.LogError($"Registration of event callback {eventType} failed.");
145 | continue;
146 | }
147 |
148 | Plugins._plugin_registercallback(plugin.PluginHandle, eventType, BuildCallback(plugin, method, eventInfoType));
149 |
150 | registeredEventTypes.Add(eventType);
151 |
152 | PluginBase.LogInfo($"Event callback {eventType} registered!");
153 | }
154 |
155 | return new Registrations(plugin, registeredEventTypes);
156 | }
157 |
158 | private sealed class Registrations : IDisposable
159 | {
160 | private PluginBase _plugin;
161 | private HashSet _registeredEventTypes;
162 |
163 | public Registrations(PluginBase plugin, HashSet registeredEventTypes)
164 | {
165 | _plugin = plugin;
166 | _registeredEventTypes = registeredEventTypes;
167 | }
168 |
169 | public void Dispose()
170 | {
171 | var plugin = Interlocked.Exchange(ref _plugin, null);
172 |
173 | if (plugin != null)
174 | {
175 | foreach (var eventType in _registeredEventTypes)
176 | {
177 | if (Plugins._plugin_unregistercallback(plugin.PluginHandle, eventType))
178 | PluginBase.LogInfo($"Event callback {eventType} unregistered!");
179 | else
180 | PluginBase.LogError($"Unregistration of event callback {eventType} failed.");
181 | }
182 |
183 | _registeredEventTypes = null;
184 | }
185 | }
186 | }
187 | }
188 | }
--------------------------------------------------------------------------------
/DotNetPlugin.Stub/ExpressionFunctions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Linq.Expressions;
5 | using System.Reflection;
6 | using System.Runtime.CompilerServices;
7 | using System.Runtime.InteropServices;
8 | using System.Threading;
9 | using DotNetPlugin.NativeBindings.SDK;
10 |
11 | namespace DotNetPlugin
12 | {
13 | ///
14 | /// Attribute for automatically registering expression functions in x64Dbg.
15 | ///
16 | [AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = false)]
17 | public class ExpressionFunctionAttribute : Attribute
18 | {
19 | public string Name { get; }
20 |
21 | public ExpressionFunctionAttribute() { }
22 |
23 | public ExpressionFunctionAttribute(string name)
24 | {
25 | Name = name;
26 | }
27 | }
28 |
29 | internal static class ExpressionFunctions
30 | {
31 | private static readonly MethodInfo s_marshalReadIntPtrMethod = new Func(Marshal.ReadIntPtr).Method;
32 | private static readonly MethodInfo s_intPtrToUIntPtrMethod = new Func(IntPtrToUIntPtr).Method;
33 |
34 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
35 | private static UIntPtr IntPtrToUIntPtr(IntPtr value) => (nuint)(nint)value;
36 |
37 | private static Plugins.CBPLUGINEXPRFUNCTION_RAWARGS BuildCallback(PluginBase plugin, MethodInfo method, int methodParamCount)
38 | {
39 | var argcParam = Expression.Parameter(typeof(int));
40 | var argvParam = Expression.Parameter(typeof(IntPtr));
41 | var userdataParam = Expression.Parameter(typeof(object));
42 |
43 | var callArgs = Enumerable.Range(0, methodParamCount)
44 | .Select((param, i) => Expression.Call(
45 | s_intPtrToUIntPtrMethod,
46 | Expression.Call(s_marshalReadIntPtrMethod, argvParam, Expression.Constant(i * IntPtr.Size))))
47 | .ToArray();
48 |
49 | var call = method.IsStatic ? Expression.Call(method, callArgs) : Expression.Call(Expression.Constant(plugin), method, callArgs);
50 |
51 | var lambda = Expression.Lambda(call, argcParam, argvParam, userdataParam);
52 |
53 | return lambda.Compile();
54 | }
55 |
56 | public static IDisposable Initialize(PluginBase plugin, MethodInfo[] pluginMethods)
57 | {
58 | // expression function names are case-sensitive
59 | var registeredNames = new HashSet();
60 |
61 | var methods = pluginMethods
62 | .SelectMany(method => method.GetCustomAttributes().Select(attribute => (method, attribute)));
63 |
64 | foreach (var (method, attribute) in methods)
65 | {
66 | var name = attribute.Name ?? method.Name;
67 |
68 | if (method.ReturnType != typeof(UIntPtr))
69 | {
70 | PluginBase.LogError($"Registration of expression function '{name}' is skipped. Method '{method.Name}' has an invalid return type.");
71 | continue;
72 | }
73 |
74 | var methodParams = method.GetParameters();
75 | if (methodParams.Any(param => param.ParameterType != typeof(UIntPtr)))
76 | {
77 | PluginBase.LogError($"Registration of expression function '{name}' is skipped. Method '{method.Name}' has an invalid signature.");
78 | continue;
79 | }
80 |
81 | if (registeredNames.Contains(name) ||
82 | !Plugins._plugin_registerexprfunction(plugin.PluginHandle, name, methodParams.Length, BuildCallback(plugin, method, methodParams.Length), null))
83 | {
84 | PluginBase.LogError($"Registration of expression function '{name}' failed.");
85 | continue;
86 | }
87 |
88 | registeredNames.Add(name);
89 | }
90 |
91 | return new Registrations(plugin, registeredNames);
92 | }
93 |
94 | private sealed class Registrations : IDisposable
95 | {
96 | private PluginBase _plugin;
97 | private HashSet _registeredNames;
98 |
99 | public Registrations(PluginBase plugin, HashSet registeredNames)
100 | {
101 | _plugin = plugin;
102 | _registeredNames = registeredNames;
103 | }
104 |
105 | public void Dispose()
106 | {
107 | var plugin = Interlocked.Exchange(ref _plugin, null);
108 |
109 | if (plugin != null)
110 | {
111 | foreach (var name in _registeredNames)
112 | {
113 | if (!Plugins._plugin_unregisterexprfunction(plugin.PluginHandle, name))
114 | PluginBase.LogError($"Unregistration of expression function '{name}' failed.");
115 | }
116 |
117 | _registeredNames = null;
118 | }
119 | }
120 | }
121 | }
122 | }
--------------------------------------------------------------------------------
/DotNetPlugin.Stub/IPlugin.cs:
--------------------------------------------------------------------------------
1 | using DotNetPlugin.NativeBindings.SDK;
2 |
3 | namespace DotNetPlugin
4 | {
5 | ///
6 | /// Defines an API to interact with x64dbg.
7 | ///
8 | internal interface IPlugin
9 | {
10 | int PluginHandle { get; }
11 |
12 | bool Init();
13 | void Setup(ref Plugins.PLUG_SETUPSTRUCT setupStruct);
14 | bool Stop();
15 |
16 | void OnMenuEntry(ref Plugins.PLUG_CB_MENUENTRY info);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/DotNetPlugin.Stub/IPluginSession.cs:
--------------------------------------------------------------------------------
1 | #if ALLOW_UNLOADING
2 |
3 | using System;
4 |
5 | namespace DotNetPlugin
6 | {
7 | ///
8 | /// Represents the lifecycle of a plugin instance. (Supports Impl assembly unloading.)
9 | ///
10 | internal interface IPluginSession : IPlugin, IDisposable
11 | {
12 | new int PluginHandle { set; }
13 | }
14 | }
15 |
16 | #endif
--------------------------------------------------------------------------------
/DotNetPlugin.Stub/Menus.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Drawing;
4 | using DotNetPlugin.NativeBindings.SDK;
5 |
6 | namespace DotNetPlugin
7 | {
8 | ///
9 | /// Not thread-safe. If you want to modify the menu structure dynamically, you are responsible for synchronization.
10 | /// See also .
11 | ///
12 | public sealed class Menus : IDisposable
13 | {
14 | private int _lastId;
15 | internal Dictionary _menuItemsById;
16 |
17 | internal Menus(int pluginHandle, ref Plugins.PLUG_SETUPSTRUCT setupStruct)
18 | {
19 | PluginHandle = pluginHandle;
20 |
21 | All = new[]
22 | {
23 | Main = new Menu(this, setupStruct.hMenu),
24 | Disasm = new Menu(this, setupStruct.hMenuDisasm),
25 | Dump = new Menu(this, setupStruct.hMenuDump),
26 | Stack = new Menu(this, setupStruct.hMenuStack),
27 | Graph = new Menu(this, setupStruct.hMenuGraph),
28 | Memmap = new Menu(this, setupStruct.hMenuMemmap),
29 | Symmod = new Menu(this, setupStruct.hMenuSymmod),
30 | };
31 |
32 | _menuItemsById = new Dictionary();
33 | }
34 |
35 | public void Dispose()
36 | {
37 | if (_menuItemsById != null)
38 | {
39 | Clear();
40 | _menuItemsById = null;
41 | }
42 | }
43 |
44 | internal void EnsureNotDisposed()
45 | {
46 | if (_menuItemsById == null)
47 | throw new ObjectDisposedException(nameof(Menus));
48 | }
49 |
50 | internal int PluginHandle { get; }
51 |
52 | public Menu Main; // main menu
53 | public Menu Disasm; // disasm menu
54 | public Menu Dump; // dump menu
55 | public Menu Stack; // stack menu
56 | public Menu Graph; // graph menu
57 | public Menu Memmap; // memory map menu
58 | public Menu Symmod; // symbol module menu
59 |
60 | public IReadOnlyList