mirror of
https://github.com/cheat-engine/cheat-engine
synced 2026-08-15 02:26:08 -04:00
1208 lines
29 KiB
ObjectPascal
Executable file
1208 lines
29 KiB
ObjectPascal
Executable file
unit frmMemoryViewExUnit;
|
|
|
|
{$mode delphi}
|
|
|
|
interface
|
|
|
|
uses
|
|
{$ifdef darwin}
|
|
macport, LCLType, LCLIntf,
|
|
{$endif}
|
|
{$ifdef windows}
|
|
windows,
|
|
{$endif}
|
|
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs,
|
|
ExtCtrls, StdCtrls, ComCtrls, Menus, memdisplay, newkernelhandler, cefuncproc,
|
|
syncobjs, math, savedscanhandler, foundlisthelper, CustomTypeHandler,
|
|
symbolhandler, inputboxtopunit, commonTypeDefs, GL, GLext, Types, DPIHelper, betterControls;
|
|
|
|
|
|
type TMVCompareMethod=(cmOr, cmXor, cmAnd);
|
|
|
|
type
|
|
TMemoryDataSource=class(TThread)
|
|
private
|
|
cs: TCriticalSection;
|
|
address: ptruint;
|
|
buf: pbytearray;
|
|
bufsize: integer;
|
|
faddresslistonly: boolean;
|
|
fcompareagainstsavedscan: boolean;
|
|
fvartype: TVariableType;
|
|
fvarsize: integer;
|
|
|
|
comparemethod: TMVCompareMethod;
|
|
|
|
temppagebuf: pbytearray;
|
|
|
|
addresslist: TFoundList;
|
|
previousvaluelist: TSavedScanHandler;
|
|
ct: TCustomtype;
|
|
|
|
|
|
|
|
public
|
|
procedure lock;
|
|
procedure unlock;
|
|
procedure setRegion(address: ptruint; buf: pointer; size: integer);
|
|
procedure execute; override;
|
|
procedure fetchmem;
|
|
procedure setaddresslist(state: boolean; listname: string);
|
|
procedure setcompare(state: boolean; compareMethod: TMVCompareMethod; listname: string);
|
|
constructor create(suspended: boolean);
|
|
end;
|
|
|
|
TMemEntry = record
|
|
address:PtrUInt;
|
|
size:integer;
|
|
end;
|
|
|
|
{ TfrmMemoryViewEx }
|
|
|
|
TfrmMemoryViewEx = class(TForm)
|
|
btnMEMMAP: TButton;
|
|
cbAddresslist: TComboBox;
|
|
cbAddresslistOnly: TCheckBox;
|
|
cbColor: TComboBox;
|
|
cbCompare: TCheckBox;
|
|
cbSavedList: TComboBox;
|
|
cbType: TComboBox;
|
|
edtAddress: TEdit;
|
|
edtPitch: TEdit;
|
|
Label1: TLabel;
|
|
Label2: TLabel;
|
|
Label3: TLabel;
|
|
lblZOOM: TLabel;
|
|
lblAddress: TLabel;
|
|
Panel4: TPanel;
|
|
Panel5: TPanel;
|
|
Panel6: TPanel;
|
|
pbMEM: TPaintBox;
|
|
Panel1: TPanel;
|
|
Panel2: TPanel;
|
|
Panel3: TPanel;
|
|
rbAnd: TRadioButton;
|
|
rbOr: TRadioButton;
|
|
rbXor: TRadioButton;
|
|
sbVERT: TScrollBar;
|
|
tbPitch: TTrackBar;
|
|
tbZoom: TTrackBar;
|
|
procedure btnMEMMAPClick(Sender: TObject);
|
|
procedure cbAddresslistChange(Sender: TObject);
|
|
procedure cbAddresslistOnlyChange(Sender: TObject);
|
|
procedure cbAddresslistDropDown(Sender: TObject);
|
|
procedure cbCompareChange(Sender: TObject);
|
|
procedure cbSavedListChange(Sender: TObject);
|
|
procedure cbColorChange(Sender: TObject);
|
|
procedure cbTypeChange(Sender: TObject);
|
|
procedure edtAddressKeyDown(Sender: TObject; var Key: Word;
|
|
Shift: TShiftState);
|
|
|
|
procedure edtPitchChange(Sender: TObject);
|
|
procedure FormCreate(Sender: TObject);
|
|
procedure FormDestroy(Sender: TObject);
|
|
procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
|
|
procedure FormResize(Sender: TObject);
|
|
procedure FormShow(Sender: TObject);
|
|
procedure Panel1Click(Sender: TObject);
|
|
procedure pbMEMPaint(Sender: TObject);
|
|
procedure sbVERTChange(Sender: TObject);
|
|
procedure sbVERTKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
|
|
procedure tbPitchChange(Sender: TObject);
|
|
procedure tbZoomChange(Sender: TObject);
|
|
|
|
Procedure mdMouseDown(Sender:Tobject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
|
|
procedure mdMouseMove(Sender:Tobject;Shift: TShiftState; X, Y: Integer);
|
|
procedure mdMouseUp(Sender:Tobject;Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
|
|
procedure mdMouseWheel(Sender: TObject; Shift: TShiftState; WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
|
|
procedure mdRecenterDrag;
|
|
private
|
|
buf: pbytearray;
|
|
bufsize: integer;
|
|
datasource: TMemoryDataSource;
|
|
showing_help:boolean;
|
|
mem_map:TList;
|
|
procedure Panel1DblClick(Sender: TObject);
|
|
function getCompareMethod: TMVCompareMethod;
|
|
function ondata(newAddress: ptruint; PreferedMinimumSize: integer; var newbase: pointer; var newsize: integer): boolean;
|
|
procedure UpdateZoomText(val:single);
|
|
procedure UpdateAddress(val:PtrUInt);
|
|
procedure UpdateZoomBar(val:single);
|
|
procedure UpdateScrollbar(val:PtrUInt);
|
|
procedure ClearMemMap;
|
|
procedure MDResize;
|
|
public
|
|
md: TMemDisplay;
|
|
procedure DisplayHelp;
|
|
end;
|
|
|
|
|
|
implementation
|
|
|
|
uses MemoryBrowserFormUnit, MainUnit, ProcessHandlerUnit;
|
|
|
|
{$R *.lfm}
|
|
|
|
{ TMemoryDataSource }
|
|
|
|
constructor TMemoryDataSource.create(suspended: boolean);
|
|
begin
|
|
cs:=tcriticalsection.create;
|
|
|
|
getmem(temppagebuf, 4096); //so it doesn't need to be allocated/freed each fetchmem call
|
|
|
|
inherited create(suspended);
|
|
end;
|
|
|
|
procedure TMemoryDataSource.setcompare(state: boolean; compareMethod: TMVCompareMethod; listname: string);
|
|
begin
|
|
if state then
|
|
begin
|
|
|
|
cs.Enter;
|
|
try
|
|
if previousvaluelist<>nil then
|
|
freeandnil(previousvaluelist);
|
|
|
|
previousvaluelist:=TSavedScanHandler.create(mainform.memscan.GetScanFolder, listname);
|
|
previousvaluelist.AllowNotFound:=true;
|
|
previousvaluelist.AllowRandomAccess:=true;
|
|
|
|
self.compareMethod:=comparemethod;
|
|
|
|
finally
|
|
cs.Leave;
|
|
end;
|
|
|
|
end;
|
|
|
|
fcompareagainstsavedscan:=state;
|
|
end;
|
|
|
|
procedure TMemoryDataSource.setaddresslist(state: boolean; listname: string);
|
|
begin
|
|
if state then
|
|
begin
|
|
//Open a "PreviousValue object for the current memscan results.
|
|
|
|
cs.Enter;
|
|
|
|
try
|
|
if addresslist<>nil then
|
|
freeandnil(addresslist);
|
|
|
|
addresslist:=TFoundList.create(nil, mainform.memscan, listname);
|
|
addresslist.Initialize;
|
|
fvartype:=mainform.memscan.VarType;
|
|
ct:=mainform.memscan.CustomType;
|
|
fvarsize:=mainform.memscan.Getbinarysize div 8;
|
|
|
|
finally
|
|
cs.leave;
|
|
end;
|
|
end;
|
|
|
|
|
|
faddresslistonly:=state;
|
|
|
|
fetchmem; //update now
|
|
end;
|
|
|
|
procedure TMemoryDataSource.fetchmem;
|
|
var x: ptrUint;
|
|
a,a2: ptruint;
|
|
s: integer;
|
|
|
|
s2: integer;
|
|
|
|
p: PByteArray;
|
|
i: qword;
|
|
j: integer;
|
|
|
|
|
|
toread: integer;
|
|
begin
|
|
lock;
|
|
|
|
if buf<>nil then //not yet initialized
|
|
begin
|
|
|
|
a:=address;
|
|
i:=qword(-1);
|
|
if faddresslistonly then
|
|
i:=addresslist.FindClosestAddress(address-fvarsize+1); //all following accesses will be sequential
|
|
|
|
|
|
toread:=bufsize;
|
|
|
|
|
|
//while a<address+bufsize do
|
|
|
|
while toread>0 do
|
|
begin
|
|
s:=minX((address+bufsize)-a, 4096-(a mod 4096)); //the number of bytes left in this page or for this buffer
|
|
|
|
x:=0;
|
|
if faddresslistonly then
|
|
begin
|
|
//check if this page has any addresses.
|
|
zeromemory(@buf[a-address], s);
|
|
|
|
if int64(i)<>-1 then
|
|
begin
|
|
a2:=addresslist.GetAddress(i);
|
|
//get the first addresses that belong to this page (or has bytes in it)
|
|
while (i<addresslist.count-1) and (a2<a-fvarsize+1) do
|
|
begin
|
|
inc(i);
|
|
a2:=addresslist.GetAddress(i)
|
|
end;
|
|
|
|
while (i<addresslist.count-1) and (a2<a+s) do
|
|
begin
|
|
//render to the buffer
|
|
s2:=fvarsize;
|
|
if integer(a2-a)<0 then //cut off if it falls before the region
|
|
begin
|
|
dec(s2, integer(a2-a));
|
|
inc(a2, integer(a2-a));
|
|
end;
|
|
|
|
if (a2-a+s2)>s then //cut off if it falls after the region
|
|
begin
|
|
s2:=s-(a2-a);
|
|
end;
|
|
|
|
if s2>0 then
|
|
begin
|
|
x:=0;
|
|
ReadProcessMemory(processhandle, pointer(a2), @buf[a2-address], s2, x);
|
|
|
|
if fcompareagainstsavedscan and (previousvaluelist<>nil) then
|
|
begin
|
|
//get the saved scan
|
|
p:=previousvaluelist.getpointertoaddress(a2, fvartype, ct);
|
|
if p<>nil then
|
|
begin
|
|
case comparemethod of
|
|
cmor: for j:=0 to x-1 do buf[a2-address+j]:=buf[a2-address+j] or p[j];
|
|
cmxor: for j:=0 to x-1 do buf[a2-address+j]:=buf[a2-address+j] xor p[j];
|
|
cmand: for j:=0 to x-1 do buf[a2-address+j]:=buf[a2-address+j] and p[j];
|
|
|
|
end;
|
|
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
inc(i);
|
|
a2:=addresslist.GetAddress(i);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
end
|
|
else
|
|
begin
|
|
ReadProcessMemory(processhandle, pointer(a), @buf[a-address], s, x);
|
|
if x<s then //zero the unread bytes
|
|
zeromemory(@buf[a-address], s-x);
|
|
end;
|
|
|
|
dec(toread,s);
|
|
|
|
a:=a+s; //next page
|
|
end;
|
|
|
|
end;
|
|
unlock;
|
|
end;
|
|
|
|
procedure TMemoryDataSource.execute;
|
|
begin
|
|
while not terminated do
|
|
begin
|
|
sleep(100);
|
|
|
|
fetchmem;
|
|
end;
|
|
end;
|
|
|
|
procedure TMemoryDataSource.lock;
|
|
begin
|
|
cs.enter
|
|
end;
|
|
|
|
procedure TMemoryDataSource.unlock;
|
|
begin
|
|
cs.leave;
|
|
end;
|
|
|
|
procedure TMemoryDataSource.setRegion(address: ptruint; buf: pointer; size: integer);
|
|
begin
|
|
lock;
|
|
self.address:=address;
|
|
self.buf:=buf;
|
|
bufsize:=size;
|
|
|
|
fetchmem;
|
|
unlock;
|
|
|
|
|
|
end;
|
|
|
|
{ TfrmMemoryViewEx }
|
|
function TfrmMemoryViewEx.ondata(newAddress: ptruint; PreferedMinimumSize: integer; var newbase: pointer; var newsize: integer): boolean;
|
|
begin
|
|
datasource.lock;
|
|
if bufsize<PreferedMinimumSize then
|
|
begin
|
|
try
|
|
ReAllocMem(buf, PreferedMinimumSize+4096);
|
|
except
|
|
beep;
|
|
end;
|
|
|
|
if buf=nil then
|
|
bufsize:=0
|
|
else
|
|
bufsize:=PreferedMinimumSize+4096;
|
|
end;
|
|
|
|
datasource.setRegion(newaddress, buf, bufsize);
|
|
datasource.unlock;
|
|
|
|
newbase:=buf;
|
|
newsize:=bufsize;
|
|
result:=newsize>=PreferedMinimumSize; //allow the move if allocated enough memory
|
|
end;
|
|
|
|
procedure TfrmMemoryViewEx.FormCreate(Sender: TObject);
|
|
begin
|
|
//create a datasource thread
|
|
mem_map:=Tlist.Create;
|
|
|
|
datasource:=TMemoryDataSource.create(true); //possible to add multiple readers in the future
|
|
|
|
md:=TMemDisplay.Create(self);
|
|
md.onData:=ondata;
|
|
md.OnMouseDown:=mdMouseDown;
|
|
md.OnMouseUp:=mdMouseUp;
|
|
md.OnMouseMove:=mdMouseMove;
|
|
md.OnMouseWheel:=mdMouseWheel;
|
|
md.OnDblClick:=Panel1DblClick;
|
|
md.OnClick:=Panel1Click;
|
|
md.setPitch(1024);
|
|
md.zoom:=1;
|
|
md.Align:=alClient;
|
|
md.parent:=panel1;
|
|
|
|
bufsize:=panel1.Height*md.pitch;
|
|
getmem(buf,bufsize);
|
|
|
|
datasource.setRegion(MemoryBrowser.hexview.Address and ptruint(not $FFF), buf, bufsize);
|
|
md.setPointer(MemoryBrowser.hexview.Address and ptruint(not $FFF), buf, bufsize);
|
|
|
|
UpdateZoomBar(md.zoom);
|
|
UpdateZoomText(md.zoom);
|
|
UpdateAddress(md.address);
|
|
edtPitch.Text:=IntTostr(md.pitch);
|
|
tbPitch.Position:=md.pitch;
|
|
|
|
datasource.Start;
|
|
end;
|
|
|
|
procedure TfrmMemoryViewEx.MDResize;
|
|
var psize,newsize: integer;
|
|
newp:Pointer;
|
|
a:PtrUInt;
|
|
begin
|
|
if(not Assigned(md))then
|
|
exit;
|
|
if(not Assigned(datasource))then
|
|
exit;
|
|
|
|
psize:=(trunc(md.height / md.zoom)+16)*md.pitch;
|
|
a:=md.address;
|
|
|
|
if(assigned(md.fOnData) and md.fOnData(a,psize,newp,newsize))then
|
|
begin
|
|
md.p:=newp;
|
|
md.size:=newsize;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMemoryViewEx.FormShow(Sender: TObject);
|
|
begin
|
|
MDResize;
|
|
|
|
AdjustComboboxSize(cbAddresslist, canvas);
|
|
AdjustComboboxSize(cbSavedList, canvas);
|
|
|
|
end;
|
|
|
|
procedure TfrmMemoryViewEx.FormResize(Sender: TObject);
|
|
begin
|
|
MDResize;
|
|
end;
|
|
|
|
procedure TfrmMemoryViewEx.ClearMemMap;
|
|
var i:integer;
|
|
entry:^TMemEntry;
|
|
begin
|
|
if(not Assigned(mem_map))then
|
|
exit;
|
|
for i:=0 to mem_map.Count-1 do
|
|
begin
|
|
entry:=mem_map[i];
|
|
Dispose(entry);
|
|
end;
|
|
mem_map.Clear;
|
|
end;
|
|
|
|
procedure TfrmMemoryViewEx.FormDestroy(Sender: TObject);
|
|
begin
|
|
if datasource<>nil then
|
|
begin
|
|
datasource.Terminate;
|
|
datasource.WaitFor;
|
|
freeandnil(datasource);
|
|
end;
|
|
ClearMemMap;
|
|
end;
|
|
|
|
procedure TfrmMemoryViewEx.FormKeyDown(Sender: TObject; var Key: Word;
|
|
Shift: TShiftState);
|
|
begin
|
|
if(key=VK_F1)then
|
|
begin
|
|
if(not showing_help)then
|
|
begin
|
|
showing_help:=true;
|
|
DisplayHelp;
|
|
showing_help:=false;
|
|
end;
|
|
end
|
|
else if(key=VK_ESCAPE)then
|
|
self.close
|
|
else if(key=VK_F5)then
|
|
edtAddress.SetFocus
|
|
else if(key=Ord('g'))then
|
|
begin
|
|
if(ssCtrl in Shift)then
|
|
edtAddress.SetFocus;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMemoryViewEx.Panel1Click(Sender: TObject);
|
|
begin
|
|
sbVERT.SetFocus;
|
|
end;
|
|
|
|
procedure TfrmMemoryViewEx.pbMEMPaint(Sender: TObject);
|
|
var i:integer;
|
|
entry:^TMemEntry;
|
|
max,a,b:Double;
|
|
y,y2,tmp,w:integer;
|
|
lasty,lasty2:integer;
|
|
begin
|
|
if(not Assigned(mem_map))then
|
|
exit;
|
|
max:=High(UINT);
|
|
if(processhandler.is64Bit)then
|
|
max:=High(PtrUint);
|
|
max:=max / pbMEM.Height;
|
|
if(max=0)then
|
|
exit;
|
|
lasty:=-1;
|
|
lasty2:=-1;
|
|
pbMEM.Canvas.Brush.Color:=clDefault;
|
|
pbMEM.Canvas.Clear;
|
|
pbMEM.Canvas.Brush.Color:=clRed;
|
|
w:=pbMEM.Width;
|
|
for i:=0 to mem_map.Count-1 do
|
|
begin
|
|
entry:=mem_map[i];
|
|
a:=entry.address;
|
|
b:=a / max;
|
|
y:=Trunc(b);
|
|
b:=(a+entry.size)/max;
|
|
y2:=trunc(b);
|
|
if(y=lasty)then
|
|
begin
|
|
if(y2=lasty2)then
|
|
continue;
|
|
end;
|
|
tmp:=y2;
|
|
if(y2=y)then
|
|
tmp:=y+1;
|
|
pbMEM.Canvas.FillRect(0,y,w,tmp);
|
|
lasty:=y;
|
|
lasty2:=y2;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMemoryViewEx.sbVERTChange(Sender: TObject);
|
|
var i:integer;
|
|
x,y:PtrUInt;
|
|
begin
|
|
if(not Assigned(processhandler))then
|
|
exit;
|
|
y:=sbVERT.Max;
|
|
if(y=0)then
|
|
exit;
|
|
x:=$FFFFFFFF;
|
|
if(processhandler.is64Bit)then
|
|
x:=PtrUInt(-1);
|
|
x:=x div y;
|
|
i:=sbVERT.Position;
|
|
x:=x*i;
|
|
md.MoveTo(0,0);
|
|
md.setPointer(x);
|
|
UpdateAddress(x);
|
|
end;
|
|
|
|
procedure TfrmMemoryViewEx.sbVERTKeyDown(Sender: TObject; var Key: Word;
|
|
Shift: TShiftState);
|
|
var i:integer;
|
|
start_address,end_address,next_address:PtrUInt;
|
|
entry:^TMemEntry;
|
|
found:boolean;
|
|
next:boolean;
|
|
function is_range_valid(a,b:PtrUInt):boolean;
|
|
var i:integer;
|
|
begin
|
|
result:=false;
|
|
for i:=0 to mem_map.Count-1 do
|
|
begin
|
|
entry:=mem_map[i];
|
|
if(entry.address >= a)then
|
|
begin
|
|
if(entry.address <= b)then
|
|
begin
|
|
result:=true;
|
|
break;
|
|
end;
|
|
end;
|
|
if((entry.address+entry.size) >= a)then
|
|
begin
|
|
if((entry.address+entry.size) <= b)then
|
|
begin
|
|
result:=true;
|
|
break;
|
|
end;
|
|
end;
|
|
if(a >= entry.address)then
|
|
begin
|
|
if(b <= (entry.address+entry.size))then
|
|
begin
|
|
result:=true;
|
|
break;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
procedure do_normal_scroll;
|
|
var delta:PtrUInt;
|
|
a,b,c:LongWord;
|
|
begin
|
|
if(processhandler.is64Bit)then
|
|
begin
|
|
delta:=end_address-start_address;
|
|
end
|
|
else
|
|
begin
|
|
a:=start_address;
|
|
b:=end_address;
|
|
c:=b-a;
|
|
delta:=c;
|
|
end;
|
|
case key of
|
|
VK_RIGHT,VK_DOWN: delta:=delta div 4;
|
|
VK_LEFT,VK_UP: delta:=-delta div 4;
|
|
VK_NEXT: delta:=(delta*15) div 16;
|
|
VK_PRIOR: delta:=-(delta*15) div 16;
|
|
end;
|
|
next_address:=start_address+delta;
|
|
end;
|
|
|
|
begin
|
|
if(not(key in [VK_NEXT,VK_PRIOR,VK_LEFT,VK_RIGHT,VK_UP,VK_DOWN]))then
|
|
exit;
|
|
if(not assigned(mem_map))then
|
|
exit;
|
|
|
|
|
|
found:=false;
|
|
|
|
start_address:=md.getAddressFromScreenPosition(0,0);
|
|
end_address:=md.getAddressFromScreenPosition(0,md.Height-1);
|
|
|
|
next_address:=start_address;
|
|
|
|
|
|
if(is_range_valid(start_address,end_address) or (mem_map.Count=0))then
|
|
begin
|
|
do_normal_scroll;
|
|
found:=true;
|
|
end
|
|
else
|
|
begin
|
|
next_address:=start_address;
|
|
next:=false;
|
|
if(key in [VK_NEXT,VK_RIGHT,VK_DOWN])then
|
|
next:=true;
|
|
|
|
if(next)then
|
|
begin
|
|
for i:=0 to mem_map.Count-1 do
|
|
begin
|
|
entry:=mem_map[i];
|
|
if(entry.address>end_address)then
|
|
begin
|
|
next_address:=entry.address;
|
|
found:=true;
|
|
break;
|
|
end;
|
|
end;
|
|
if(not found)then
|
|
begin
|
|
if(mem_map.Count>0)then
|
|
begin
|
|
entry:=mem_map[0];
|
|
next_address:=entry.address;
|
|
end
|
|
else
|
|
do_normal_scroll;
|
|
found:=true;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
for i:=mem_map.Count-1 downto 0 do
|
|
begin
|
|
entry:=mem_map[i];
|
|
if((entry.address+entry.size)<start_address)then
|
|
begin
|
|
next_address:=entry.address+entry.size;
|
|
found:=true;
|
|
break;
|
|
end;
|
|
end;
|
|
if(not found)then
|
|
begin
|
|
if(mem_map.Count>0)then
|
|
begin
|
|
entry:=mem_map[mem_map.Count-1];
|
|
next_address:=entry.address;
|
|
end
|
|
else
|
|
next_address:=0;
|
|
found:=true;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
if(found)then
|
|
begin
|
|
md.MoveTo(0,0);
|
|
md.setPointer(next_address);
|
|
UpdateAddress(next_address);
|
|
UpdateScrollbar(next_address);
|
|
key:=0;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMemoryViewEx.cbAddresslistOnlyChange(Sender: TObject);
|
|
begin
|
|
cbAddresslist.enabled:=cbAddresslistOnly.checked;
|
|
cbCompare.Enabled:=cbAddresslistOnly.checked;
|
|
cbSavedList.enabled:=cbAddresslistOnly.checked;
|
|
|
|
if datasource<>nil then
|
|
datasource.setaddresslist(cbAddresslistOnly.checked, 'TMP');
|
|
end;
|
|
|
|
procedure TfrmMemoryViewEx.cbAddresslistChange(Sender: TObject);
|
|
begin
|
|
if cbAddresslist.ItemIndex=0 then
|
|
datasource.setaddresslist(cbAddresslistOnly.checked, 'TMP')
|
|
else
|
|
datasource.setaddresslist(cbAddresslistOnly.checked, cbAddresslist.text);
|
|
end;
|
|
|
|
procedure TfrmMemoryViewEx.btnMEMMAPClick(Sender: TObject);
|
|
var
|
|
mbi : _MEMORY_BASIC_INFORMATION;
|
|
address: PtrUInt;
|
|
mappedfilename: string;
|
|
kernelmode: boolean=false;
|
|
entry:^TMemEntry;
|
|
begin
|
|
if(not Assigned(md))then
|
|
exit;
|
|
if(not Assigned(mem_map))then
|
|
exit;
|
|
|
|
if DBKLoaded then
|
|
kernelmode:=ssCtrl in GetKeyShiftState;
|
|
|
|
ClearMemMap;
|
|
|
|
address:=0;
|
|
mbi.RegionSize:=$1000;
|
|
while (GetRegionInfo(processhandle,pointer(address),mbi,sizeof(mbi), mappedfilename)<>0) and ((address+mbi.RegionSize)>address) do
|
|
begin
|
|
if(mbi.State=MEM_COMMIT)then
|
|
begin
|
|
New(entry);
|
|
entry.address:=address;
|
|
entry.size:=mbi.RegionSize;
|
|
mem_map.Add(Pointer(entry));
|
|
end;
|
|
|
|
inc(address,mbi.RegionSize);
|
|
if not kernelmode then
|
|
begin
|
|
if processhandler.is64Bit then
|
|
begin
|
|
{$IFDEF CPU64}
|
|
if (address>=QWORD($8000000000000000)) then exit;
|
|
{$ENDIF}
|
|
end
|
|
else
|
|
if (address>=$80000000) then exit;
|
|
end;
|
|
end;
|
|
pbMEM.Repaint;
|
|
end;
|
|
|
|
procedure TfrmMemoryViewEx.cbAddresslistDropDown(Sender: TObject);
|
|
begin
|
|
TComboBox(sender).Items.Clear;
|
|
TComboBox(sender).DropDownCount:=mainform.memscan.getsavedresults(TComboBox(sender).Items)+1;
|
|
TComboBox(sender).Items.Insert(0,'Current scanlist');
|
|
end;
|
|
|
|
function TfrmMemoryViewEx.getCompareMethod: TMVCompareMethod;
|
|
//returns the compare method currently selected
|
|
begin
|
|
result:=cmOr;
|
|
if rbxor.checked then
|
|
result:=cmxOr
|
|
else
|
|
if rbAnd.checked then
|
|
result:=cmAnd;
|
|
|
|
end;
|
|
|
|
procedure TfrmMemoryViewEx.cbCompareChange(Sender: TObject);
|
|
begin
|
|
cbSavedList.enabled:=cbCompare.checked;
|
|
rbOr.enabled:=cbCompare.checked;
|
|
rbAnd.enabled:=cbCompare.checked;
|
|
rbXor.enabled:=cbCompare.checked;
|
|
|
|
datasource.setcompare(cbCompare.checked, getCompareMethod, 'TMP');
|
|
end;
|
|
|
|
procedure TfrmMemoryViewEx.cbSavedListChange(Sender: TObject);
|
|
begin
|
|
if cbSavedList.ItemIndex=0 then
|
|
datasource.setcompare(cbCompare.checked, getCompareMethod, 'TMP')
|
|
else
|
|
datasource.setcompare(cbCompare.checked, getCompareMethod, cbSavedList.text);
|
|
end;
|
|
|
|
procedure TfrmMemoryViewEx.cbColorChange(Sender: TObject);
|
|
begin
|
|
{
|
|
Dithered (1 Byte/pixel)
|
|
RGB (3 Bytes/Pixel)
|
|
BGR (3 Bytes/Pixel)
|
|
RGBA (4 Bytes/Pixel)
|
|
BGRA (4 Bytes/Pixel)
|
|
}
|
|
case cbcolor.itemindex of
|
|
0: md.setFormat(GL_COLOR_INDEX);
|
|
1: md.setFormat(GL_RGB);
|
|
2: md.setFormat(GL_BGR);
|
|
3: md.setFormat(GL_RGBA);
|
|
4: md.setFormat(GL_BGRA);
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMemoryViewEx.cbTypeChange(Sender: TObject);
|
|
begin
|
|
|
|
|
|
{
|
|
Byte
|
|
Unsigned Short
|
|
Short
|
|
Unsigned Int
|
|
Int
|
|
Float
|
|
3-3-2
|
|
2-3-3 R
|
|
5-6-5
|
|
5-6-5 R
|
|
4-4-4-4
|
|
4-4-4-4 R
|
|
5-5-5-1
|
|
1-5-5-5 R
|
|
8-8-8-8
|
|
8-8-8-8 R
|
|
10-10-10-2
|
|
2-10-10-10 R
|
|
}
|
|
|
|
case cbtype.ItemIndex of
|
|
0: md.setType(GL_UNSIGNED_BYTE);
|
|
1: md.setType(GL_UNSIGNED_SHORT);
|
|
2: md.setType(GL_SHORT);
|
|
3: md.setType(GL_UNSIGNED_INT);
|
|
4: md.setType(GL_INT);
|
|
5: md.setType(GL_FLOAT);
|
|
6: md.setType(GL_UNSIGNED_BYTE_3_3_2);
|
|
7: md.setType(GL_UNSIGNED_BYTE_2_3_3_REV);
|
|
8: md.setType(GL_UNSIGNED_SHORT_5_6_5);
|
|
9: md.setType(GL_UNSIGNED_SHORT_5_6_5_REV);
|
|
10: md.setType(GL_UNSIGNED_SHORT_4_4_4_4);
|
|
11: md.setType(GL_UNSIGNED_SHORT_4_4_4_4_REV);
|
|
12: md.setType(GL_UNSIGNED_SHORT_5_5_5_1);
|
|
13: md.setType(GL_UNSIGNED_SHORT_1_5_5_5_REV);
|
|
14: md.setType(GL_UNSIGNED_INT_8_8_8_8);
|
|
15: md.setType(GL_UNSIGNED_INT_8_8_8_8_REV);
|
|
16: md.setType(GL_UNSIGNED_INT_10_10_10_2);
|
|
17: md.setType(GL_UNSIGNED_INT_2_10_10_10_REV);
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMemoryViewEx.Panel1DblClick(Sender: TObject);
|
|
var c: tpoint;
|
|
address: ptruint;
|
|
begin
|
|
c:=md.ScreenToClient(mouse.cursorpos);
|
|
address:=md.getAddressFromScreenPosition(c.x, c.y);
|
|
MemoryBrowser.hexview.Address:=address;
|
|
MemoryBrowser.show;
|
|
end;
|
|
|
|
procedure TfrmMemoryViewEx.edtPitchChange(Sender: TObject);
|
|
var newpitch: integer;
|
|
cb:TNotifyEvent;
|
|
x:integer;
|
|
begin
|
|
try
|
|
newpitch:=strtoint(edtpitch.Caption);
|
|
md.setPitch(newpitch);
|
|
edtPitch.Font.Color:=clDefault;
|
|
if(md.fPitch <> newpitch)then
|
|
begin
|
|
cb:=edtPitch.OnChange;
|
|
edtPitch.OnChange:=nil;
|
|
edtPitch.Caption:=IntToStr(md.fPitch);
|
|
edtPitch.OnChange:=cb;
|
|
end;
|
|
MDResize;
|
|
cb:=tbPitch.OnChange;
|
|
tbPitch.OnChange:=nil;
|
|
x:=md.fPitch;
|
|
if(x>tbPitch.Max)then
|
|
x:=tbPitch.Max;
|
|
tbPitch.Position:=x;
|
|
tbPitch.OnChange:=cb;
|
|
except
|
|
edtPitch.Font.Color:=clred;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMemoryViewEx.tbPitchChange(Sender: TObject);
|
|
var cb:TNotifyEvent;
|
|
pos:integer;
|
|
begin
|
|
cb:=edtPitch.OnChange;
|
|
edtPitch.OnChange:=nil;
|
|
pos:=tbPitch.position;
|
|
if((GetKeyState(VK_CONTROL) and $8000) <> 0)then
|
|
pos:=pos*10;
|
|
edtPitch.caption:=inttostr(pos);
|
|
edtPitch.OnChange:=cb;
|
|
md.setPitch(pos);
|
|
MDResize;
|
|
end;
|
|
|
|
procedure TfrmMemoryViewEx.UpdateZoomText(val:single);
|
|
begin
|
|
lblZOOM.Caption:=Format('Zoom:%f',[val]);
|
|
end;
|
|
|
|
procedure TfrmMemoryViewEx.UpdateZoomBar(val:single);
|
|
var i:integer;
|
|
begin
|
|
if(val<=1)then
|
|
begin
|
|
i:=Round(val*256);
|
|
tbZoom.Position:=i
|
|
end
|
|
else
|
|
begin
|
|
i:=Round(((val-1)*8)+256);
|
|
tbZoom.Position:=i;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMemoryViewEx.tbZoomChange(Sender: TObject);
|
|
var i:integer;
|
|
tmp:single;
|
|
begin
|
|
i:=tbZoom.Position;
|
|
if(i>256)then
|
|
begin
|
|
tmp:=i-256;
|
|
tmp:=tmp/8;
|
|
tmp:=tmp+1;
|
|
md.zoom:=tmp;
|
|
end
|
|
else
|
|
begin
|
|
tmp:=i;
|
|
tmp:=tmp/256.0;
|
|
md.zoom:=tmp;
|
|
end;
|
|
UpdateZoomText(md.zoom);
|
|
md.render;
|
|
end;
|
|
|
|
procedure TfrmMemoryViewEx.UpdateScrollbar(val:PtrUInt);
|
|
var y:double;
|
|
x:Qword;
|
|
cb:TNotifyEvent;
|
|
begin
|
|
if(not Assigned(processhandler))then
|
|
exit;
|
|
x:=$FFFFFFFF;
|
|
if(processhandler.is64Bit)then
|
|
x:=qword(-1);
|
|
y:=val/x;
|
|
y:=Abs(y*sbVERT.Max);
|
|
cb:=sbVERT.OnChange;
|
|
sbVERT.OnChange:=nil;
|
|
sbVERT.Position:=Round(y);
|
|
sbVERT.OnChange:=cb;
|
|
end;
|
|
|
|
procedure TfrmMemoryViewEx.UpdateAddress(val:PtrUInt);
|
|
var s:string;
|
|
fmt:string;
|
|
begin
|
|
fmt:='%.8X';
|
|
if((val and $FFFFFFFF00000000) <> 0)then
|
|
fmt:='%.16X';
|
|
s:=Format(fmt,[val]);
|
|
edtAddress.Caption:=s;
|
|
edtAddress.SelLength:=0;
|
|
end;
|
|
|
|
procedure TfrmMemoryViewEx.edtAddressKeyDown(Sender: TObject; var Key: Word;
|
|
Shift: TShiftState);
|
|
var val:PtrUInt;
|
|
begin
|
|
if(key=VK_RETURN)then
|
|
begin
|
|
md.MoveTo(0,0);
|
|
val:=symhandler.getAddressFromName(edtAddress.Text);
|
|
md.setPointer(val);
|
|
UpdateAddress(val);
|
|
UpdateScrollbar(val);
|
|
end;
|
|
end;
|
|
|
|
Procedure TfrmMemoryViewEx.mdMouseDown(Sender:Tobject;Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
|
|
var a:PtrUInt;
|
|
begin
|
|
if button=mbleft then
|
|
begin
|
|
md.isDragging:=true;
|
|
md.DragOrigin.x:=x;
|
|
md.DragOrigin.y:=y;
|
|
md.PosOrigin.x:=md.fXpos;
|
|
md.PosOrigin.y:=md.fYpos;
|
|
|
|
md.dragaddress:=ssCtrl in shift;
|
|
if(md.dragAddress)then
|
|
md.addressOrigin:=md.address;
|
|
a:=md.getAddressFromScreenPosition(0,0);
|
|
UpdateAddress(a);
|
|
UpdateScrollbar(a);
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMemoryViewEx.mdMouseMove(Sender:Tobject;Shift: TShiftState; X, Y: Integer);
|
|
var a: ptruint;
|
|
newp: pointer;
|
|
newsize: integer;
|
|
begin
|
|
if(md.isDragging)then
|
|
begin
|
|
with md do
|
|
begin
|
|
if(dragaddress)then
|
|
begin
|
|
//move the address by the difference in X position
|
|
a:=addressOrigin-trunc((PosOrigin.x-(DragOrigin.x-x))/zoom)*fPixelByteSize;
|
|
if assigned(fOnData) and fOnData(a,size,newp,newsize) then
|
|
begin
|
|
address:=a;
|
|
p:=newp;
|
|
size:=newsize;
|
|
LimitCoordinates; //recheck with the new ypos. (in case of size change (end of buf?))
|
|
end;
|
|
render;
|
|
end
|
|
else
|
|
MoveTo(PosOrigin.x-(DragOrigin.x-x), PosOrigin.y+(DragOrigin.y-y));
|
|
a:=md.getAddressFromScreenPosition(0,0);
|
|
UpdateAddress(a);
|
|
UpdateScrollbar(a);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMemoryViewEx.mdMouseUp(Sender:Tobject;Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
|
|
begin
|
|
if button=mbleft then
|
|
md.isDragging:=false;
|
|
|
|
//todo: Add a pixel click event handler
|
|
|
|
md.render;
|
|
end;
|
|
|
|
procedure TfrmMemoryViewEx.mdMouseWheel(Sender: TObject; Shift: TShiftState;
|
|
WheelDelta: Integer;
|
|
MousePos: TPoint;
|
|
var Handled: Boolean);
|
|
var oldx, oldy: single;
|
|
tmp:ptruint;
|
|
val:integer;
|
|
a:PtrUInt;
|
|
begin
|
|
with md do
|
|
begin
|
|
if(ssctrl in Shift)then
|
|
begin
|
|
oldx:=(-fXpos+(MousePos.x))/fZoom;
|
|
oldy:=(fYpos+(MousePos.y))/fZoom;
|
|
if WheelDelta>0 then
|
|
begin
|
|
if(fzoom<=32)then
|
|
begin
|
|
//zoom in
|
|
//get the pixel at center of the screen
|
|
|
|
if ssShift in Shift then
|
|
fZoom:=fZoom * 1.2
|
|
else
|
|
fZoom:=fZoom * 2;
|
|
|
|
fXpos:=trunc(-oldx*fZoom+(MousePos.x));
|
|
fypos:=trunc(oldy*fZoom-(MousePos.y));
|
|
end;
|
|
end
|
|
else if WheelDelta<0 then
|
|
begin
|
|
if(fZoom>0.2)then
|
|
begin
|
|
//zoom out
|
|
if ssShift in Shift then
|
|
fZoom:=fZoom / 1.2
|
|
else
|
|
fZoom:=fZoom / 2;
|
|
|
|
fXpos:=trunc(-oldx*fZoom+(MousePos.x));
|
|
fypos:=trunc(oldy*fZoom-(MousePos.y));
|
|
end;
|
|
end;
|
|
UpdateZoomText(fZoom);
|
|
UpdateZoomBar(fZoom);
|
|
end
|
|
else if(ssshift in Shift)then
|
|
begin
|
|
val:=10;
|
|
if(ssRight in shift)then
|
|
val:=1;
|
|
if(WheelDelta<0)then
|
|
setPitch(fPitch-(val*fPixelByteSize))
|
|
else
|
|
setPitch(fPitch+(val*fPixelByteSize));
|
|
edtPitch.Caption:=IntToStr(fPitch);
|
|
tbPitch.Position:=fPitch;
|
|
end
|
|
else
|
|
begin
|
|
val:=1;
|
|
if(ssRight in shift)then
|
|
begin
|
|
val:=4;
|
|
if(ssAlt in shift)then
|
|
val:=40;
|
|
end
|
|
else if(ssAlt in shift)then
|
|
val:=10;
|
|
val:=val*(-WheelDelta);
|
|
fYpos:=fYpos+val;
|
|
end;
|
|
|
|
|
|
LimitCoordinates;
|
|
setupFont;
|
|
render;
|
|
a:=md.getAddressFromScreenPosition(0,0);
|
|
UpdateAddress(a);
|
|
UpdateScrollbar(a);
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmMemoryViewEx.DisplayHelp;
|
|
var s,msg:string;
|
|
begin
|
|
msg:='ctrl+wheel=zoom'#13#10+
|
|
'shift+wheel=pitch'#13#10+
|
|
'(+RMB)'#13#10+
|
|
'wheel=scroll'#13#10+
|
|
'(+RMB or +alt)'#13#10+
|
|
'ctrl+click=move address'#13#10;
|
|
s:=Format(#13#10'xpos=%d ypos=%d'#13#10+
|
|
'pixelsize=%d'#13#10+
|
|
'size=%.8X'#13#10+
|
|
'addr=%.8X'#13#10+
|
|
'width=%d'#13#10+
|
|
'height=%d'#13#10+
|
|
'ptr=%p'#13#10,
|
|
[md.fXpos,md.fYpos,
|
|
md.fPixelByteSize,
|
|
md.size,
|
|
md.address,
|
|
md.Width,
|
|
md.Height,
|
|
md.p]);
|
|
msg:=msg+s;
|
|
MessageBox(self.Handle,PAnsiChar(msg),'MV HELP',MB_OK {$ifdef windows}or MB_SYSTEMMODAL{$endif});
|
|
end;
|
|
|
|
procedure TfrmMemoryViewEx.mdRecenterDrag;
|
|
var p: tpoint;
|
|
begin
|
|
if(md.isDragging)then
|
|
begin
|
|
p:=self.ScreenToClient(mouse.cursorpos);
|
|
|
|
mdMouseDown(self,mbLeft, [], p.x, p.y);
|
|
end;
|
|
end;
|
|
|
|
end.
|
|
|