Grundsätzlich verwende ich ptrace
, um einen Shell-Code zu einem Remote-Prozess zur Ausführung zu injizieren. Aber ich habe ein seltsames Verhalten bezüglich des RIP-Registers gefunden.seltsame Verhaltenseinstellung RIP mit ptrace
Was ich tue ist, ich kopiere meinen Shell-Code an die Startadresse, wo das Programm zugeordnet ist. Dann setze ich den RIP mit ptrace auf die Adresse, wo die Startadresse ist. Und dann setze ich den Zielprozess zur Ausführung des Codes fort. Sobald der Shell-Code beendet ist (indem int3
ausgeführt wird), erhalte ich ein Signal und stelle den Code wieder her, den ich gerade geändert habe.
Es funktioniert gut, außer wenn der Remote-Prozess ist blockiert innerhalb eines Systemaufrufs wie sleep
. Wenn der Remote-Prozess innerhalb eines Systemaufrufs in dem Moment blockiert wird, in dem ich den Prozess anhefte, nachdem ich den RIP auf den Ort gesetzt habe, an dem ich meinen Shell-Code ausführen möchte, und dann den Zielprozess wieder aktiviere, werde ich feststellen, dass der RIP tatsächlich 2 weniger ist als die Adresse, die ich in den Ptrace-Anruf eingegeben habe. Wenn ich zum Beispiel den RIP auf 0x4000 setze, wird der RIP nach dem Fortsetzen 0x3ffe. Normalerweise stürzt es wegen des Segmentfehlers für meinen Fall ab. Aber wenn ich das Register gleich nachdem ich es eingestellt habe, ohne den Prozess wieder aufzunehmen, ist der RIP der Wert, den ich gerade gesetzt habe. Momentan arbeite ich daran, indem ich 2 nop-Anweisungen vor meinen Shell-Code einfüge und immer 2 hinzufüge, wenn ich den RIP einstelle. Ich will nur wissen, gibt es etwas, das ich vermisse, um den RIP zu setzen, oder meine ganze Methode, Code zu injizieren, ist total instabil?
Meine Dev-Box ist Ubuntu14.04, Kernel ist 3.13.0-45-generisch.
Können Sie etwas darüber erklären, warum der Kernel die Größe von syscall subtrahieren muss, wenn er den Anruf fortsetzt? Vielen Dank ! – dianpeng
Ich nehme an, es ist Teil der RESTART-Behandlung. Sie stoppen es, indem Sie ihm ein Signal senden. Wenn der Kernel den Syscall nach Beendigung des Signal-Handlers neu starten möchte, muss er in den Kernel zurückkehren. Dazu müssen Sie sicherstellen, dass Sie die Anweisung "syscall" erneut ausführen. –