mirror of
https://github.com/cheat-engine/cheat-engine
synced 2026-08-15 02:26:08 -04:00
566 lines
13 KiB
ObjectPascal
Executable file
566 lines
13 KiB
ObjectPascal
Executable file
unit addressparser;
|
|
|
|
{$MODE Delphi}
|
|
|
|
interface
|
|
|
|
uses
|
|
{$ifdef darwin}macport,{$endif}
|
|
LCLIntf,SysUtils,dialogs,symbolhandler, NewKernelHandler;
|
|
|
|
resourcestring
|
|
rsAPThisIsNotAValidAddress = 'This is not a valid address';
|
|
|
|
type
|
|
TSeperator = (plus,minus,multiply); //the things the disassembler shows (NO DIVIDE)
|
|
|
|
TAddressParser=class
|
|
private
|
|
STR: string;
|
|
blurb: string;
|
|
ch: integer;
|
|
address: ptruint;
|
|
increase: boolean;
|
|
total: array of byte; //0=seperator 1=value
|
|
values: array of int64;
|
|
seperators: array of TSeperator;
|
|
|
|
SpecialContext: PContext;
|
|
|
|
|
|
|
|
procedure seperator;
|
|
procedure value;
|
|
|
|
procedure x86register;
|
|
procedure e;
|
|
procedure arm_F;
|
|
|
|
procedure armregister;
|
|
procedure arm64register;
|
|
|
|
function simplify3: boolean;
|
|
function simplify2: boolean;
|
|
function simplify1: boolean;
|
|
public
|
|
procedure setSpecialContext(c: PContext);
|
|
function getaddress(S: string;skipsymhandler: boolean=false):ptrUint;
|
|
function getBaseAddress(s: string):ptruint;
|
|
end;
|
|
|
|
|
|
var mainthreadAddressParser: TAddressParser;
|
|
|
|
function getaddress(S: string):ptrUint; //for old code
|
|
|
|
implementation
|
|
|
|
uses memorybrowserformunit, StrUtils, ProcessHandlerUnit;
|
|
|
|
|
|
procedure TAddressParser.seperator;
|
|
//sets the seperator
|
|
begin
|
|
|
|
setlength(total,length(total)+1);
|
|
total[length(total)-1]:=0;
|
|
|
|
setlength(seperators,length(seperators)+1);
|
|
case str[ch] of
|
|
'+' : seperators[length(seperators)-1]:=plus;
|
|
'-' : seperators[length(seperators)-1]:=minus;
|
|
'*' : seperators[length(seperators)-1]:=multiply;
|
|
end;
|
|
inc(ch);
|
|
end;
|
|
|
|
procedure TAddressParser.value;
|
|
//copy all characters of 0 to 9 in tempstr
|
|
var tmp: ptruint;
|
|
strp: pchar;
|
|
count: integer;
|
|
begin
|
|
|
|
strp:=@str[ch];
|
|
val('$'+string(strp),tmp,count);
|
|
|
|
setlength(total,length(total)+1);
|
|
total[length(total)-1]:=1; //value
|
|
|
|
setlength(values,length(values)+1);
|
|
values[length(values)-1]:=tmp;
|
|
|
|
inc(ch,count-2);
|
|
if count=0 then ch:=length(str)+1; //it went to the end
|
|
end;
|
|
|
|
procedure TAddressParser.armregister;
|
|
var
|
|
tmp: ptruint;
|
|
tmps: string;
|
|
c: PARMCONTEXT;
|
|
|
|
regnr: integer;
|
|
regnrstr: string;
|
|
begin
|
|
if SpecialContext<>nil then
|
|
c:=PARMCONTEXT(SpecialContext)
|
|
else
|
|
c:=memorybrowser.context;
|
|
|
|
regnr:=-1;
|
|
if str[ch]='R' then
|
|
begin
|
|
regnrstr:='';
|
|
inc(ch);
|
|
while str[ch] in ['0'..'9'] do
|
|
begin
|
|
regnrstr:=regnrstr+str[ch];
|
|
inc(ch);
|
|
end;
|
|
regnr:=regnrstr.ToInteger;
|
|
end
|
|
else
|
|
if (str[ch]='F') and (str[ch+1]='P') then begin regnr:=11; inc(ch,2); end else
|
|
if (str[ch]='I') and (str[ch+1]='P') then begin regnr:=12; inc(ch,2); end else
|
|
if (str[ch]='S') and (str[ch+1]='P') then begin regnr:=13; inc(ch,2); end else
|
|
if (str[ch]='L') and (str[ch+1]='R') then begin regnr:=14; inc(ch,2); end else
|
|
if (str[ch]='P') and (str[ch+1]='C') then begin regnr:=15; inc(ch,2); end;
|
|
|
|
if regnr<>-1 then
|
|
begin
|
|
setlength(total,length(total)+1);
|
|
total[length(total)-1]:=1; //value
|
|
|
|
setlength(values,length(values)+1);
|
|
values[length(values)-1]:=ptruint(@c^.R0)+sizeof(dword)*regnr;
|
|
end;
|
|
end;
|
|
|
|
procedure TAddressParser.arm64register;
|
|
var
|
|
tmp: ptruint;
|
|
tmps: string;
|
|
c: PARMCONTEXT;
|
|
|
|
regnr: integer;
|
|
regnrstr: string;
|
|
begin
|
|
if SpecialContext<>nil then
|
|
c:=PARMCONTEXT(SpecialContext)
|
|
else
|
|
c:=memorybrowser.context;
|
|
|
|
regnr:=-1;
|
|
if str[ch]='X' then
|
|
begin
|
|
regnrstr:='';
|
|
inc(ch);
|
|
while str[ch] in ['0'..'9'] do
|
|
begin
|
|
regnrstr:=regnrstr+str[ch];
|
|
inc(ch);
|
|
end;
|
|
regnr:=regnrstr.ToInteger;
|
|
end
|
|
else
|
|
if (str[ch]='S') and (str[ch+1]='P') then begin regnr:=31; inc(ch,2); end;
|
|
|
|
if regnr<>-1 then
|
|
begin
|
|
setlength(total,length(total)+1);
|
|
total[length(total)-1]:=1; //value
|
|
|
|
setlength(values,length(values)+1);
|
|
values[length(values)-1]:=ptruint(@c^.R0)+sizeof(dword)*regnr;
|
|
end;
|
|
end;
|
|
|
|
procedure TAddressParser.x86register;
|
|
var tmp: ptruint;
|
|
tmps: string;
|
|
c: Pcontext;
|
|
xregnrstr: string;
|
|
xregnr: integer;
|
|
begin
|
|
|
|
tmp:=0;
|
|
tmps:=copy(str,ch,3);
|
|
if SpecialContext<>nil then
|
|
c:=SpecialContext
|
|
else
|
|
c:=memorybrowser.context;
|
|
|
|
if c=nil then raise exception.Create(rsAPThisIsNotAValidAddress);
|
|
|
|
if tmps[1] in ['X','Y'] then
|
|
begin
|
|
if tmps.Substring(1,2)='MM' then
|
|
begin
|
|
inc(ch,3);
|
|
xregnrstr:='';
|
|
while str[ch] in ['0'..'9'] do
|
|
begin
|
|
xregnrstr:=xregnrstr+str[ch];
|
|
inc(ch);
|
|
end;
|
|
|
|
xregnr:=xregnrstr.ToInteger;
|
|
|
|
setlength(total,length(total)+1);
|
|
total[length(total)-1]:=1; //value
|
|
|
|
setlength(values,length(values)+1);
|
|
values[length(values)-1]:=pptruint(@c^.{$ifdef cpu64}FltSave.XmmRegisters[xregnr]{$else}ext.XMMRegisters[xregnr]{$endif})^;
|
|
|
|
exit;
|
|
end
|
|
else
|
|
raise exception.Create(rsAPThisIsNotAValidAddress);
|
|
|
|
end
|
|
else
|
|
begin
|
|
|
|
if tmps='EAX' then tmp:=c^.{$ifdef cpu64}rax{$else}eax{$endif} else
|
|
if tmps='EBX' then tmp:=c^.{$ifdef cpu64}rbx{$else}ebx{$endif} else
|
|
if tmps='ECX' then tmp:=c^.{$ifdef cpu64}rcx{$else}ecx{$endif} else
|
|
if tmps='EDX' then tmp:=c^.{$ifdef cpu64}rdx{$else}edx{$endif} else
|
|
if tmps='ESI' then tmp:=c^.{$ifdef cpu64}rsi{$else}esi{$endif} else
|
|
if tmps='EDI' then tmp:=c^.{$ifdef cpu64}rdi{$else}edi{$endif} else
|
|
if tmps='EBP' then tmp:=c^.{$ifdef cpu64}rbp{$else}ebp{$endif} else
|
|
if tmps='ESP' then tmp:=c^.{$ifdef cpu64}rsp{$else}esp{$endif} else
|
|
if tmps='EIP' then tmp:=c^.{$ifdef cpu64}rip{$else}eip{$endif}
|
|
{$ifdef cpu64}
|
|
else
|
|
if tmps='RAX' then tmp:=c^.rax else
|
|
if tmps='RBX' then tmp:=c^.rbx else
|
|
if tmps='RCX' then tmp:=c^.rcx else
|
|
if tmps='RDX' then tmp:=c^.rdx else
|
|
if tmps='RSI' then tmp:=c^.rsi else
|
|
if tmps='RDI' then tmp:=c^.rdi else
|
|
if tmps='RBP' then tmp:=c^.rbp else
|
|
if tmps='RSP' then tmp:=c^.rsp else
|
|
if tmps='RIP' then tmp:=c^.rip else
|
|
if tmps='R10' then tmp:=c^.r10 else
|
|
if tmps='R11' then tmp:=c^.r11 else
|
|
if tmps='R12' then tmp:=c^.r12 else
|
|
if tmps='R13' then tmp:=c^.r13 else
|
|
if tmps='R14' then tmp:=c^.r14 else
|
|
if tmps='R15' then tmp:=c^.r15 else
|
|
begin
|
|
tmps:=copy(str,ch,2);
|
|
if tmps='R8' then tmp:=c^.r8 else
|
|
if tmps='R9' then tmp:=c^.r9;
|
|
end
|
|
{$endif}
|
|
;
|
|
end;
|
|
setlength(total,length(total)+1);
|
|
total[length(total)-1]:=1; //value
|
|
|
|
setlength(values,length(values)+1);
|
|
values[length(values)-1]:=tmp;
|
|
|
|
inc(ch,length(tmps));
|
|
end;
|
|
|
|
|
|
procedure TAddressParser.arm_F;
|
|
begin
|
|
if (ch+1<=length(str)) then //could be FP
|
|
begin
|
|
case str[ch+1] of
|
|
'P' :armregister; //FP
|
|
else value;
|
|
end;
|
|
end
|
|
else value;
|
|
end;
|
|
|
|
procedure TAddressParser.E;
|
|
//find out if this is a register or a value
|
|
begin
|
|
if (ch+2<=length(str)) then //the 3th char of a reg is a X,I or P , so no A to F
|
|
begin
|
|
case str[ch+2] of
|
|
'X','I','P' :x86register;
|
|
else value;
|
|
end;
|
|
end
|
|
else value;
|
|
end;
|
|
|
|
function TAddressParser.simplify3: boolean;
|
|
var scount,vcount: integer;
|
|
i,j: integer;
|
|
begin
|
|
//calculate the *'s
|
|
result:=false;
|
|
scount:=0;
|
|
vcount:=0;
|
|
for i:=0 to length(total)-1 do
|
|
begin
|
|
if total[i]=0 then
|
|
begin //at a * multiplie the value before and after. (start from left to right)
|
|
if seperators[scount]=multiply then
|
|
begin
|
|
for j:=scount to length(seperators)-2 do
|
|
seperators[j]:=seperators[j+1];
|
|
setlength(seperators,length(seperators)-1);
|
|
|
|
values[vcount-1]:=values[vcount-1]*values[vcount];
|
|
for j:=vcount to length(values)-2 do
|
|
values[j]:=values[j+1];
|
|
setlength(values,length(values)-1);
|
|
|
|
//now remove the seperator and value after it
|
|
for j:=i to length(total)-4 do //DUH!!!!!!! 0101010101 (i could just cut the last 2 of...)
|
|
begin
|
|
total[j]:=total[j+2];
|
|
total[j+1]:=total[j+3];
|
|
end;
|
|
|
|
setlength(total,length(total)-2);
|
|
|
|
result:=true;
|
|
exit;
|
|
end;
|
|
inc(scount);
|
|
end else inc(vcount);
|
|
|
|
end;
|
|
end;
|
|
|
|
|
|
function TAddressParser.simplify2: boolean;
|
|
var scount: integer;
|
|
i,j: integer;
|
|
begin
|
|
//find the spots that have 2 seperators next to eachother and remove the + from it
|
|
scount:=0;
|
|
result:=false;
|
|
for i:=0 to length(total)-2 do
|
|
begin
|
|
if total[i]=0 then
|
|
begin
|
|
if total[i+1]=0 then //2 separators next to eachother
|
|
begin
|
|
if seperators[scount]=plus then
|
|
begin
|
|
for j:=scount to length(seperators)-2 do
|
|
seperators[j]:=seperators[j+1];
|
|
setlength(seperators,length(seperators)-1);
|
|
|
|
for j:=i to length(total)-2 do
|
|
total[j]:=total[j+1];
|
|
setlength(total,length(total)-1);
|
|
result:=true;
|
|
exit;
|
|
end else
|
|
begin //this'll take care of ** too
|
|
for j:=scount+1 to length(seperators)-2 do
|
|
seperators[j]:=seperators[j+1];
|
|
setlength(seperators,length(seperators)-1);
|
|
|
|
for j:=i+1 to length(total)-2 do
|
|
total[j]:=total[j+1];
|
|
setlength(total,length(total)-1);
|
|
result:=true;
|
|
exit;
|
|
end;
|
|
end;
|
|
inc(scount);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
function TAddressParser.simplify1: boolean;
|
|
var scount,vcount: integer;
|
|
i,j: integer;
|
|
begin
|
|
//find a - and remove it
|
|
//then do valueafter:=-valueafter
|
|
scount:=0;
|
|
vcount:=0;
|
|
for i:=0 to length(total)-1 do
|
|
begin
|
|
if total[i]=0 then
|
|
begin
|
|
if seperators[scount]=minus then
|
|
begin
|
|
values[vcount]:=-values[vcount];
|
|
seperators[scount]:=plus;
|
|
result:=true;
|
|
exit;
|
|
end;
|
|
inc(scount);
|
|
end else inc(vcount);
|
|
end;
|
|
result:=false;
|
|
end;
|
|
|
|
|
|
function TAddressParser.getaddress(s: string;skipsymhandler: boolean=false): ptrUint;
|
|
var i,j: integer;
|
|
scount,vcount: integer;
|
|
tempstr: string;
|
|
haserror: boolean;
|
|
|
|
c: Pcontext;
|
|
begin
|
|
if skipsymhandler=false then
|
|
begin
|
|
if SpecialContext<>nil then
|
|
c:=SpecialContext
|
|
else
|
|
c:=memorybrowser.context;
|
|
|
|
result:=symhandler.getaddressfromname(s,false,haserror, c);
|
|
if (result<>0) and (not haserror) then exit;
|
|
end;
|
|
|
|
if s='' then s:='0';
|
|
setlength(total,2);
|
|
setlength(values,1);
|
|
setlength(seperators,1);
|
|
values[0]:=0; //0+
|
|
seperators[0]:=plus;
|
|
total[0]:=1; //value
|
|
total[1]:=0; //seperator
|
|
|
|
|
|
ch:=1;
|
|
address:=0;
|
|
increase:=true;
|
|
str:=uppercase(s);
|
|
|
|
if processhandler.SystemArchitecture=archX86 then
|
|
begin
|
|
while ch<=length(s) do
|
|
begin
|
|
case str[ch] of
|
|
'$' : begin
|
|
inc(ch);
|
|
value;
|
|
end;
|
|
'0'..'9' : value;
|
|
'A'..'D' : value;
|
|
'E' : E;
|
|
'F' : value;
|
|
'R','X','Y': x86register;
|
|
|
|
'+','-','*' : seperator;
|
|
else raise exception.Create(rsAPThisIsNotAValidAddress);
|
|
|
|
end;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
//ARM
|
|
if processhandler.is64Bit then
|
|
begin
|
|
//arm64
|
|
while ch<=length(s) do
|
|
begin
|
|
case str[ch] of
|
|
'$' : begin
|
|
inc(ch);
|
|
value;
|
|
end;
|
|
'0'..'9' : value;
|
|
'A'..'F' : value;
|
|
'X','S' : arm64register; //X##, SP
|
|
'+','-','*' : seperator;
|
|
else raise exception.Create(rsAPThisIsNotAValidAddress);
|
|
|
|
end;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
//arm32
|
|
while ch<=length(s) do
|
|
begin
|
|
case str[ch] of
|
|
'$' : begin
|
|
inc(ch);
|
|
value;
|
|
end;
|
|
'0'..'9' : value;
|
|
'A'..'E' : value;
|
|
'F': arm_F;
|
|
'R','S','L', 'P': armregister; //R##, SP, LR, PC
|
|
'+','-','*' : seperator;
|
|
else raise exception.Create(rsAPThisIsNotAValidAddress);
|
|
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
//total should now be filled with a string consisting of 0 and 1
|
|
while simplify1 do ; //remove the - seperators
|
|
while simplify2 do ; //remove double seperators
|
|
while simplify3 do ; //remove the * by replacing the values with the multiplied value
|
|
|
|
for i:=0 to length(values)-1 do inc(address,values[i]);
|
|
result:=address;
|
|
|
|
end;
|
|
|
|
function TAddressParser.getBaseAddress(s: string):ptruint;
|
|
var maxvalue: ptruint;
|
|
i: integer;
|
|
part: string;
|
|
begin
|
|
//strip of the +XXXX part if XXXX is a hexadecimal value
|
|
i:=RPos('+',s);
|
|
if i>0 then
|
|
begin
|
|
part:=copy(s,i+1);
|
|
try
|
|
strtoint('$'+part);
|
|
//still here so yes
|
|
s:=copy(s,1,i-1);
|
|
exit(getAddress(s,true));
|
|
except
|
|
|
|
end;
|
|
end;
|
|
|
|
//still here, use the 'old' method
|
|
|
|
getaddress(s, true);
|
|
maxvalue:=0;
|
|
for i:=0 to length(values)-1 do
|
|
begin
|
|
if values[i]>0 then
|
|
begin
|
|
if maxvalue<ptruint(values[i]) then
|
|
maxvalue:=ptruint(values[i]);
|
|
end;
|
|
end;
|
|
|
|
result:=maxvalue;
|
|
end;
|
|
|
|
procedure TAddressParser.setSpecialContext(c: PContext);
|
|
begin
|
|
SpecialContext:=c;
|
|
end;
|
|
|
|
function getaddress(S: string):ptrUint;
|
|
begin
|
|
result:=mainthreadAddressParser.getaddress(s);
|
|
end;
|
|
|
|
initialization
|
|
mainthreadAddressParser:=TAddressParser.create;
|
|
|
|
finalization
|
|
mainthreadAddressParser.free;
|
|
|
|
end.
|