2015-03-11 4 views
5

ich nach einer Möglichkeit, die EDX-Registrierung an einer bestimmten Adresse zu lesen, wie in dieser Frage gestellt: Read eax registerautomatisch ein Debug-Prozess von C# -Code und Leseregisterwerten

Obwohl meine Lösung in C# sein muss und ich habe versucht, es zu machen, was ich in diesem Moment bekam ist:

public static IntPtr GetEdx(IntPtr address, Process process) 
    { 
     const uint DBG_EXCEPTION_NOT_HANDLED = 0x80010001; 
     const uint EXCEPTION_SINGLE_STEP = 0x80000004; 
     const int DBG_CONTINUE = 0x00010002; // Seems to work better than DBG_EXCEPTION_NOT_HANDLED 

     //DebugSetProcessKillOnExit(0); 
     DEBUG_EVENT evt = new DEBUG_EVENT(); 
     // Attach to the process we provided the thread as an argument 
     if (!DebugActiveProcess(process.Id)) 
      throw new Win32Exception(); 

     CONTEXT context = new CONTEXT(); 

     foreach (ProcessThread thread in process.Threads) 
     { 
      uint iThreadId = (uint)thread.Id; 
      IntPtr hThread = 
       OpenThread(
        ThreadAccessFlags.SUSPEND_RESUME | ThreadAccessFlags.SET_CONTEXT | 
        ThreadAccessFlags.GET_CONTEXT, false, iThreadId); 

      // Suspent the thread 
      if (SuspendThread(hThread) == -1) throw new ApplicationException("Cannot suspend thread."); 

      context = new CONTEXT 
      { 
       ContextFlags = (uint)CONTEXT_FLAGS.CONTEXT_DEBUG_REGISTERS | 
           (uint)CONTEXT_FLAGS.CONTEXT_INTEGER 
      }; 

      // Get the context 
      if (!GetThreadContext(hThread, ref context)) 
       throw new Win32Exception(); 

      // Change the context 

      context.Dr0 = (uint)address; 
      context.Dr7 = 0x00000001; 

      // Set the changed context back 
      if (!SetThreadContext(hThread, ref context)) 
       throw new Win32Exception(); 

      // Check if setting the context give any errors 
      var error = Marshal.GetLastWin32Error(); 
      if (error != 0) 
      { 
       throw new ApplicationException("Error is setting context."); 
      } 

      // Resume the thread 
      if (ResumeThread(hThread) == -1) throw new ApplicationException("Cannot resume thread."); 
     } 

     while (true) 
     { 
      if (!WaitForDebugEvent(out evt, -1)) 
       throw new Win32Exception(); 

      // Multiple if's for easier debugging at this moment 
      if (evt.dwDebugEventCode == (uint)DebugEventType.EXCEPTION_DEBUG_EVENT) 
      { 
       if (evt.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_SINGLE_STEP) 
       { 
        if (evt.Exception.ExceptionRecord.ExceptionAddress == address) 
        { 
         context = new CONTEXT 
         { 
          ContextFlags = (uint)CONTEXT_FLAGS.CONTEXT_DEBUG_REGISTERS | 
              (uint)CONTEXT_FLAGS.CONTEXT_INTEGER 
         }; 
         GetThreadContext((IntPtr)evt.dwThreadId, ref context); 
         return (IntPtr)context.Ebx; // ebx get 
        } 
       } 
      } 

      ContinueDebugEvent(evt.dwProcessId, evt.dwThreadId, DBG_CONTINUE);//DBG_EXCEPTION_NOT_HANDLED); 
     } 
    } 

Mit einer ganzen Menge von Kernel32 Methoden:

