windows-exe-decompiler-mcp-server 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CODEX_INSTALLATION.md +69 -0
- package/COPILOT_INSTALLATION.md +77 -0
- package/LICENSE +21 -0
- package/README.md +314 -0
- package/bin/windows-exe-decompiler-mcp-server.js +3 -0
- package/dist/analysis-provenance.d.ts +184 -0
- package/dist/analysis-provenance.js +74 -0
- package/dist/analysis-task-runner.d.ts +31 -0
- package/dist/analysis-task-runner.js +160 -0
- package/dist/artifact-inventory.d.ts +23 -0
- package/dist/artifact-inventory.js +175 -0
- package/dist/cache-manager.d.ts +128 -0
- package/dist/cache-manager.js +454 -0
- package/dist/confidence-semantics.d.ts +66 -0
- package/dist/confidence-semantics.js +122 -0
- package/dist/config.d.ts +335 -0
- package/dist/config.js +193 -0
- package/dist/database.d.ts +227 -0
- package/dist/database.js +601 -0
- package/dist/decompiler-worker.d.ts +441 -0
- package/dist/decompiler-worker.js +1962 -0
- package/dist/dynamic-trace.d.ts +95 -0
- package/dist/dynamic-trace.js +629 -0
- package/dist/env-validator.d.ts +15 -0
- package/dist/env-validator.js +249 -0
- package/dist/error-handler.d.ts +28 -0
- package/dist/error-handler.example.d.ts +22 -0
- package/dist/error-handler.example.js +141 -0
- package/dist/error-handler.js +139 -0
- package/dist/ghidra-analysis-status.d.ts +49 -0
- package/dist/ghidra-analysis-status.js +178 -0
- package/dist/ghidra-config.d.ts +134 -0
- package/dist/ghidra-config.js +464 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +200 -0
- package/dist/job-queue.d.ts +169 -0
- package/dist/job-queue.js +407 -0
- package/dist/logger.d.ts +106 -0
- package/dist/logger.js +176 -0
- package/dist/policy-guard.d.ts +115 -0
- package/dist/policy-guard.js +243 -0
- package/dist/process-output.d.ts +15 -0
- package/dist/process-output.js +90 -0
- package/dist/prompts/function-explanation-review.d.ts +5 -0
- package/dist/prompts/function-explanation-review.js +64 -0
- package/dist/prompts/semantic-name-review.d.ts +5 -0
- package/dist/prompts/semantic-name-review.js +63 -0
- package/dist/runtime-correlation.d.ts +34 -0
- package/dist/runtime-correlation.js +279 -0
- package/dist/runtime-paths.d.ts +3 -0
- package/dist/runtime-paths.js +11 -0
- package/dist/selection-diff.d.ts +667 -0
- package/dist/selection-diff.js +53 -0
- package/dist/semantic-name-suggestion-artifacts.d.ts +116 -0
- package/dist/semantic-name-suggestion-artifacts.js +314 -0
- package/dist/server.d.ts +129 -0
- package/dist/server.js +578 -0
- package/dist/tools/artifact-read.d.ts +235 -0
- package/dist/tools/artifact-read.js +317 -0
- package/dist/tools/artifacts-diff.d.ts +728 -0
- package/dist/tools/artifacts-diff.js +304 -0
- package/dist/tools/artifacts-list.d.ts +515 -0
- package/dist/tools/artifacts-list.js +389 -0
- package/dist/tools/attack-map.d.ts +290 -0
- package/dist/tools/attack-map.js +519 -0
- package/dist/tools/cache-observability.d.ts +4 -0
- package/dist/tools/cache-observability.js +36 -0
- package/dist/tools/code-function-cfg.d.ts +50 -0
- package/dist/tools/code-function-cfg.js +102 -0
- package/dist/tools/code-function-decompile.d.ts +55 -0
- package/dist/tools/code-function-decompile.js +103 -0
- package/dist/tools/code-function-disassemble.d.ts +43 -0
- package/dist/tools/code-function-disassemble.js +185 -0
- package/dist/tools/code-function-explain-apply.d.ts +255 -0
- package/dist/tools/code-function-explain-apply.js +225 -0
- package/dist/tools/code-function-explain-prepare.d.ts +535 -0
- package/dist/tools/code-function-explain-prepare.js +276 -0
- package/dist/tools/code-function-explain-review.d.ts +397 -0
- package/dist/tools/code-function-explain-review.js +589 -0
- package/dist/tools/code-function-rename-apply.d.ts +248 -0
- package/dist/tools/code-function-rename-apply.js +220 -0
- package/dist/tools/code-function-rename-prepare.d.ts +506 -0
- package/dist/tools/code-function-rename-prepare.js +279 -0
- package/dist/tools/code-function-rename-review.d.ts +574 -0
- package/dist/tools/code-function-rename-review.js +761 -0
- package/dist/tools/code-functions-list.d.ts +37 -0
- package/dist/tools/code-functions-list.js +91 -0
- package/dist/tools/code-functions-rank.d.ts +34 -0
- package/dist/tools/code-functions-rank.js +90 -0
- package/dist/tools/code-functions-reconstruct.d.ts +2725 -0
- package/dist/tools/code-functions-reconstruct.js +2807 -0
- package/dist/tools/code-functions-search.d.ts +39 -0
- package/dist/tools/code-functions-search.js +90 -0
- package/dist/tools/code-reconstruct-export.d.ts +1212 -0
- package/dist/tools/code-reconstruct-export.js +4002 -0
- package/dist/tools/code-reconstruct-plan.d.ts +274 -0
- package/dist/tools/code-reconstruct-plan.js +342 -0
- package/dist/tools/dotnet-metadata-extract.d.ts +541 -0
- package/dist/tools/dotnet-metadata-extract.js +355 -0
- package/dist/tools/dotnet-reconstruct-export.d.ts +567 -0
- package/dist/tools/dotnet-reconstruct-export.js +1151 -0
- package/dist/tools/dotnet-types-list.d.ts +325 -0
- package/dist/tools/dotnet-types-list.js +201 -0
- package/dist/tools/dynamic-dependencies.d.ts +115 -0
- package/dist/tools/dynamic-dependencies.js +213 -0
- package/dist/tools/dynamic-memory-import.d.ts +10 -0
- package/dist/tools/dynamic-memory-import.js +567 -0
- package/dist/tools/dynamic-trace-import.d.ts +10 -0
- package/dist/tools/dynamic-trace-import.js +235 -0
- package/dist/tools/entrypoint-fallback-disasm.d.ts +30 -0
- package/dist/tools/entrypoint-fallback-disasm.js +89 -0
- package/dist/tools/ghidra-analyze.d.ts +88 -0
- package/dist/tools/ghidra-analyze.js +208 -0
- package/dist/tools/ghidra-health.d.ts +37 -0
- package/dist/tools/ghidra-health.js +212 -0
- package/dist/tools/ioc-export.d.ts +209 -0
- package/dist/tools/ioc-export.js +542 -0
- package/dist/tools/packer-detect.d.ts +165 -0
- package/dist/tools/packer-detect.js +284 -0
- package/dist/tools/pe-exports-extract.d.ts +175 -0
- package/dist/tools/pe-exports-extract.js +253 -0
- package/dist/tools/pe-fingerprint.d.ts +234 -0
- package/dist/tools/pe-fingerprint.js +269 -0
- package/dist/tools/pe-imports-extract.d.ts +105 -0
- package/dist/tools/pe-imports-extract.js +245 -0
- package/dist/tools/report-generate.d.ts +157 -0
- package/dist/tools/report-generate.js +457 -0
- package/dist/tools/report-summarize.d.ts +2131 -0
- package/dist/tools/report-summarize.js +596 -0
- package/dist/tools/runtime-detect.d.ts +135 -0
- package/dist/tools/runtime-detect.js +247 -0
- package/dist/tools/sample-ingest.d.ts +94 -0
- package/dist/tools/sample-ingest.js +327 -0
- package/dist/tools/sample-profile-get.d.ts +183 -0
- package/dist/tools/sample-profile-get.js +121 -0
- package/dist/tools/sandbox-execute.d.ts +441 -0
- package/dist/tools/sandbox-execute.js +392 -0
- package/dist/tools/strings-extract.d.ts +375 -0
- package/dist/tools/strings-extract.js +314 -0
- package/dist/tools/strings-floss-decode.d.ts +143 -0
- package/dist/tools/strings-floss-decode.js +259 -0
- package/dist/tools/system-health.d.ts +434 -0
- package/dist/tools/system-health.js +446 -0
- package/dist/tools/task-cancel.d.ts +21 -0
- package/dist/tools/task-cancel.js +70 -0
- package/dist/tools/task-status.d.ts +27 -0
- package/dist/tools/task-status.js +106 -0
- package/dist/tools/task-sweep.d.ts +22 -0
- package/dist/tools/task-sweep.js +77 -0
- package/dist/tools/tool-help.d.ts +340 -0
- package/dist/tools/tool-help.js +261 -0
- package/dist/tools/yara-scan.d.ts +554 -0
- package/dist/tools/yara-scan.js +313 -0
- package/dist/types.d.ts +266 -0
- package/dist/types.js +41 -0
- package/dist/worker-pool.d.ts +204 -0
- package/dist/worker-pool.js +650 -0
- package/dist/workflows/deep-static.d.ts +104 -0
- package/dist/workflows/deep-static.js +276 -0
- package/dist/workflows/function-explanation-review.d.ts +655 -0
- package/dist/workflows/function-explanation-review.js +440 -0
- package/dist/workflows/reconstruct.d.ts +2053 -0
- package/dist/workflows/reconstruct.js +666 -0
- package/dist/workflows/semantic-name-review.d.ts +2418 -0
- package/dist/workflows/semantic-name-review.js +521 -0
- package/dist/workflows/triage.d.ts +659 -0
- package/dist/workflows/triage.js +1374 -0
- package/dist/workspace-manager.d.ts +150 -0
- package/dist/workspace-manager.js +411 -0
- package/ghidra_scripts/DecompileFunction.java +487 -0
- package/ghidra_scripts/DecompileFunction.py +150 -0
- package/ghidra_scripts/ExtractCFG.java +256 -0
- package/ghidra_scripts/ExtractCFG.py +233 -0
- package/ghidra_scripts/ExtractFunctions.java +442 -0
- package/ghidra_scripts/ExtractFunctions.py +101 -0
- package/ghidra_scripts/README.md +125 -0
- package/ghidra_scripts/SearchFunctionReferences.java +380 -0
- package/helpers/DotNetMetadataProbe/DotNetMetadataProbe.csproj +9 -0
- package/helpers/DotNetMetadataProbe/Program.cs +566 -0
- package/install-to-codex.ps1 +178 -0
- package/install-to-copilot.ps1 +303 -0
- package/package.json +101 -0
- package/requirements.txt +9 -0
- package/workers/requirements-dynamic.txt +11 -0
- package/workers/requirements.txt +8 -0
- package/workers/speakeasy_compat.py +175 -0
- package/workers/static_worker.py +5183 -0
- package/workers/yara_rules/default.yar +33 -0
- package/workers/yara_rules/malware_families.yar +93 -0
- package/workers/yara_rules/packers.yar +80 -0
|
@@ -0,0 +1,566 @@
|
|
|
1
|
+
using System.Reflection;
|
|
2
|
+
using System.Reflection.Metadata;
|
|
3
|
+
using System.Reflection.Metadata.Ecma335;
|
|
4
|
+
using System.Reflection.PortableExecutable;
|
|
5
|
+
using System.Text.Json;
|
|
6
|
+
|
|
7
|
+
internal sealed record ProbeOptions(
|
|
8
|
+
string SamplePath,
|
|
9
|
+
bool IncludeTypes,
|
|
10
|
+
bool IncludeMethods,
|
|
11
|
+
int MaxTypes,
|
|
12
|
+
int MaxMethodsPerType
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
internal static class Program
|
|
16
|
+
{
|
|
17
|
+
private static readonly JsonSerializerOptions JsonOptions = new()
|
|
18
|
+
{
|
|
19
|
+
WriteIndented = false
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
public static int Main(string[] args)
|
|
23
|
+
{
|
|
24
|
+
var result = Run(args);
|
|
25
|
+
Console.WriteLine(JsonSerializer.Serialize(result, JsonOptions));
|
|
26
|
+
return 0;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
private static object Run(string[] args)
|
|
30
|
+
{
|
|
31
|
+
try
|
|
32
|
+
{
|
|
33
|
+
var options = ParseArgs(args);
|
|
34
|
+
if (!File.Exists(options.SamplePath))
|
|
35
|
+
{
|
|
36
|
+
return Fail($"Sample path does not exist: {options.SamplePath}");
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
using var stream = File.OpenRead(options.SamplePath);
|
|
40
|
+
using var peReader = new PEReader(stream);
|
|
41
|
+
|
|
42
|
+
if (!peReader.HasMetadata)
|
|
43
|
+
{
|
|
44
|
+
return Fail("PE image does not expose CLR metadata.");
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
var mdReader = peReader.GetMetadataReader();
|
|
48
|
+
var warnings = new List<string>();
|
|
49
|
+
|
|
50
|
+
var assemblyDefinition = mdReader.IsAssembly
|
|
51
|
+
? mdReader.GetAssemblyDefinition()
|
|
52
|
+
: default(AssemblyDefinition);
|
|
53
|
+
var assemblyName = mdReader.IsAssembly ? SafeString(mdReader, assemblyDefinition.Name) : null;
|
|
54
|
+
var assemblyVersion = mdReader.IsAssembly ? assemblyDefinition.Version.ToString() : null;
|
|
55
|
+
var moduleDefinition = mdReader.GetModuleDefinition();
|
|
56
|
+
var moduleName = SafeString(mdReader, moduleDefinition.Name);
|
|
57
|
+
var targetFramework = TryReadTargetFramework(mdReader);
|
|
58
|
+
|
|
59
|
+
var typeRows = new List<object>();
|
|
60
|
+
var namespaceCounts = new Dictionary<string, (int Types, int Methods)>(StringComparer.OrdinalIgnoreCase);
|
|
61
|
+
|
|
62
|
+
var allTypeDefinitions = mdReader.TypeDefinitions
|
|
63
|
+
.Select(handle => BuildTypeInfo(mdReader, handle, options.IncludeMethods, options.MaxMethodsPerType))
|
|
64
|
+
.Where(item => !item.IsCompilerGenerated)
|
|
65
|
+
.ToList();
|
|
66
|
+
|
|
67
|
+
foreach (var type in allTypeDefinitions)
|
|
68
|
+
{
|
|
69
|
+
var key = string.IsNullOrWhiteSpace(type.Namespace) ? "<global>" : type.Namespace;
|
|
70
|
+
if (!namespaceCounts.TryGetValue(key, out var counts))
|
|
71
|
+
{
|
|
72
|
+
counts = (0, 0);
|
|
73
|
+
}
|
|
74
|
+
namespaceCounts[key] = (counts.Types + 1, counts.Methods + type.MethodCount);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
var typeLimit = Math.Max(1, options.MaxTypes);
|
|
78
|
+
if (allTypeDefinitions.Count > typeLimit)
|
|
79
|
+
{
|
|
80
|
+
warnings.Add($"Type list truncated from {allTypeDefinitions.Count} to {typeLimit}.");
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
foreach (var type in allTypeDefinitions
|
|
84
|
+
.OrderByDescending(item => item.MethodCount)
|
|
85
|
+
.ThenBy(item => item.FullName, StringComparer.OrdinalIgnoreCase)
|
|
86
|
+
.Take(typeLimit))
|
|
87
|
+
{
|
|
88
|
+
var methods = options.IncludeMethods
|
|
89
|
+
? type.Methods.Select(method => new
|
|
90
|
+
{
|
|
91
|
+
name = method.Name,
|
|
92
|
+
token = method.Token,
|
|
93
|
+
rva = method.Rva,
|
|
94
|
+
attributes = method.Attributes,
|
|
95
|
+
is_constructor = method.IsConstructor,
|
|
96
|
+
is_static = method.IsStatic,
|
|
97
|
+
}).ToArray()
|
|
98
|
+
: Array.Empty<object>();
|
|
99
|
+
|
|
100
|
+
typeRows.Add(new
|
|
101
|
+
{
|
|
102
|
+
token = type.Token,
|
|
103
|
+
@namespace = type.Namespace,
|
|
104
|
+
name = type.Name,
|
|
105
|
+
full_name = type.FullName,
|
|
106
|
+
kind = type.Kind,
|
|
107
|
+
visibility = type.Visibility,
|
|
108
|
+
base_type = type.BaseType,
|
|
109
|
+
method_count = type.MethodCount,
|
|
110
|
+
field_count = type.FieldCount,
|
|
111
|
+
nested_type_count = type.NestedTypeCount,
|
|
112
|
+
flags = type.Flags,
|
|
113
|
+
methods,
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
var references = mdReader.AssemblyReferences
|
|
118
|
+
.Select(handle =>
|
|
119
|
+
{
|
|
120
|
+
var reference = mdReader.GetAssemblyReference(handle);
|
|
121
|
+
return new
|
|
122
|
+
{
|
|
123
|
+
name = SafeString(mdReader, reference.Name),
|
|
124
|
+
version = reference.Version.ToString(),
|
|
125
|
+
culture = reference.Culture.IsNil ? null : SafeString(mdReader, reference.Culture),
|
|
126
|
+
};
|
|
127
|
+
})
|
|
128
|
+
.OrderBy(item => item.name, StringComparer.OrdinalIgnoreCase)
|
|
129
|
+
.ToArray();
|
|
130
|
+
|
|
131
|
+
var resources = mdReader.ManifestResources
|
|
132
|
+
.Select(handle =>
|
|
133
|
+
{
|
|
134
|
+
var resource = mdReader.GetManifestResource(handle);
|
|
135
|
+
return new
|
|
136
|
+
{
|
|
137
|
+
name = SafeString(mdReader, resource.Name),
|
|
138
|
+
attributes = resource.Attributes.ToString(),
|
|
139
|
+
implementation = resource.Implementation.IsNil
|
|
140
|
+
? "embedded"
|
|
141
|
+
: resource.Implementation.Kind.ToString(),
|
|
142
|
+
};
|
|
143
|
+
})
|
|
144
|
+
.OrderBy(item => item.name, StringComparer.OrdinalIgnoreCase)
|
|
145
|
+
.ToArray();
|
|
146
|
+
|
|
147
|
+
var namespaceRows = namespaceCounts
|
|
148
|
+
.OrderByDescending(item => item.Value.Methods)
|
|
149
|
+
.ThenBy(item => item.Key, StringComparer.OrdinalIgnoreCase)
|
|
150
|
+
.Select(item => new
|
|
151
|
+
{
|
|
152
|
+
name = item.Key,
|
|
153
|
+
type_count = item.Value.Types,
|
|
154
|
+
method_count = item.Value.Methods,
|
|
155
|
+
})
|
|
156
|
+
.ToArray();
|
|
157
|
+
|
|
158
|
+
var corHeader = peReader.PEHeaders.CorHeader;
|
|
159
|
+
var entryPointToken = corHeader is null || corHeader.EntryPointTokenOrRelativeVirtualAddress == 0
|
|
160
|
+
? null
|
|
161
|
+
: $"0x{corHeader.EntryPointTokenOrRelativeVirtualAddress:X8}";
|
|
162
|
+
var isLibrary = (peReader.PEHeaders.CoffHeader.Characteristics & Characteristics.Dll) != 0;
|
|
163
|
+
|
|
164
|
+
return new
|
|
165
|
+
{
|
|
166
|
+
ok = true,
|
|
167
|
+
warnings,
|
|
168
|
+
data = new
|
|
169
|
+
{
|
|
170
|
+
is_dotnet = true,
|
|
171
|
+
assembly_name = assemblyName,
|
|
172
|
+
assembly_version = assemblyVersion,
|
|
173
|
+
module_name = moduleName,
|
|
174
|
+
metadata_version = mdReader.MetadataVersion,
|
|
175
|
+
target_framework = targetFramework,
|
|
176
|
+
is_library = isLibrary,
|
|
177
|
+
entry_point_token = entryPointToken,
|
|
178
|
+
assembly_references = references,
|
|
179
|
+
resources,
|
|
180
|
+
namespaces = namespaceRows,
|
|
181
|
+
types = options.IncludeTypes ? typeRows.ToArray() : Array.Empty<object>(),
|
|
182
|
+
summary = new
|
|
183
|
+
{
|
|
184
|
+
type_count = allTypeDefinitions.Count,
|
|
185
|
+
method_count = allTypeDefinitions.Sum(item => item.MethodCount),
|
|
186
|
+
namespace_count = namespaceRows.Length,
|
|
187
|
+
assembly_reference_count = references.Length,
|
|
188
|
+
resource_count = resources.Length,
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
catch (Exception ex)
|
|
194
|
+
{
|
|
195
|
+
return Fail(ex.Message);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
private static ProbeOptions ParseArgs(string[] args)
|
|
200
|
+
{
|
|
201
|
+
if (args.Length == 0 || string.IsNullOrWhiteSpace(args[0]))
|
|
202
|
+
{
|
|
203
|
+
throw new InvalidOperationException("Usage: DotNetMetadataProbe <sample-path> [--include-types=true|false] [--include-methods=true|false] [--max-types=N] [--max-methods-per-type=N]");
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
var samplePath = args[0];
|
|
207
|
+
var includeTypes = true;
|
|
208
|
+
var includeMethods = true;
|
|
209
|
+
var maxTypes = 80;
|
|
210
|
+
var maxMethodsPerType = 24;
|
|
211
|
+
|
|
212
|
+
foreach (var raw in args.Skip(1))
|
|
213
|
+
{
|
|
214
|
+
if (!raw.StartsWith("--", StringComparison.Ordinal))
|
|
215
|
+
{
|
|
216
|
+
continue;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
var parts = raw.Substring(2).Split('=', 2);
|
|
220
|
+
var key = parts[0].Trim();
|
|
221
|
+
var value = parts.Length > 1 ? parts[1].Trim() : string.Empty;
|
|
222
|
+
|
|
223
|
+
switch (key)
|
|
224
|
+
{
|
|
225
|
+
case "include-types":
|
|
226
|
+
includeTypes = ParseBool(value, includeTypes);
|
|
227
|
+
break;
|
|
228
|
+
case "include-methods":
|
|
229
|
+
includeMethods = ParseBool(value, includeMethods);
|
|
230
|
+
break;
|
|
231
|
+
case "max-types":
|
|
232
|
+
maxTypes = ParsePositiveInt(value, maxTypes);
|
|
233
|
+
break;
|
|
234
|
+
case "max-methods-per-type":
|
|
235
|
+
maxMethodsPerType = ParsePositiveInt(value, maxMethodsPerType);
|
|
236
|
+
break;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
return new ProbeOptions(samplePath, includeTypes, includeMethods, maxTypes, maxMethodsPerType);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
private static bool ParseBool(string value, bool fallback)
|
|
244
|
+
{
|
|
245
|
+
return bool.TryParse(value, out var parsed) ? parsed : fallback;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
private static int ParsePositiveInt(string value, int fallback)
|
|
249
|
+
{
|
|
250
|
+
return int.TryParse(value, out var parsed) && parsed > 0 ? parsed : fallback;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
private static object Fail(string error) => new
|
|
254
|
+
{
|
|
255
|
+
ok = false,
|
|
256
|
+
errors = new[] { error },
|
|
257
|
+
};
|
|
258
|
+
|
|
259
|
+
private static string? SafeString(MetadataReader reader, StringHandle handle)
|
|
260
|
+
{
|
|
261
|
+
return handle.IsNil ? null : reader.GetString(handle);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
private static string? ResolveTypeName(MetadataReader reader, EntityHandle handle)
|
|
265
|
+
{
|
|
266
|
+
if (handle.IsNil)
|
|
267
|
+
{
|
|
268
|
+
return null;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
return handle.Kind switch
|
|
272
|
+
{
|
|
273
|
+
HandleKind.TypeDefinition => ResolveTypeDefinitionName(reader, (TypeDefinitionHandle)handle),
|
|
274
|
+
HandleKind.TypeReference => ResolveTypeReferenceName(reader, (TypeReferenceHandle)handle),
|
|
275
|
+
HandleKind.TypeSpecification => "TypeSpecification",
|
|
276
|
+
_ => handle.Kind.ToString(),
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
private static string ResolveTypeDefinitionName(MetadataReader reader, TypeDefinitionHandle handle)
|
|
281
|
+
{
|
|
282
|
+
var definition = reader.GetTypeDefinition(handle);
|
|
283
|
+
var ns = SafeString(reader, definition.Namespace);
|
|
284
|
+
var name = SafeString(reader, definition.Name) ?? "<unnamed>";
|
|
285
|
+
return string.IsNullOrWhiteSpace(ns) ? name : $"{ns}.{name}";
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
private static string ResolveTypeReferenceName(MetadataReader reader, TypeReferenceHandle handle)
|
|
289
|
+
{
|
|
290
|
+
var reference = reader.GetTypeReference(handle);
|
|
291
|
+
var ns = SafeString(reader, reference.Namespace);
|
|
292
|
+
var name = SafeString(reader, reference.Name) ?? "<unnamed>";
|
|
293
|
+
return string.IsNullOrWhiteSpace(ns) ? name : $"{ns}.{name}";
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
private static string GetTypeVisibility(TypeAttributes attributes)
|
|
297
|
+
{
|
|
298
|
+
return (attributes & TypeAttributes.VisibilityMask) switch
|
|
299
|
+
{
|
|
300
|
+
TypeAttributes.Public => "public",
|
|
301
|
+
TypeAttributes.NotPublic => "internal",
|
|
302
|
+
TypeAttributes.NestedPublic => "nested_public",
|
|
303
|
+
TypeAttributes.NestedPrivate => "nested_private",
|
|
304
|
+
TypeAttributes.NestedFamily => "nested_family",
|
|
305
|
+
TypeAttributes.NestedAssembly => "nested_internal",
|
|
306
|
+
TypeAttributes.NestedFamORAssem => "nested_protected_internal",
|
|
307
|
+
TypeAttributes.NestedFamANDAssem => "nested_private_protected",
|
|
308
|
+
_ => "unknown",
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
private static string GetTypeKind(MetadataReader reader, TypeDefinition definition)
|
|
313
|
+
{
|
|
314
|
+
var attributes = definition.Attributes;
|
|
315
|
+
var baseType = ResolveTypeName(reader, definition.BaseType);
|
|
316
|
+
|
|
317
|
+
if ((attributes & TypeAttributes.ClassSemanticsMask) == TypeAttributes.Interface)
|
|
318
|
+
{
|
|
319
|
+
return "interface";
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
if (string.Equals(baseType, "System.Enum", StringComparison.Ordinal))
|
|
323
|
+
{
|
|
324
|
+
return "enum";
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
if (string.Equals(baseType, "System.ValueType", StringComparison.Ordinal))
|
|
328
|
+
{
|
|
329
|
+
return "struct";
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
if (string.Equals(baseType, "System.MulticastDelegate", StringComparison.Ordinal))
|
|
333
|
+
{
|
|
334
|
+
return "delegate";
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
return "class";
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
private static bool IsCompilerGenerated(string? namespaceName, string? typeName)
|
|
341
|
+
{
|
|
342
|
+
var ns = namespaceName ?? string.Empty;
|
|
343
|
+
var name = typeName ?? string.Empty;
|
|
344
|
+
return name.StartsWith("<", StringComparison.Ordinal)
|
|
345
|
+
|| ns.StartsWith("<", StringComparison.Ordinal)
|
|
346
|
+
|| name.Contains("AnonymousType", StringComparison.Ordinal)
|
|
347
|
+
|| name.Contains("DisplayClass", StringComparison.Ordinal);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
private static string[] CollectTypeFlags(TypeDefinition definition)
|
|
351
|
+
{
|
|
352
|
+
var flags = new List<string>();
|
|
353
|
+
var attributes = definition.Attributes;
|
|
354
|
+
|
|
355
|
+
if ((attributes & TypeAttributes.Abstract) != 0)
|
|
356
|
+
{
|
|
357
|
+
flags.Add("abstract");
|
|
358
|
+
}
|
|
359
|
+
if ((attributes & TypeAttributes.Sealed) != 0)
|
|
360
|
+
{
|
|
361
|
+
flags.Add("sealed");
|
|
362
|
+
}
|
|
363
|
+
if ((attributes & TypeAttributes.SpecialName) != 0)
|
|
364
|
+
{
|
|
365
|
+
flags.Add("special_name");
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
return flags.ToArray();
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
private static string[] CollectMethodFlags(MethodDefinition definition)
|
|
372
|
+
{
|
|
373
|
+
var flags = new List<string>();
|
|
374
|
+
var attributes = definition.Attributes;
|
|
375
|
+
|
|
376
|
+
switch (attributes & MethodAttributes.MemberAccessMask)
|
|
377
|
+
{
|
|
378
|
+
case MethodAttributes.Public:
|
|
379
|
+
flags.Add("public");
|
|
380
|
+
break;
|
|
381
|
+
case MethodAttributes.Private:
|
|
382
|
+
flags.Add("private");
|
|
383
|
+
break;
|
|
384
|
+
case MethodAttributes.Family:
|
|
385
|
+
flags.Add("protected");
|
|
386
|
+
break;
|
|
387
|
+
case MethodAttributes.Assembly:
|
|
388
|
+
flags.Add("internal");
|
|
389
|
+
break;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
if ((attributes & MethodAttributes.Static) != 0)
|
|
393
|
+
{
|
|
394
|
+
flags.Add("static");
|
|
395
|
+
}
|
|
396
|
+
if ((attributes & MethodAttributes.Abstract) != 0)
|
|
397
|
+
{
|
|
398
|
+
flags.Add("abstract");
|
|
399
|
+
}
|
|
400
|
+
if ((attributes & MethodAttributes.Virtual) != 0)
|
|
401
|
+
{
|
|
402
|
+
flags.Add("virtual");
|
|
403
|
+
}
|
|
404
|
+
if ((attributes & MethodAttributes.PinvokeImpl) != 0)
|
|
405
|
+
{
|
|
406
|
+
flags.Add("pinvoke");
|
|
407
|
+
}
|
|
408
|
+
if ((attributes & MethodAttributes.SpecialName) != 0)
|
|
409
|
+
{
|
|
410
|
+
flags.Add("special_name");
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
return flags.ToArray();
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
private static string? ResolveCustomAttributeType(MetadataReader reader, CustomAttribute attribute)
|
|
417
|
+
{
|
|
418
|
+
var constructor = attribute.Constructor;
|
|
419
|
+
return constructor.Kind switch
|
|
420
|
+
{
|
|
421
|
+
HandleKind.MemberReference => ResolveMemberReferenceParentType(reader, (MemberReferenceHandle)constructor),
|
|
422
|
+
HandleKind.MethodDefinition => ResolveMethodDefinitionParentType(reader, (MethodDefinitionHandle)constructor),
|
|
423
|
+
_ => null,
|
|
424
|
+
};
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
private static string? ResolveMemberReferenceParentType(MetadataReader reader, MemberReferenceHandle handle)
|
|
428
|
+
{
|
|
429
|
+
var reference = reader.GetMemberReference(handle);
|
|
430
|
+
return ResolveTypeName(reader, reference.Parent);
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
private static string? ResolveMethodDefinitionParentType(MetadataReader reader, MethodDefinitionHandle handle)
|
|
434
|
+
{
|
|
435
|
+
var method = reader.GetMethodDefinition(handle);
|
|
436
|
+
return ResolveTypeName(reader, method.GetDeclaringType());
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
private static string? ReadSingleStringCustomAttribute(MetadataReader reader, CustomAttribute attribute)
|
|
440
|
+
{
|
|
441
|
+
try
|
|
442
|
+
{
|
|
443
|
+
var blobReader = reader.GetBlobReader(attribute.Value);
|
|
444
|
+
if (blobReader.Length < 2 || blobReader.ReadUInt16() != 1)
|
|
445
|
+
{
|
|
446
|
+
return null;
|
|
447
|
+
}
|
|
448
|
+
return blobReader.ReadSerializedString();
|
|
449
|
+
}
|
|
450
|
+
catch
|
|
451
|
+
{
|
|
452
|
+
return null;
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
private static string? TryReadTargetFramework(MetadataReader reader)
|
|
457
|
+
{
|
|
458
|
+
if (!reader.IsAssembly)
|
|
459
|
+
{
|
|
460
|
+
return null;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
var assemblyDefinition = reader.GetAssemblyDefinition();
|
|
464
|
+
foreach (var attributeHandle in assemblyDefinition.GetCustomAttributes())
|
|
465
|
+
{
|
|
466
|
+
var attribute = reader.GetCustomAttribute(attributeHandle);
|
|
467
|
+
var attributeType = ResolveCustomAttributeType(reader, attribute);
|
|
468
|
+
if (!string.Equals(
|
|
469
|
+
attributeType,
|
|
470
|
+
"System.Runtime.Versioning.TargetFrameworkAttribute",
|
|
471
|
+
StringComparison.Ordinal))
|
|
472
|
+
{
|
|
473
|
+
continue;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
var value = ReadSingleStringCustomAttribute(reader, attribute);
|
|
477
|
+
if (!string.IsNullOrWhiteSpace(value))
|
|
478
|
+
{
|
|
479
|
+
return value;
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
return null;
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
private static TypeRow BuildTypeInfo(
|
|
487
|
+
MetadataReader reader,
|
|
488
|
+
TypeDefinitionHandle handle,
|
|
489
|
+
bool includeMethods,
|
|
490
|
+
int maxMethodsPerType
|
|
491
|
+
)
|
|
492
|
+
{
|
|
493
|
+
var definition = reader.GetTypeDefinition(handle);
|
|
494
|
+
var namespaceName = SafeString(reader, definition.Namespace);
|
|
495
|
+
var typeName = SafeString(reader, definition.Name) ?? "<unnamed>";
|
|
496
|
+
var fullName = string.IsNullOrWhiteSpace(namespaceName) ? typeName : $"{namespaceName}.{typeName}";
|
|
497
|
+
var methods = new List<MethodRow>();
|
|
498
|
+
|
|
499
|
+
if (includeMethods)
|
|
500
|
+
{
|
|
501
|
+
foreach (var methodHandle in definition.GetMethods())
|
|
502
|
+
{
|
|
503
|
+
var method = reader.GetMethodDefinition(methodHandle);
|
|
504
|
+
methods.Add(new MethodRow(
|
|
505
|
+
SafeString(reader, method.Name) ?? "<unnamed>",
|
|
506
|
+
$"0x{MetadataTokens.GetToken(methodHandle):X8}",
|
|
507
|
+
method.RelativeVirtualAddress,
|
|
508
|
+
CollectMethodFlags(method),
|
|
509
|
+
string.Equals(SafeString(reader, method.Name), ".ctor", StringComparison.Ordinal)
|
|
510
|
+
|| string.Equals(SafeString(reader, method.Name), ".cctor", StringComparison.Ordinal),
|
|
511
|
+
method.Attributes.HasFlag(MethodAttributes.Static)
|
|
512
|
+
));
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
if (methods.Count > maxMethodsPerType)
|
|
517
|
+
{
|
|
518
|
+
methods = methods
|
|
519
|
+
.OrderByDescending(item => item.Rva)
|
|
520
|
+
.ThenBy(item => item.Name, StringComparer.OrdinalIgnoreCase)
|
|
521
|
+
.Take(maxMethodsPerType)
|
|
522
|
+
.ToList();
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
return new TypeRow(
|
|
526
|
+
$"0x{MetadataTokens.GetToken(handle):X8}",
|
|
527
|
+
namespaceName ?? string.Empty,
|
|
528
|
+
typeName,
|
|
529
|
+
fullName,
|
|
530
|
+
GetTypeKind(reader, definition),
|
|
531
|
+
GetTypeVisibility(definition.Attributes),
|
|
532
|
+
ResolveTypeName(reader, definition.BaseType),
|
|
533
|
+
definition.GetMethods().Count(),
|
|
534
|
+
definition.GetFields().Count(),
|
|
535
|
+
definition.GetNestedTypes().Count(),
|
|
536
|
+
CollectTypeFlags(definition),
|
|
537
|
+
methods,
|
|
538
|
+
IsCompilerGenerated(namespaceName, typeName)
|
|
539
|
+
);
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
internal sealed record MethodRow(
|
|
544
|
+
string Name,
|
|
545
|
+
string Token,
|
|
546
|
+
int Rva,
|
|
547
|
+
string[] Attributes,
|
|
548
|
+
bool IsConstructor,
|
|
549
|
+
bool IsStatic
|
|
550
|
+
);
|
|
551
|
+
|
|
552
|
+
internal sealed record TypeRow(
|
|
553
|
+
string Token,
|
|
554
|
+
string Namespace,
|
|
555
|
+
string Name,
|
|
556
|
+
string FullName,
|
|
557
|
+
string Kind,
|
|
558
|
+
string Visibility,
|
|
559
|
+
string? BaseType,
|
|
560
|
+
int MethodCount,
|
|
561
|
+
int FieldCount,
|
|
562
|
+
int NestedTypeCount,
|
|
563
|
+
string[] Flags,
|
|
564
|
+
List<MethodRow> Methods,
|
|
565
|
+
bool IsCompilerGenerated
|
|
566
|
+
);
|