Skip to content

Commit

Permalink
Added symbol enumerator and code to query a symbol's machine type.
Browse files Browse the repository at this point in the history
  • Loading branch information
tyranid authored and tyranid committed Apr 25, 2024
1 parent 53b6587 commit 507f1d8
Show file tree
Hide file tree
Showing 9 changed files with 659 additions and 7 deletions.
3 changes: 3 additions & 0 deletions NtApiDotNet/NtApiDotNet.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -530,9 +530,12 @@
<Compile Include="Win32\ConsoleSession.cs" />
<Compile Include="Win32\Debugger\DbgHelpCallbackActionCode.cs" />
<Compile Include="Win32\Debugger\DbgHelpDebugCallbackHandler.cs" />
<Compile Include="Win32\Debugger\IDiaSession.cs" />
<Compile Include="Win32\Debugger\IDiaSymbol.cs" />
<Compile Include="Win32\Debugger\IMAGEHLP_CBA_EVENTW.cs" />
<Compile Include="Win32\Debugger\IMAGEHLP_DEFERRED_SYMBOL_LOADW.cs" />
<Compile Include="Win32\Debugger\IMAGEHLP_STACK_FRAME.cs" />
<Compile Include="Win32\Debugger\ISymbolEnumerator.cs" />
<Compile Include="Win32\DirectoryService\DirectoryServiceBinding.cs" />
<Compile Include="Win32\DirectoryService\DirectoryServiceNameError.cs" />
<Compile Include="Win32\DirectoryService\DirectoryServiceNameFlags.cs" />
Expand Down
1 change: 1 addition & 0 deletions NtApiDotNet/NtSectionNative.cs
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ public enum DllMachineType : ushort
SH5 = 0x1A8,
THUMB = 0x1C2,
WCEMIPSV2 = 0x169,
ARM64EC = 0xA641,
ARM64 = 0xAA64,
}

Expand Down
7 changes: 6 additions & 1 deletion NtApiDotNet/Win32/Debugger/DataSymbolInformation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,17 @@ public class DataSymbolInformation : SymbolInformation
/// Address of the symbol.
/// </summary>
public long Address { get; }
/// <summary>
/// The machine type of the symbol.
/// </summary>
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;
}
}
}
80 changes: 74 additions & 6 deletions NtApiDotNet/Win32/Debugger/DbgHelpSymbolResolver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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";

Expand Down Expand Up @@ -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;
Expand All @@ -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<SymbolLoadedModule> _loaded_modules;
private readonly TextWriter _trace_writer;
private readonly bool _trace_symbol_loading;
Expand All @@ -250,6 +258,11 @@ IntPtr size
private void GetFunc<T>(ref T f) where T : Delegate
{
f = _dbghelp_lib.GetFunctionPointer<T>();
}

private void GetFuncNoThrow<T>(ref T f) where T : Delegate
{
f = _dbghelp_lib.GetFunctionPointer<T>(false);
}

private void GetFunc<T>(ref T f, string name) where T : Delegate
Expand All @@ -267,6 +280,29 @@ private static string GetNameFromSymbolInfo(SafeStructureInOutBuffer<SYMBOL_INFO
return buffer.Data.ReadNulTerminatedUnicodeString();
}

private DllMachineType GetSymbolMachineType(SYMBOL_INFO sym_info)
{
IDiaSession session = null;
IDiaSymbol symbol = null;
try
{
if (_sym_get_dia_session == null || !_sym_get_dia_session(Handle, sym_info.ModBase, out session))
return DllMachineType.UNKNOWN;

if (session.findSymbolByVA(sym_info.Address, sym_info.Tag, out symbol) != 0)
return DllMachineType.UNKNOWN;

return (DllMachineType)symbol.machineType;
}
finally
{
if (symbol != null)
Marshal.ReleaseComObject(symbol);
if (session != null)
Marshal.ReleaseComObject(session);
}
}

private static SafeStructureInOutBuffer<SYMBOL_INFO> MapSymbolInfo(IntPtr symbol_info)
{
int base_size = Marshal.SizeOf(typeof(SYMBOL_INFO));
Expand Down Expand Up @@ -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;
Expand All @@ -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));
}
}

Expand Down Expand Up @@ -850,8 +888,20 @@ private Tuple<string, Uri> GetFallbackSymbolPaths(string symbol_path)
}
}
return Tuple.Create(cache_path, server_path);
}

private bool GetSymbolInfo(List<SymbolInformation> symbols, IntPtr symbol_info, Dictionary<long, SymbolLoadedModule> 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
Expand Down Expand Up @@ -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<SymbolInformation> EnumerateSymbols(IntPtr base_address, string mask)
{
if (string.IsNullOrWhiteSpace(mask))
{
throw new ArgumentException($"'{nameof(mask)}' cannot be null or whitespace.", nameof(mask));
}

List<SymbolInformation> symbols = new List<SymbolInformation>();
Dictionary<long, SymbolLoadedModule> 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
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -1178,8 +1246,8 @@ void IDisposable.Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}

}

#endregion
}
}
55 changes: 55 additions & 0 deletions NtApiDotNet/Win32/Debugger/IDiaSession.cs
Original file line number Diff line number Diff line change
@@ -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);
}
}
Loading

0 comments on commit 507f1d8

Please sign in to comment.