2017-07-25 5 views
0

Es gibt eine Funktion in diesem Programm, das zur Zeit ein 1. kehrt ziehe ich würde für sie ein 0.Wie Rückgabewert von Funktion ändern

Daraus ich ableiten: wir den Offset zu dem Programmzähler hinzufügen können, uregs[R_PC]+arg0, die Adresse des Rückgabewertes zu finden.

Ich habe eine 32-Bit "0" zugewiesen, und ich versuche, 2 Bytes davon in die Adresse schreiben, wo der Rückgabewert lebt (unsere Funktion erwartet eine BOOL16 zurückgeben, so dass wir nur 2 Bytes von 0 benötigen) :

sudo dtrace -p "$(getpid)" -w -n ' 
int *zero; 
BEGIN { zero=alloca(4); *zero=0; } 
pid$target::TextOutA:return { 
    copyout(zero, uregs[R_PC]+arg0, 2); 
}' 

natürlich bekomme ich:

dtrace: Fehler auf aktivierten Sonde ID 2 (ID 320426: pid60498: gdi32.dll.so: TextOutA: return): ungültige Adresse (0x41f21c) in Aktion # 1 bei DIF-Offset 60

uregs[R_PC] ist vermutlich eine Userspace-Adresse. Wahrscheinlich copyout() will eine Kerneladresse.

Wie übersetze ich die Userspace-Adresse uregs[R_PC] in kernel-space? Ich weiß, dass wir mit copyin() Daten lesen können, die unter User-Space-Adresse in Kernel-Space gespeichert sind. Aber das gibt uns nicht die Kernadresse dieses Speichers.

Alternativ: Gibt es eine andere Möglichkeit, den Rückgabewert mithilfe von DTrace zu ändern?

+0

Ich sehe nicht, wie 'arg0 + u_regs [R_PC];' bekommt Sie die Adresse des Rückgabewerts. Das sind zwei Adressen. Hinzufügen von ihnen scheint keinen Sinn zu machen. Woher kennen Sie die Adresse des Rückgabewerts? Es könnte sehr gut über Register weitergegeben werden. Der tatsächliche Rückgabewert * ist in "arg1". Siehe http://docs.oracle.com/cd/E19253-01/817-6223/chp-pid/index.html –

+0

mein Verständnis aus der Dokumentation ist, dass 'u_regs [R_PC]' ist der Programmzähler, und das ' arg0' ist ein _offset vom Programmzähler_. "u_regs [R_PC]' ist also eine _absolute_ Adresse, und 'arg0' ist ein _relative offset_, das Sie zu dieser absoluten Adresse hinzufügen können, um zu einer anderen absoluten Adresse zu gelangen. – Birchlabs

+0

wie für 'arg1': sicherlich hält dies den _value_, aber meine Absicht war es, den Wert zu modifizieren, bevor die Funktion it_ zurückgibt. Das einzige Werkzeug, das wir zum Ändern von Daten in DTrace ('copyout()') haben, erfordert, dass wir die Adresse der Daten kennen. – Birchlabs

Antwort

1

DTrace ist nicht das richtige Werkzeug dafür. Sie sollten stattdessen einen Debugger wie dbx, mdb oder gdb verwenden.

In der Zwischenzeit werde ich versuchen, einige der Konzepte, die Sie erwähnt haben, zu klären.

Zu Beginn können Sie im Quellcode für eine einfache Funktion sehen, dass es eine einzelne Rückkehr gibt. Es ist durchaus möglich, dass das kompilierte Ergebnis, d. H. Die maschinenspezifische Implementierung der Funktion, auch nur einen einzigen Austrittspunkt enthält. In der Regel enthält die Implementierung jedoch wahrscheinlich mehr als einen Ausgangspunkt, und es kann für einen Entwickler nützlich sein, zu wissen, von welcher spezifischen Funktion eine zurückgegeben wurde. Es ist diese Information, die als ein Offset vom Start der Funktion beschrieben wird, der durch eine Rückkehrsonde arg0 gegeben wird. Ihr D-Skript versucht dann, einen Teil des Programms oder der Bibliothek selbst zu aktualisieren. obwohl die Addition von arg0 die Zieladresse etwas zufällig macht, liegt das Ergebnis höchstwahrscheinlich immer noch im Textabschnitt, der schreibgeschützt ist.

Zweitens gibt die Implementierung einer Funktion im allgemeinen Fall einen Wert zurück, indem sie in einem bestimmten Register gespeichert wird; z.B. %rax auf amd64. Ein Überschreiben eines Rückgabewerts würde somit das Überschreiben eines Registerwerts erforderlich machen. Dies ist unmöglich, da der Zugriff von DTrace auf die Benutzer-Land-Register schreibgeschützt ist.

Es ist möglich, dass eine Funktion so implementiert wird, dass sie bei der Rückgabe den Rückgabewert von einem bestimmten Speicherort wiederherstellt, bevor sie in das entsprechende Register geschrieben wird.Wenn dies der Fall wäre, könnte man tatsächlich den Wert im Speicher ändern (given its location), kurz bevor er aufgerufen wird. Dies funktioniert jedoch nur für eine Teilmenge von Fällen: Der Rückgabewert könnte gleichermaßen in einem anderen Register enthalten sein oder einfach als Konstante im Programmtext selbst ausgedrückt werden. In jedem Fall wäre es weitaus problematischer als es angesichts der Existenz geeigneterer Debugging-Tools wert wäre.

+0

brilliant! Danke für die ausführliche Erklärung. Die verknüpfte Antwort ist ebenfalls nützlich. Okay, also zeigt arg0 auf eine _Instruktion_ (also "eine der Rückgabeanweisungen in dieser Funktion") und nicht auf die Daten - selbst wenn ich die Kernel-Space-Adresse hatte, ist es nicht das, wonach ich suchte . Ja, das ist wahrscheinlich ein Job für ein anderes Werkzeug. – Birchlabs