Boldar - Fr 11.03.16 19:16
Titel: Stacktrace erstellen, Callstack ermitteln
Hi,
ich möchte gerne einen stack-Trace des Call-stacks in einer x86-Anwendung erstellen.
Mir ist bewusst, dass die Jedi-Libraries das können, ich möchte das aber gerne selber machen.
Ich weiss schon so ungefähr, dass man sich an den return-calls entlanghangelt, und dabei ausnutzt, dass alle Funktionen diese Zeile haben
Quelltext
1: 2:
| 0 D40224 55 push ebp 1 D40225 8BEC mov ebp, esp |
Dass bedeuted, man muss quasi immer den nächsten ebp ermitteln, und dann den return-pointer finden.
Der stack sollte an der stelle dann doch so aussehen:
Quelltext
1: 2: 3: 4:
| xxxx return-pointer alter ebp Lokale variablen <--- Dahin zeigt der neue ebp |
d.h. ich benutze den ebp, um den alten ebp zu ermitteln und hangele mich da durch und ermittele jedes mal die return-pointer. Der sollte dann also an [ebp+8] liegen.
Wie sieht dass dan in der Praxis aus? Mir fehlt da so ein bisschen der ansatz. Hat jemand so etwas schonmal gemacht und kann mir da ein paar code-Zeilen (bzw. asm-Zeilen) liefern, mit denen ich anfangen kann?
Ich möchte jetzt nicht unbedingt fertigen Code, sondern eher einen Ansatz, wie man das ganze angeht.
lg Boldar
Boldar - Do 17.03.16 11:21
Ich habs jetzt hinbekommen, falls es jemanden interessiert. Es war eigentlich recht einfach, wenn man erstmal drauf kommt:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36:
| function _isBadReadPtr (p: pointer;size: integer):boolean; var dw: SIZE_T; mbi: windows.MEMORY_BASIC_INFORMATION; begin result := false; dw := Virtualquery (p, mbi, sizeof (mbi)); result := (mbi.Protect=PAGE_READONLY )or (mbi.Protect=PAGE_READWRITE )or (mbi.Protect=PAGE_WRITECOPY )or (mbi.Protect=PAGE_EXECUTE_READ )or (mbi.Protect=PAGE_EXECUTE_READWRITE)or (mbi.Protect=PAGE_EXECUTE_WRITECOPY); if (mbi.Protect = PAGE_GUARD ) then result := false; if (mbi.Protect = PAGE_NOACCESS) then result := false; result := not result; end;
function GetCallStackTrace: AnsiString; var ret, stackwalk: ^pointer; conter: integer; begin asm mov stackwalk, ebp end; while Cardinal(stackwalk^) <> 0 do begin ret := stackwalk; Inc(ret); if _isBadReadPtr(ret, 8) then break; if _isBadReadPtr(stackwalk, 8) then break; result := result + inspectfunc(ret^); stackwalk := stackwalk^; end; end; |