Ошибка WaitForDebugEvent (kernel32.dll) или что?
Я новичок, и мне нужна ваша помощь в решении этой проблемы. Я пытаюсь создать простой отладчик, чтобы понять, как работает отладчик и как загружается exes в память. Я уже написал код, который также работает, но теперь возникает проблема: когда я пытаюсь вызвать WaitForDebugEvent (функция kernel32), чтобы получить событие отладки, оно работает, на самом деле переменная debug_event записана, но эта функция очищает все переменные в моем приложении. Так же понятно и:
this (current form)
EventArgs (arguments of my form load function)
object sender (the object who called the function)
Поэтому я не могу продолжить выполнение своего приложения, потому что все переменные были удалены. Я бы не подумал, что это ошибка в32 или Visual Studio...
Это код:
(Структуры и импорт, полученные из pInvoke.net и MSDN)
[DllImport("kernel32.dll")]
static extern bool DebugActiveProcess(uint dwProcessId);
[DllImport("kernel32.dll", EntryPoint = "WaitForDebugEvent")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool WaitForDebugEvent([In] ref DEBUG_EVENT lpDebugEvent, uint dwMilliseconds);
[DllImport("kernel32.dll")]
static extern bool ContinueDebugEvent(uint dwProcessId, uint dwThreadId, uint dwContinueStatus);
[DllImport("kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool DebugActiveProcessStop([In] int Pid);
public struct DEBUG_EVENT
{
public int dwDebugEventCode;
public int dwProcessId;
public int dwThreadId;
public struct u
{
public EXCEPTION_DEBUG_INFO Exception;
public CREATE_THREAD_DEBUG_INFO CreateThread;
public CREATE_PROCESS_DEBUG_INFO CreateProcessInfo;
public EXIT_THREAD_DEBUG_INFO ExitThread;
public EXIT_PROCESS_DEBUG_INFO ExitProcess;
public LOAD_DLL_DEBUG_INFO LoadDll;
public UNLOAD_DLL_DEBUG_INFO UnloadDll;
public OUTPUT_DEBUG_STRING_INFO DebugString;
public RIP_INFO RipInfo;
};
};
[StructLayout(LayoutKind.Sequential)]
public struct EXCEPTION_DEBUG_INFO
{
public EXCEPTION_RECORD ExceptionRecord;
public uint dwFirstChance;
}
[StructLayout(LayoutKind.Sequential)]
public struct EXCEPTION_RECORD
{
public uint ExceptionCode;
public uint ExceptionFlags;
public IntPtr ExceptionRecord;
public IntPtr ExceptionAddress;
public uint NumberParameters;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 15, ArraySubType = UnmanagedType.U4)]
public uint[] ExceptionInformation;
}
public delegate uint PTHREAD_START_ROUTINE(IntPtr lpThreadParameter);
[StructLayout(LayoutKind.Sequential)]
public struct CREATE_THREAD_DEBUG_INFO
{
public IntPtr hThread;
public IntPtr lpThreadLocalBase;
public PTHREAD_START_ROUTINE lpStartAddress;
}
//public delegate uint PTHREAD_START_ROUTINE(IntPtr lpThreadParameter);
[StructLayout(LayoutKind.Sequential)]
public struct CREATE_PROCESS_DEBUG_INFO
{
public IntPtr hFile;
public IntPtr hProcess;
public IntPtr hThread;
public IntPtr lpBaseOfImage;
public uint dwDebugInfoFileOffset;
public uint nDebugInfoSize;
public IntPtr lpThreadLocalBase;
public PTHREAD_START_ROUTINE lpStartAddress;
public IntPtr lpImageName;
public ushort fUnicode;
}
[StructLayout(LayoutKind.Sequential)]
public struct EXIT_THREAD_DEBUG_INFO
{
public uint dwExitCode;
}
[StructLayout(LayoutKind.Sequential)]
public struct EXIT_PROCESS_DEBUG_INFO
{
public uint dwExitCode;
}
[StructLayout(LayoutKind.Sequential)]
public struct LOAD_DLL_DEBUG_INFO
{
public IntPtr hFile;
public IntPtr lpBaseOfDll;
public uint dwDebugInfoFileOffset;
public uint nDebugInfoSize;
public IntPtr lpImageName;
public ushort fUnicode;
}
[StructLayout(LayoutKind.Sequential)]
public struct UNLOAD_DLL_DEBUG_INFO
{
public IntPtr lpBaseOfDll;
}
[StructLayout(LayoutKind.Sequential)]
public struct OUTPUT_DEBUG_STRING_INFO
{
[MarshalAs(UnmanagedType.LPStr)]
public string lpDebugStringData;
public ushort fUnicode;
public ushort nDebugStringLength;
}
[StructLayout(LayoutKind.Sequential)]
public struct RIP_INFO
{
public uint dwError;
public uint dwType;
}
И основной цикл отладчика:
private void Form1_Load(object sender, EventArgs e)
{
DebugActiveProcess((uint)Process.GetProcessesByName("notepad")[0].Id);
DEBUG_EVENT debug_event = new DEBUG_EVENT();
CONTEXT context = new CONTEXT();
context.ContextFlags = (uint)CONTEXT_FLAGS.CONTEXT_ALL;
while (true)
{
unchecked
{
if (WaitForDebugEvent(ref debug_event, (uint)double.PositiveInfinity))
{
...
ContinueDebugEvent((uint)debug_event.dwProcessId, (uint)debug_event.dwThreadId, (uint)0x10002);
}
}
}
}
Что я могу сделать? Заранее спасибо...
РЕДАКТИРОВАТЬ:
Я переписал код на C++, чтобы увидеть, была ли там проблема. Но не было никаких проблем... так что я думаю, что проблема заключается только в C#. Это код на C++:
ИМПОРТ:
#include <windows.h>
#include <tlhelp32.h>
#include <msclr\marshal_cppstd.h>
КОД:
private: System::Void DebuggerForm_Load(System::Object^ sender, System::EventArgs^ e) {
std::wstring processName = msclr::interop::marshal_as<std::wstring, String^>("myExe.exe");
DWORD id = getProcessId(processName);
if (id == 0) std::exit(0);
DebugActiveProcess(id);
DEBUG_EVENT debug_event = { 0 };
while (true)
{
if (WaitForDebugEvent(&debug_event, INFINITE)) {
// TODO
ContinueDebugEvent(debug_event.dwProcessId, debug_event.dwThreadId, DBG_CONTINUE);
}
}
}
DWORD getProcessId(const std::wstring& processName)
{
PROCESSENTRY32 processInfo;
processInfo.dwSize = sizeof(processInfo);
HANDLE processesSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
if (processesSnapshot == INVALID_HANDLE_VALUE)
return 0;
Process32First(processesSnapshot, &processInfo);
if (!processName.compare(processInfo.szExeFile))
{
CloseHandle(processesSnapshot);
return processInfo.th32ProcessID;
}
while (Process32Next(processesSnapshot, &processInfo))
{
if (!processName.compare(processInfo.szExeFile))
{
CloseHandle(processesSnapshot);
return processInfo.th32ProcessID;
}
}
CloseHandle(processesSnapshot);
return 0;
}
1 ответ
Прежде всего, вы должны включить SE_DEBUG_NAME
привилегия на целевой процесс:
(SE_DEBUG_NAME
= "SeDebugPrivilege")
- использование
OpenProcessToken
сTOKEN_ADJUST_PRIVILEGES
а такжеTOKEN_QUERY
флаги доступа. - использование
LookupPrivilegeValue
чтобы получить LUID изSE_DEBUG_NAME
имя привилегии. - использование
AdjustTokenPrivileges
чтобы включитьSE_DEBUG_NAME
привилегия. CloseHandle
Для третьего шага вам нужен TOKEN_PRIVILEGES
структура, где PrivilegesCount
поле должно быть установлено в 1
, Также Вы должны установить первый (нулевой индекс) элемент Privilege
поле (Luid
: см 2-й шаг, Attributes
: SE_PRIVILEGE_ENABLED
)
DEBUG_EVENT
состав:
u
Поле структуры является объединением, это означает, что оно содержит только одну из перечисленных структур. Попробуй использовать LayoutKind.Explicit
и украсить каждое поле с атрибутом FieldOffset
определить правильное смещение внутри структуры. Попробуй это:
[StructLayout(LayoutKind.Explicit)]
public struct DEBUG_EVENT
{
[FieldOffset(0)]
public int dwDebugEventCode;
[FieldOffset(4)]
public int dwProcessId;
[FieldOffset(8)]
public int dwThreadId;
[FieldOffset(12)]
[StructLayout(LayoutKind.Explicit)]
public struct u {
[FieldOffset(0)]
public EXCEPTION_DEBUG_INFO Exception;
[FieldOffset(0)]
public CREATE_THREAD_DEBUG_INFO CreateThread;
[FieldOffset(0)]
public CREATE_PROCESS_DEBUG_INFO CreateProcessInfo;
[FieldOffset(0)]
public EXIT_THREAD_DEBUG_INFO ExitThread;
[FieldOffset(0)]
public EXIT_PROCESS_DEBUG_INFO ExitProcess;
[FieldOffset(0)]
public LOAD_DLL_DEBUG_INFO LoadDll;
[FieldOffset(0)]
public UNLOAD_DLL_DEBUG_INFO UnloadDll;
[FieldOffset(0)]
public OUTPUT_DEBUG_STRING_INFO DebugString;
[FieldOffset(0)]
public RIP_INFO RipInfo;
}
};