Quote:
Originally Posted by Ende!
|
Wenn du z.B. einen Hardware Breakpoint auf den Befehl x an Adresse 401488h setzen willst, funktioniert das so:
Quote:
Context.ContextFlags = CONTEXT_DEBUG_REGISTERS;
Context.Dr0 = 0x401488;
Context.Dr7 |= 0x00000001; // or Dr7, 00 00 00 00 00 00 00 00 00000000 0 0 0 0 0 0 0 1 b
SetThreadContext(ThreadId, &Context);
|
| LEN3 | R/W3 | LEN2 | R/W2 | LEN1 | R/W1 | LEN0 | R/W0 | reserviert | G3 | L3 | G2 | L2 | G1 | L1 | G0 | L0 |
|---|
| | | | | | | 00 | 00 | | | | | | | | 0 | 1 |
LEN = 00b bedeutet ja 1-Byte und
R/W = 00b bedeutet on execute
(Wenn evtl. schon Debug Register gesetzt worden sind, müsstest du erstmal über GetThreadContext die Inhalte der Register abfragen und dann gucken, ob eines von Dr0-Dr3 frei ist und beim Verändern von Dr7 müssen die alten Werte natürlich erhalten bleiben, also BPs löschen über
and mit invertierten Werten und hinzufügen über
or)
Soll jetzt noch ein On Write Breakpoint für eine Integer-Variable hinzugefügt werden, funktioniert das so:
Quote:
Context.Dr1 = &meine_variable;
Context.Dr7 |= 0x00D00004; // or Dr7, 00 00 00 00 11 01 00 00 00000000 0 0 0 0 0 1 0 0 b
|
| LEN3 | R/W3 | LEN2 | R/W2 | LEN1 | R/W1 | LEN0 | R/W0 | reserviert | G3 | L3 | G2 | L2 | G1 | L1 | G0 | L0 |
|---|
| | | | | 11 | 01 | | | | | | | | 0 | 1 | | |
LEN = 11b bedeutet 4-Byte und
R/W = 01b bedeutet on write
Um die Benutzung zu vereinfachen, schreibst du dir dann am besten eine HW BPs-Klasse o.Ä., wo du dann mit Bit-Shifts und Enums für Dr7 arbeitest statt mit konstanten Werten wie oben.
Zusätzlich geben dir B0-B3 aus Dr6 im Exception Handler an, ob die einzelnen Bedingungen der HW BPs erfüllt sind. Also wenn z.B. Dr0 gleich 401488h, R/W0 gleich 00b und LEN0 gleich 00b sind und EIP auch gleich 401488h ist, dann wäre diese Bedingung erfüllt und B0 wäre somit beim Eintritt in den Exception Handler gesetzt.
B0-B3 werden allerdings unabhängig von L0-L3 gesetzt, heißt um keine False-Positives zu kriegen, müsstest du zuerst L0-L3 abfragen, um zu wissen, welche HW BPs momentan aktiv sind, und dann kannst du das entsprechende Bx-Bit von Dr6 überprüfen, wodurch du dann in Erfahrung bringst, durch welche(n) HW BP(s) Single Stepping ausgelöst wurde.
Darüber hinaus kannst du natürlich auch einfach ExceptionAddress oder EIP abfragen und mit der Adresse, die du hooken möchtest, vergleichen und EIP dann neu setzen, also z.B. auf deinen Hook. Für das Aufrufen der originalen Funktion brauchst du aber logischerweise wie bei Detours ein Trampolin oder du musst den HW BP temporär deaktivieren, um eine Endlosrekursion zu vermeiden.
Anmerkungen:
* LEN gibt die maximale Größe an, heißt wenn LEN = 11b ist und dann über inc byte [meine_variable] auf die Variable zugegriffen wird, wird dennoch getrappt sprich: Single Step ausgelöst
* Bei On Execute-BPs LEN immer auf 00b setzen, wie Ende schon meinte
* Execute-Breakpoints trappen, wenn EIP auf der Adresse ist, heißt noch bevor die Instruktionen ausgeführt werden, was wiederum bedeutet, dass du den BP erst einmal wieder löschen musst, damit der Befehl ausgeführt werden kann, sonst wird an dem Befehl immer und immer wieder getrappt.
Data-Breakpoints trappen, nachdem auf die Speicheradresse zugegriffen wurde, also auf der nächsten Instruktion
* Global Level BPs gibt es im Protected Mode nicht, deswegen musst du immer L0-L3 setzen.
* Dr7.GE und .LE werden heutzutage nicht mehr verwendet, also sind diese beiden Bitfelder auch nicht von Interesse.
* Dr7.GD kann man anscheinend im Usermode nicht setzen und wird daher wahrscheinlich nur für den Kernelmode relevant sein.