[DllImport("kernel32.dll")] 
    static extern int ResumeThread(IntPtr hThread); 
    [DllImport("kernel32.dll")] 
    static extern uint SuspendThread(IntPtr hThread); 
    [DllImport("kernel32.dll")] 
    public static extern IntPtr OpenThread(ThreadAccessFlags dwDesiredAccess, bool bInheritHandle, uint dwThreadId); 
    [DllImport("Kernel32.dll", SetLastError = true)] 
    static extern bool DebugActiveProcess(int dwProcessId); 
    [DllImport("Kernel32.dll", SetLastError = true)] 
    static extern bool WaitForDebugEvent([Out] out DEBUG_EVENT lpDebugEvent, int dwMilliseconds); 
    [DllImport("Kernel32.dll", SetLastError = true)] 
    static extern bool ContinueDebugEvent(int dwProcessId, int dwThreadId, uint dwContinueStatus); 
    [DllImport("Kernel32.dll", SetLastError = true)] 
    public static extern bool IsDebuggerPresent(); 
    [DllImport("kernel32.dll")] 
    private static extern bool GetThreadContext(IntPtr hThread, ref CONTEXT lpContext); 
    [DllImport("kernel32.dll")] 
    public static extern bool SetThreadContext(IntPtr hThread, ref CONTEXT lpContext); 

    [StructLayout(LayoutKind.Sequential)] 
    public unsafe struct DEBUG_EVENT 
    { 
     public readonly uint dwDebugEventCode; 
     public readonly int dwProcessId; 
     public readonly int dwThreadId; 


     [MarshalAs(UnmanagedType.ByValArray, SizeConst = 86, ArraySubType = UnmanagedType.U1)] 
     private readonly byte[] debugInfo; 


     public EXCEPTION_DEBUG_INFO Exception 
     { 
      get 
      { 
       if (debugInfo == null) 
        return new EXCEPTION_DEBUG_INFO(); 


       fixed (byte* ptr = debugInfo) 
       { 
        return *(EXCEPTION_DEBUG_INFO*)ptr; 
       } 
      } 
     } 


     public LOAD_DLL_DEBUG_INFO LoadDll 
     { 
      get 
      { 
       if (debugInfo == null) 
        return new LOAD_DLL_DEBUG_INFO(); 


       fixed (byte* ptr = debugInfo) 
       { 
        return *(LOAD_DLL_DEBUG_INFO*)ptr; 
       } 
      } 
     } 
    } 

    [StructLayout(LayoutKind.Sequential)] 
    public struct LOAD_DLL_DEBUG_INFO 
    { 
     public readonly IntPtr hFile; 
     public readonly IntPtr lpBaseOfDll; 
     public readonly uint dwDebugInfoFileOffset; 
     public readonly uint nDebugInfoSize; 
     public readonly IntPtr lpImageName; 
     public readonly ushort fUnicode; 
    } 


    [StructLayout(LayoutKind.Sequential)] 
    public struct EXCEPTION_DEBUG_INFO 
    { 
     public EXCEPTION_RECORD ExceptionRecord; 
     public readonly uint dwFirstChance; 
    } 


    [StructLayout(LayoutKind.Sequential)] 
    public struct EXCEPTION_RECORD 
    { 
     public readonly uint ExceptionCode; 
     public readonly uint ExceptionFlags; 
     public readonly IntPtr ExceptionRecord; 
     public readonly IntPtr ExceptionAddress; 
     public readonly uint NumberParameters; 


     //[MarshalAs(UnmanagedType.ByValArray, SizeConst = 15, ArraySubType = UnmanagedType.U4)] 
     //public readonly uint[] ExceptionInformation; 


     public unsafe fixed uint ExceptionInformation[15]; 
    } 


    public enum DebugEventType : int 
    { 
     CREATE_PROCESS_DEBUG_EVENT = 3, //Reports a create-process debugging event. The value of u.CreateProcessInfo specifies a CREATE_PROCESS_DEBUG_INFO structure. 
     CREATE_THREAD_DEBUG_EVENT = 2, //Reports a create-thread debugging event. The value of u.CreateThread specifies a CREATE_THREAD_DEBUG_INFO structure. 
     EXCEPTION_DEBUG_EVENT = 1, //Reports an exception debugging event. The value of u.Exception specifies an EXCEPTION_DEBUG_INFO structure. 
     EXIT_PROCESS_DEBUG_EVENT = 5, //Reports an exit-process debugging event. The value of u.ExitProcess specifies an EXIT_PROCESS_DEBUG_INFO structure. 
     EXIT_THREAD_DEBUG_EVENT = 4, //Reports an exit-thread debugging event. The value of u.ExitThread specifies an EXIT_THREAD_DEBUG_INFO structure. 
     LOAD_DLL_DEBUG_EVENT = 6, //Reports a load-dynamic-link-library (DLL) debugging event. The value of u.LoadDll specifies a LOAD_DLL_DEBUG_INFO structure. 
     OUTPUT_DEBUG_STRING_EVENT = 8, //Reports an output-debugging-string debugging event. The value of u.DebugString specifies an OUTPUT_DEBUG_STRING_INFO structure. 
     RIP_EVENT = 9, //Reports a RIP-debugging event (system debugging error). The value of u.RipInfo specifies a RIP_INFO structure. 
     UNLOAD_DLL_DEBUG_EVENT = 7, //Reports an unload-DLL debugging event. The value of u.UnloadDll specifies an UNLOAD_DLL_DEBUG_INFO structure. 
    } 

    [StructLayout(LayoutKind.Sequential)] 
    public struct CONTEXT 
    { 
     public uint ContextFlags; 
     public uint Dr0; 
     public uint Dr1; 
     public uint Dr2; 
     public uint Dr3; 
     public uint Dr6; 
     public uint Dr7; 
     public FLOATING_SAVE_AREA FloatSave; 
     public uint SegGs; 
     public uint SegFs; 
     public uint SegEs; 
     public uint SegDs; 
     public uint Edi; 
     public uint Esi; 
     public uint Ebx; 
     public uint Edx; 
     public uint Ecx; 
     public uint Eax; 
     public uint Ebp; 
     public uint Eip; 
     public uint SegCs; 
     public uint EFlags; 
     public uint Esp; 
     public uint SegSs; 
     [MarshalAs(UnmanagedType.ByValArray, SizeConst = 512)] 
     public byte[] ExtendedRegisters; 
    } 

    public enum CONTEXT_FLAGS : uint 
    { 
     CONTEXT_i386 = 0x10000, 
     CONTEXT_i486 = 0x10000, 
     CONTEXT_CONTROL = CONTEXT_i386 | 0x01, 
     CONTEXT_INTEGER = CONTEXT_i386 | 0x02, 
     CONTEXT_SEGMENTS = CONTEXT_i386 | 0x04, 
     CONTEXT_FLOATING_POINT = CONTEXT_i386 | 0x08, 
     CONTEXT_DEBUG_REGISTERS = CONTEXT_i386 | 0x10, 
     CONTEXT_EXTENDED_REGISTERS = CONTEXT_i386 | 0x20, 
     CONTEXT_FULL = CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS, 
     CONTEXT_ALL = CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS | CONTEXT_FLOATING_POINT | CONTEXT_DEBUG_REGISTERS | CONTEXT_EXTENDED_REGISTERS 
    } 

    [Flags] 
    public enum ThreadAccessFlags : int 
    { 
     TERMINATE = 0x0001, 
     SUSPEND_RESUME = 0x0002, 
     GET_CONTEXT = 0x0008, 
     SET_CONTEXT = 0x0010, 
     SET_INFORMATION = 0x0020, 
     QUERY_INFORMATION = 0x0040, 
     SET_THREAD_TOKEN = 0x0080, 
     IMPERSONATE = 0x0100, 
     DIRECT_IMPERSONATION = 0x0200 
    } 

    [StructLayout(LayoutKind.Sequential)] 
    public struct FLOATING_SAVE_AREA 
    { 
     public uint ControlWord; 
     public uint StatusWord; 
     public uint TagWord; 
     public uint ErrorOffset; 
     public uint ErrorSelector; 
     public uint DataOffset; 
     public uint DataSelector; 

     // missing some stuff 
     public uint Cr0NpxState; 
    } 

    [DllImport("kernel32.dll")] 
    private static extern int VirtualQueryEx(IntPtr hProcess, IntPtr lpAddress, out MEMORY_BASIC_INFORMATION lpBuffer, int dwLength); 

    [DllImport("kernel32.dll")] 
    public static extern bool ReadProcessMemory(IntPtr hProcess, int lpBaseAddress, byte[] buffer, int size, 
     int lpNumberOfBytesRead); 

