简体   繁体   中英

WaitForDebugEvent (kernel32.dll) bug or what?

i'm new and i need your help resolving this issue. I'm trying to create a simple debugger to understand how debuggers works and how is loaded exes in memory. I have already written the code which works as well, but now there is the problem: when i try to call WaitForDebugEvent (a kernel32 function) to get the debug event it works, in fact the debug_event variable is written, but this function clears all the variables in my application. So it clear also:

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

So i can't continue executing my app because all the vars were deleted. I wouldn't think this is a kernel32 or a Visual Studio bug...

This is the code:

(Structs and imports got from pInvoke.net and 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;
    }

And the main loop of debugger:

    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);
                }
            }
        }
    }

What can i do? Thanks in advance...

EDIT:

I have rewritten the code in C++ to see if the problem there was there too. But there was no issue... so i think the problem lays only in C#. This is the code in C++:

IMPORTS:

#include <windows.h>
#include <tlhelp32.h>
#include <msclr\marshal_cppstd.h>

CODE:

        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;
        }

First of all, You should enable the SE_DEBUG_NAME privilege on the targeted process:

( SE_DEBUG_NAME = "SeDebugPrivilege")

  1. Use OpenProcessToken with TOKEN_ADJUST_PRIVILEGES and TOKEN_QUERY access flags.
  2. Use LookupPrivilegeValue to retrieve the LUID of the SE_DEBUG_NAME privilege name.
  3. Use AdjustTokenPrivileges to enable the SE_DEBUG_NAME privilege.
  4. CloseHandle

For the 3rd step you need a TOKEN_PRIVILEGES structure, where the PrivilegesCount field must set to 1 . Also You must set the first(zero index) item of the Privilege field ( Luid : see 2nd step, Attributes : SE_PRIVILEGE_ENABLED )

The DEBUG_EVENT structure:

The u field of the structure is an union, it means that it only contains one of the listed structs. Try to use LayoutKind.Explicit and decorate every field with the attribute FieldOffset to define the correct offset inside the structure. Try this:

[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;
    }
};

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM