unit stacktrace2; {$MODE Delphi} interface uses LCLIntf, sysutils, classes, symbolhandler, CEFuncProc, NewKernelHandler, byteinterpreter, commonTypeDefs; procedure seperatestacktraceline(s: string; var address: string; var bytes: string; var details: string); procedure ce_stacktrace(esp: ptrUint; ebp: ptrUint; eip: ptrUint; stack: Pbytearray; sizeinbytes: integer; trace: tstrings; force4byteblocks: boolean=true; showmodulesonly: boolean=false; nosystemmodules:boolean=false; maxdepth:integer=0; referenceaddress: ptruint=0; referencename:string=''); implementation uses StrUtils, ProcessHandlerUnit; procedure seperatestacktraceline(s: string; var address: string; var bytes: string; var details: string); var i,j: integer; begin //has 2 ' - ' occurances i:=pos(' - ',s); address:=copy(s,1,i-1); j:=posex(' - ',s,i+3); bytes:=copy(s,i+3,j-(i+3)); details:=copy(s,j+3,length(s)); //leftover end; procedure ce_stacktrace(esp: ptrUint; ebp: ptrUint; eip: ptrUint; stack: Pbytearray; sizeinbytes: integer; trace: tstrings; force4byteblocks: boolean=true; showmodulesonly: boolean=false; nosystemmodules:boolean=false; maxdepth:integer=0; referenceaddress: ptruint=0; referencename:string=''); { ce_stacktrace will walk the provided stack trying to figure out functionnames ,passed strings and optional other data esp must be aligned on a 4 byte boundary the first entry alignment but other entries will try to be forced to 4 byte alignment unless otherwise needed (double, string,...) if eip is in a known function location this can help with the parameter naming (for the location of ebp) esp is the first 4 byte of stack nosystemmodules is only in effect when show moduleso only is enabled } var alignedstack: pbytearray; alignedstack32: PDwordArray absolute alignedstack; alignedstack64: Puint64Array absolute alignedstack; i: integer; Entries: integer; currentStackpos: ptruint; currentStackValue: ptruint; address: string; value: string; secondary: string; v: TVariableType; oldi: integer; originalesp: ptruint; offset: ptrint; offsetstring: string; pref: char; begin if processhandler.SystemArchitecture=archX86 then begin if processhandler.is64bit then pref := 'r' else pref := 'e'; originalesp := esp; i := esp mod processhandler.pointersize; if i > 0 then begin //unalligned alignedstack := stack + (processhandler.pointersize - i); Dec(sizeinbytes, processhandler.pointersize - i); Inc(esp, i); end else alignedstack := stack; Dec(sizeinbytes, sizeinbytes mod processhandler.pointersize); //so it's a full boundary Entries := sizeinbytes div processhandler.pointersize; i := 0; while i < entries do begin oldi := i; if referenceaddress = 0 then offsetstring := '(' + pref + 'sp+' + inttohex(esp - originalesp, 1) + ')' else begin offset := esp - referenceaddress; if offset < 0 then offsetstring := '(' + referencename + '-' + inttohex(-offset, 1) + ')' else offsetstring := '(' + referencename + '+' + inttohex(offset, 1) + ')'; end; address := inttohex(esp, 8) + ' ' + offsetstring; if processhandler.is64bit then begin currentStackpos := ptruint(@alignedstack64[i]); Value := inttohex(alignedstack64[i], 16); currentStackValue := ptruint(alignedstack64[i]); end else begin currentStackpos := ptruint(@alignedstack32[i]); Value := inttohex(alignedstack32[i], 8); currentStackValue := ptruint(alignedstack32[i]); end; v := vtdword; //figure out what alignedstack[i] is. if showmodulesonly then begin if symhandler.inModule(currentStackValue) and ((not nosystemmodules) or (not symhandler.inSystemModule(currentStackValue))) then v := vtPointer else begin Inc(i); Inc(esp, (i - oldi) * processhandler.pointersize); continue; //skip end; end else v := FindTypeOfData(esp, pointer(currentstackpos), sizeinbytes - (i * processhandler.pointersize)); if v in [vtbyte..vtQword] then begin //override into pointersize type if processhandler.is64bit then v := vtQword else v := vtDword; end; secondary := DataToString(@currentStackValue, processhandler.pointersize, v); //optional: find the lengts of a string and increase i with the number of stack elements used in the string Inc(i); trace.AddObject(address + ' - ' + Value + ' - ' + secondary, pointer(esp)); if (maxdepth > 0) and (trace.Count >= maxdepth) then exit; Inc(esp, (i - oldi) * processhandler.pointersize); end; end; end; end.