【问题标题】:WaitForDebugEvent (kernel32.dll) bug or what?WaitForDebugEvent (kernel32.dll) 错误还是什么?
【发布时间】:2015-03-19 14:56:03
【问题描述】:

我是新手,我需要您的帮助来解决这个问题。 我正在尝试创建一个简单的调试器来了解调试器是如何工作的以及如何在内存中加载 exe。我已经编写了可以正常工作的代码,但是现在出现了问题:当我尝试调用 WaitForDebugEvent(一个 kernel32 函数)来获取它工作的调试事件时,实际上写入了 debug_event 变量,但是这个函数清除了所有我的应用程序中的变量。所以也很清楚:

this (current form)
EventArgs (arguments of my form load function)
object sender (the object who called the function)

所以我无法继续执行我的应用程序,因为所有变量都已删除。我不认为这是 kernel32 或 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;
        }

【问题讨论】:

  • 将变量命名为与 API 函数相同的名称可能不是一个好主意。
  • 您说的是哪些变量? (C# 或 C++ 代码)

标签: c# debugging visual-studio-2013 kernel32


【解决方案1】:

首先,您应该在目标进程上启用SE_DEBUG_NAME 权限:

(SE_DEBUG_NAME = "SeDebugPrivilege")

  1. OpenProcessTokenTOKEN_ADJUST_PRIVILEGESTOKEN_QUERY 访问标志一起使用。
  2. 使用LookupPrivilegeValue 检索SE_DEBUG_NAME 权限名称的LUID。
  3. 使用AdjustTokenPrivileges 启用SE_DEBUG_NAME 权限。
  4. CloseHandle

对于第三步,您需要一个TOKEN_PRIVILEGES 结构,其中PrivilegesCount 字段必须设置为1。此外,您必须设置Privilege 字段的第一个(零索引)项(Luid:参见第二步,AttributesSE_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;
    }
};

【讨论】:

  • 这能解决我的问题吗...?我不认为这是一个特权问题。我做了一些互联网搜索,我发现这可能是代码和变量的汇编优化问题......我将很快编辑关于这个的问题
  • 我认为您的 DEBUG_EVENT 结构没有正确“编组”。乍一看,我没有看你的结构,因为你说,你是从 pinvoke 导入的。答案已更新
  • 它不起作用,它在 [FieldOffset(12)] 上给我一个错误,“FieldOffset”在此声明类型上无效......所以我用 C++ 重写了代码以查看是否那里调试功能工作......答案是肯定的,在 C++ 中没有问题(问题已更新) - 所以问题似乎只存在于 C# 代码中
猜你喜欢
  • 2010-11-02
  • 2013-12-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-18
  • 2010-11-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多