从已调试进程MainModule获取符号



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

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

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

我使用ProcessModuleCollection modules = ProcessData.Instance.MPMR.ReadProcess.Modules;来获取进程的所有已加载模块。这非常有效。

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

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

这是CheatEngine的一张截图:从作弊引擎获得的符号

正如您所看到的,有一些像"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可执行文件符号的概念,或者缺少一些东西。

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

现在,另一组有趣的参考代码示例是Debugger扩展,它允许您"snif"此处显示的值

最新更新