Aber aus irgendeinem Grunde trifft es nie evt.Exception.ExceptionRecord.ExceptionAddress == address

Ich bin ziemlich neu im Speicher lesen und habe eine harte Zeit herausfinden, was ist falsch mit dem Code oben.

EDIT: Auch wenn ich die context.Dr7 = 0x00000001; auskommentieren die Anwendung, die ich versuche zu lesen stürzt ab.

+0

Es ist schwierig, ohne weitere Informationen zu sagen - was ist die Natur des Programms, das Sie versuchen zu debuggen und wie haben Sie den richtigen Wert für den Parameter 'Adresse' festgestellt? –

+0

@Damien_The_Unbeliever Das Programm selbst ist ein Einzelspieler-Spiel in C++. Und ich kenne die richtigen Werte wegen der Verwendung von Cheat Engine. – Julian

Antwort

1

Die Theorie:

Sie wollen einen Prozess anhängen, in ihm einen Haltepunkt setzen, registrieren Sie für dieses Ereignis ein Ereignis in der Debugger-Anwendung und warten. Sie müssen den Haltepunkt an die Adresse setzen, die Sie als Parameter angeben, und durch Lesen des Kontexts sollten Sie in der Lage sein, den Inhalt von EDX zu sehen. Dies scheint vernünftig zu sein, so wie es ein menschlicher Entwickler tun würde.

Die Umsetzung:

