fix some of the scanning issues

This commit is contained in:
cheatengine@gmail.com 2015-03-16 22:49:07 +00:00
parent a3173523df
commit aac15c7195
11 changed files with 342 additions and 38 deletions

View File

@ -8013,7 +8013,7 @@ var
shouldend: boolean;
begin
vqe:=TVirtualQueryExCache.create(processhandle);
{ vqe:=TVirtualQueryExCache.create(processhandle);
a:=0;
while VirtualQueryEx(processhandle, pointer(a), mbi, sizeof(mbi))<>0 do
@ -8056,7 +8056,7 @@ begin
vqe.free;
vqe.free; }
end;
procedure ChangeIcon(hModule: HModule; restype: PChar; resname: PChar;

View File

@ -725,6 +725,8 @@ var
VirtualQueryEx_StartCache: TVirtualQueryEx_StartCache;
VirtualQueryEx_EndCache: TVirtualQueryEx_EndCache;
GetRegionInfo: function (hProcess: THandle; lpAddress: Pointer; var lpBuffer: TMemoryBasicInformation; dwLength: DWORD; var mapsline: string): DWORD; stdcall;
{ just include vmxfunctions
@ -1411,6 +1413,33 @@ begin
end;
{$ifdef windows}
function GetRegionInfo_Windows(hProcess: THandle; lpAddress: Pointer; var lpBuffer: TMemoryBasicInformation; dwLength: DWORD; var mapsline: string): DWORD; stdcall;
var
i: integer;
mappedfilename: pchar;
begin
result:=VirtualQueryEx(hProcess, lpAddress, lpBuffer, dwLength);
if (result=sizeof(lpbuffer)) then
begin
getmem(mappedfilename,256);
i:=GetMappedFileName(hProcess,lpBuffer.BaseAddress, mappedfilename, 255);
mappedfilename[i]:=#0;
mapsline:=mappedfilename;
freemem(mappedfilename);
end;
end;
{$endif}
function GetRegionInfo_Stub(hProcess: THandle; lpAddress: Pointer; var lpBuffer: TMemoryBasicInformation; dwLength: DWORD; var mapsline: string): DWORD; stdcall;
begin
result:=VirtualQueryEx(hProcess, lpAddress, lpBuffer, dwLength);
mapsline:='';
end;
var x: string;
psa: thandle;
@ -1442,6 +1471,8 @@ initialization
WindowsKernel:=LoadLibrary('Kernel32.dll'); //there is no kernel33.dll
if WindowsKernel=0 then Raise Exception.create(rsFucked);
//by default point to these exports:
ReadProcessMemory:=GetProcAddress(WindowsKernel,'ReadProcessMemory');
WriteProcessMemory:=GetProcAddress(WindowsKernel,'WriteProcessMemory');
@ -1506,6 +1537,12 @@ initialization
u32:=loadlibrary('user32.dll');
PrintWindow:=GetProcAddress(u32,'PrintWindow');
{$ifdef windows}
GetRegionInfo:=GetRegionInfo_Windows;
{$else}
GetRegionInfo:=GetRegionInfo_Stub;
{$endif}
getLBROffset;

View File

@ -106,7 +106,6 @@
<Unit14>
<Filename Value="foundlisthelper.pas"/>
<IsPartOfProject Value="True"/>
<UnitName Value="foundlisthelper"/>
</Unit14>
<Unit15>
<Filename Value="CustomTypeHandler.pas"/>
@ -119,7 +118,6 @@
<Unit17>
<Filename Value="jni\jnitfoundlist.pas"/>
<IsPartOfProject Value="True"/>
<UnitName Value="jnitfoundlist"/>
</Unit17>
<Unit18>
<Filename Value="jni\jnitmemscan.pas"/>
@ -129,7 +127,6 @@
<Unit19>
<Filename Value="jni\jnitobject.pas"/>
<IsPartOfProject Value="True"/>
<UnitName Value="jniTObject"/>
</Unit19>
<Unit20>
<Filename Value="symbollisthandler.pas"/>
@ -166,12 +163,10 @@
<Unit27>
<Filename Value="MemoryRecordUnit.pas"/>
<IsPartOfProject Value="True"/>
<UnitName Value="MemoryRecordUnit"/>
</Unit27>
<Unit28>
<Filename Value="pointerparser.pas"/>
<IsPartOfProject Value="True"/>
<UnitName Value="pointerparser"/>
</Unit28>
<Unit29>
<Filename Value="jni\jniaddresslist.pas"/>
@ -207,7 +202,8 @@
</Linking>
<Other>
<CustomOptions Value="-dJNI
-dlowmemoryusage"/>
-dlowmemoryusage
-OoFASTMATH"/>
</Other>
</CompilerOptions>
<Debugging>

View File

@ -87,6 +87,8 @@ var
t: qword;
begin
result:=0;
log('CEConnect called');
hostname:=jniGetString(PEnv, hname);
@ -98,11 +100,14 @@ begin
log('Host='+inttohex(host.s_addr,1));
log('Port='+inttohex(port,1));
c:=nil;
t:=GetTickCount64;
while GetTickCount64<t+timeout do
begin
c:=getConnection;
if c<>nil then break;
sleep(200);
end;
log('c='+inttohex(ptruint(c),1));
@ -154,6 +159,85 @@ begin
result:=arraylist;
end;
function ReadMemoryIntoBuffer(PEnv: PJNIEnv; Obj: JObject; baseAddress: jlong; buffer: jbyteArray):jboolean; //(name: 'ReadMemoryIntoBuffer'; signature: '(L[B)Z'; fnPtr: @ReadMemoryIntoBuffer)
var
buffersize: jint;
iscopy: jboolean;
pbuf: PJByte;
x: ptruint;
test: PByteArray;
i: integer;
begin
result:=0;
//log('ReadMemoryIntoBuffer');
//log('address:'+inttohex(qword(baseAddress),8));
buffersize:=PEnv^.GetArrayLength(penv, buffer);
// log('buffersize='+inttostr(buffersize));
iscopy:=0;
pbuf:=penv^.GetByteArrayElements(penv, buffer, iscopy);
if (pbuf<>nil) then
begin
// log('acquired buffer at '+inttohex(ptruint(pbuf),8)+' iscopy='+inttostr(iscopy));
for i:=0 to buffersize-1 do
pbytearray(pbuf)[i]:=i;
if ReadProcessMemory(processhandle, pointer(baseaddress), pbuf, buffersize, x) then
result:=1;
// log('releasing buffer');
penv^.ReleaseByteArrayElements(penv, buffer, pbuf, 0);
end
else
begin
// log('failure to aquire buffer');
end;
end;
function GetRegionInfoString(PEnv: PJNIEnv; Obj: JObject; address: jlong): jstring;
var
mbi: TMemoryBasicInformation;
mapsline: string;
begin
log('GetRegionInfoString');
Log('1');
mapsline:='';
Log('2');
if GetRegionInfo(processhandle, pointer(address), mbi, sizeof(mbi), mapsline)>0 then
begin
Log('3a');
log('success');
if (mapsline='') then
mapsline:=inttohex(ptruint(mbi.BaseAddress),8)+' -> '+inttohex(ptruint(mbi.baseaddress)+mbi.RegionSize,8);
if (mbi.Protect=PAGE_NOACCESS) then
mapsline:='Not readable: '+inttohex(ptruint(mbi.BaseAddress),8)+' -> '+inttohex(ptruint(mbi.baseaddress)+mbi.RegionSize,8);
result:=penv^.NewStringUTF(penv, pchar(mapsline));
end
else
begin
Log('3b');
Log('fail');
result:=penv^.newStringUTF(penv, '----');
end;
end;
procedure SetNetworkRPMCacheTimeout(PEnv: PJNIEnv; Obj: JObject; timeout: jfloat); cdecl;
begin
if timeout>0 then
@ -209,7 +293,15 @@ begin
tempdirOverride:=_path;
end;
const methodcount=7;
procedure TerminateCEServer (PEnv: PJNIEnv; Obj: JObject); cdecl;
var c: TCEConnection;
begin
c:=getConnection;
if c<>nil then
c.TerminateServer;
end;
const methodcount=10;
//experiment: make a memscan class in java and give it references to things like memscan_firstscan where the java class contains the memscan long
@ -221,8 +313,11 @@ var jnimethods: array [0..methodcount-1] of JNINativeMethod =(
(name: 'FetchSymbols'; signature: '(Z)V'; fnPtr: @FetchSymbols),
(name: 'SetTempPath'; signature: '(Ljava/lang/String;)V'; fnPtr: @SetTempPath),
(name: 'SetNetworkRPMCacheTimeout'; signature: '(F)V'; fnPtr: @SetNetworkRPMCacheTimeout)
(name: 'SetNetworkRPMCacheTimeout'; signature: '(F)V'; fnPtr: @SetNetworkRPMCacheTimeout),
(name: 'ReadMemoryIntoBuffer'; signature: '(J[B)Z'; fnPtr: @ReadMemoryIntoBuffer),
(name: 'GetRegionInfoString'; signature: '(J)Ljava/lang/String;'; fnPtr: @GetRegionInfoString),
(name: 'TerminateCEServer'; signature: '()V'; fnPtr: @TerminateCEServer)
);
function JNI_OnLoad(vm: PJavaVM; reserved: pointer): jint; cdecl;

View File

@ -86,19 +86,16 @@ procedure TFormMemoryRegions.FormShow(Sender: TObject);
var address: PtrUInt;
mbi : _MEMORY_BASIC_INFORMATION;
temp:string;
mappedfilename: pchar;
mappedfilename: string;
i: integer;
begin
getmem(mappedfilename,256);
try
listview1.Clear;
//query the process for the memory regions
address:=0;
mbi.RegionSize:=$1000;
while (Virtualqueryex(processhandle,pointer(address),mbi,sizeof(mbi))<>0) and ((address+mbi.RegionSize)>address) do
while (GetRegionInfo(processhandle,pointer(address),mbi,sizeof(mbi), mappedfilename)<>0) and ((address+mbi.RegionSize)>address) do
begin
setlength(moreinfo,length(moreinfo)+1);
moreinfo[length(moreinfo)-1].address:=ptrUint(mbi.BaseAddress);
@ -151,19 +148,12 @@ begin
listview1.Items[listview1.Items.Count-1].SubItems.add(inttohex(mbi.regionsize,1));
// if mbi._Type=MEM_MAPPED then
begin
i:=GetMappedFileName(processhandle,mbi.BaseAddress, mappedfilename, 255);
mappedfilename[i]:=#0;
listview1.Items[listview1.Items.Count-1].SubItems.Add(mappedfilename);
end;
listview1.Items[listview1.Items.Count-1].SubItems.Add(mappedfilename);
inc(address,mbi.RegionSize);
end;
finally
freemem(mappedfilename);
end;
end;

View File

@ -237,13 +237,18 @@ begin
l:=penv^.GetArrayLength(penv, offsets);
// log('the offsets array length='+inttostr(l));
iscopy:=0;
offsetlist:=PJintArray(penv^.GetIntArrayElements(penv,offsets, iscopy));
if offsetlist<>nil then
begin
setlength(r.pointeroffsets, l);
for i:=0 to l-1 do
r.pointeroffsets[i]:=offsetlist[i];
setlength(r.pointeroffsets, l);
for i:=0 to l-1 do
r.pointeroffsets[i]:=offsetlist[i];
penv^.ReleaseIntArrayElements(penv, offsets, PJint(offsetlist),0);
penv^.ReleaseIntArrayElements(penv, offsets, PJint(offsetlist),JNI_ABORT);
end
else
log('offsetlist=nil');
end;

View File

@ -39,10 +39,20 @@ begin
end;
end;
const methodcount=2;
function symbolhandler_inModule(PEnv: PJNIEnv; Obj: JObject; address: jlong): jboolean; cdecl;
begin
if symhandler.inModule(address) then
result:=1
else
result:=0;
end;
const methodcount=3;
var jnimethods: array [0..methodcount-1] of JNINativeMethod =(
(name: 'getAddressFromName'; signature: '(Ljava/lang/String;)J'; fnPtr: @symbolhandler_getAddressFromName),
(name: 'getAddressFromName'; signature: '(Ljava/lang/String;Z)J'; fnPtr: @symbolhandler_getAddressFromName2)
(name: 'getAddressFromName'; signature: '(Ljava/lang/String;Z)J'; fnPtr: @symbolhandler_getAddressFromName2),
(name: 'inModule'; signature: '(J)Z'; fnPtr: @symbolhandler_inModule)
);
procedure InitializeJniSymbolHandler(env: PJNIEnv);
@ -50,7 +60,6 @@ var c: jclass;
begin
c:=env^.FindClass(env, 'org/cheatengine/SymbolHandler');
env^.RegisterNatives(env, c, @jnimethods[0], methodcount);
end;
end.

View File

@ -137,6 +137,10 @@ begin
scanvalue2:=jniGetString(penv, sv2);
protectionflags:=jniGetString(penv, pf);
log('scanvalue1='+scanvalue1);
log('scanvalue2='+scanvalue2);
log('protectionflags='+protectionflags);
ms.parseProtectionflags(protectionflags);
ms.firstscan(TScanOption(scanOption), TVariableType(variabletype), TRoundingType(roundingtype), scanvalue1, scanvalue2, startaddress, stopaddress, hexadecimal<>0, binaryasstring<>0, unicode<>0, casesensitive<>0, TFastScanMethod(fastscanmethod), jnigetstring(penv, fastscanparameter), nil);
end;

View File

@ -4656,10 +4656,15 @@ end;
procedure TScanner.execute;
begin
(*
{$if defined(cpui386) or defined(cpux86_64)}
Set8087CW($133f); //disable floating point exceptions in this thread
SetSSECSR($1f80);
{$endif}
*)
SetExceptionMask([exInvalidOp, exDenormalized, exZeroDivide, exOverflow, exUnderflow, exPrecision]);
try
scanwriter:=TScanfilewriter.create(self,self.OwningScanController,addressfile,memoryfile);
@ -4683,6 +4688,8 @@ begin
haserror:=true;
errorstring:='thread '+inttostr(scannernr)+':'+e.message;
log('Scanner exception:'+errorstring);
//tell all siblings to terminate, something messed up
//and I can just do this, since the ScanController is waiting for us, and terminate is pretty much atomic
//for i:=0 to length(OwningScanController.scanners)-1 do
@ -6648,6 +6655,10 @@ var i: integer;
currentstate: Tscanregionpreference;
begin
//parse the protectionflags string and set scanWritable, scanExecutable and scanCopyOnWrite;
scanWritable:=scanDontCare;
scanCopyOnWrite:=scanDontCare;
scanExecutable:=scanDontCare;
protectionflags:=uppercase(protectionflags);
currentstate:=scanDontCare;

View File

@ -94,6 +94,8 @@ type
function VirtualQueryEx_StartCache(hProcess: THandle; flags: DWORD): boolean;
procedure VirtualQueryEx_EndCache(hProcess: THandle);
function GetRegionInfo(hProcess: THandle; lpAddress: Pointer; var lpBuffer: TMemoryBasicInformation; dwLength: DWORD; var mapsline: string): DWORD;
function ReadProcessMemory(hProcess: THandle; lpBaseAddress: Pointer; lpBuffer: Pointer; nSize: DWORD; var lpNumberOfBytesRead: PTRUINT): BOOL;
function WriteProcessMemory(hProcess: THandle; const lpBaseAddress: Pointer; lpBuffer: Pointer; nSize: DWORD; var lpNumberOfBytesWritten: PTRUINT): BOOL;
procedure beginWriteProcessMemory;
@ -111,6 +113,9 @@ type
function loadModule(hProcess: THandle; modulepath: string): boolean;
function loadExtension(hProcess: Thandle): boolean;
function speedhack_setSpeed(hProcess: THandle; speed: single): boolean;
procedure TerminateServer;
property connected: boolean read fConnected;
constructor create;
@ -166,6 +171,16 @@ const
//
CMD_VIRTUALQUERYEXFULL=31;
CMD_GETREGIONINFO=32; //extended version of VirtualQueryEx which also get the full string
procedure TCEConnection.TerminateServer;
var command: byte;
begin
command:=CMD_TERMINATESERVER;
send(@command, sizeof(command));
end;
@ -360,10 +375,20 @@ var pages: array of TPageInfo;
m: PByte;
begin
//log(format('TCEConnection.CReadProcessMemory: Read %d bytes from %p into %p',[nsize, lpBaseAddress, lpBuffer]));
result:=false;
lpNumberOfBytesRead:=0;
pagecount:=1+((ptruint(lpBaseAddress)+nSize-1) shr 12) - (ptruint(lpBaseAddress) shr 12);
currenttarget:=ptruint(lpBaseAddress)+nsize-1;
if currenttarget<ptruint(lpBaseAddress) then //overflow
begin
pagecount:=2+(currenttarget shr 12);
end
else
pagecount:=1+((ptruint(lpBaseAddress)+nSize-1) shr 12) - (ptruint(lpBaseAddress) shr 12);
setlength(pages, pagecount);
QueryPerformanceFrequency(freq);
@ -530,8 +555,13 @@ end;
function TCEConnection.ReadProcessMemory(hProcess: THandle; lpBaseAddress: Pointer; lpBuffer: Pointer; nSize: DWORD; var lpNumberOfBytesRead: PTRUINT): BOOL;
begin
// log(format('TCEConnection.ReadProcessMemory: Read %d bytes from %p into %p',[nsize, lpBaseAddress, lpBuffer]));
if ((hProcess shr 24) and $ff)= $ce then
begin
// Log('hProcess is valid');
result:=false;
lpNumberOfBytesRead:=0;
@ -541,10 +571,14 @@ begin
if (nsize<=8192) then
begin
//log('nsize<=8192. Calling CReadProcessMemory');
result:=CReadProcessMemory(hProcess, lpBaseAddress, lpBuffer, nsize, lpNumberOfBytesRead);
end
else //just fetch it all from the net , ce usually does not fetch more than 8KB for random accesses, so would be a waste of time
begin
// log('nsize>8192. Calling NReadProcessMemory');
result:=NReadProcessMemory(hProcess, lpBaseaddress, lpbuffer, nsize, lpNumberOfBytesRead);
end;
@ -971,6 +1005,8 @@ var
vqecache: TVirtualQueryExCache;
begin
result:=0;
if VirtualQueryExCacheMap.TryGetValue(hProcess, vqecache) then //check if there is a cache going on for this handle
begin
//yes, get it from the cache
@ -1030,6 +1066,93 @@ begin
end;
end;
function TCEConnection.GetRegionInfo(hProcess: THandle; lpAddress: Pointer; var lpBuffer: TMemoryBasicInformation; dwLength: DWORD; var mapsline: string): DWORD;
var
input: packed record
command: byte;
handle: integer;
baseaddress: qword;
end;
output: packed record
result: byte;
protection: dword;
_type: dword;
baseaddress: qword;
size: qword;
end;
mapslinesize: byte;
ml: pchar;
begin
result:=0;
log('TCEConnection.GetRegionInfo');
if isNetworkHandle(hProcess) then
begin
log('valid handle');
result:=0;
input.command:=CMD_GETREGIONINFO;
input.handle:=hProcess and $ffffff;
input.baseaddress:=qword(lpAddress);
if send(@input, sizeof(input))>0 then
begin
if receive(@output, sizeof(output))>0 then
begin
if output.result>0 then
begin
lpBuffer.BaseAddress:=pointer(output.baseaddress);
lpBuffer.AllocationBase:=lpBuffer.BaseAddress;
lpbuffer.AllocationProtect:=PAGE_NOACCESS;
lpbuffer.Protect:=output.protection;
if output.protection=PAGE_NOACCESS then
begin
lpbuffer.State:=MEM_FREE;
lpbuffer._Type:=0;
end
else
begin
lpbuffer.State:=MEM_COMMIT;
lpbuffer._Type:=output._type;
end;
lpbuffer.RegionSize:=output.size;
result:=dwlength;
end
else
result:=0;
end;
//extended part of CMD_GETREGIONINFO;
log('receiving extended state');
if receive(@mapslinesize, sizeof(mapslinesize))>0 then
begin
log('received extended state');
log('mapelinesize='+inttostr(mapslinesize));
getmem(ml, mapslinesize+1);
if (ml<>nil) then
begin
receive(ml, mapslinesize);
ml[mapslinesize]:=#0;
mapsline:=ml;
freemem(ml);
end;
end;
end;
end;
end;
function TCEConnection.OpenProcess(dwDesiredAccess:DWORD; bInheritHandle:WINBOOL; dwProcessId:DWORD):HANDLE;
var OpenProcessCommand: packed record
command: byte;
@ -1685,9 +1808,12 @@ begin
else
begin
inc(retry);
OutputDebugString('fail '+inttostr(retry));
// OutputDebugString('fail '+inttostr(retry));
end;
end;
if not fconnected then
OutputDebugString('Connection failure');
end;
destructor TCEConnection.destroy;

View File

@ -8,7 +8,7 @@ uses
{$ifdef JNI}
Classes, SysUtils, networkinterface, unixporthelper, newkernelhandler;
{$else}
{jwawindows,} windows, Classes, SysUtils, networkinterface, newkernelhandler;
{jwawindows,} windows, Classes, SysUtils, networkinterface, newkernelhandler, CEFuncProc;
{$endif}
@ -34,6 +34,7 @@ function NetworkCloseHandle(handle: THandle):WINBOOL; stdcall;
function NetworkSetBreakpoint(handle: THandle; threadid: integer; debugregister: integer; address: PtrUInt; bptype: integer; bpsize: integer): boolean;
function NetworkRemoveBreakpoint(handle: THandle; threadid: integer; debugregister: integer; wasWatchpoint: boolean): boolean;
function NetworkGetRegionInfo(hProcess: THandle; lpAddress: Pointer; var lpBuffer: TMemoryBasicInformation; dwLength: DWORD; var mapsline: string): DWORD; stdcall;
implementation
@ -166,27 +167,47 @@ function NetworkReadProcessMemory(hProcess: THandle; lpBaseAddress, lpBuffer: Po
var a,b: dword;
c,d: ptruint;
begin
//log('NetworkReadProcessMemory');
//log(format('Read %d bytes from %p into %p',[nsize, lpBaseAddress, lpBuffer]));
if getConnection<>nil then
begin
// log('Has connection');
result:=connection.readProcessMemory(hProcess, lpBaseAddress, lpBuffer, nSize, lpNumberOfBytesRead);
if (result=false) and (connection.connected=false) and (getConnection<>nil) then //try again one more time
begin
// log('read fail1. Try smaller chunk');
//try a smaller chunk
a:=nsize div 2;
b:=nsize-a;
c:=0;
d:=0;
result:=connection.readProcessMemory(hProcess, lpBaseAddress, lpBuffer, a, c);
if result and (b>0) then
result:=connection.readProcessMemory(hProcess, pointer(ptruint(lpBaseAddress)+a), pointer(ptruint(lpBuffer)+a), b, d);
lpNumberOfBytesRead:=c+d;
//log('a='+inttostr(a));
// log('b='+inttostr(b));
result:=connection.readProcessMemory(hProcess, lpBaseAddress, lpBuffer, a, c);
// log('after read 1/2');
if result and (b>0) and (c>0) then //first read succesful, there is something else to read, and it actually has read
begin
result:=connection.readProcessMemory(hProcess, pointer(ptruint(lpBaseAddress)+a), pointer(ptruint(lpBuffer)+a), b, d);
// log('after read 2/2');
end;
if @lpNumberOfBytesRead<>nil then
lpNumberOfBytesRead:=c+d;
end;
end
else
result:=false;
//log('Returning from rpm');
end;
function NetworkWriteProcessMemory(hProcess: THandle; const lpBaseAddress: Pointer; lpBuffer: Pointer; nSize: DWORD; var lpNumberOfBytesWritten: ptruint): BOOL; stdcall;
@ -198,6 +219,14 @@ begin
end;
function NetworkGetRegionInfo(hProcess: THandle; lpAddress: Pointer; var lpBuffer: TMemoryBasicInformation; dwLength: DWORD; var mapsline: string): DWORD; stdcall;
begin
if getConnection<>nil then
result:=connection.GetRegionInfo(hProcess, lpAddress, lpBuffer, dwLength, mapsline)
else
result:=0;
end;
function NetworkVirtualQueryEx(hProcess: THandle; lpAddress: Pointer; var lpBuffer: TMemoryBasicInformation; dwLength: DWORD): DWORD; stdcall;
begin
if getConnection<>nil then
@ -298,6 +327,8 @@ begin
newkernelhandler.VirtualFreeEx:=@networkVirtualFreeEx;
newkernelhandler.CreateRemoteThread:=@networkCreateRemoteThread;
newkernelhandler.GetRegionInfo:=@NetworkGetRegionInfo;
newkernelhandler.VirtualQueryEx_StartCache:=@NetworkVirtualQueryEx_StartCache;