【问题标题】:Getting Symbols from debugged process MainModule从调试的进程 MainModule 中获取符号
【发布时间】:2015-11-02 15:51:08
【问题描述】:

我开始用 C# 编写调试器,以调试操作系统上的任何进程。目前,它只能处理断点(硬件、软件和内存),但现在我想显示进程的操作码。

我的第一次尝试是使用 nidsasm (NASM),但这不合适,因为启动后 a.Net 应用程序汇编指令与 ndisasm 不同(使用 CheatEngine 测试)。

所以我搜索了一段时间,从 dbghelp.dll 中找到了一些方法,可以调用这些方法来列出所有加载的模块和符号(加上基地址)。好的,我的尝试是,用 SharpDisasm 分别拆解所有模块。

我使用ProcessModuleCollection modules = ProcessData.Instance.MPMR.ReadProcess.Modules; 来获取进程的所有加载模块。这完美无缺。

现在我尝试加载 MainModule 的符号,但在这一点上,我坚持执行。我使用 p/Invoke 和其他必要的函数(如 SymInitialize)实现了 SymEnumSymbols 函数。

当我使用例如“User32.dll”的 BaseAddress 调用它时,所有符号都完美打印,但对于 MainModule,我没有得到任何符号。

这是来自 CheatEngine 的截图: Symbols gained from Cheat Engine

如您所见,有像“Form1_Load”这样的符号,我的实现中没有。

这是必要的代码示例:

if (!DebugApi.SymInitialize(ProcessData.Instance.MPMR.M_hProcess, null, false))
{
    var err = Marshal.GetLastWin32Error();

    //throw new Exception("GetMemoryInfo failed : GetLastError() : " + new Win32Exception(err).Message);
    Console.WriteLine("GetMemoryInfo failed : GetLastError() : " + new Win32Exception(err).Message);
    return;
}

if (!DebugApi.SymEnumSymbols(ProcessData.Instance.MPMR.M_hProcess, (ulong)ProcessData.Instance.MPMR.ReadProcess.MainModule.BaseAddress, "!", DebugApi.EnumSyms, IntPtr.Zero))
{
    var err = Marshal.GetLastWin32Error();

    //throw new Exception("GetMemoryInfo failed : GetLastError() : " + new Win32Exception(err).Message);
    Console.WriteLine("GetMemoryInfo failed : GetLastError() : " + new Win32Exception(err).Message);
    return;
}

DebugApi.SymCleanup(ProcessData.Instance.MPMR.M_hProcess);

还有我的 DebugApi,以及所有必要的 p/Invoke 函数。

public class DebugApi
{

    [DllImport("dbghelp.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool SymInitialize(IntPtr hProcess, string UserSearchPath, [MarshalAs(UnmanagedType.Bool)]bool fInvadeProcess);

    [DllImport("dbghelp.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool SymCleanup(IntPtr hProcess);

    [DllImport("dbghelp.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    public static extern ulong SymLoadModuleEx(IntPtr hProcess, IntPtr hFile, string ImageName, string ModuleName, long BaseOfDll, int DllSize, IntPtr Data, int Flags);

    [DllImport("dbghelp.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool SymEnumSymbols(IntPtr hProcess, ulong BaseOfDll, string Mask, PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback, IntPtr UserContext);

    public delegate bool PSYM_ENUMERATESYMBOLS_CALLBACK(ref SYMBOL_INFO pSymInfo, uint SymbolSize, IntPtr UserContext);

    public static bool EnumSyms(ref SYMBOL_INFO pSymInfo, uint SymbolSize, IntPtr UserContext)
    {
        Console.Out.WriteLine("Name: " + pSymInfo.Name);
        return true;
    }

    [Flags]
    public enum SymFlag : uint
    {
        VALUEPRESENT = 0x00000001,
        REGISTER = 0x00000008,
        REGREL = 0x00000010,
        FRAMEREL = 0x00000020,
        PARAMETER = 0x00000040,
        LOCAL = 0x00000080,
        CONSTANT = 0x00000100,
        EXPORT = 0x00000200,
        FORWARDER = 0x00000400,
        FUNCTION = 0x00000800,
        VIRTUAL = 0x00001000,
        THUNK = 0x00002000,
        TLSREL = 0x00004000,
    }

    [Flags]
    public enum SymTagEnum : uint
    {
        Null,
        Exe,
        Compiland,
        CompilandDetails,
        CompilandEnv,
        Function,
        Block,
        Data,
        Annotation,
        Label,
        PublicSymbol,
        UDT,
        Enum,
        FunctionType,
        PointerType,
        ArrayType,
        BaseType,
        Typedef,
        BaseClass,
        Friend,
        FunctionArgType,
        FuncDebugStart,
        FuncDebugEnd,
        UsingNamespace,
        VTableShape,
        VTable,
        Custom,
        Thunk,
        CustomType,
        ManagedType,
        Dimension
    };

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
    public struct SYMBOL_INFO
    {
        public uint SizeOfStruct;
        public uint TypeIndex;
        public ulong Reserved1;
        public ulong Reserved2;
        public uint Reserved3;
        public uint Size;
        public ulong ModBase;
        public SymFlag Flags;
        public ulong Value;
        public ulong Address;
        public uint Register;
        public uint Scope;
        public SymTagEnum Tag;
        public int NameLen;
        public int MaxNameLen;

        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1024)]
        public string Name;
    }

}

我的函数应该没问题,因为它适用于其他模块(例如加载的 dll)。也许我不理解 .Net 可执行文件的符号概念或缺少某些东西。

【问题讨论】:

  • 不,错误的调试引擎。下载 mdbg 示例以了解如何调试托管代码。
  • 祝你好运 Cedric,调试的世界需要深入研究普通人不知道的各种东西。这就是为什么带有 SOS 扩展的 WINDBG 是最好的。但即便如此,该工具也需要一段时间来学习。如果你能改进,你就有了一些东西……我同意 Hans 的观点,MDBG 是开始的地方。
  • 谢谢汉斯,我已经找到了 mdbg 示例,但在示例中找不到我的问题的解决方案。我使用 NativeDebugWrappers 作为调试器,调用 kernel32 函数进行调试。但是对于从 pe 可执行文件(在本例中为 .Net 可执行文件)的 MainModule 加载符号,我没有在那里找到任何东西,也许我的眼睛已经厌倦了一整天的互联网搜索。
  • @Strece 我知道它已经过时了,但仍然......你说 MainModule 的符号是什么意思?我认为可以直接从元数据中提取有关程序集类/函数的信息。当您需要将执行的 IL 代码绑定到源代码时,符号特别有用,例如在调试器中显示当前代码语句。

标签: c# debugging pinvoke debug-symbols


【解决方案1】:

您是否正在寻找 System.Diagnostics.SymbolStore.ISymbolScope。 看看SymbolAccess 类,您可以使用它来访问返回 ISymbolVariable[] 的 ISymbolScope.GetLocals() 和 GetChildren() 再次返回一个名为 ISymbolVariable[] 的数组

现在另一组有趣的参考代码示例是调试器扩展,可让您“嗅探”值,如 here 所示

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-09-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-12
    相关资源
    最近更新 更多