From 507f1d81242ba1689f4d159a75113c31ad7bf2f9 Mon Sep 17 00:00:00 2001 From: tyranid Date: Wed, 24 Apr 2024 20:55:33 -0700 Subject: [PATCH] Added symbol enumerator and code to query a symbol's machine type. --- NtApiDotNet/NtApiDotNet.csproj | 3 + NtApiDotNet/NtSectionNative.cs | 1 + .../Win32/Debugger/DataSymbolInformation.cs | 7 +- .../Win32/Debugger/DbgHelpSymbolResolver.cs | 80 ++- NtApiDotNet/Win32/Debugger/IDiaSession.cs | 55 ++ NtApiDotNet/Win32/Debugger/IDiaSymbol.cs | 481 ++++++++++++++++++ .../Win32/Debugger/ISymbolEnumerator.cs | 33 ++ .../Win32/Debugger/SymbolInformation.cs | 2 + .../Win32/Debugger/SymbolInformationType.cs | 4 + 9 files changed, 659 insertions(+), 7 deletions(-) create mode 100644 NtApiDotNet/Win32/Debugger/IDiaSession.cs create mode 100644 NtApiDotNet/Win32/Debugger/IDiaSymbol.cs create mode 100644 NtApiDotNet/Win32/Debugger/ISymbolEnumerator.cs diff --git a/NtApiDotNet/NtApiDotNet.csproj b/NtApiDotNet/NtApiDotNet.csproj index 101cd923f..43b4b6814 100644 --- a/NtApiDotNet/NtApiDotNet.csproj +++ b/NtApiDotNet/NtApiDotNet.csproj @@ -530,9 +530,12 @@ + + + diff --git a/NtApiDotNet/NtSectionNative.cs b/NtApiDotNet/NtSectionNative.cs index aeb2c2691..ab9f42f3d 100644 --- a/NtApiDotNet/NtSectionNative.cs +++ b/NtApiDotNet/NtSectionNative.cs @@ -181,6 +181,7 @@ public enum DllMachineType : ushort SH5 = 0x1A8, THUMB = 0x1C2, WCEMIPSV2 = 0x169, + ARM64EC = 0xA641, ARM64 = 0xAA64, } diff --git a/NtApiDotNet/Win32/Debugger/DataSymbolInformation.cs b/NtApiDotNet/Win32/Debugger/DataSymbolInformation.cs index 4dc8cfbbc..a355f0b8d 100644 --- a/NtApiDotNet/Win32/Debugger/DataSymbolInformation.cs +++ b/NtApiDotNet/Win32/Debugger/DataSymbolInformation.cs @@ -23,12 +23,17 @@ public class DataSymbolInformation : SymbolInformation /// Address of the symbol. /// public long Address { get; } + /// + /// The machine type of the symbol. + /// + public DllMachineType MachineType { get; } internal DataSymbolInformation(SymTagEnum tag, int size, int type_index, - long address, SymbolLoadedModule module, string name) + long address, SymbolLoadedModule module, string name, DllMachineType machine_type) : base(tag, size, type_index, module, name) { Address = address; + MachineType = machine_type; } } } diff --git a/NtApiDotNet/Win32/Debugger/DbgHelpSymbolResolver.cs b/NtApiDotNet/Win32/Debugger/DbgHelpSymbolResolver.cs index 4d5f6b278..2a6c63bc5 100644 --- a/NtApiDotNet/Win32/Debugger/DbgHelpSymbolResolver.cs +++ b/NtApiDotNet/Win32/Debugger/DbgHelpSymbolResolver.cs @@ -30,7 +30,7 @@ namespace NtApiDotNet.Win32.Debugger { - internal sealed partial class DbgHelpSymbolResolver : ISymbolResolver, ISymbolTypeResolver, IDisposable + internal sealed partial class DbgHelpSymbolResolver : ISymbolResolver, ISymbolTypeResolver, ISymbolEnumerator, IDisposable { public static string DEFAULT_SYMSRV = "https://msdl.microsoft.com/download/symbols"; @@ -215,6 +215,13 @@ delegate bool SymGetHomeDirectoryW( HomeDirectoryType type, [In, Out] StringBuilder dir, IntPtr size + ); + + [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode, SetLastError = true)] + delegate bool SymGetDiaSession( + SafeKernelObjectHandle hProcess, + long BaseOfDll, + [MarshalAs(UnmanagedType.Interface)] out IDiaSession DiaSession ); private readonly SafeLoadLibraryHandle _dbghelp_lib; @@ -239,6 +246,7 @@ IntPtr size private readonly SymSetContext _sym_set_context; private readonly SymEnumSymbolsW _sym_enum_symbols; private readonly SymGetHomeDirectoryW _sym_get_home_directory; + private readonly SymGetDiaSession _sym_get_dia_session; private IEnumerable _loaded_modules; private readonly TextWriter _trace_writer; private readonly bool _trace_symbol_loading; @@ -250,6 +258,11 @@ IntPtr size private void GetFunc(ref T f) where T : Delegate { f = _dbghelp_lib.GetFunctionPointer(); + } + + private void GetFuncNoThrow(ref T f) where T : Delegate + { + f = _dbghelp_lib.GetFunctionPointer(false); } private void GetFunc(ref T f, string name) where T : Delegate @@ -267,6 +280,29 @@ private static string GetNameFromSymbolInfo(SafeStructureInOutBuffer MapSymbolInfo(IntPtr symbol_info) { int base_size = Marshal.SizeOf(typeof(SYMBOL_INFO)); @@ -707,7 +743,8 @@ private DataSymbolInformation GetSymbolInfoForAddress(IntPtr address) var result = sym_info.Result; return new DataSymbolInformation(result.Tag, result.Size, result.TypeIndex, - result.Address, GetModuleForAddress(new IntPtr(result.ModBase)), GetNameFromSymbolInfo(sym_info)); + result.Address, GetModuleForAddress(new IntPtr(result.ModBase)), + GetNameFromSymbolInfo(sym_info), GetSymbolMachineType(result)); } return null; @@ -724,7 +761,8 @@ private DataSymbolInformation GetSymbolInfoForName(string name) } var result = sym_info.Result; return new DataSymbolInformation(result.Tag, result.Size, result.TypeIndex, - result.Address, GetModuleForAddress(new IntPtr(result.ModBase)), GetNameFromSymbolInfo(sym_info)); + result.Address, GetModuleForAddress(new IntPtr(result.ModBase)), + GetNameFromSymbolInfo(sym_info), GetSymbolMachineType(result)); } } @@ -850,8 +888,20 @@ private Tuple GetFallbackSymbolPaths(string symbol_path) } } return Tuple.Create(cache_path, server_path); + } + + private bool GetSymbolInfo(List symbols, IntPtr symbol_info, Dictionary modules) + { + using (var sym_info = MapSymbolInfo(symbol_info)) + { + var result = sym_info.Result; + var symbol = new DataSymbolInformation(result.Tag, result.Size, result.TypeIndex, + result.Address, GetModuleForAddress(new IntPtr(result.ModBase)), + GetNameFromSymbolInfo(sym_info), GetSymbolMachineType(result)); + symbols.Add(symbol); + return true; + } } - #endregion #region Public Methods @@ -1058,6 +1108,23 @@ public TypeInformation GetTypeForSymbolByAddress(IntPtr address) var ret = CreateType(type_cache, symbol.Tag, symbol.Module.BaseAddress.ToInt64(), symbol.TypeIndex, symbol.Size, symbol.Module, symbol.Name, symbol.Address); type_cache.FixupPointerTypes(); return ret; + } + + public IEnumerable EnumerateSymbols(IntPtr base_address, string mask) + { + if (string.IsNullOrWhiteSpace(mask)) + { + throw new ArgumentException($"'{nameof(mask)}' cannot be null or whitespace.", nameof(mask)); + } + + List symbols = new List(); + Dictionary modules = GetLoadedModules().ToDictionary(m => m.BaseAddress.ToInt64()); + if (!_sym_enum_symbols(Handle, base_address.ToInt64(), + mask, (s, z, x) => GetSymbolInfo(symbols, s, modules), IntPtr.Zero)) + { + Win32Utils.GetLastWin32Error().ToNtException(); + } + return symbols.AsReadOnly(); } #endregion @@ -1091,6 +1158,7 @@ internal DbgHelpSymbolResolver(NtProcess process, string dbghelp_path, string sy GetFunc(ref _sym_enum_symbols); GetFunc(ref _sym_set_context); GetFunc(ref _sym_get_home_directory); + GetFuncNoThrow(ref _sym_get_dia_session); _trace_writer = trace_writer ?? new TraceTextWriter(); SymOptions options = SymOptions.INCLUDE_32BIT_MODULES | SymOptions.UNDNAME | SymOptions.DEFERRED_LOADS; @@ -1178,8 +1246,8 @@ void IDisposable.Dispose() { Dispose(true); GC.SuppressFinalize(this); - } - + } + #endregion } } diff --git a/NtApiDotNet/Win32/Debugger/IDiaSession.cs b/NtApiDotNet/Win32/Debugger/IDiaSession.cs new file mode 100644 index 000000000..9b783b485 --- /dev/null +++ b/NtApiDotNet/Win32/Debugger/IDiaSession.cs @@ -0,0 +1,55 @@ +// Copyright 2018 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// NOTE: This file is a modified version of SymbolResolver.cs from OleViewDotNet +// https://github.com/tyranid/oleviewdotnet. It's been relicensed from GPLv3 by +// the original author James Forshaw to be used under the Apache License for this +// project. + +using System.Runtime.InteropServices; + +namespace NtApiDotNet.Win32.Debugger +{ + [ComImport] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [Guid("2F609EE1-D1C8-4E24-8288-3326BADCD211")] + internal interface IDiaSession + { + [DispId(1)] + ulong loadAddress + { + get; + [param: In] + set; + } + + [DispId(2)] + IDiaSymbol globalScope + { + [return: MarshalAs(UnmanagedType.Interface)] + get; + } + void getEnumTables(); + void getSymbolsByAddr(); + void findChildren(); + void findChildrenEx(); + void findChildrenExByAddr(); + void findChildrenExByVA(); + void findChildrenExByRVA(); + void findSymbolByAddr(); + void findSymbolByRVA(); + [PreserveSig] + int findSymbolByVA([In] long va, [In] SymTagEnum symTag, [MarshalAs(UnmanagedType.Interface)] out IDiaSymbol ppSymbol); + } +} diff --git a/NtApiDotNet/Win32/Debugger/IDiaSymbol.cs b/NtApiDotNet/Win32/Debugger/IDiaSymbol.cs new file mode 100644 index 000000000..7fa384239 --- /dev/null +++ b/NtApiDotNet/Win32/Debugger/IDiaSymbol.cs @@ -0,0 +1,481 @@ +// Copyright 2018 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// NOTE: This file is a modified version of SymbolResolver.cs from OleViewDotNet +// https://github.com/tyranid/oleviewdotnet. It's been relicensed from GPLv3 by +// the original author James Forshaw to be used under the Apache License for this +// project. + +using System; +using System.Runtime.InteropServices; + +namespace NtApiDotNet.Win32.Debugger +{ + [ComImport] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [Guid("CB787B2F-BD6C-4635-BA52-933126BD2DCD")] + internal interface IDiaSymbol + { + [DispId(0)] + uint symIndexId + { + get; + } + [DispId(1)] + uint symTag + { + get; + } + [DispId(2)] + string name + { + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + [DispId(3)] + IDiaSymbol lexicalParent + { + [return: MarshalAs(UnmanagedType.Interface)] + get; + } + [DispId(4)] + IDiaSymbol classParent + { + [return: MarshalAs(UnmanagedType.Interface)] + get; + } + [DispId(5)] + IDiaSymbol type + { + [return: MarshalAs(UnmanagedType.Interface)] + get; + } + [DispId(6)] + uint dataKind + { + get; + } + [DispId(7)] + uint locationType + { + get; + } + [DispId(8)] + uint addressSection + { + get; + } + [DispId(9)] + uint addressOffset + { + get; + } + [DispId(10)] + uint relativeVirtualAddress + { + get; + } + [DispId(11)] + ulong virtualAddress + { + get; + } + [DispId(12)] + uint registerId + { + get; + } + [DispId(13)] + int offset + { + get; + } + [DispId(14)] + ulong length + { + get; + } + [DispId(15)] + uint slot + { + get; + } + [DispId(16)] + int volatileType + { + get; + } + [DispId(17)] + int constType + { + get; + } + [DispId(18)] + int unalignedType + { + get; + } + [DispId(19)] + uint access + { + get; + } + [DispId(20)] + string libraryName + { + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + [DispId(21)] + uint platform + { + get; + } + [DispId(22)] + uint language + { + get; + } + [DispId(23)] + int editAndContinueEnabled + { + get; + } + [DispId(24)] + uint frontEndMajor + { + get; + } + [DispId(25)] + uint frontEndMinor + { + get; + } + [DispId(26)] + uint frontEndBuild + { + get; + } + [DispId(27)] + uint backEndMajor + { + get; + } + [DispId(28)] + uint backEndMinor + { + get; + } + [DispId(29)] + uint backEndBuild + { + get; + } + [DispId(30)] + string sourceFileName + { + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + [DispId(31)] + string unused + { + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + [DispId(32)] + uint thunkOrdinal + { + get; + } + [DispId(33)] + int thisAdjust + { + get; + } + [DispId(34)] + uint virtualBaseOffset + { + get; + } + [DispId(35)] + int @virtual + { + get; + } + [DispId(36)] + int intro + { + get; + } + [DispId(37)] + int pure + { + get; + } + [DispId(38)] + uint callingConvention + { + get; + } + [DispId(39)] + object value + { + [return: MarshalAs(UnmanagedType.Struct)] + get; + } + [DispId(40)] + uint baseType + { + get; + } + [DispId(41)] + uint token + { + get; + } + [DispId(42)] + uint timeStamp + { + get; + } + [DispId(43)] + Guid guid + { + get; + } + [DispId(44)] + string symbolsFileName + { + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + [DispId(46)] + int reference + { + get; + } + [DispId(47)] + uint count + { + get; + } + [DispId(49)] + uint bitPosition + { + get; + } + [DispId(50)] + IDiaSymbol arrayIndexType + { + [return: MarshalAs(UnmanagedType.Interface)] + get; + } + [DispId(51)] + int packed + { + get; + } + [DispId(52)] + int constructor + { + get; + } + [DispId(53)] + int overloadedOperator + { + get; + } + [DispId(54)] + int nested + { + get; + } + [DispId(55)] + int hasNestedTypes + { + get; + } + [DispId(56)] + int hasAssignmentOperator + { + get; + } + [DispId(57)] + int hasCastOperator + { + get; + } + [DispId(58)] + int scoped + { + get; + } + [DispId(59)] + int virtualBaseClass + { + get; + } + [DispId(60)] + int indirectVirtualBaseClass + { + get; + } + [DispId(61)] + int virtualBasePointerOffset + { + get; + } + [DispId(62)] + IDiaSymbol virtualTableShape + { + [return: MarshalAs(UnmanagedType.Interface)] + get; + } + [DispId(64)] + uint lexicalParentId + { + get; + } + [DispId(65)] + uint classParentId + { + get; + } + [DispId(66)] + uint typeId + { + get; + } + [DispId(67)] + uint arrayIndexTypeId + { + get; + } + [DispId(68)] + uint virtualTableShapeId + { + get; + } + [DispId(69)] + int code + { + get; + } + [DispId(70)] + int function + { + get; + } + [DispId(71)] + int managed + { + get; + } + [DispId(72)] + int msil + { + get; + } + [DispId(73)] + uint virtualBaseDispIndex + { + get; + } + [DispId(74)] + string undecoratedName + { + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + [DispId(75)] + uint age + { + get; + } + [DispId(76)] + uint signature + { + get; + } + [DispId(77)] + int compilerGenerated + { + get; + } + [DispId(78)] + int addressTaken + { + get; + } + [DispId(79)] + uint rank + { + get; + } + [DispId(80)] + IDiaSymbol lowerBound + { + [return: MarshalAs(UnmanagedType.Interface)] + get; + } + [DispId(81)] + IDiaSymbol upperBound + { + [return: MarshalAs(UnmanagedType.Interface)] + get; + } + [DispId(82)] + uint lowerBoundId + { + get; + } + [DispId(83)] + uint upperBoundId + { + get; + } + void get_dataBytes([In] uint cbData, out uint pcbData, out byte pbData); + void findChildren(); + void findChildrenEx(); + void findChildrenExByAddr(); + void findChildrenExByVA(); + void findChildrenExByRVA(); + [DispId(84)] + uint targetSection + { + get; + } + [DispId(85)] + uint targetOffset + { + get; + } + [DispId(86)] + uint targetRelativeVirtualAddress + { + get; + } + [DispId(87)] + ulong targetVirtualAddress + { + get; + } + [DispId(88)] + uint machineType + { + get; + } + } +} diff --git a/NtApiDotNet/Win32/Debugger/ISymbolEnumerator.cs b/NtApiDotNet/Win32/Debugger/ISymbolEnumerator.cs new file mode 100644 index 000000000..313d52c7e --- /dev/null +++ b/NtApiDotNet/Win32/Debugger/ISymbolEnumerator.cs @@ -0,0 +1,33 @@ +// Copyright 2020 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using System; +using System.Collections.Generic; + +namespace NtApiDotNet.Win32.Debugger +{ + /// + /// Interface to enumerate symbols by name. + /// + public interface ISymbolEnumerator + { + /// + /// Enumerate symbols by name. + /// + /// Optional base address of the DLL. + /// The symbol name mask. + /// The list of symbols. + IEnumerable EnumerateSymbols(IntPtr base_address, string mask); + } +} diff --git a/NtApiDotNet/Win32/Debugger/SymbolInformation.cs b/NtApiDotNet/Win32/Debugger/SymbolInformation.cs index d2c8a3553..f37b08903 100644 --- a/NtApiDotNet/Win32/Debugger/SymbolInformation.cs +++ b/NtApiDotNet/Win32/Debugger/SymbolInformation.cs @@ -55,6 +55,8 @@ private static SymbolInformationType MapType(SymTagEnum tag) return SymbolInformationType.Function; case SymTagEnum.SymTagPointerType: return SymbolInformationType.Pointer; + case SymTagEnum.SymTagData: + return SymbolInformationType.Data; default: return SymbolInformationType.UndefinedType; } diff --git a/NtApiDotNet/Win32/Debugger/SymbolInformationType.cs b/NtApiDotNet/Win32/Debugger/SymbolInformationType.cs index c3148d1e4..95f82558c 100644 --- a/NtApiDotNet/Win32/Debugger/SymbolInformationType.cs +++ b/NtApiDotNet/Win32/Debugger/SymbolInformationType.cs @@ -44,6 +44,10 @@ public enum SymbolInformationType /// Pointer, /// + /// A data value type. + /// + Data, + /// /// Undefined. /// UndefinedType,