Einzelnen Beitrag anzeigen

w3seek
(Gast)

n/a Beiträge
 
#13

Re: OutputDebugString überwachen

  Alt 29. Mär 2005, 00:21
Ich bin davon ausgegangen dass er nur die OutputDebugString ausgaben eines bestimmten prozesses moechte. Mir ist DebugView selbstverstaendlich bekannt und es setzt in der Tat einen Level tiefer an.

Um OutputDebugString zu verstehen, ist ein wenig SEH (Structured Exception Handling) notwendig. Zuerst sollte man wissen, dass sobald ein prozess debugged wird, jede Exception erst einmal an den debugger weitergeleitet wird der ueber die weitere Vorgehensweise entscheided (im prinzip wie jeder "normale" exception handler), dies funktioniert ueber die sog. debug ports.

OutputDebugString macht im prinzip nichts anderes, als dass es eine spezielle exception ausloest (DBG_PRINTEXCEPTION_C). Ist nun ein debugger praesent fuer diesen prozess, wird dieser aktiv (d.h. der debug port sendet eine nachricht an den debugger prozess der den Thread, der gerade in WaitForDebugEvent waert, aufwachen laesst und die exception informationen uebermittelt. Waehrend der debugger diese exception dann behandelt, ist der thread der sie ausgeloest hat, im Schlummerzustand so dass es dem Debugger ermoeglicht saemtliche zusaetzliche Informationen wie image dumps, register dumps, stack traces, ... auszulesen. Der Debugger kann dabei (wie jeder exception handler) auch die Ausfuehrung des threads uneingeschraenkt beeinflussen, beispielsweise die Register veraendern um Instruktionen zu ueberspringen oder den stack unwind (RtlUnwind) durchfuehren, oder die exception unbehandelt lassen so dass sich der thread spaeter selbst um die behandlung kuemmern muss. Schliesslich um die Ausfuehrung des Threads fortzusetzen, muss der debugger noch ContinueDebugEvent aufrufen, das den eingeschlaeferten Thread wieder aufwachen laesst.

Im Prinzip durchlaeuft jeder Debugger diese Schleife um breakpoints, debug ausgaben, ... zu behandeln.

DebugView ist aber in diesem Sinne kein richtiger debugger, d.h. er wird nicht automatisch aktiv sobald eine exception ausgeloest wird. Er macht sich dagegen einer anderen Eigenschaft (die weniger dokumentiert ist) zunutze die OutputDebugStringA hat. Wenn naemlich kein debugger aktiv ist, der diese spezielle exception behandelt, schreibt es diese informationen in eine named (DBWIN_BUFFER) section (aka Memory Mapped File, wie bereits angemerkt wurde). Named, deswegen, dass es im object namespace von jedem Prozess in der selben session (entsprechende Rechte vorausgesetzt) auffindbar ist. Diese section ist fuer alle Prozesse lesbar und schreibbar, weshalb man jeglichen zugriff darauf sichern sollte da die Informationen beim Lesen der Daten jederzeit veraendert oder corrupted werden koennen. Damit DebugView also nicht staendig von diesem puffer lesen (pollen) muss, um herauszufinden ob daten hineingeschrieben wurden, gibt es noch named events(DBWIN_BUFFER_READY und DBWIN_DATA_READY), die OutputDebugString ausloest. DBWIN_BUFFER_READY zeigt an, ob jemand gerade mit dieser section arbeitet und verhindert OutputDebugString Daten in der section zu veraendern. Sobald man also den string aus dem puffer gelesen hatte, sollte man diesen event wieder signalisieren so dass weitere OutputDebugString aufrufe erfolgen koennen. Dies deckt die Synchronisierung zum lesen/schreiben der Daten in diese section ab, um jetzt beispielsweise DebugView nicht staendig pollen lassen zu muessen, gibt es noch den DBWIN_DATA_READY event, welchen OutputDebugString signalisiert sobald es die nachricht in die section geschrieben hat.

Kurz gefasst sieht die Vorgehensweise zum globalen Auslesen der OutputDebugString messages so aus:
1. Die DBWIN_BUFFER section mappen
2. Handles zu den DBWIN_BUFFER_READY und DBWIN_DATA_READY events erstellen
3. Den DBWIN_BUFFER_READY event setzen so dass OutputDebugString wieder Zugriff auf den puffer hat
4. Auf den DBWIN_DATA_READY event warten welcher signalisiert, dass neue nachrichten vorhanden sind
5. Die geoeffneten Handles schliessen

Die Schritte 2-4 in einer Endlosschleife durchfuehren wenn man mehr als nur eine Nachricht abfangen moechte.

Zu bemerken ist, dass man damit nur jene Debug ausgaben abfangen kann, die von Prozessen gesendet werden, die nicht mit einem Debugger verbunden sind, da sonst diese spezielle exception an den Debugger uebermittelt wuerde.

Ich hoffe ich konnte das halbwegs erklaeren (sorry fuer die vielen Rechtschreib- und Grammatikfehler), so sollte das in der Realitaet funktionieren.

Einen Treiber braucht man jedenfalls fuer das Abfangen von OutputDebugString nicht, anders sieht es mit DbgPrint aus, denn dafuer gibt es eine kernel mode implementierung (ntoskrnl.exe) und eine user mode implementierung (ntdll) - welche letztendlich aber auf den gleichen port schreiben...
  Mit Zitat antworten Zitat