cheat-engine/Cheat Engine/Filehandler.pas
2022-09-06 22:01:34 +02:00

307 lines
6.8 KiB
ObjectPascal
Executable File

unit Filehandler;
{$MODE Delphi}
{
implement replaced handlers for ReadProcessMemory and WriteProcessMemory so it
reads/writes to the file instead
}
interface
uses
{$ifdef darwin}
macport,
{$endif}
{$ifdef windows}
jwawindows, windows,
{$endif}
LCLIntf, syncobjs, sysutils, Classes;
function ReadProcessMemoryFile(hProcess: THandle; const lpBaseAddress: Pointer; lpBuffer: Pointer; nSize: DWORD; var lpNumberOfBytesRead: ptruint): BOOL; stdcall;
function WriteProcessMemoryFile(hProcess: THandle; const lpBaseAddress: Pointer; lpBuffer: Pointer; nSize: DWORD; var lpNumberOfBytesWritten: ptruint): BOOL; stdcall;
function VirtualQueryExFile(hProcess: THandle; lpAddress: Pointer; var lpBuffer: TMemoryBasicInformation; dwLength: DWORD): DWORD; stdcall;
procedure CommitChanges(fn: string='');
var filename: string;
filedata: TMemorystream;
filebaseaddress: ptruint;
//filehandle: thandle;
bigendianfileaccess: boolean=false;
blockfilehandlerpopup: boolean=false;
implementation
uses dialogs, controls;
procedure CommitChanges(fn: string='');
begin
if filedata<>nil then
begin
if fn='' then
fn:=filename;
filedata.SaveToFile(fn);
end;
end;
var filecs: tcriticalsection; //only 1 filehandle, so make sure rpm does not change the filepointer while another is still reading it
function ReadProcessMemoryFile(hProcess: THandle; const lpBaseAddress: Pointer; lpBuffer: Pointer; nSize: DWORD; var lpNumberOfBytesRead: ptruint): BOOL; stdcall;
var filesize,ignore:dword;
i: integer;
b: pdword;
t: dword;
ba: ptruint;
s: integer;
begin
//ignore hprocess
if filedata=nil then
begin
exit(false);
lpNumberOfBytesRead:=0;
end;
{$ifdef windows}
if hprocess=GetCurrentProcess then
exit(windows.ReadProcessMemory(hProcess, lpBaseAddress, lpBuffer, nSize, lpNumberOfBytesRead));
{$endif}
result:=false;
ba:=ptruint(lpBaseAddress);
inc(ba,ptruint(filedata.Memory));
dec(ba,filebaseaddress);
filesize:=filedata.Size;
if ptruint(lpbaseaddress)<filebaseaddress then exit;
if ptrUint(lpbaseaddress)>=filebaseaddress+filesize then exit;
s:=nsize;
if ptrUint(lpbaseaddress)+s>=filebaseaddress+filesize then
begin
ZeroMemory(lpBuffer, nsize);
dec(s, ((ptrUint(lpbaseaddress)+s)-(filebaseaddress+filesize)));
end;
if s<=0 then exit;
nsize:=s;
CopyMemory(lpbuffer,pointer(ba),nsize);
lpNumberOfBytesRead:=nsize;
result:=true;
{$ifndef CPUAARCH64}
if bigendianfileaccess then
begin
i:=0;
while i<nSize do
begin
if (nsize-i)>=4 then
begin
b:=@PByteArray(lpBuffer)[i];
t:=b^;
{$ifdef cpu64}
asm
push rax
xor rax,rax
mov eax,t
bswap eax
mov t,eax
pop rax
end;
{$else}
asm
push eax
xor eax,eax
mov eax,t
bswap eax
mov t,eax
pop eax
end;
{$endif}
b^:=t;
end;
inc(i, 4);
end;
end;
{$endif}
end;
function WriteProcessMemoryFile(hProcess: THandle; const lpBaseAddress: Pointer; lpBuffer: Pointer; nSize: DWORD; var lpNumberOfBytesWritten: ptruint): BOOL; stdcall;
var filesize,ignore:dword;
i,o: integer;
b: pdword;
t: dword;
ba: ptruint;
s: integer;
begin
//ignore hprocess
{$ifdef windows}
if hprocess=GetCurrentProcess then
exit(windows.WriteProcessMemory(hProcess, lpBaseAddress, lpBuffer, nSize, lpNumberOfBytesWritten));
{$endif}
if filedata=nil then
begin
exit(false);
lpNumberOfBytesWritten:=0;
end;
result:=false;
ba:=ptruint(lpBaseAddress);
inc(ba,ptruint(filedata.Memory));
dec(ba,filebaseaddress);
filesize:=filedata.Size;
s:=nsize;
if ptrUint(lpbaseaddress)<filebaseaddress then exit(False);
if ptrUint(lpbaseaddress)+s>(filebaseaddress+filesize) then
begin
if (MainThreadID=GetCurrentThreadId) and (not blockfilehandlerpopup) then
begin
i:=ptrUint(lpbaseaddress-filebaseaddress)+s;
if MessageDlg('Change the file size to '+inttostr(i)+' bytes?',mtConfirmation,[mbyes,mbno],0)=mryes then
begin
filedata.SetSize(i);
ZeroMemory(pointer(ptruint(filedata.Memory)+filesize), i-filesize);
filesize:=filedata.size;
end
else
dec(s, ((ptrUint(lpbaseaddress)+s)-filesize));
end
else
dec(s, ((ptrUint(lpbaseaddress)+s)-filesize));
end;
if s<=0 then exit;
nsize:=s;
CopyMemory(pointer(ba),lpbuffer,nsize);
lpNumberOfBytesWritten:=nsize;
result:=true;
{$ifndef CPUAARCH64}
if bigendianfileaccess then
begin
i:=0;
while i<nSize do
begin
if (nsize-i)>=4 then
begin
b:=@PByteArray(lpBuffer)[i];
t:=b^;
{$ifdef cpu64}
asm
push rax
xor rax,rax
mov eax,t
bswap eax
mov t,eax
pop rax
end;
{$else}
asm
push eax
xor eax,eax
mov eax,t
bswap eax
mov t,eax
pop eax
end;
{$endif}
b^:=t;
end;
inc(i, 4);
end;
end;
{$endif}
end;
function VirtualQueryExFile(hProcess: THandle; lpAddress: Pointer; var lpBuffer: TMemoryBasicInformation; dwLength: DWORD): DWORD; stdcall;
var ignore: dword;
filesize: ptrUint;
begin
lpBuffer.BaseAddress:=pointer((ptrUint(lpAddress) div $1000)*$1000);
if ptruint(lpAddress)<filebaseaddress then
begin
lpbuffer.AllocationBase:=pointer(0);
lpbuffer.AllocationProtect:=0;
lpbuffer.State:=MEM_FREE;
lpbuffer.protect:=PAGE_NOACCESS;
lpbuffer._Type:=0;
lpbuffer.RegionSize:=filebaseaddress-ptruint(lpBuffer.BaseAddress);
result:=dwlength;
end
else
begin
filesize:=filedata.Size; // getfilesize(hprocess,@ignore);
lpbuffer.AllocationBase:=pointer(filebaseaddress);
lpbuffer.AllocationProtect:=PAGE_EXECUTE_READWRITE;
lpbuffer.RegionSize:=filesize-ptruint(lpBuffer.BaseAddress-lpbuffer.AllocationBase);
if (lpbuffer.RegionSize mod 4096)>0 then
lpbuffer.RegionSize:=lpbuffer.RegionSize+($1000-lpbuffer.RegionSize mod $1000);
lpbuffer.State:=mem_commit;
lpbuffer.Protect:=PAGE_EXECUTE_READWRITE;
lpbuffer._Type:=MEM_PRIVATE;
if (ptrUint(lpAddress)>filesize+filebaseaddress) //bigger than the file
then
begin
zeromemory(@lpbuffer,dwlength);
result:=0
end
else
result:=dwlength;
end;
end;
initialization
filecs:=tcriticalsection.create;
finalization
filecs.free;
end.