Получение символов из отлаженного процесса MainModule
Я начал писать отладчик на С# для отладки любого процесса в моей операционной системе. На данный момент он может обрабатывать только точки останова (HW, SW и Memory), но теперь я хотел показать код операции процесса.
Моя первая попытка была с nidsasm (NASM), но это не подходит, потому что после запуска инструкции ассемблера приложения .Net отличаются от ndisasm (протестировано с CheatEngine).
Поэтому я некоторое время искал и нашел несколько методов из dbghelp.dll, которые можно вызвать, чтобы вывести список всех загруженных модулей и символов (плюс базовый адрес). Хорошо, я пытаюсь разобрать все модули отдельно с помощью SharpDisasm.
Я использую ProcessModuleCollection modules = ProcessData.Instance.MPMR.ReadProcess.Modules;
, чтобы получить все загруженные модули процесса. Это отлично работает.
Теперь я попытался загрузить символы MainModule, но на этом этапе я застрял с реализацией. Я реализовал функцию SymEnumSymbols с помощью p/Invoke и других необходимых функций, таких как SymInitialize.
Когда я вызываю его с BaseAddress, например, "User32.dll", все символы печатаются отлично, но для MainModule я не получил никаких символов.
Это скриншот из CheatEngine:
Символы, полученные от 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 или чего-то не хватает.
Ответы
Ответ 1
Может ли быть так, что вы ищете System.Diagnostics.SymbolStore.ISymbolScope.
Взгляните на класс SymbolAccess, вы можете использовать его для получения доступа к ISymbolScope.GetLocals(), который возвращает ISymbolVariable [] и GetChildren(), снова возвращая в это время массив ISymbolVariable []
Теперь еще один интересный набор примеров эталонного кода - расширение Debugger, которое позволяет вам "перехватывать" значения, как показано здесь here