mirror of
https://github.com/cheat-engine/cheat-engine
synced 2026-08-15 02:26:08 -04:00
165 lines
4.9 KiB
ObjectPascal
Executable file
165 lines
4.9 KiB
ObjectPascal
Executable file
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.
|