bei der Implementierung der Suche, die Methode, die Sie versuchen, den Haltepunkt an der Adresse zum Einsatz bringen scheint verdächtig. Lesen here Ich verstehe, dass das Versuchen, den Kontext auf einem laufenden Thread festzulegen, unvorhersehbare Ergebnisse ergeben kann. Möglicherweise fehlen Ihnen auch die ausreichenden Berechtigungen. Angenommen, Sie haben die Berechtigungen versuchen Sie, die Threads zu stoppen, bevor Sie den Kontext festlegen.

Das andere Problem, das ich voraussage, ist, dass der Thread, den Sie stoppen möchten und Debug hat einen Kontext, der so wenig wie möglich geändert werden muss. Ich denke, dass Sie zuerst den Thread stoppen sollten, lesen Sie seinen Kontext, ändern Sie das Dr0-Flag (vorausgesetzt, dass Sie dort den Haltepunkt setzen) und legen Sie den Kontext mit allen anderen Registerinformationen unverändert.

Ohne dass, ich denke, dass Sie im Grunde die Ausführung des Programms ändern und Ich habe ein starkes Gefühl, dass einige dieser Register nur gelesen werden.

Dies sind zwei Dinge, die Sie beachten müssen. Ich hoffe es hilft.

Debugging:

Wenn das nicht funktioniert, müssen Sie eine Funktion hinzufügen, die GetLastError() sehen verwendet, warum die Funktionen nicht (ich bin Verdacht SetThreadContext() wird derjenige sein verursachen Probleme beim ersten Mal).

Sie müssen auch prüfen, ob die Kontextstruktur richtig definiert ist und alle Mitglieder haben die gleiche Reihenfolge diejenigen, hathere definiert. Die Struktur muss genau wie im nicht verwalteten Code durch den C# -Code ausgerichtet werden.

Überprüfen Sie auch, ob Sie mit einem 64-Bit-Betriebssystem arbeiten. Der Kontext eines Threads in einem 64-Bit-Betriebssystem ist anders als bei 32-Bit. Register werden um 64b erweitert und so weiter. Wenn Sie ein 64-Bit-Betriebssystem verwenden, muss die Kontextstruktur neu definiert werden. Das Gleiche gilt, wenn Sie eine ARM-Maschine verwenden.

+0

danke für Ihre sehr klare Antwort. Ich bin auf dem Weg nach Hause und ich werde über das, was Sie gesagt haben, nachlesen und versuchen, meinen Code zu ändern. – Julian

+0

Ich habe den Code in 'Suspend' und' Resume' geändert. Der Dr0 ist in der Tat die Adresse, von der ich versuche zu lesen, aber selbst mit den aktuellen Änderungen wird es niemals die 'evt.Exception.ExceptionRecord.ExceptionAddress == Adresse' treffen. – Julian

+0

Das noch größere Problem besteht darin, dass Sie den Kontext des Threads nicht kopieren, ändern und dann den geänderten Kontext als neuen Kontext festlegen. Sie müssen das auch tun. – VAndrei

-1

Ihre Antwort scheint in einer der Kommentare zu verstecken Sie mit den anderen Code transplantierten ... Die Funktionen einstellen und Thread-Kontext erfordern einen Griff an einem Faden (wahrscheinlich geöffnet mit Openthread mit entsprechenden Berechtigungen zu erhalten, die mindestens Kontext abrufen/setzen). Stattdessen geben Sie anscheinend eine vergebene Prozess-ID weiter. Sie sollten in Erwägung ziehen, den Rückgabewert für den Erfolg zu überprüfen, da dies wahrscheinlich zur Identifizierung Ihres Problems beigetragen hätte.

+0

Sie können den Originalcode sehen, wenn Sie sich die verknüpfte Frage ansehen. Es gibt keinen fehlenden Code, so weit das Beispiel in der verknüpften Frage geht. Ich überprüfe auch die Rückgabewerte und alle geben ein 'wahr' mit Ausnahme der if-Anweisung 'evt.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_SINGLE_STEP' – Julian

+0

Ah, Sie sprechen über den' SetThreadContext' und in der Tat, das 'false' zurückgibt . Und es ist nicht wie 'HILFE, SCHREIBE EINEN DEBUGGER FÜR MICH!' Ich habe selbst recherchiert, komme aber nicht weiter. Und ohne große Kenntnisse über die Win32 API oder ihre Methoden frage ich nur, was mit dem obigen Code falsch wäre. Aber ich werde herausfinden, was mit der 'SetThreadContext'-Methode falsch sein könnte. – Julian

+0

Warum sogar stören, wenn Mike Stall ausgezeichnetes Microsoft.Samples.Debugging-Paket [Link] (http://blogs.msdn.com/b/jmstall/archive/2006/07/05/managed-wrappers-for-native-debug -api.aspx) kann in NuGet verwendet werden und enthält einen Wrapper für die native Debugging-API? – Eglin

Verwandte Themen