mirror of
https://github.com/cheat-engine/cheat-engine
synced 2026-08-15 02:26:08 -04:00
3273 lines
88 KiB
ObjectPascal
3273 lines
88 KiB
ObjectPascal
unit CEFuncProc;
|
|
//This version of CEFuncProc has been COPIED to the server dir
|
|
//Cheat Engine regular WONT look at this
|
|
|
|
interface
|
|
|
|
uses Windows,StdCtrls,Classes,SysUtils,dialogs,tlhelp32,forms,messages,
|
|
Graphics,
|
|
ComCtrls,
|
|
reinit,
|
|
assemblerunit,
|
|
imagehlp,
|
|
registry,
|
|
|
|
{$ifdef netclient}
|
|
netapis,
|
|
{$else}
|
|
NewKernelHandler,
|
|
{$ifndef standalonetrainer}
|
|
{$ifndef netserver}
|
|
hypermode,
|
|
firstscanhandler,
|
|
{$endif}
|
|
{$endif}
|
|
{$endif}
|
|
math,syncobjs, shellapi, ProcessHandlerUnit;
|
|
|
|
//memscan
|
|
type TScanOption=(soUnknownValue,soExactValue,soValueBetween,soBiggerThan,soSmallerThan, soIncreasedValue, soIncreasedValueBy, soDecreasedValue, soDecreasedValueBy, soChanged, soUnchanged, soSameAsFirst, soCustom);
|
|
type TScanType=(stNewScan, stFirstScan, stNextScan);
|
|
type TRoundingType=(rtRounded,rtExtremerounded,rtTruncated);
|
|
type TVariableType=(vtByte, vtWord, vtDword, vtQword, vtSingle, vtDouble, vtString, vtUnicodeString, vtByteArray, vtBinary, vtAll, vtCustom, vtPointer);
|
|
type TCustomScanType=(cstNone, cstAutoAssembler, cstCPP, cstDLLFunction);
|
|
|
|
|
|
type PUINT64 = ^uint64;
|
|
Type TBytes = array of integer; //An array that represents a row of byte. Ints are used to be able to represent wildcards (-1)
|
|
type tfloatscan=(rounded,extremerounded,truncated);
|
|
Type TMemoryRegion = record
|
|
BaseAddress: Dword;
|
|
MemorySize: Dword;
|
|
IsChild: boolean; //means there is a region before it
|
|
startaddress: pointer; //pointer to a spot in the whole memory copy, it means the start of this region
|
|
end;
|
|
type TMemoryRegions = array of TMemoryRegion;
|
|
type PMemoryRegions = ^TMemoryRegions;
|
|
|
|
type TBitAddress = record
|
|
address: dword;
|
|
bit: dword;
|
|
end;
|
|
|
|
type TBitAddressArray=array [0..0] of TBitAddress;
|
|
type PBitAddressArray=^TBitAddressArray;
|
|
|
|
type TProcessListInfo=record
|
|
processID: dword;
|
|
processIcon: HICON;
|
|
end;
|
|
PProcessListInfo=^TProcessListInfo;
|
|
|
|
type TFreememoryThread = class(tthread)
|
|
public
|
|
Bitscan: array of byte;
|
|
tempbits: array of byte;
|
|
FoundAddress: array of dword;
|
|
FoundValue1:Array of Byte;
|
|
FoundValue2:Array of word;
|
|
FoundValue3:Array of Dword;
|
|
FoundValue7:Array of Int64;
|
|
FoundValue8:array of byte;
|
|
FoundValue4:Array of Single;
|
|
FoundValue5:Array of Double;
|
|
foundValue6:Array of int64; //byte ?????
|
|
FoundValue1switch:Array of Byte;
|
|
FoundValue2switch:Array of word;
|
|
FoundValue3switch:Array of Dword;
|
|
FoundValue7switch:Array of Int64;
|
|
FoundValue8switch:array of byte;
|
|
FoundValue4switch:Array of Single;
|
|
FoundValue5switch:Array of Double;
|
|
foundValue6switch:Array of int64;
|
|
|
|
foundaddressB: array of TBitAddress;
|
|
previousmemory: array of byte;
|
|
|
|
SearchAddress: array of dword;
|
|
SearchAddressB: array of TBitAddress;
|
|
|
|
previousmemory1: array of Byte;
|
|
previousmemory2: array of word;
|
|
previousmemory3: array of dword;
|
|
previousmemory4: array of Single;
|
|
previousmemory5: array of Double;
|
|
previousmemory6: array of int64; //Byte;
|
|
PreviousMemory7: Array of Int64;
|
|
PreviousMemory8: array of byte;
|
|
previousmemory1switch: array of Byte;
|
|
previousmemory2switch: array of word;
|
|
previousmemory3switch: array of dword;
|
|
previousmemory4switch: array of Single;
|
|
previousmemory5switch: array of Double;
|
|
previousmemory6switch: array of int64; //Byte;
|
|
PreviousMemory7switch: Array of Int64;
|
|
PreviousMemory8switch: array of byte;
|
|
|
|
Memory: ^Byte;
|
|
memory2: ^byte;
|
|
bytes: array of integer; //-1=wildcard
|
|
bytearray: array of byte;
|
|
|
|
procedure execute; override;
|
|
end;
|
|
|
|
|
|
|
|
function ConvertHexStrToRealStr(const s: string): string;
|
|
function HexStrToInt(const S: string): Integer;
|
|
function HexStrToInt64(const S: string): Int64;
|
|
|
|
function readAndParseAddress(address: dword; variableType: TVariableType): string;
|
|
function isjumporcall(address: dword; var addresstojumpto: dword): boolean;
|
|
{
|
|
procedure quicksortmemoryregions(lo,hi: integer); //obsolete
|
|
}
|
|
|
|
procedure rewritecode(processhandle: thandle; address:dword; buffer: pointer; size:dword);
|
|
procedure rewritedata(processhandle: thandle; address:dword; buffer: pointer; size:dword);
|
|
|
|
procedure GetProcessList(ProcessList: TListBox); overload;
|
|
procedure GetProcessList(ProcessList: TStrings); overload;
|
|
procedure GetWindowList(ProcessList: TListBox; showInvisible: boolean=true);
|
|
function AvailMem:dword;
|
|
function isreadable(address:dword):boolean;
|
|
|
|
|
|
procedure RemoveAddress(address: Dword;bit: Byte; vartype: Integer);
|
|
|
|
function GetCEdir:string;
|
|
procedure Open_Process;
|
|
Procedure Shutdown;
|
|
function KeyToStr(key:word):string;
|
|
|
|
function undolastscan(valtype: integer;hexadecimal:boolean): integer;
|
|
|
|
procedure ConvertStringToBytes(scanvalue:string; hex:boolean;var bytes: TBytes);
|
|
function getbit(bitnr: integer; bt: dword):integer;
|
|
procedure setbit(bitnr: integer; var bt: Byte;state:integer); overload;
|
|
procedure setbit(bitnr: integer; var bt: dword;state:integer); overload;
|
|
|
|
function eflags_setCF(flagvalue: dword; value: integer): DWORD;
|
|
function eflags_setPF(flagvalue: dword; value: integer): DWORD;
|
|
function eflags_setAF(flagvalue: dword; value: integer): DWORD;
|
|
function eflags_setZF(flagvalue: dword; value: integer): DWORD;
|
|
function eflags_setSF(flagvalue: dword; value: integer): DWORD;
|
|
function eflags_setTF(flagvalue: dword; value: integer): DWORD;
|
|
function eflags_setIF(flagvalue: dword; value: integer): DWORD;
|
|
function eflags_setDF(flagvalue: dword; value: integer): DWORD;
|
|
function eflags_setOF(flagvalue: dword; value: integer): DWORD;
|
|
function eflags_setIOPL(flagvalue: dword; value: integer): DWORD;
|
|
function eflags_setNT(flagvalue: dword; value: integer): DWORD;
|
|
function eflags_setRF(flagvalue: dword; value: integer): DWORD;
|
|
function eflags_setVM(flagvalue: dword; value: integer): DWORD;
|
|
function eflags_setAC(flagvalue: dword; value: integer): DWORD;
|
|
function eflags_setVIF(flagvalue: dword; value: integer): DWORD;
|
|
function eflags_setVIP(flagvalue: dword; value: integer): DWORD;
|
|
function eflags_setID(flagvalue: dword; value: integer): DWORD;
|
|
|
|
|
|
|
|
|
|
function ByteStringToText(s: string;hex: boolean):string;
|
|
function ByteStringToDouble(s: string;hex: boolean):double;
|
|
function ByteStringToSingle(s: string;hex: boolean):single;
|
|
function ByteStringToInt(s: string;hex: boolean):int64;
|
|
function VarToBytes(v: pointer; size: integer): string;
|
|
function RawToString(const buf: array of byte; vartype: integer;showashex: boolean; bufsize: integer):string;
|
|
function IntToBin(i: int64):string;
|
|
function BinToInt(s: string): int64;
|
|
|
|
procedure decimal(var key: char);
|
|
procedure hexadecimal(var key: char);
|
|
|
|
function GetSystemType: Integer;
|
|
|
|
|
|
procedure ToggleOtherWindows;
|
|
|
|
Procedure InjectDll(dllname: string; functiontocall: string='');
|
|
Function GetRelativeFilePath(filename: string):string;
|
|
|
|
function GetCPUCount: integer;
|
|
function HasHyperthreading: boolean;
|
|
procedure SaveFormPosition(form: Tform; extra: array of integer);
|
|
function LoadFormPosition(form: Tform; var x: array of integer):boolean;
|
|
|
|
function heapflagstostring(heapflags: dword): string;
|
|
function allocationtypetostring(alloctype: dword): string;
|
|
function allocationprotecttostring(protect: dword): string;
|
|
function freetypetostring(freetype: dword):string;
|
|
function isAddress(address: dword):boolean;
|
|
function isExecutableAddress(address: dword):boolean;
|
|
|
|
{$ifndef standalonetrainer}
|
|
Procedure CreateCodeCave(address:dword; sourceaddress:dword; sizeofcave: integer);
|
|
{$endif}
|
|
|
|
procedure errorbeep;
|
|
|
|
|
|
|
|
{$ifndef net}
|
|
procedure SetLanguage;
|
|
|
|
{$endif}
|
|
|
|
{$ifndef standalonetrainer}
|
|
procedure DetachIfPossible;
|
|
{$endif}
|
|
|
|
procedure getexecutablememoryregionsfromregion(start: dword; stop:dword; var memoryregions: TMemoryRegions);
|
|
|
|
const
|
|
Exact_value = 0;
|
|
Increased_value = 1;
|
|
Increased_value_by = 2;
|
|
Decreased_value = 3;
|
|
Decreased_value_by = 4;
|
|
Changed_value = 5;
|
|
Unchanged_value = 6;
|
|
Advanced_Scan = 7;
|
|
String_Scan = 8;
|
|
SmallerThan = 9;
|
|
BiggerThan = 10;
|
|
Userdefined = 11; //not used
|
|
ValueBetween = 12;
|
|
SameAsFirst = 13;
|
|
|
|
splitvalue=400000;
|
|
number=600; //is my using the new value on my system arround 580000
|
|
|
|
WM_HOTKEY2=WM_USER+$800;
|
|
|
|
type
|
|
MemoryRecordcet3 = record
|
|
Description : string[50];
|
|
Address : dword;
|
|
VarType : byte;
|
|
Bit : Byte;
|
|
Frozen : boolean;
|
|
FrozenValue : Int64;
|
|
Group: Byte;
|
|
end;
|
|
|
|
type TCEPointer=record
|
|
Address: Dword; //only used when last pointer in list
|
|
Interpretableaddress: string; //same as address
|
|
offset: integer;
|
|
end;
|
|
|
|
type TCEAlloc=record
|
|
address: dword;
|
|
varname: string;
|
|
size: dword;
|
|
end;
|
|
type PCEAlloc=^TCEAlloc;
|
|
type TCEAllocArray=array of TCEAlloc;
|
|
|
|
type
|
|
MemoryRecord = record
|
|
Description : string;
|
|
Address : dword;
|
|
interpretableaddress: string;
|
|
VarType : byte;
|
|
unicode : boolean;
|
|
IsPointer: Boolean;
|
|
pointers: array of TCEPointer;
|
|
Bit : Byte;
|
|
bitlength: integer;
|
|
Frozen : boolean;
|
|
FrozenValue : Int64;
|
|
OldValue: string; //not saved
|
|
Frozendirection: integer; //0=always freeze,1=only freeze when going up,2=only freeze when going down
|
|
Group: Byte;
|
|
ShowAsHex: boolean;
|
|
autoassemblescript: string;
|
|
allocs: TCEAllocArray;
|
|
end;
|
|
|
|
type
|
|
MemoryRecordOld = record
|
|
Description : string[50];
|
|
Address : dword;
|
|
VarType : byte;
|
|
Frozen : boolean;
|
|
FrozenValue : Dword;
|
|
end;
|
|
|
|
type TDwordArray=array[0..100] of dword;
|
|
type PDwordArray=^TDwordArray;
|
|
|
|
type TSingleArray=array[0..100] of single;
|
|
type PSingleArray=^TSingleArray;
|
|
|
|
type TdoubleArray=array[0..100] of double;
|
|
type PdoubleArray=^TdoubleArray;
|
|
|
|
type Tint64Array=array[0..100] of int64;
|
|
type Pint64Array=^Tint64Array;
|
|
|
|
type Tuint64Array=array[0..100] of uint64;
|
|
type Puint64Array=^Tuint64Array;
|
|
|
|
|
|
|
|
type TScanSettings = record
|
|
UseHyperscan: boolean;
|
|
scanning: boolean;
|
|
CEProcessID: dword;
|
|
CEMainThreadID: Dword;
|
|
applicantionhandle: thandle;
|
|
mainformHandle: THandle;
|
|
formscanningHandle: THandle;
|
|
hyperscanwindow: Thandle;
|
|
StartAddress: Dword;
|
|
StopAddress: Dword;
|
|
Scantype: Integer;
|
|
ValueType: Integer;
|
|
roundingtype: tfloatscan;
|
|
scan:byte;
|
|
readonly: boolean;
|
|
FastScan: boolean;
|
|
Hexadecimal: boolean;
|
|
unicode: boolean;
|
|
percentage: boolean;
|
|
LowMemoryUsage: boolean;
|
|
Skip_PAGE_NOCACHE:boolean;
|
|
scan_mem_private:boolean;
|
|
scan_mem_image:boolean;
|
|
scan_mem_mapped: boolean;
|
|
scanvalue: string[255];
|
|
scanvalue2: string[255];
|
|
CheatEngineDir: string[255];
|
|
buffersize:dword;
|
|
priority:integer;
|
|
nrofbits:integer;
|
|
bitstring: string[255];
|
|
bitoffsetchange: integer;
|
|
asktocontinue: boolean;
|
|
HookDirect3d: boolean;
|
|
HookOpenGL: boolean;
|
|
PacketEditor: boolean;
|
|
Stealthed: boolean;
|
|
hooknewprocesses: boolean;
|
|
end;
|
|
|
|
type tspeedhackspeed=record
|
|
speed: single;
|
|
sleeptime: dword;
|
|
end;
|
|
|
|
type TKeyCombo=array [0..4] of word;
|
|
type TKeys=record
|
|
configured: boolean;
|
|
CEDir: string[255];
|
|
cewindow: thandle;
|
|
|
|
callibrationmode: boolean; //false=no textureselect hud
|
|
callibrationkey: TKeycombo;
|
|
|
|
setcallibration: boolean;
|
|
mousecallibrationhorizontal1point: single;
|
|
mousecallibrationvertical1point: single;
|
|
|
|
mousecallibrationhorizontal2point: single;
|
|
mousecallibrationvertical2point: single;
|
|
|
|
mousecallibrationhorizontal5point: single;
|
|
mousecallibrationvertical5point: single;
|
|
|
|
mousecallibrationhorizontal10point: single;
|
|
mousecallibrationvertical10point: single;
|
|
|
|
mousecallibrationhorizontal20point: single;
|
|
mousecallibrationvertical20point: single;
|
|
|
|
mousecallibrationhorizontal40point: single;
|
|
mousecallibrationvertical40point: single;
|
|
|
|
loadaimsettingsfile: tkeycombo;
|
|
saveaimsettingsfile: tkeycombo;
|
|
aimsettings1: string[255];
|
|
Aimsettings2: string[255];
|
|
Aimsettings3: string[255];
|
|
|
|
setaimsetting1: tkeycombo;
|
|
setaimsetting2: tkeycombo;
|
|
setaimsetting3: tkeycombo;
|
|
|
|
nexttexture: tkeycombo;
|
|
previoustexture: tkeycombo;
|
|
locktexture: tkeycombo;
|
|
|
|
IncreaseX: tkeycombo;
|
|
DecreaseX: TKeyCombo;
|
|
Increasey: tkeycombo;
|
|
Decreasey: TKeyCombo;
|
|
Increasez: tkeycombo;
|
|
Decreasez: TKeyCombo;
|
|
|
|
HoldAutoaimtoggle: boolean;
|
|
autoshoot: boolean;
|
|
autoaimtoggle: tKeycombo;
|
|
increaselag: tkeycombo;
|
|
decreaselag: tkeycombo;
|
|
|
|
zoomin,zoomout: TKeyCombo;
|
|
nozoom: tKeyCombo;
|
|
zoom1: tKeyCombo;
|
|
zoomlevel1: single;
|
|
zoom2: tkeycombo;
|
|
zoomlevel2: single;
|
|
zoom3: tkeycombo;
|
|
zoomlevel3: single;
|
|
zoom4: tkeycombo;
|
|
zoomlevel4: single;
|
|
zoom5: tkeycombo;
|
|
zoomlevel5: single;
|
|
|
|
zoomdelta: single;
|
|
lagdelta: integer;
|
|
|
|
setlag: boolean;
|
|
lagtoset: dword;
|
|
usefpslag: boolean;
|
|
|
|
rotateleft: tKeycombo;
|
|
rotateright: tkeycombo;
|
|
rotateup: tkeycombo;
|
|
rotatedown: tkeycombo;
|
|
moveleft: tkeycombo;
|
|
moveright: tkeycombo;
|
|
moveup: tkeycombo;
|
|
movedown: tkeycombo;
|
|
moveforward: tkeycombo;
|
|
movebackwards: tkeycombo;
|
|
|
|
movespeed: single;
|
|
rotatespeed: single;
|
|
|
|
setcameraback: tkeycombo;
|
|
|
|
zbuffer: tkeycombo;
|
|
fog: tkeycombo;
|
|
lighting: tkeycombo;
|
|
wireframe: tkeycombo;
|
|
|
|
ShowKeylist: tkeycombo;
|
|
|
|
SaveAlltextures: TKeycombo;
|
|
|
|
selectedlagrecord: string[50];
|
|
lagmemorytype: byte;
|
|
getlagfrommemory: boolean;
|
|
nrofoffsets: dword;
|
|
lagaddress: dword;
|
|
offset1: dword;
|
|
offset2: dword;
|
|
offset3: dword;
|
|
offset4: dword;
|
|
offset5: dword;
|
|
offset6: dword;
|
|
offset7: dword;
|
|
offset8: dword;
|
|
offset9: dword;
|
|
offset10: dword;
|
|
offset11: dword;
|
|
offset12: dword;
|
|
offset13: dword;
|
|
offset14: dword;
|
|
offset15: dword;
|
|
|
|
|
|
pollinginterval: integer;
|
|
end;
|
|
type PKeys= ^TKeys;
|
|
|
|
type TKeys2=record
|
|
configured: boolean;
|
|
CEDir: string[255];
|
|
cewindow: thandle;
|
|
|
|
textures: tkeycombo;
|
|
lighting: tkeycombo;
|
|
depthtest: tkeycombo;
|
|
fog: tkeycombo;
|
|
|
|
|
|
zoomin,zoomout: TKeyCombo;
|
|
nozoom: tKeyCombo;
|
|
zoom1: tKeyCombo;
|
|
zoomlevel1: single;
|
|
zoom2: tkeycombo;
|
|
zoomlevel2: single;
|
|
zoom3: tkeycombo;
|
|
zoomlevel3: single;
|
|
zoom4: tkeycombo;
|
|
zoomlevel4: single;
|
|
zoom5: tkeycombo;
|
|
zoomlevel5: single;
|
|
|
|
zoomdelta: single;
|
|
|
|
|
|
pollinginterval: integer;
|
|
end;
|
|
type PKeys2= ^TKeys2;
|
|
|
|
|
|
|
|
function ConvertKeyComboToString(x: tkeycombo):string;
|
|
|
|
{
|
|
ProcessID and ProcessHandle as functions untill all code has been converted to
|
|
make use of ProcessHandlerUnit
|
|
}
|
|
function ProcessID: dword;
|
|
function ProcessHandle: THandle;
|
|
|
|
//Global vars:
|
|
var
|
|
old8087CW: word; //you never know...
|
|
ProcessSelected: Boolean;
|
|
//ProcessID: Dword; //deperecated
|
|
//ProcessHandle: Thandle;
|
|
|
|
Skip_PAGE_NOCACHE: boolean=false;
|
|
Scan_MEM_PRIVATE: boolean=true;
|
|
Scan_MEM_IMAGE: boolean=true;
|
|
Scan_MEM_MAPPED: boolean=false;
|
|
|
|
CheatEngineDir: String;
|
|
WindowsDir: string;
|
|
GetProcessIcons: Boolean;
|
|
ProcessesWithIconsOnly: boolean;
|
|
|
|
//scanhelpers
|
|
nrofbits: integer;
|
|
Bitscan: array of byte;
|
|
tempbits: array of byte;
|
|
|
|
bitoffsetchange: integer;
|
|
|
|
FoundValue1:Array of Byte;
|
|
FoundValue1switch:Array of Byte;
|
|
|
|
FoundValue2:Array of word;
|
|
FoundValue2switch:Array of word;
|
|
|
|
FoundValue3:Array of Dword;
|
|
FoundValue3switch:Array of Dword;
|
|
|
|
FoundValue4:Array of Single;
|
|
FoundValue4switch:Array of Single;
|
|
|
|
FoundValue5:Array of Double;
|
|
FoundValue5switch:Array of Double;
|
|
|
|
foundValue6:Array of int64;
|
|
foundValue6switch:Array of int64;
|
|
|
|
FoundValue7:Array of Int64;
|
|
FoundValue7switch:Array of Int64;
|
|
|
|
FoundValue8:array of byte;
|
|
FoundValue8switch:array of byte;
|
|
|
|
FoundAddress: array of dword;
|
|
FoundAddressSwitch: array of dword;
|
|
|
|
foundaddressB: array of TBitAddress;
|
|
foundaddressBswitch: array of TBitAddress;
|
|
|
|
|
|
tempbytearray: array of byte;
|
|
tempwordarray: array of word;
|
|
tempdwordarray: array of dword;
|
|
tempsinglearray: array of single;
|
|
tempdoublearray: array of double;
|
|
tempint64array: array of int64;
|
|
|
|
|
|
//--------
|
|
previousmemory: array of byte;
|
|
|
|
SearchAddress: array of dword;
|
|
searchaddressswitch: array of dword;
|
|
|
|
SearchAddressB: array of TBitAddress;
|
|
|
|
previousmemory1,previousmemory1switch: array of Byte;
|
|
previousmemory2,previousmemory2switch: array of word;
|
|
previousmemory3,previousmemory3switch: array of dword;
|
|
previousmemory4,previousmemory4switch: array of Single;
|
|
previousmemory5,previousmemory5switch: array of Double;
|
|
previousmemory6,previousmemory6switch: array of int64; //Byte;
|
|
PreviousMemory7,previousmemory7switch: Array of Int64;
|
|
PreviousMemory8,previousmemory8switch: array of byte;
|
|
|
|
//---------
|
|
helpstr,helpstr2: string;
|
|
bytes: array of integer; //-1=wildcard
|
|
bytearray: array of byte;
|
|
|
|
|
|
|
|
// MemoryRegion: array of TMemoryRegion;
|
|
// MemoryRegions: Integer;
|
|
|
|
// Memory: Array of Byte;
|
|
Memory: ^Byte;
|
|
memory2: ^byte;
|
|
|
|
|
|
advanced: boolean;
|
|
//global files, so when an exception happens I can close them
|
|
addressfile, memoryfile: File;
|
|
newAddressfile,newmemoryfile: File;
|
|
|
|
buffersize: dword=512*1024;
|
|
overridedebug: boolean;
|
|
|
|
totalbytes: dword;
|
|
currentbyte: dword;
|
|
|
|
|
|
//hide/show windows
|
|
windowlist: array of thandle;
|
|
lastforeground,lastactive: thandle;
|
|
donthidelist: array of string;
|
|
onlyfront: boolean;
|
|
allwindowsareback:boolean;
|
|
|
|
HyperscanFileMapping: THandle;
|
|
HyperscanView: ^TScanSettings;
|
|
|
|
hookedin:boolean;
|
|
keys: PKeys;
|
|
keys2: PKeys2;
|
|
keysfilemapping: THandle;
|
|
|
|
//stealth globals
|
|
le: dword;
|
|
ownprocesshandle: THandle;
|
|
stealthhook: thandle;
|
|
|
|
//windows version data
|
|
iswin2kplus: boolean;
|
|
scanpriority: TThreadPriority;
|
|
|
|
{$ifndef standalonetrainer}
|
|
{$ifndef net}
|
|
hypermode: thypermode;
|
|
useAPCtoInjectDLL: boolean;
|
|
{$endif}
|
|
{$endif}
|
|
|
|
tempdir: pchar;
|
|
|
|
|
|
processhandler: TProcessHandler;
|
|
|
|
implementation
|
|
|
|
{$ifdef net}
|
|
uses disassembler,debugger;
|
|
{$endif}
|
|
|
|
{$ifndef net}
|
|
|
|
{$ifndef standalonetrainer}
|
|
uses disassembler,debugger,symbolhandler,frmProcessWatcherUnit,kerneldebugger, formsettingsunit;
|
|
{$else}
|
|
uses symbolhandler;
|
|
{$endif}
|
|
|
|
{$endif}
|
|
|
|
function ProcessID: dword;
|
|
begin
|
|
result:=ProcessHandler.Processid;
|
|
end;
|
|
|
|
function ProcessHandle: THandle;
|
|
begin
|
|
result:=ProcessHandler.ProcessHandle;
|
|
end;
|
|
|
|
|
|
procedure TFreememorythread.execute;
|
|
begin
|
|
setlength(bitscan,0);
|
|
setlength(tempbits,0);
|
|
setlength(FoundAddress,0);
|
|
|
|
setlength(FoundValue1,0);
|
|
setlength(FoundValue2,0);
|
|
setlength(FoundValue3,0);
|
|
setlength(FoundValue4,0);
|
|
setlength(FoundValue5,0);
|
|
setlength(foundValue6,0);
|
|
setlength(FoundValue7,0);
|
|
setlength(FoundValue8,0);
|
|
setlength(FoundValue1switch,0);
|
|
setlength(FoundValue2switch,0);
|
|
setlength(FoundValue3switch,0);
|
|
setlength(FoundValue4switch,0);
|
|
setlength(FoundValue5switch,0);
|
|
setlength(foundValue6switch,0);
|
|
setlength(FoundValue7switch,0);
|
|
setlength(FoundValue8switch,0);
|
|
|
|
|
|
//floating point notations
|
|
|
|
|
|
setlength(foundaddressB,0);
|
|
|
|
setlength(previousmemory,0);
|
|
|
|
setlength(SearchAddress,0);
|
|
setlength(SearchAddressB,0);
|
|
|
|
setlength(previousmemory1,0);
|
|
setlength(previousmemory2,0);
|
|
setlength(previousmemory3,0);
|
|
setlength(previousmemory4,0);
|
|
setlength(previousmemory5,0);
|
|
setlength(previousmemory6,0);
|
|
setlength(PreviousMemory7,0);
|
|
setlength(PreviousMemory8,0);
|
|
|
|
setlength(previousmemory1switch,0);
|
|
setlength(previousmemory2switch,0);
|
|
setlength(previousmemory3switch,0);
|
|
setlength(previousmemory4switch,0);
|
|
setlength(previousmemory5switch,0);
|
|
setlength(previousmemory6switch,0);
|
|
setlength(PreviousMemory7switch,0);
|
|
setlength(PreviousMemory8switch,0);
|
|
|
|
if not advanced then //if the lastscan was a advanced, better not whipe the memory (yet!)
|
|
begin
|
|
if memory<>nil then freemem(memory);
|
|
memory:=nil;
|
|
|
|
if memory2<>nil then freemem(memory2);
|
|
memory2:=nil;
|
|
end;
|
|
|
|
setlength(bytes,0);
|
|
setlength(bytearray,0);
|
|
end;
|
|
|
|
type TSaveDataThread=class(tthread)
|
|
public
|
|
buffer1: pointer;
|
|
buffer2: pointer;
|
|
buffersize1: dword;
|
|
buffersize2: dword;
|
|
file1: ^file;
|
|
file2: ^file;
|
|
datawritten: tevent;
|
|
dataavailable:tevent;
|
|
|
|
procedure execute; override;
|
|
constructor create(suspended:boolean);
|
|
destructor destroy; override;
|
|
end;
|
|
|
|
procedure TSaveDataThread.execute;
|
|
var ignore: dword;
|
|
begin
|
|
dataavailable.WaitFor(infinite);
|
|
while not terminated do
|
|
begin
|
|
blockwrite(file1^,buffer1^,buffersize1,ignore);
|
|
blockwrite(file2^,buffer2^,buffersize2,ignore);
|
|
|
|
datawritten.SetEvent; //tell the others that you're ready to write again
|
|
dataavailable.WaitFor(infinite); //wait for the 'ready to write' event
|
|
end;
|
|
end;
|
|
|
|
destructor TSaveDataThread.destroy;
|
|
begin
|
|
datawritten.Free;
|
|
dataavailable.free;
|
|
inherited destroy;
|
|
end;
|
|
|
|
constructor TSaveDataThread.create(suspended:boolean);
|
|
begin
|
|
datawritten:=tevent.Create(nil,false,true,'');
|
|
dataavailable:=tevent.create(nil,false,false,'');
|
|
|
|
inherited create(suspended);
|
|
end;
|
|
|
|
var FlushThread:TSaveDataThread;
|
|
|
|
procedure flushbuffer(var file1, file2:file; buffer1:pointer; buffer1size:integer; buffer2:pointer; buffer2size:integer);
|
|
begin
|
|
flushthread.datawritten.ResetEvent;
|
|
|
|
flushthread.file1:=@file1;
|
|
flushthread.file2:=@file2;
|
|
flushthread.buffer1:=buffer1;
|
|
flushthread.buffer2:=buffer2;
|
|
flushthread.buffersize1:=buffer1size;
|
|
flushthread.buffersize2:=buffer2size;
|
|
flushthread.dataavailable.SetEvent;
|
|
end;
|
|
|
|
procedure finishflushing;
|
|
begin
|
|
flushthread.datawritten.WaitFor(infinite);
|
|
flushthread.datawritten.SetEvent;
|
|
end;
|
|
|
|
//------------------------------------
|
|
|
|
type TPrefetchDataThread=class(tthread)
|
|
public
|
|
buffer1: pointer;
|
|
buffer2: pointer;
|
|
buffersize1: dword;
|
|
buffersize2: dword;
|
|
file1: ^file;
|
|
file2: ^file;
|
|
dataread: tevent;
|
|
startreading:tevent;
|
|
|
|
actualread: dword;
|
|
|
|
procedure execute; override;
|
|
constructor create(suspended:boolean);
|
|
destructor destroy; override;
|
|
end;
|
|
|
|
procedure TPrefetchDataThread.execute;
|
|
var ignore,tmp: dword;
|
|
begin
|
|
startreading.WaitFor(infinite);
|
|
|
|
while not terminated do
|
|
begin
|
|
self.actualread:=0;
|
|
blockread(file1^,buffer1^,buffersize1,tmp);
|
|
blockread(file2^,buffer2^,buffersize2,ignore);
|
|
|
|
self.actualread:=tmp;
|
|
|
|
dataread.SetEvent; //tell the others that you're ready to read again
|
|
startreading.WaitFor(infinite);
|
|
end;
|
|
end;
|
|
|
|
destructor TPrefetchDataThread.destroy;
|
|
begin
|
|
dataread.Free;
|
|
startreading.free;
|
|
inherited destroy;
|
|
end;
|
|
|
|
constructor TPrefetchDataThread.create(suspended:boolean);
|
|
begin
|
|
dataread:=tevent.Create(nil,false,true,'');
|
|
startreading:=tevent.create(nil,false,false,'');
|
|
|
|
inherited create(suspended);
|
|
end;
|
|
|
|
var PrefetchThread:TPrefetchDataThread;
|
|
|
|
procedure prefetchbuffer(var file1, file2:file; buffer1:pointer; buffer1size:integer; buffer2:pointer; buffer2size:integer);
|
|
begin
|
|
PrefetchThread.dataread.ResetEvent;
|
|
|
|
PrefetchThread.file1:=@file1;
|
|
PrefetchThread.file2:=@file2;
|
|
PrefetchThread.buffer1:=buffer1;
|
|
PrefetchThread.buffer2:=buffer2;
|
|
PrefetchThread.buffersize1:=buffer1size;
|
|
PrefetchThread.buffersize2:=buffer2size;
|
|
PrefetchThread.startreading.SetEvent;
|
|
end;
|
|
|
|
function finishprefetching:dword;
|
|
begin
|
|
PrefetchThread.dataread.WaitFor(infinite);//wait for the datread event to be set
|
|
result:=prefetchthread.actualread;
|
|
end;
|
|
|
|
procedure errorbeep;
|
|
begin
|
|
beep;
|
|
sleep(100);
|
|
beep;
|
|
sleep(100);
|
|
beep;
|
|
sleep(100);
|
|
end;
|
|
|
|
function isreadable(address:dword):boolean;
|
|
var mbi: _MEMORY_BASIC_INFORMATION;
|
|
begin
|
|
VirtualQueryEx(processhandle,pointer(address),mbi,sizeof(mbi));
|
|
result:=mbi.State=mem_commit;
|
|
end;
|
|
|
|
function RawToString(const buf: array of byte; vartype: integer;showashex: boolean; bufsize: integer):string;
|
|
var x: pchar;
|
|
i: integer;
|
|
begin
|
|
//buffsize has to match the type else error
|
|
if bufsize=0 then
|
|
begin
|
|
result:='???';
|
|
exit;
|
|
end;
|
|
|
|
try
|
|
case vartype of
|
|
0: if bufsize<>1 then result:='???' else if showashex then result:=inttohex(buf[0],2) else result:=inttostr(buf[0]);
|
|
1: if bufsize<>2 then result:='???' else if showashex then result:=inttohex(pshortint(@buf[0])^,2) else result:=inttostr(pshortint(@buf[0])^);
|
|
2: if bufsize<>4 then result:='???' else if showashex then result:=inttohex(pint(@buf[0])^,4) else result:=inttostr(pint(@buf[0])^);
|
|
3: if bufsize<>4 then result:='???' else result:=floattostr(psingle(@buf[0])^);
|
|
4: if bufsize<>8 then result:='???' else result:=floattostr(pdouble(@buf[0])^);
|
|
6: if bufsize<>4 then result:='???' else if showashex then result:=inttohex(pint64(@buf[0])^,8) else result:=inttostr(pint64(@buf[0])^);
|
|
7:
|
|
begin
|
|
getmem(x,bufsize+1);
|
|
x[bufsize]:=#0;
|
|
result:=x;
|
|
freemem(x);
|
|
end;
|
|
|
|
8: //array of bytes
|
|
begin
|
|
result:='';
|
|
for i:=0 to bufsize-1 do
|
|
result:=result+'-'+inttohex(buf[bufsize],2);
|
|
end;
|
|
|
|
else result:='not supported in this version';
|
|
end;
|
|
except
|
|
result:='Not convertable';
|
|
end;
|
|
end;
|
|
|
|
function ConvertKeyComboToString(x: tkeycombo):string;
|
|
var i: integer;
|
|
newstr: string;
|
|
begin
|
|
result:='';
|
|
for i:=0 to 4 do
|
|
if x[i]=0 then
|
|
break
|
|
else
|
|
begin
|
|
newstr:='';
|
|
case x[i] of
|
|
vk_lbutton: newstr:='Left MB';
|
|
vk_mbutton: newstr:='Middle MB';
|
|
vk_rbutton: newstr:='Right MB';
|
|
VK_BACK : newstr:='Backspace';
|
|
VK_SHIFT: newstr:='Shift';
|
|
VK_CONTROL: newstr:='Ctrl';
|
|
VK_MENU: newstr:='Alt';
|
|
VK_TAB : newstr:='Tab';
|
|
VK_CLEAR : newstr:='Clear';
|
|
VK_RETURN : newstr:='Enter';
|
|
VK_PAUSE : newstr:='Pause';
|
|
VK_CAPITAL : newstr:='Caps Lock';
|
|
VK_ESCAPE : newstr:='Esc';
|
|
VK_SPACE : newstr:='Space bar';
|
|
VK_PRIOR : newstr:='Page Up';
|
|
VK_NEXT : newstr:='Page Down';
|
|
VK_END : newstr:='End';
|
|
VK_HOME : newstr:='Home';
|
|
VK_LEFT : newstr:='Left Arrow';
|
|
VK_UP : newstr:='Up Arrow';
|
|
VK_RIGHT : newstr:='Right Arrow';
|
|
VK_DOWN : newstr:='Down Arrow';
|
|
VK_SELECT : newstr:='Select';
|
|
VK_PRINT : newstr:='Print';
|
|
VK_EXECUTE : newstr:='Execute';
|
|
VK_SNAPSHOT : newstr:='Print Screen';
|
|
VK_INSERT : newstr:='Insert';
|
|
VK_DELETE : newstr:='Delete';
|
|
VK_HELP : newstr:='Help';
|
|
VK_LWIN : newstr:='Left Windows key';
|
|
VK_RWIN : newstr:='Right Windows key';
|
|
VK_APPS : newstr:='Applications key';
|
|
VK_NUMPAD0 : newstr:='numeric 0';
|
|
VK_NUMPAD1 : newstr:='numeric 1';
|
|
VK_NUMPAD2 : newstr:='numeric 2';
|
|
VK_NUMPAD3 : newstr:='numeric 3';
|
|
VK_NUMPAD4 : newstr:='numeric 4';
|
|
VK_NUMPAD5 : newstr:='numeric 5';
|
|
VK_NUMPAD6 : newstr:='numeric 6';
|
|
VK_NUMPAD7 : newstr:='numeric 7';
|
|
VK_NUMPAD8 : newstr:='numeric 8';
|
|
VK_NUMPAD9 : newstr:='numeric 9';
|
|
VK_MULTIPLY : newstr:='numeric *';
|
|
VK_ADD : newstr:='numeric +';
|
|
VK_SEPARATOR : newstr:='numeric Separator';
|
|
VK_SUBTRACT : newstr:='numeric -';
|
|
VK_DECIMAL : newstr:='numeric .';
|
|
VK_DIVIDE : newstr:='numeric /';
|
|
VK_F1 : newstr:='F1';
|
|
VK_F2 : newstr:='F2';
|
|
VK_F3 : newstr:='F3';
|
|
VK_F4 : newstr:='F4';
|
|
VK_F5 : newstr:='F5';
|
|
VK_F6 : newstr:='F6';
|
|
VK_F7 : newstr:='F7';
|
|
VK_F8 : newstr:='F8';
|
|
VK_F9 : newstr:='F9';
|
|
VK_F10 : newstr:='F10';
|
|
VK_F11 : newstr:='F11';
|
|
VK_F12 : newstr:='F12';
|
|
VK_F13 : newstr:='F13';
|
|
VK_F14 : newstr:='F14';
|
|
VK_F15 : newstr:='F15';
|
|
VK_F16 : newstr:='F16';
|
|
VK_F17 : newstr:='F17';
|
|
VK_F18 : newstr:='F18';
|
|
VK_F19 : newstr:='F19';
|
|
VK_F20 : newstr:='F20';
|
|
VK_F21 : newstr:='F21';
|
|
VK_F22 : newstr:='F22';
|
|
VK_F23 : newstr:='F23';
|
|
VK_F24 : newstr:='F24';
|
|
VK_NUMLOCK : newstr:='Num Lock';
|
|
VK_SCROLL : newstr:='Scroll Lock';
|
|
48..57 : newstr:=chr(x[i]);
|
|
65..90 : newstr:=chr(x[i]);
|
|
else newstr:='#'+inttostr(x[i]);
|
|
end;
|
|
|
|
result:=result+newstr+'+';
|
|
end;
|
|
|
|
result:=copy(result,1,length(result)-1);
|
|
end;
|
|
|
|
procedure getexecutablememoryregionsfromregion(start: dword; stop:dword; var memoryregions: tmemoryregions);
|
|
var address: dword;
|
|
mbi: memory_basic_information;
|
|
begin
|
|
setlength(memoryregions,0);
|
|
address:=start;
|
|
while (address<stop) and (VirtualQueryEx(processhandle,pointer(address),mbi,sizeof(mbi))<>0) and ((address+mbi.RegionSize)>address) do
|
|
begin
|
|
if ((mbi.AllocationProtect and PAGE_EXECUTE)=PAGE_EXECUTE) or
|
|
((mbi.AllocationProtect and PAGE_EXECUTE_READ)=PAGE_EXECUTE_READ) or
|
|
((mbi.AllocationProtect and PAGE_EXECUTE_READWRITE)=PAGE_EXECUTE_READWRITE) or
|
|
((mbi.AllocationProtect and PAGE_EXECUTE_WRITECOPY)=PAGE_EXECUTE_WRITECOPY) then
|
|
begin
|
|
//executable
|
|
setlength(memoryregions,length(memoryregions)+1);
|
|
memoryregions[length(memoryregions)-1].BaseAddress:=dword(mbi.baseaddress);
|
|
memoryregions[length(memoryregions)-1].MemorySize:=mbi.RegionSize;
|
|
end;
|
|
|
|
inc(address,mbi.RegionSize);
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
{$ifndef standalonetrainer}
|
|
procedure FillMemoryProcess(start:dword;count:dword;fillvalue:byte);
|
|
var buf: array of byte;
|
|
original,actualwritten:dword;
|
|
begin
|
|
setlength(buf,count);
|
|
try
|
|
fillmemory(@buf[0],count,fillvalue);
|
|
rewritedata(processhandle,start,@buf[0],count);
|
|
finally
|
|
setlength(buf,0);
|
|
end;
|
|
end;
|
|
|
|
|
|
Procedure CreateCodeCave(address:dword; sourceaddress:dword; sizeofcave: integer);
|
|
var x,y: dword;
|
|
i:integer;
|
|
ignore,temp: string;
|
|
replacedopcodes: array of string;
|
|
jumpback: array [0..4] of byte;
|
|
reassembledinstruction:tassemblerbytes;
|
|
|
|
overwritesize: dword;
|
|
begin
|
|
x:=sourceaddress;
|
|
|
|
while x<(sourceaddress+5) do
|
|
begin
|
|
setlength(replacedopcodes,length(replacedopcodes)+1);
|
|
temp:=disassemble(x,ignore);
|
|
temp:=copy(temp,pos('-',temp)+1,length(temp));
|
|
temp:=copy(temp,pos('-',temp)+2,length(temp));
|
|
|
|
replacedopcodes[length(replacedopcodes)-1]:=temp;
|
|
end;
|
|
|
|
overwritesize:=x-sourceaddress;
|
|
|
|
x:=address+sizeofcave-5;
|
|
y:=x;
|
|
|
|
jumpback[0]:=$e9;
|
|
pdword(@jumpback[1])^:=sourceaddress-x;
|
|
|
|
virtualprotectex(processhandle,pointer(address),sizeofcave,PAGE_EXECUTE_READWRITE ,x);
|
|
fillmemoryprocess(address,sizeofcave,$90);
|
|
|
|
if sizeofcave>5 then
|
|
writeprocessmemory(processhandle,pointer(y),@jumpback[0],5,x);
|
|
|
|
x:=address;
|
|
for i:=0 to length(replacedopcodes)-1 do
|
|
begin
|
|
assemble(replacedopcodes[i],x,reassembledinstruction);
|
|
writeprocessmemory(processhandle,pointer(x),@reassembledinstruction[0],length(reassembledinstruction),y);
|
|
inc(x,length(reassembledinstruction));
|
|
end;
|
|
|
|
virtualprotectex(processhandle,pointer(sourceaddress),overwritesize,x,y);
|
|
|
|
|
|
//now place the jmp
|
|
setlength(reassembledinstruction,overwritesize);
|
|
reassembledinstruction[0]:=$e9;
|
|
pdword(@reassembledinstruction[1])^:=address-sourceaddress-5;
|
|
|
|
for i:=5 to overwritesize-1 do
|
|
reassembledinstruction[i]:=$90;
|
|
|
|
RewriteData(processhandle,sourceaddress,@reassembledinstruction[0],overwritesize);
|
|
end;
|
|
{$endif}
|
|
|
|
|
|
|
|
{$ifndef net}
|
|
procedure SetLanguage;
|
|
begin
|
|
{$ifdef DEU}if LoadNewResourceModule(LANG_GERMAN) <> 0 then ReinitializeForms{$endif}
|
|
{$ifdef RUS}if LoadNewResourceModule(LANG_RUSSIAN) <> 0 then ReinitializeForms{$endif}
|
|
{$ifdef NLD}if LoadNewResourceModule(LANG_DUTCH) <> 0 then ReinitializeForms{$endif}
|
|
end;
|
|
{$endif}
|
|
|
|
{$ifndef standalonetrainer}
|
|
{$ifndef net}
|
|
//Returns a random threadid owned by the target process
|
|
function getathreadid(processid:dword):dword;
|
|
var i: integer;
|
|
ths: thandle;
|
|
tE: threadentry32;
|
|
begin
|
|
if frmProcessWatcher<>nil then
|
|
begin
|
|
//first find a processid using the processwatcher
|
|
|
|
frmProcessWatcher.processesMREW.BeginRead;
|
|
try
|
|
for i:=0 to length(frmProcessWatcher.processes)-1 do
|
|
if frmProcessWatcher.processes[i].processid=processid then
|
|
begin
|
|
if length(frmProcessWatcher.processes[i].threadlist)>0 then
|
|
begin
|
|
result:=frmProcessWatcher.processes[i].threadlist[0].threadid;
|
|
exit;
|
|
end;
|
|
end;
|
|
finally
|
|
frmProcessWatcher.processesMREW.EndRead;
|
|
end;
|
|
|
|
end;
|
|
|
|
//no exit yet, so use a enumeration of all threads and this processid
|
|
ths:=CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD,0);
|
|
if ths<>0 then
|
|
begin
|
|
te.dwSize:=sizeof(te);
|
|
if Thread32First(ths,te) then
|
|
begin
|
|
repeat
|
|
if te.th32OwnerProcessID=processid then
|
|
begin
|
|
result:=te.th32ThreadID;
|
|
closehandle(ths);
|
|
exit;
|
|
end;
|
|
|
|
|
|
until not thread32Next(ths,te);
|
|
end;
|
|
end;
|
|
|
|
closehandle(ths);
|
|
end;
|
|
{$endif}
|
|
|
|
procedure DetachIfPossible;
|
|
var crashcounter: integer;
|
|
waitform: TForm;
|
|
msg: tlabel;
|
|
begin
|
|
//detach the debugger
|
|
|
|
waitform:=nil;
|
|
crashcounter:=0;
|
|
|
|
{$ifndef net}
|
|
if debuggerthread=nil then
|
|
begin
|
|
if kdebugger.isactive then
|
|
KDebugger.StopDebugger;
|
|
|
|
exit;
|
|
end
|
|
else debuggerthread.Terminate;
|
|
|
|
if @DebugActiveProcessStop=@DebugActiveProcessStopProstitute then //lets help it a hand if it cant detach gracefully
|
|
terminateprocess(processhandle,0)
|
|
else
|
|
begin
|
|
if debuggerthread<>nil then
|
|
begin
|
|
//show a window asking the user to wait and not to freak out and think CE crashed!
|
|
waitform:=TForm.Create(nil);
|
|
with waitform do
|
|
begin
|
|
waitform.Caption:='Detaching...';
|
|
msg:=TLabel.Create(waitform);
|
|
msg.Caption:='Please wait while Cheat Engine tries to detach from the current process(This wont take longer than 30 seconds)';
|
|
|
|
waitform.Width:=msg.Width+20;
|
|
waitform.clientHeight:=50;
|
|
|
|
msg.Left:=7;
|
|
msg.Top:=(waitform.ClientHeight div 2) - (msg.Height div 2);
|
|
msg.Parent:=waitform;
|
|
|
|
//waitform.Parent:=self;
|
|
waitform.BorderStyle:=bsDialog;
|
|
waitform.BorderIcons:=[];
|
|
|
|
waitform.Position:=poScreenCenter;
|
|
waitform.Show;
|
|
waitform.Repaint;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
while (debuggerthread<>nil) and (debuggerthread.attached) and (crashcounter<30) do
|
|
begin
|
|
inc(crashcounter);
|
|
sleep(1000);
|
|
end;
|
|
|
|
if crashcounter=30 then messagedlg('Detaching failed!!! Your process is lost!',mtError,[mbok],0);
|
|
|
|
if waitform<>nil then
|
|
begin
|
|
waitform.Hide;
|
|
waitform.Free;
|
|
waitform:=nil;
|
|
end;
|
|
|
|
|
|
{$endif}
|
|
|
|
end;
|
|
{$endif}
|
|
|
|
|
|
Procedure InjectDll(dllname: string; functiontocall: string='');
|
|
var LoadLibraryPtr: pointer;
|
|
GetProcAddressPtr: Pointer;
|
|
|
|
|
|
h: Thandle;
|
|
|
|
inject: array [0..4095] of byte;
|
|
x:dword;
|
|
|
|
outp:TAssemblerBytes;
|
|
counter: integer;
|
|
position,position2: dword;
|
|
|
|
dllLocation: string;
|
|
startaddresS: dword;
|
|
functionloc: dword;
|
|
injectionlocation: pointer;
|
|
threadhandle: thandle;
|
|
begin
|
|
h:=LoadLibrary('Kernel32.dll');
|
|
if h=0 then raise exception.Create('No kernel32.dll loaded');
|
|
|
|
injectionlocation:=nil;
|
|
try
|
|
try
|
|
getprocaddressptr:=pointer(symhandler.getAddressFromName('GetProcAddress',true));
|
|
except
|
|
GetProcAddressPtr:=GetProcAddress(h,'GetProcAddress');
|
|
end;
|
|
|
|
if getprocaddressptr=nil then raise exception.Create('GetProcAddress not found');
|
|
|
|
try
|
|
LoadLibraryPtr:=pointer(symhandler.getAddressFromName('LoadLibraryA',true));
|
|
except
|
|
//failed getting the address of LoadLibraryA, use old method
|
|
LoadLibraryPtr:=GetProcAddress(h,'LoadLibraryA');
|
|
end;
|
|
|
|
|
|
if LoadLibraryptr=nil then raise exception.Create('LoadLibraryA not found');
|
|
|
|
injectionlocation:=VirtualAllocEx(processhandle,nil,4096,MEM_COMMIT,PAGE_EXECUTE_READWRITE);
|
|
|
|
if injectionlocation=nil then raise exception.Create('Failed to allocate memory');
|
|
|
|
dlllocation:=dllname;
|
|
|
|
position:=dword(injectionlocation);
|
|
position2:=0;
|
|
copymemory(@inject[0],pchar(dllLocation+#0),length(dllLocation)+1);
|
|
inc(position,length(dllLocation)+1);
|
|
inc(position2,length(dllLocation)+1);
|
|
|
|
functionloc:=position;
|
|
copymemory(@inject[position2],pchar(functiontocall+#0),length(functiontocall)+1);
|
|
inc(position,length(functiontocall)+1);
|
|
inc(position2,length(functiontocall)+1);
|
|
startaddress:=position;
|
|
|
|
//loadlibrary(cehook);
|
|
assemble('PUSH '+IntToHex(dword(injectionlocation),8),position,outp);
|
|
copymemory(@inject[position2],outp,length(outp));
|
|
inc(position,length(outp));
|
|
inc(position2,length(outp));
|
|
|
|
assemble('CALL '+IntToHex(dword(LoadLibraryPtr),8),position,outp);
|
|
copymemory(@inject[position2],outp,length(outp));
|
|
inc(position,length(outp));
|
|
inc(position2,length(outp));
|
|
|
|
|
|
//safetycode, test if the dll was actually loaded and skip if not
|
|
assemble('TEST EAX,EAX',position,outp);
|
|
copymemory(@inject[position2],outp,length(outp));
|
|
inc(position,length(outp));
|
|
inc(position2,length(outp));
|
|
|
|
assemble('JNE '+inttohex(position+3+5,8),position,outp); //jump over the ret
|
|
copymemory(@inject[position2],outp,length(outp));
|
|
inc(position,length(outp));
|
|
inc(position2,length(outp));
|
|
|
|
assemble('MOV EAX,2',position,outp); //exitcode=2
|
|
copymemory(@inject[position2],outp,length(outp));
|
|
inc(position,length(outp));
|
|
inc(position2,length(outp));
|
|
|
|
assemble('RET',position,outp);
|
|
copymemory(@inject[position2],outp,length(outp));
|
|
inc(position,length(outp));
|
|
inc(position2,length(outp));
|
|
|
|
|
|
if functiontocall<>'' then
|
|
begin
|
|
//getprocaddress
|
|
assemble('PUSH '+IntToHex(functionloc,8),position,outp);
|
|
copymemory(@inject[position2],outp,length(outp));
|
|
inc(position,length(outp));
|
|
inc(position2,length(outp));
|
|
|
|
assemble('PUSH EAX',position,outp);
|
|
copymemory(@inject[position2],outp,length(outp));
|
|
inc(position,length(outp));
|
|
inc(position2,length(outp));
|
|
|
|
assemble('CALL '+IntToHex(dword(GetProcAddressPtr),8),position,outp);
|
|
copymemory(@inject[position2],outp,length(outp));
|
|
inc(position,length(outp));
|
|
inc(position2,length(outp));
|
|
|
|
assemble('TEST EAX,EAX',position,outp);
|
|
copymemory(@inject[position2],outp,length(outp));
|
|
inc(position,length(outp));
|
|
inc(position2,length(outp));
|
|
|
|
assemble('JNE '+inttohex(position+3+5,8),position,outp);
|
|
copymemory(@inject[position2],outp,length(outp));
|
|
inc(position,length(outp));
|
|
inc(position2,length(outp));
|
|
|
|
assemble('MOV EAX,3',position,outp); //exitcode=3
|
|
copymemory(@inject[position2],outp,length(outp));
|
|
inc(position,length(outp));
|
|
inc(position2,length(outp));
|
|
|
|
assemble('RET',position,outp);
|
|
copymemory(@inject[position2],outp,length(outp));
|
|
inc(position,length(outp));
|
|
inc(position2,length(outp));
|
|
|
|
//call function
|
|
assemble('CALL EAX',position,outp);
|
|
copymemory(@inject[position2],outp,length(outp));
|
|
inc(position,length(outp));
|
|
inc(position2,length(outp));
|
|
end;
|
|
|
|
|
|
assemble('MOV EAX,1',position,outp); //causes the exitcode of the thread be 1
|
|
copymemory(@inject[position2],outp,length(outp));
|
|
inc(position,length(outp));
|
|
inc(position2,length(outp));
|
|
|
|
assemble('RET',position,outp);
|
|
copymemory(@inject[position2],outp,length(outp));
|
|
inc(position,length(outp));
|
|
inc(position2,length(outp));
|
|
|
|
|
|
//call the routine
|
|
|
|
if not writeprocessmemory(processhandle,injectionlocation,@inject[0],position2,x) then raise exception.Create('Failed to inject the dll loader');
|
|
|
|
{$ifndef standalonetrainer}
|
|
{$ifndef net}
|
|
|
|
useapctoinjectdll:=false;
|
|
if useapctoinjectdll then
|
|
begin
|
|
showmessage('injected code at:'+inttohex(startaddress,8));
|
|
|
|
//suspend , message, resume is needed to prevent a crash when it is in a message loop
|
|
ntsuspendprocess(processid);
|
|
x:=getathreadid(processid);
|
|
PostThreadMessage(x,wm_paint,0,0);
|
|
CreateRemoteAPC(x,pointer(startaddress));
|
|
ntresumeprocess(processid);
|
|
end
|
|
else
|
|
|
|
{$endif}
|
|
{$endif}
|
|
begin
|
|
threadhandle:=createremotethread(processhandle,nil,0,pointer(startaddress),nil,0,x);
|
|
if threadhandle=0 then raise exception.Create('Failed to execute the dll loader');
|
|
|
|
counter:=10000 div 10;
|
|
while (waitforsingleobject(threadhandle,10)=WAIT_TIMEOUT) and (counter>0) do
|
|
begin
|
|
if GetCurrentThreadID = MainThreadID then
|
|
CheckSynchronize; //handle sychronize calls while it's waiting
|
|
|
|
dec(counter);
|
|
end;
|
|
|
|
if (counter=0) then
|
|
raise exception.Create('The injection thread took longer than 10 seconds to execute. Injection routine not freed');
|
|
|
|
if getexitcodethread(threadhandle,x) then
|
|
begin
|
|
case x of
|
|
1: ;//success
|
|
2: raise exception.Create('Failed injecting the DLL');
|
|
3: raise exception.Create('Failed executing the function of the dll');
|
|
else raise exception.Create('Unknown error during injection');
|
|
end;
|
|
end; //else unsure, did it work or not , or is it crashing?
|
|
|
|
end;
|
|
finally
|
|
FreeLibrary(h);
|
|
if injectionlocation<>nil then
|
|
virtualfreeex(processhandle,injectionlocation,0,MEM_RELEASE );
|
|
end;
|
|
|
|
end;
|
|
|
|
procedure ToggleOtherWindows;
|
|
type Tprocesslistitem = record
|
|
processid: dword;
|
|
processname: string;
|
|
end;
|
|
var winhandle: Hwnd;
|
|
winprocess: Dword;
|
|
i,j: integer;
|
|
SNAPHandle: THandle;
|
|
ProcessEntry: ProcessEntry32;
|
|
Check: Boolean;
|
|
processlist: array of Tprocesslistitem;
|
|
hideall,hidethisone: boolean;
|
|
begin
|
|
hideall:=false;
|
|
|
|
allwindowsareback:=false;
|
|
|
|
if length(windowlist)<>0 then
|
|
begin
|
|
for i:=0 to length(windowlist)-1 do
|
|
showwindow(windowlist[i],SW_SHOW);
|
|
|
|
setlength(windowlist,0);
|
|
allwindowsareback:=true;
|
|
exit;
|
|
end;
|
|
|
|
lastactive:=getactivewindow;
|
|
lastforeground:=GetForegroundWindow;
|
|
|
|
if onlyfront then
|
|
begin
|
|
GetWindowThreadProcessId(lastforeground,addr(winprocess));
|
|
if getcurrentprocessid=winprocess then
|
|
begin
|
|
beep;
|
|
sleep(100);
|
|
beep;
|
|
sleep(100);
|
|
exit;
|
|
end;
|
|
|
|
setlength(windowlist,1);
|
|
windowlist[0]:=lastforeground;
|
|
showwindow(lastforeground,sw_hide);
|
|
exit;
|
|
end;
|
|
|
|
|
|
if length(donthidelist)>0 then
|
|
begin
|
|
//first get a process list
|
|
SNAPHandle:=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
|
|
If SnapHandle>0 then
|
|
begin
|
|
ProcessEntry.dwSize:=SizeOf(ProcessEntry);
|
|
Check:=Process32First(SnapHandle,ProcessEntry);
|
|
while check do
|
|
begin
|
|
if processentry.th32ProcessID<>0 then
|
|
begin
|
|
setlength(processlist,length(processlist)+1);
|
|
processlist[length(processlist)-1].processid:=processentry.th32ProcessID;
|
|
processlist[length(processlist)-1].processname:=lowercase(ExtractFilename(processentry.szExeFile));
|
|
end;
|
|
check:=Process32Next(SnapHandle,ProcessEntry);
|
|
end;
|
|
end else hideall:=true; //else sorry dude, but no exceptions for you, say goodbye to ALL your windows
|
|
end else hideall:=true;
|
|
|
|
winhandle:=getwindow(GetForegroundWindow,GW_HWNDFIRST);
|
|
|
|
while winhandle<>0 do
|
|
begin
|
|
GetWindowThreadProcessId(winhandle,addr(winprocess));
|
|
|
|
if (winprocess<>getCurrentProcessID) {and (winprocess<>3600) }then
|
|
begin
|
|
if isWindowVisible(winhandle) then
|
|
begin
|
|
hidethisone:=true;
|
|
if not hideall then
|
|
begin
|
|
//see if you can hide it or not
|
|
//check this window process with the process list
|
|
//and then see if the processname equals an item from the donthide list
|
|
for i:=0 to length(processlist)-1 do
|
|
if processlist[i].processid=winprocess then
|
|
begin
|
|
//found the process id, now check if the processname of this process equals an item from the list
|
|
for j:=0 to length(donthidelist)-1 do
|
|
if processlist[i].processname=donthidelist[j] then //it's in so do not hide
|
|
begin
|
|
hidethisone:=false;
|
|
break;
|
|
end;
|
|
break;
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
if hidethisone then
|
|
begin
|
|
showwindow(winhandle,SW_HIDE);
|
|
// setwindowpos(winhandle,0,0,0,0,0,SWP_HIDEWINDOW or SWP_NOREPOSITION or SWP_NOSIZE or SWP_NOZORDER or SWP_NOACTIVATE or SWP_NOREDRAW or SWP_NOSENDCHANGING);
|
|
setlength(windowlist,length(windowlist)+1);
|
|
windowlist[length(windowlist)-1]:=winhandle;
|
|
end;
|
|
// showwindow(winhandle,sw_show); //remove this for real version
|
|
end;
|
|
end;
|
|
|
|
winhandle:=getwindow(winhandle,GW_HWNDNEXT);
|
|
end;
|
|
|
|
// application.BringToFront;
|
|
end;
|
|
|
|
function GetSystemType: Integer; //from Stuart Johnson with a little change by me
|
|
const
|
|
{ operating system constants }
|
|
|
|
cOsUnknown = 999999;
|
|
cOsWin95 = 0;
|
|
cOsWin98 = 1;
|
|
cOsWin98SE = 2;
|
|
cOsWinME = 3;
|
|
cOsWinNT = 4;
|
|
cOsWin2000 = 5;
|
|
cOsWinXP = 6;
|
|
cOsNewer = 7;
|
|
|
|
var
|
|
osVerInfo : TOSVersionInfo;
|
|
majorVer, minorVer : Integer;
|
|
|
|
begin
|
|
if overridedebug then
|
|
begin
|
|
result:=cOsWinXP;
|
|
exit;
|
|
end;
|
|
|
|
{ set operating system type flag }
|
|
osVerInfo.dwOSVersionInfoSize := SizeOf(TOSVersionInfo);
|
|
if GetVersionEx(osVerInfo) then
|
|
begin
|
|
majorVer := osVerInfo.dwMajorVersion;
|
|
minorVer := osVerInfo.dwMinorVersion;
|
|
case osVerInfo.dwPlatformId of
|
|
VER_PLATFORM_WIN32_NT : { Windows NT/2000 }
|
|
begin
|
|
if majorVer <= 4 then
|
|
result := cOsWinNT
|
|
else
|
|
if (majorVer = 5) AND (minorVer= 0) then
|
|
result := cOsWin2000
|
|
else
|
|
if (majorVer = 5) AND (minorVer = 1) then
|
|
result := cOsWinXP
|
|
else if (majorver > 5) then result:=cOsNewer
|
|
else
|
|
result := cOsUnknown;
|
|
end; {case }
|
|
VER_PLATFORM_WIN32_WINDOWS : { Windows 9x/ME }
|
|
begin
|
|
if (majorVer = 4) AND (minorVer = 0) then
|
|
result := cOsWin95
|
|
else
|
|
if (majorVer = 4) AND (minorVer = 10) then
|
|
begin
|
|
if osVerInfo.szCSDVersion[1] = 'A' then
|
|
result := cOsWin98SE
|
|
else
|
|
result := cOsWin98;
|
|
end {if Version = 'A'}
|
|
else
|
|
if (majorVer = 4) AND (minorVer = 90) then
|
|
result := cOsWinME
|
|
else
|
|
result := cOsUnknown;
|
|
end; {case VER_PLATFORM_WIN32_WINDOWS}
|
|
else
|
|
result := cOsUnknown;
|
|
end;
|
|
end
|
|
else
|
|
result := cOsUnknown;
|
|
end;
|
|
|
|
|
|
|
|
function KeyToStr(key:word):string;
|
|
begin
|
|
case key of
|
|
VK_BACK : result:='Backspace';
|
|
VK_TAB : result:='Tab';
|
|
VK_CLEAR : result:='Clear';
|
|
VK_RETURN : result:='Enter';
|
|
VK_PAUSE : result:='Pause';
|
|
VK_CAPITAL : result:='Caps Lock';
|
|
VK_ESCAPE : result:='Esc';
|
|
VK_SPACE : result:='Space bar';
|
|
VK_PRIOR : result:='Page Up';
|
|
VK_NEXT : result:='Page Down';
|
|
VK_END : result:='End';
|
|
VK_HOME : result:='Home';
|
|
VK_LEFT : result:='Left Arrow';
|
|
VK_UP : result:='Up Arrow';
|
|
VK_RIGHT : result:='Right Arrow';
|
|
VK_DOWN : result:='Down Arrow';
|
|
VK_SELECT : result:='Select';
|
|
VK_PRINT : result:='Print';
|
|
VK_EXECUTE : result:='Execute';
|
|
VK_SNAPSHOT : result:='Print Screen';
|
|
VK_INSERT : result:='Insert';
|
|
VK_DELETE : result:='Delete';
|
|
VK_HELP : result:='Help';
|
|
VK_LWIN : result:='Left Windows key';
|
|
VK_RWIN : result:='Right Windows key';
|
|
VK_APPS : result:='Applications key';
|
|
VK_NUMPAD0 : result:='numeric 0';
|
|
VK_NUMPAD1 : result:='numeric 1';
|
|
VK_NUMPAD2 : result:='numeric 2';
|
|
VK_NUMPAD3 : result:='numeric 3';
|
|
VK_NUMPAD4 : result:='numeric 4';
|
|
VK_NUMPAD5 : result:='numeric 5';
|
|
VK_NUMPAD6 : result:='numeric 6';
|
|
VK_NUMPAD7 : result:='numeric 7';
|
|
VK_NUMPAD8 : result:='numeric 8';
|
|
VK_NUMPAD9 : result:='numeric 9';
|
|
VK_MULTIPLY : result:='numeric *';
|
|
VK_ADD : result:='numeric +';
|
|
VK_SEPARATOR : result:='numeric Separator';
|
|
VK_SUBTRACT : result:='numeric -';
|
|
VK_DECIMAL : result:='numeric .';
|
|
VK_DIVIDE : result:='numeric /';
|
|
VK_F1 : result:='F1';
|
|
VK_F2 : result:='F2';
|
|
VK_F3 : result:='F3';
|
|
VK_F4 : result:='F4';
|
|
VK_F5 : result:='F5';
|
|
VK_F6 : result:='F6';
|
|
VK_F7 : result:='F7';
|
|
VK_F8 : result:='F8';
|
|
VK_F9 : result:='F9';
|
|
VK_F10 : result:='F10';
|
|
VK_F11 : result:='F11';
|
|
VK_F12 : result:='F12';
|
|
VK_F13 : result:='F13';
|
|
VK_F14 : result:='F14';
|
|
VK_F15 : result:='F15';
|
|
VK_F16 : result:='F16';
|
|
VK_F17 : result:='F17';
|
|
VK_F18 : result:='F18';
|
|
VK_F19 : result:='F19';
|
|
VK_F20 : result:='F20';
|
|
VK_F21 : result:='F21';
|
|
VK_F22 : result:='F22';
|
|
VK_F23 : result:='F23';
|
|
VK_F24 : result:='F24';
|
|
VK_NUMLOCK : result:='Num Lock';
|
|
VK_SCROLL : result:='Scroll Lock';
|
|
48..57 : result:=chr(key);
|
|
65..90 : result:=chr(key);
|
|
else result:='#'+IntToStr(key);
|
|
end;
|
|
|
|
end;
|
|
|
|
procedure decimal(var key: char); //removed
|
|
begin
|
|
{
|
|
case key of
|
|
chr(8) : ;
|
|
chr(16) : ;
|
|
'0'..'9' : ;
|
|
else key:=chr(0);
|
|
end;
|
|
}
|
|
end;
|
|
|
|
procedure hexadecimal(var key: char); //removed
|
|
begin
|
|
{case key of
|
|
chr(8) : ;
|
|
chr(16) : ;
|
|
'A'..'F' : ;
|
|
'a'..'f' : key:=uppercase(key)[1];
|
|
'0'..'9' : ;
|
|
else key:=chr(0);
|
|
end; }
|
|
end;
|
|
|
|
function ByteStringToText(s: string;hex: boolean):string;
|
|
var temp: tbytes;
|
|
i,j: integer;
|
|
begin
|
|
ConvertStringToBytes(s,hex,temp);
|
|
result:='';
|
|
|
|
for i:=0 to length(temp)-1 do
|
|
if temp[i]>$13 then
|
|
result:=result+chr(temp[i]);
|
|
end;
|
|
|
|
|
|
function ByteStringToDouble(s: string;hex: boolean):double;
|
|
var temp: tbytes;
|
|
temp2: double;
|
|
p: ^byte;
|
|
i,j: integer;
|
|
begin
|
|
ConvertStringToBytes(s,hex,temp);
|
|
p:=@temp2;
|
|
|
|
if length(temp)<8 then
|
|
begin
|
|
j:=length(temp);
|
|
setlength(temp,8);
|
|
for i:=j to 7 do
|
|
temp[i]:=0;
|
|
end;
|
|
|
|
for i:=0 to length(temp)-1 do
|
|
begin
|
|
if temp[i]=-1 then temp[i]:=0;
|
|
|
|
p^:=byte(temp[i]);
|
|
inc(p);
|
|
end;
|
|
|
|
result:=temp2;
|
|
end;
|
|
|
|
|
|
function ByteStringToSingle(s: string;hex: boolean):single;
|
|
var temp: tbytes;
|
|
temp2: single;
|
|
p: ^byte;
|
|
i,j: integer;
|
|
begin
|
|
ConvertStringToBytes(s,hex,temp);
|
|
p:=@temp2;
|
|
|
|
if length(temp)<4 then
|
|
begin
|
|
j:=length(temp);
|
|
setlength(temp,4);
|
|
for i:=j to 3 do
|
|
temp[i]:=0;
|
|
end;
|
|
|
|
for i:=0 to length(temp)-1 do
|
|
begin
|
|
if temp[i]=-1 then temp[i]:=0;
|
|
|
|
p^:=byte(temp[i]);
|
|
inc(p);
|
|
end;
|
|
|
|
result:=temp2;
|
|
end;
|
|
|
|
function ByteStringToInt(s: string;hex: boolean):int64;
|
|
var temp: tbytes;
|
|
i: integer;
|
|
power: integer;
|
|
|
|
begin
|
|
ConvertStringToBytes(s,hex,temp);
|
|
power:=0;
|
|
result:=0;
|
|
|
|
for i:=0 to length(temp)-1 do
|
|
begin
|
|
result:=result+(temp[i]*trunc(math.power(256,power)));
|
|
inc(power);
|
|
end;
|
|
end;
|
|
|
|
function VarToBytes(v: pointer; size: integer): string;
|
|
var p: ^byte;
|
|
j,k: integer;
|
|
res: array of string;
|
|
begin
|
|
result:='';
|
|
p:=v;
|
|
|
|
setlength(res,size);
|
|
|
|
for k:=0 to size-1 do
|
|
begin
|
|
res[k]:=inttohex(p^,2);
|
|
inc(p);
|
|
end;
|
|
|
|
j:=size;
|
|
for k:=size-1 to 1 do
|
|
if res[k]='00' then dec(j);
|
|
|
|
for k:=0 to j-1 do
|
|
result:=result+res[k]+' ';
|
|
|
|
result:=copy(result,1,length(result)-1);
|
|
end;
|
|
|
|
function BinToInt(s: string): int64;
|
|
var i: integer;
|
|
begin
|
|
result:=0;
|
|
for i:=length(s) downto 1 do
|
|
if s[i]='1' then result:=result+trunc(power(2,length(s)-i ));
|
|
end;
|
|
|
|
function Inttobin(i: int64): string;
|
|
var temp,temp2: string;
|
|
j: integer;
|
|
begin
|
|
temp:='';
|
|
while i>0 do
|
|
begin
|
|
if (i mod 2)>0 then temp:=temp+'1'
|
|
else temp:=temp+'0';
|
|
i:=i div 2;
|
|
end;
|
|
|
|
temp2:='';
|
|
for j:=length(temp) downto 1 do
|
|
temp2:=temp2+temp[j];
|
|
result:=temp2;
|
|
end;
|
|
|
|
|
|
|
|
function getbit(bitnr: integer; bt: dword):integer;
|
|
begin
|
|
result:=(bt shr bitnr) and 1;
|
|
end;
|
|
|
|
procedure setbit(bitnr: integer; var bt: dword;state:integer); overload;
|
|
{
|
|
pre: bitnr=bit between 0 and 7
|
|
bt=pointer to the byte
|
|
post: bt has the bit set specified in state
|
|
result: bt has a bit set or unset
|
|
}
|
|
begin
|
|
bt:=bt and (not (1 shl bitnr));
|
|
bt:=bt or (state shl bitnr);
|
|
end;
|
|
|
|
procedure setbit(bitnr: integer; var bt: Byte;state:integer); overload;
|
|
{
|
|
pre: bitnr=bit between 0 and 7
|
|
bt=pointer to the byte
|
|
post: bt has the bit set specified in state
|
|
result: bt has a bit set or unset
|
|
}
|
|
var d: dword;
|
|
begin
|
|
d:=bt;
|
|
setbit(bitnr,d,state);
|
|
bt:=d;
|
|
end;
|
|
|
|
function eflags_setCF(flagvalue: dword; value: integer): DWORD;
|
|
begin
|
|
result:=flagvalue and (not (1 shl 0)) or (value shl 0);
|
|
end;
|
|
|
|
function eflags_setPF(flagvalue: dword; value: integer): DWORD;
|
|
begin
|
|
result:=flagvalue and (not (1 shl 2)) or (value shl 2);
|
|
end;
|
|
|
|
function eflags_setAF(flagvalue: dword; value: integer): DWORD;
|
|
begin
|
|
result:=flagvalue and (not (1 shl 4)) or (value shl 4);
|
|
end;
|
|
|
|
function eflags_setZF(flagvalue: dword; value: integer): DWORD;
|
|
begin
|
|
result:=flagvalue and (not (1 shl 6)) or (value shl 6);
|
|
end;
|
|
|
|
function eflags_setSF(flagvalue: dword; value: integer): DWORD;
|
|
begin
|
|
result:=flagvalue and (not (1 shl 7)) or (value shl 7);
|
|
end;
|
|
|
|
function eflags_setTF(flagvalue: dword; value: integer): DWORD;
|
|
begin
|
|
result:=flagvalue and (not (1 shl 8)) or (value shl 8);
|
|
end;
|
|
|
|
function eflags_setIF(flagvalue: dword; value: integer): DWORD;
|
|
begin
|
|
result:=flagvalue and (not (1 shl 9)) or (value shl 9);
|
|
end;
|
|
|
|
function eflags_setDF(flagvalue: dword; value: integer): DWORD;
|
|
begin
|
|
result:=flagvalue and (not (1 shl 10)) or (value shl 10);
|
|
end;
|
|
|
|
function eflags_setOF(flagvalue: dword; value: integer): DWORD;
|
|
begin
|
|
result:=flagvalue and (not (1 shl 11)) or (value shl 11);
|
|
end;
|
|
|
|
function eflags_setIOPL(flagvalue: dword; value: integer): DWORD;
|
|
begin
|
|
result:=flagvalue and (not (3 shl 12)) or (value shl 12);
|
|
end;
|
|
|
|
function eflags_setNT(flagvalue: dword; value: integer): DWORD;
|
|
begin
|
|
result:=flagvalue and (not (1 shl 14)) or (value shl 14);
|
|
end;
|
|
|
|
function eflags_setRF(flagvalue: dword; value: integer): DWORD;
|
|
begin
|
|
result:=flagvalue and (not (1 shl 16)) or (value shl 16);
|
|
end;
|
|
|
|
function eflags_setVM(flagvalue: dword; value: integer): DWORD;
|
|
begin
|
|
result:=flagvalue and (not (1 shl 17)) or (value shl 17);
|
|
end;
|
|
|
|
function eflags_setAC(flagvalue: dword; value: integer): DWORD;
|
|
begin
|
|
result:=flagvalue and (not (1 shl 18)) or (value shl 18);
|
|
end;
|
|
|
|
function eflags_setVIF(flagvalue: dword; value: integer): DWORD;
|
|
begin
|
|
result:=flagvalue and (not (1 shl 19)) or (value shl 19);
|
|
end;
|
|
|
|
function eflags_setVIP(flagvalue: dword; value: integer): DWORD;
|
|
begin
|
|
result:=flagvalue and (not (1 shl 20)) or (value shl 20);
|
|
end;
|
|
|
|
function eflags_setID(flagvalue: dword; value: integer): DWORD;
|
|
begin
|
|
result:=flagvalue and (not (1 shl 21)) or (value shl 21);
|
|
end;
|
|
|
|
function undolastscan(valtype: integer;hexadecimal:boolean): integer;
|
|
begin
|
|
deletefile(CheatEngineDir+'Memory.tmp');
|
|
deletefile(CheatEngineDir+'Addresses.tmp');
|
|
|
|
renamefile(CheatEngineDir+'Memory.UNDO',CheatEngineDir+'Memory.tmp');
|
|
renamefile(CheatEngineDir+'Addresses.UNDO',CheatEngineDir+'Addresses.tmp');
|
|
|
|
assignfile(addressfile,CheatEngineDir+'Addresses.tmp');
|
|
assignfile(memoryfile,CheatEngineDir+'Memory.tmp');
|
|
end;
|
|
|
|
function AvailMem:dword;
|
|
var x: _MEMORYSTATUS;
|
|
begin
|
|
x.dwLength:=sizeof(x);
|
|
GlobalMemoryStatus(x);
|
|
|
|
if x.dwAvailVirtual>(x.dwAvailPhys+x.dwAvailPageFile) then
|
|
result:=x.dwAvailPhys+x.dwAvailPageFile
|
|
else
|
|
result:=x.dwAvailVirtual;
|
|
|
|
end;
|
|
|
|
procedure RemoveAddress(address: Dword;bit: Byte; vartype: Integer);
|
|
type bitaddress = record
|
|
address: dword;
|
|
bit: dword;
|
|
end;
|
|
|
|
var
|
|
|
|
Addresses: Array [1..number] of Dword;
|
|
BAddress: Array [1..number] of BitAddress;
|
|
Memory: Array [1..8*number] of Byte;
|
|
i,j: Integer;
|
|
|
|
str: pchar;
|
|
|
|
found: boolean;
|
|
check,check2: Integer;
|
|
|
|
|
|
begin
|
|
assignfile(memoryfile,CheatEngineDir+'Memory.TMP');
|
|
assignfile(addressfile,CheatEngineDir+'Addresses.TMP');
|
|
reset(memoryfile,1);
|
|
reset(addressfile,1);
|
|
|
|
assignfile(newmemoryfile,CheatEngineDir+'Memory2.TMP');
|
|
assignfile(newaddressfile,CheatEngineDir+'Address2.TMP');
|
|
rewrite(newmemoryfile,1);
|
|
rewrite(newaddressfile,1);
|
|
|
|
blockread(addressfile,memory,7,check);
|
|
blockwrite(newaddressfile,memory,7,check);
|
|
|
|
found:=false;
|
|
i:=0;
|
|
|
|
if vartype=7 then //text scan
|
|
begin
|
|
i:=filesize(memoryfile);
|
|
|
|
getmem(str,i+1);
|
|
blockread(memoryfile,pointer(str)^,i,check);
|
|
str[i]:=chr(0);
|
|
blockwrite(newmemoryfile,pointer(str)^,i,check);
|
|
|
|
check:=4*number;
|
|
while (check=4*number) do
|
|
begin
|
|
blockread(addressfile,addresses,4*number,check);
|
|
i:=0;
|
|
j:=0;
|
|
while (i<check div 4) do
|
|
begin
|
|
inc(i);
|
|
if addresses[i]<>address then //if it's not the selected address write it else dont write it.
|
|
blockwrite(newaddressfile,addresses[i],4,check2);
|
|
end;
|
|
end;
|
|
end
|
|
else
|
|
if vartype<>5 then
|
|
begin
|
|
check:=4*number;
|
|
while ((not found) and (check=4*number)) do
|
|
begin
|
|
blockread(addressfile,addresses,4*number,check);
|
|
i:=0;
|
|
while (not found) and (i<(check div 4)) do
|
|
begin
|
|
inc(i);
|
|
if addresses[i]=address then
|
|
begin
|
|
found:=true;
|
|
break;
|
|
end;
|
|
end;
|
|
|
|
if not found then
|
|
begin
|
|
blockwrite(newaddressfile,addresses,4*number,check2);
|
|
case vartype of
|
|
0: begin //byte
|
|
blockread(memoryfile,memory,number,check2);
|
|
blockwrite(newmemoryfile,memory,check2,check2);
|
|
end;
|
|
|
|
1: begin //word
|
|
blockread(memoryfile,memory,2*number,check2);
|
|
blockwrite(newmemoryfile,memory,check2,check2);
|
|
end;
|
|
|
|
2: begin //dword
|
|
blockread(memoryfile,memory,4*number,check2);
|
|
blockwrite(newmemoryfile,memory,check2,check2);
|
|
end;
|
|
|
|
|
|
3: begin //float
|
|
blockread(memoryfile,memory,4*number,check2);
|
|
blockwrite(newmemoryfile,memory,check2,check2);
|
|
end;
|
|
|
|
4: begin //double
|
|
blockread(memoryfile,memory,8*number,check2);
|
|
blockwrite(newmemoryfile,memory,check2,check2);
|
|
end;
|
|
|
|
6: begin //int64
|
|
blockread(memoryfile,memory,8*number,check2);
|
|
blockwrite(newmemoryfile,memory,check2,check2);
|
|
end;
|
|
|
|
|
|
//bit doesnt come here
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
if found then
|
|
begin
|
|
for j:=i to number-1 do
|
|
addresses[j]:=addresses[j+1];
|
|
|
|
blockwrite(newaddressfile,addresses,check-4,check2);
|
|
|
|
case vartype of
|
|
0: begin //byte
|
|
blockread(memoryfile,memory,number,check2);
|
|
for j:=i to number-1 do memory[j]:=memory[j+1];
|
|
blockwrite(newmemoryfile,memory,check2-1,check2);
|
|
end;
|
|
|
|
1: begin //word
|
|
blockread(memoryfile,memory,2*number,check2);
|
|
for j:=i to number-4 do
|
|
begin
|
|
memory[j]:=memory[j+2];
|
|
memory[j+1]:=memory[j+3];
|
|
end;
|
|
blockwrite(newmemoryfile,memory,check2-2,check2);
|
|
end;
|
|
|
|
2: begin //dword
|
|
blockread(memoryfile,memory,4*number,check2);
|
|
for j:=i to number-8 do
|
|
begin
|
|
memory[j]:=memory[j+4];
|
|
memory[j+1]:=memory[j+5];
|
|
memory[j+2]:=memory[j+6];
|
|
memory[j+3]:=memory[j+7];
|
|
end;
|
|
|
|
blockwrite(newmemoryfile,memory,check2-4,check2);
|
|
end;
|
|
|
|
|
|
3: begin //float
|
|
blockread(memoryfile,memory,4*number,check2);
|
|
for j:=i to number-8 do
|
|
begin
|
|
memory[j]:=memory[j+4];
|
|
memory[j+1]:=memory[j+5];
|
|
memory[j+2]:=memory[j+6];
|
|
memory[j+3]:=memory[j+7];
|
|
end;
|
|
blockwrite(newmemoryfile,memory,check2-4,check2);
|
|
end;
|
|
|
|
4: begin //double
|
|
blockread(memoryfile,memory,8*number,check2);
|
|
for j:=i to number-16 do
|
|
begin
|
|
memory[j]:=memory[j+8];
|
|
memory[j+1]:=memory[j+9];
|
|
memory[j+2]:=memory[j+10];
|
|
memory[j+3]:=memory[j+11];
|
|
memory[j+4]:=memory[j+12];
|
|
memory[j+5]:=memory[j+13];
|
|
memory[j+6]:=memory[j+14];
|
|
memory[j+7]:=memory[j+15];
|
|
end;
|
|
blockwrite(newmemoryfile,memory,check2-8,check2);
|
|
end;
|
|
|
|
6: begin //Int64
|
|
blockread(memoryfile,memory,8*number,check2);
|
|
for j:=i to number-16 do
|
|
begin
|
|
memory[j]:=memory[j+8];
|
|
memory[j+1]:=memory[j+9];
|
|
memory[j+2]:=memory[j+10];
|
|
memory[j+3]:=memory[j+11];
|
|
memory[j+4]:=memory[j+12];
|
|
memory[j+5]:=memory[j+13];
|
|
memory[j+6]:=memory[j+14];
|
|
memory[j+7]:=memory[j+15];
|
|
end;
|
|
blockwrite(newmemoryfile,memory,check2-8,check2);
|
|
end;
|
|
|
|
|
|
end;
|
|
|
|
//and now just copy the addresses till the end
|
|
check:=4*number;
|
|
while (check=4*number) do
|
|
begin
|
|
blockread(addressfile,addresses,4*number,check);
|
|
blockwrite(newaddressfile,addresses,check,check);
|
|
end;
|
|
|
|
//and same for memory
|
|
check:=4*number;
|
|
while (check=4*number) do
|
|
begin
|
|
blockread(memoryfile,addresses,4*number,check);
|
|
blockwrite(newaddressfile,addresses,check,check);
|
|
end;
|
|
end;
|
|
|
|
end;
|
|
|
|
closefile(memoryfile);
|
|
closefile(addressfile);
|
|
closefile(newmemoryfile);
|
|
closefile(newaddressfile);
|
|
|
|
deletefile(CheatEngineDir+'Memory.UNDO');
|
|
deletefile(CheatEngineDir+'Addresses.UNDO');
|
|
renamefile(CheatEngineDir+'Memory.tmp',cheatenginedir+'Memory.UNDO');
|
|
renamefile(CheatEngineDir+'Addresses.tmp',CheatEngineDir+'Addresses.UNDO');
|
|
renamefile(CheatEngineDir+'Memory2.tmp',CheatEngineDir+'Memory.TMP');
|
|
Renamefile(CheatengineDir+'Address2.TMP',CheatEngineDir+'Addresses.TMP');
|
|
|
|
|
|
end;
|
|
|
|
procedure Open_Process;
|
|
begin
|
|
{$ifndef netclient}
|
|
ProcessHandler.ProcessHandle:=NewKernelHandler.OpenProcess(PROCESS_ALL_ACCESS,false,ProcessID);
|
|
le:=GetLastError;
|
|
{$endif}
|
|
end;
|
|
{
|
|
function MakeAddressWritable(address: dword):boolean;
|
|
var buf,x:dword;
|
|
begin
|
|
result:=false;
|
|
if ReadProcessMemory(processhandle,pointeR(address),@buf,4,x) then
|
|
begin
|
|
if ReadProcessMemory(processhandle,pointer(((address div $1000)*4)+$c0000000),@buf,4,x) then
|
|
begin
|
|
if copyonwrite then
|
|
buf:=(buf or $200) //when you write to it it will copy the page and give that to the process in writable state
|
|
else
|
|
buf:=(buf or $2); //just make it writable, even if it is shared
|
|
|
|
result:=WriteProcessMemory(processhandle,pointer(((address div $1000)*4)+$c0000000),@buf,4,x);
|
|
end;
|
|
end;
|
|
end;
|
|
}
|
|
|
|
{
|
|
procedure quicksortmemoryregions(lo,hi: integer);
|
|
var i,j: integer;
|
|
x,h: TMemoryRegion;
|
|
begin
|
|
i:=lo;
|
|
j:=hi;
|
|
|
|
x:=memoryregion[(lo+hi) div 2];
|
|
|
|
repeat
|
|
while (memoryregion[i].BaseAddress<x.BaseAddress) do inc(i);
|
|
while (memoryregion[j].BaseAddress>x.BaseAddress) do dec(j);
|
|
|
|
if i<=j then
|
|
begin
|
|
h:=memoryregion[i];
|
|
memoryregion[i]:=memoryregion[j];
|
|
memoryregion[j]:=h;
|
|
inc(i);
|
|
dec(j);
|
|
end;
|
|
|
|
until i>j;
|
|
|
|
if (lo<j) then quicksortmemoryregions(lo,j);
|
|
if (i<hi) then quicksortmemoryregions(i,hi);
|
|
end;
|
|
}
|
|
|
|
{
|
|
procedure GetProcessListSmall(ProcessList: TListBox);
|
|
Var SNAPHandle: THandle;
|
|
ProcessEntry: ProcessEntry32;
|
|
Check: Boolean;
|
|
begin
|
|
processlist.clear;
|
|
|
|
processlist.Sorted:=false;
|
|
SNAPHandle:=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
|
|
If SnapHandle>0 then
|
|
begin
|
|
ProcessEntry.dwSize:=SizeOf(ProcessEntry);
|
|
Check:=Process32First(SnapHandle,ProcessEntry);
|
|
while check do
|
|
begin
|
|
if processentry.th32ProcessID<>0 then
|
|
ProcessList.Items.Add(ExtractFilename(processentry.szExeFile));
|
|
|
|
check:=Process32Next(SnapHandle,ProcessEntry);
|
|
end;
|
|
end else raise exception.Create('I can''t get the process list. You are propably using windows NT. Use the window list instead!');
|
|
end; }
|
|
|
|
|
|
procedure GetProcessList(ProcessList: TListBox);
|
|
var sl: tstringlist;
|
|
i: integer;
|
|
pli: PProcessListInfo;
|
|
begin
|
|
sl:=tstringlist.create;
|
|
try
|
|
processlist.Sorted:=false;
|
|
for i:=0 to processlist.Items.count-1 do
|
|
if processlist.Items.Objects[i]<>nil then
|
|
begin
|
|
pli:=pointer(processlist.Items.Objects[i]);
|
|
if pli.processIcon>0 then
|
|
DestroyIcon(pli.processIcon);
|
|
freemem(pli);
|
|
end;
|
|
|
|
processlist.Items.Clear;
|
|
|
|
|
|
GetProcessList(sl);
|
|
processlist.Items.AddStrings(sl);
|
|
finally
|
|
sl.free;
|
|
end;
|
|
end;
|
|
|
|
|
|
function GetFirstModuleName(processid: dword): string;
|
|
var
|
|
SNAPHandle: THandle;
|
|
check: boolean;
|
|
ModuleEntry: MODULEENTRY32;
|
|
begin
|
|
SNAPHandle:=CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,processid);
|
|
if SNAPHandle<>0 then
|
|
begin
|
|
ModuleEntry.dwSize:=sizeof(moduleentry);
|
|
if Module32First(snaphandle,ModuleEntry) then
|
|
result:=moduleentry.szExePath
|
|
else
|
|
result:='';
|
|
|
|
closehandle(SNAPHandle);
|
|
end;
|
|
end;
|
|
|
|
procedure GetProcessList(ProcessList: TStrings);
|
|
Var SNAPHandle: THandle;
|
|
ProcessEntry: ProcessEntry32;
|
|
Check: Boolean;
|
|
|
|
HI: HICON;
|
|
ProcessListInfo: PProcessListInfo;
|
|
i: integer;
|
|
s: string;
|
|
begin
|
|
HI:=0;
|
|
|
|
for i:=0 to processlist.count-1 do
|
|
if processlist.Objects[i]<>nil then
|
|
begin
|
|
ProcessListInfo:= pointer( processlist.Objects[i]);
|
|
if ProcessListInfo.processIcon>0 then
|
|
DestroyIcon(ProcessListInfo.processIcon);
|
|
freemem(ProcessListInfo);
|
|
end;
|
|
|
|
processlist.clear;
|
|
|
|
|
|
SNAPHandle:=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
|
|
If SnapHandle>0 then
|
|
begin
|
|
ProcessEntry.dwSize:=SizeOf(ProcessEntry);
|
|
Check:=Process32First(SnapHandle,ProcessEntry);
|
|
while check do
|
|
begin
|
|
if getprocessicons then
|
|
begin
|
|
HI:=ExtractIcon(hinstance,ProcessEntry.szExeFile,0);
|
|
if HI=0 then
|
|
begin
|
|
//alternative method:
|
|
if processentry.th32ProcessID>0 then
|
|
begin
|
|
s:=GetFirstModuleName(processentry.th32ProcessID);
|
|
HI:=ExtractIcon(hinstance,pchar(s),0);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
if not (ProcessesWithIconsOnly and (hi=0)) then
|
|
begin
|
|
if processentry.th32ProcessID<>0 then
|
|
begin
|
|
// processinfo
|
|
getmem(ProcessListInfo,sizeof(TProcessListInfo));
|
|
ProcessListInfo.processID:=processentry.th32ProcessID;
|
|
ProcessListInfo.processIcon:=HI;
|
|
|
|
ProcessList.AddObject(IntTohex(processentry.th32ProcessID,8)+'-'+ExtractFilename(processentry.szExeFile), TObject(ProcessListInfo));
|
|
end;
|
|
end;
|
|
|
|
check:=Process32Next(SnapHandle,ProcessEntry);
|
|
end;
|
|
closehandle(snaphandle);
|
|
end else raise exception.Create('I can''t get the process list. You are propably using windows NT. Use the window list instead!');
|
|
end;
|
|
|
|
procedure GetWindowList(ProcessList: TListBox; showInvisible: boolean=true);
|
|
var previouswinhandle, winhandle: Hwnd;
|
|
winprocess: Dword;
|
|
temp: Pchar;
|
|
wintitle: string;
|
|
|
|
x: tstringlist;
|
|
i,j:integer;
|
|
|
|
ProcessListInfo: PProcessListInfo;
|
|
tempdword: dword;
|
|
begin
|
|
getmem(temp,101);
|
|
try
|
|
x:=tstringlist.Create;
|
|
|
|
for i:=0 to processlist.items.count-1 do
|
|
if processlist.items.Objects[i]<>nil then
|
|
begin
|
|
ProcessListInfo:=PProcessListInfo(processlist.items.Objects[i]);
|
|
if ProcessListInfo.processIcon>0 then
|
|
DestroyIcon(ProcessListInfo.processIcon);
|
|
|
|
freemem(ProcessListInfo);
|
|
end;
|
|
processlist.clear;
|
|
|
|
winhandle:=getwindow(getforegroundwindow,GW_HWNDFIRST);
|
|
|
|
i:=0;
|
|
while (winhandle<>0) and (i<10000) do
|
|
begin
|
|
if showInvisible or IsWindowVisible(winhandle) then
|
|
begin
|
|
GetWindowThreadProcessId(winhandle,addr(winprocess));
|
|
temp[0]:=#0;
|
|
getwindowtext(winhandle,temp,100);
|
|
temp[100]:=#0;
|
|
wintitle:=temp;
|
|
|
|
|
|
|
|
if length(wintitle)>0 then
|
|
begin
|
|
getmem(ProcessListInfo,sizeof(TProcessListInfo));
|
|
ProcessListInfo.processID:=winprocess;
|
|
ProcessListInfo.processIcon:=0;
|
|
{$ifndef standalonetrainer}
|
|
if formsettings.cbProcessIcons.checked then
|
|
begin
|
|
tempdword:=0;
|
|
if SendMessageTimeout(winhandle,WM_GETICON,ICON_SMALL,0,SMTO_ABORTIFHUNG, 100, tempdword )<>0 then
|
|
begin
|
|
ProcessListInfo.processIcon:=tempdword;
|
|
if ProcessListInfo.processIcon=0 then
|
|
begin
|
|
if SendMessageTimeout(winhandle,WM_GETICON,ICON_SMALL2,0,SMTO_ABORTIFHUNG, 100, tempdword )<>0 then
|
|
ProcessListInfo.processIcon:=tempdword;
|
|
|
|
if ProcessListInfo.processIcon=0 then
|
|
if SendMessageTimeout(winhandle,WM_GETICON,ICON_BIG,0,SMTO_ABORTIFHUNG, 100, tempdword )<>0 then
|
|
ProcessListInfo.processIcon:=tempdword;
|
|
end;
|
|
end else
|
|
begin
|
|
inc(i,100); //at worst case scenario this causes the list to wait 10 seconds
|
|
end;
|
|
end;
|
|
{$endif}
|
|
|
|
x.AddObject(IntTohex(winprocess,8)+'-'+wintitle,TObject(ProcessListInfo));
|
|
end;
|
|
end;
|
|
|
|
previouswinhandle:=winhandle;
|
|
winhandle:=getwindow(winhandle,GW_HWNDNEXT);
|
|
|
|
if winhandle=previouswinhandle then break;
|
|
|
|
inc(i);
|
|
end;
|
|
|
|
x.Sort;
|
|
processlist.Items.Assign(x);
|
|
finally
|
|
freemem(temp);
|
|
end;
|
|
end;
|
|
|
|
function GetCEdir:string;
|
|
begin
|
|
CheatEngineDir:=ExtractFilePath(application.ExeName);
|
|
result:=CheatEngineDir;
|
|
end;
|
|
|
|
function GetWinDir:string;
|
|
var x: pchar;
|
|
begin
|
|
getmem(x,200);
|
|
if GetWindowsDirectory(x,200)>0 then
|
|
begin
|
|
result:=x;
|
|
WindowsDir:=x;
|
|
end;
|
|
freemem(x);
|
|
end;
|
|
|
|
Procedure Shutdown;
|
|
//This will erase the temporary files and close the processhandle (In case it doesnt happen automatically)
|
|
begin
|
|
deletefile(CheatEngineDir+'Memory.TMP');
|
|
deletefile(CheatEngineDir+'Addresses.TMP');
|
|
deletefile(CheatEngineDir+'Memory.UNDO');
|
|
deletefile(CheatEngineDir+'Addresses.UNDO');
|
|
freemem(memory);
|
|
// Closehandle(processhandle);
|
|
|
|
end;
|
|
|
|
procedure ConvertStringToBytes(scanvalue:string; hex:boolean;var bytes: TBytes);
|
|
{
|
|
Converts a given string into a array of TBytes.
|
|
TBytes are not pure bytes, they can hold -1, which indicates a wildcard
|
|
}
|
|
var i,j,k: integer;
|
|
helpstr:string;
|
|
begin
|
|
setlength(bytes,0);
|
|
if length(scanvalue)=0 then exit;
|
|
|
|
while scanvalue[length(scanvalue)]=' ' do
|
|
scanvalue:=copy(scanvalue,1,length(scanvalue)-1);
|
|
|
|
if (pos('-',scanvalue)>0) or (pos(' ',scanvalue)>0) or (pos(',',scanvalue)>0) then
|
|
begin
|
|
//syntax is xx-xx-xx or xx xx xx
|
|
j:=1;
|
|
k:=0;
|
|
scanvalue:=scanvalue+' ';
|
|
|
|
for i:=1 to length(scanvalue) do
|
|
begin
|
|
if (scanvalue[i] in [' ', '-', ',']) then
|
|
begin
|
|
helpstr:=copy(scanvalue,j,i-j);
|
|
j:=i+1;
|
|
setlength(bytes,k+1);
|
|
try
|
|
if hex then bytes[k]:=strtoint('$'+helpstr)
|
|
else bytes[k]:=strtoint(helpstr);
|
|
except
|
|
bytes[k]:=-1;
|
|
//if it is not a '-' or ' ' or a valid value then I assume it is a wildcard.(I know, retarded)
|
|
end;
|
|
inc(k);
|
|
end;
|
|
end;
|
|
end else
|
|
begin
|
|
//syntax is xxxxxx
|
|
k:=0;
|
|
j:=1;
|
|
for i:=1 to length(scanvalue) do
|
|
begin
|
|
if (i mod 2)=0 then
|
|
begin
|
|
helpstr:=copy(scanvalue,j,i-j+1);
|
|
j:=i+1;
|
|
setlength(bytes,k+1);
|
|
try
|
|
bytes[k]:=strtoint('$'+helpstr);
|
|
except
|
|
bytes[k]:=-1;
|
|
end;
|
|
inc(k);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
procedure rewritedata(processhandle: thandle; address:dword; buffer: pointer; size:dword);
|
|
var written: dword;
|
|
original,a: dword;
|
|
begin
|
|
//make writable, write, restore, flush
|
|
VirtualProtectEx(processhandle, pointer(address),size,PAGE_EXECUTE_READWRITE,original);
|
|
writeprocessmemory(processhandle,pointer(address),buffer,size,written);
|
|
VirtualProtectEx(processhandle,pointer(address),size,original,a);
|
|
end;
|
|
|
|
procedure rewritecode(processhandle: thandle; address:dword; buffer: pointer; size:dword);
|
|
begin
|
|
rewritedata(processhandle,address,buffer,size);
|
|
FlushInstructionCache(processhandle,pointer(address),size);
|
|
end;
|
|
|
|
function HasHyperthreading: boolean;
|
|
var a,b,c,d: dword;
|
|
begin
|
|
result:=false;
|
|
asm
|
|
pushad
|
|
mov eax,0
|
|
cpuid
|
|
mov a,eax
|
|
mov b,ebx
|
|
mov c,ecx
|
|
mov d,edx
|
|
popad
|
|
end;
|
|
|
|
if (b=$756e6547) and (d=$49656e69) and (c=$6c65746e) then
|
|
begin
|
|
//intel cpu
|
|
asm
|
|
pushad
|
|
mov eax,1
|
|
cpuid
|
|
mov a,eax
|
|
mov b,ebx
|
|
mov c,ecx
|
|
mov d,edx
|
|
popad
|
|
end;
|
|
|
|
if ((d shr 28) and 1)=1 then
|
|
result:=true; //it has hyperthreading
|
|
end;
|
|
|
|
|
|
end;
|
|
|
|
function GetCPUCount: integer;
|
|
{
|
|
this function will return how many active cpu cores there are at your disposal
|
|
}
|
|
var cpucount: integer;
|
|
PA,SA: dword;
|
|
begin
|
|
//get the cpu and system affinity mask, only processmask is used
|
|
GetProcessAffinityMask(getcurrentprocess,PA,SA);
|
|
|
|
cpucount:=0;
|
|
while pa>0 do
|
|
begin
|
|
if (pa mod 2)=1 then inc(cpucount);
|
|
pa:=pa div 2;
|
|
end;
|
|
|
|
result:=cpucount;
|
|
|
|
if result=0 then result:=1;
|
|
end;
|
|
|
|
function LoadFormPosition(form: Tform; var x: array of integer):boolean;
|
|
var reg: tregistry;
|
|
s: string;
|
|
buf: array of integer;
|
|
buf2: array [0..100] of byte;
|
|
i: integer;
|
|
z: integer;
|
|
begin
|
|
result:=false;
|
|
reg:=tregistry.create;
|
|
try
|
|
Reg.RootKey := HKEY_CURRENT_USER;
|
|
if Reg.OpenKey('\Software\Cheat Engine',false) then
|
|
begin
|
|
if reg.valueexists('Save window positions') then
|
|
if reg.readbool('Save window positions') = false then exit;
|
|
end;
|
|
|
|
if Reg.OpenKey('\Software\Cheat Engine\Window Positions',false) then
|
|
begin
|
|
s:=form.Name;
|
|
s:=s+' Position';
|
|
|
|
if reg.ValueExists(s) then
|
|
begin
|
|
|
|
setlength(buf,4+length(x)); //for some reason it checks if
|
|
|
|
z:=reg.ReadBinaryData(s,buf[0],length(buf)*sizeof(integer));
|
|
|
|
form.position:=poDesigned;
|
|
form.top:=buf[0];
|
|
form.Left:=buf[1];
|
|
form.width:=buf[2];
|
|
form.height:=buf[3];
|
|
|
|
for i:=0 to length(x)-1 do
|
|
x[i]:=buf[4+i];
|
|
|
|
setlength(buf,0);
|
|
|
|
result:=true;
|
|
end;
|
|
end;
|
|
finally
|
|
reg.free;
|
|
end;
|
|
end;
|
|
|
|
procedure SaveFormPosition(form: Tform; extra: array of integer);
|
|
{
|
|
This function will save the position and the optional data in extra to an array element in the registry
|
|
}
|
|
var reg: tregistry;
|
|
buf: tmemorystream;
|
|
temp: integer;
|
|
i: integer;
|
|
s: string;
|
|
begin
|
|
//save window pos
|
|
reg:=tregistry.create;
|
|
try
|
|
Reg.RootKey := HKEY_CURRENT_USER;
|
|
|
|
//make sure the option to save is enabled
|
|
if Reg.OpenKey('\Software\Cheat Engine',false) then
|
|
begin
|
|
if reg.valueexists('Save window positions') then
|
|
if reg.readbool('Save window positions') = false then exit;
|
|
end;
|
|
|
|
|
|
if Reg.OpenKey('\Software\Cheat Engine\Window Positions',true) then
|
|
begin
|
|
//registry is open, gather data
|
|
buf:=tmemorystream.Create;
|
|
try
|
|
temp:=form.top;
|
|
buf.Write(temp,sizeof(temp));
|
|
|
|
temp:=form.left;
|
|
buf.Write(temp,sizeof(temp));
|
|
|
|
temp:=form.width;
|
|
buf.Write(temp,sizeof(temp));
|
|
|
|
temp:=form.height;
|
|
buf.Write(temp,sizeof(temp));
|
|
|
|
|
|
//save extra data
|
|
for i:=0 to length(extra)-1 do
|
|
buf.Write(extra[i],sizeof(extra[i]));
|
|
|
|
//and now save buf to the registry
|
|
s:=form.Name;
|
|
s:=s+' Position';
|
|
|
|
reg.WriteBinaryData(s,buf.Memory^,buf.Size);
|
|
finally
|
|
buf.free;
|
|
end;
|
|
end;
|
|
finally
|
|
reg.free;
|
|
end;
|
|
end;
|
|
|
|
function GetRelativeFilePath(filename: string):string;
|
|
begin
|
|
result:=filename;
|
|
if pos(uppercase(CheatEngineDir),uppercase(filename))=1 then
|
|
result:='.\'+copy(filename,length(CheatEnginedir)+1,length(filename));
|
|
end;
|
|
|
|
function ConvertHexStrToRealStr(const s: string): string;
|
|
{
|
|
Converts a string meant to be a hexadeimcal string to the real way delphi reads
|
|
it
|
|
e.g:
|
|
123 > $123
|
|
-123 > -$123
|
|
+123 > +$123
|
|
#123 > 123
|
|
+#123 > +123
|
|
}
|
|
var ishex: string;
|
|
start: integer;
|
|
i,j,k: integer;
|
|
|
|
bytes: string;
|
|
t: string;
|
|
f: single;
|
|
d: double;
|
|
begin
|
|
if s='' then
|
|
begin
|
|
result:=s;
|
|
exit;
|
|
end;
|
|
start:=1;
|
|
|
|
ishex:='$';
|
|
for i:=start to length(s) do
|
|
case s[i] of
|
|
'''' , '"' :
|
|
begin
|
|
//char
|
|
if (i+2)<=length(s) then
|
|
begin
|
|
bytes:='';
|
|
for j:=i+2 to length(s) do
|
|
if s[j] in ['''','"'] then
|
|
begin
|
|
bytes:=copy(s,i+1,j-(i+1));
|
|
|
|
result:='$';
|
|
for k:=length(bytes) downto 1 do
|
|
result:=result+inttohex(byte(bytes[k]),2);
|
|
|
|
//result := '$'+inttohex(byte(s[i+1]),2);
|
|
exit; //this is it, no further process required, or appreciated...
|
|
|
|
end;
|
|
|
|
|
|
|
|
end;
|
|
end;
|
|
|
|
'#' :
|
|
begin
|
|
ishex:='';
|
|
start:=2;
|
|
break;
|
|
end;
|
|
|
|
'(' :
|
|
begin
|
|
if copy(s,1,5)='(INT)' then
|
|
begin
|
|
t:=copy(s,6,length(s));
|
|
val(t, k,j);
|
|
if j=0 then
|
|
begin
|
|
result:='$'+inttohex(k,8);
|
|
|
|
if s[1]='-' then
|
|
result:='-'+result;
|
|
|
|
if s[1]='+' then
|
|
result:='+'+result;
|
|
|
|
exit;
|
|
end;
|
|
end;
|
|
|
|
if copy(s,1,8)='(DOUBLE)' then
|
|
begin
|
|
t:=copy(s,9,length(s));
|
|
val(t, d,j);
|
|
if j=0 then
|
|
begin
|
|
result:='$'+inttohex(PINT64(@d)^,8);
|
|
|
|
if s[1]='-' then
|
|
result:='-'+result;
|
|
|
|
if s[1]='+' then
|
|
result:='+'+result;
|
|
|
|
exit;
|
|
end;
|
|
end;
|
|
|
|
if copy(s,1,7)='(FLOAT)' then
|
|
begin
|
|
t:=copy(s,8,length(s));
|
|
val(t, f,j);
|
|
if j=0 then
|
|
begin
|
|
result:='$'+inttohex(pdword(@f)^,8);
|
|
|
|
if s[1]='-' then
|
|
result:='-'+result;
|
|
|
|
if s[1]='+' then
|
|
result:='+'+result;
|
|
|
|
exit;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
if s[1]='-' then
|
|
begin
|
|
result:='-'+ishex+copy(s,start+1,length(s))
|
|
end
|
|
else
|
|
if s[1]='+' then
|
|
begin
|
|
result:='+'+ishex+copy(s,start+1,length(s));
|
|
end
|
|
else
|
|
begin
|
|
result:=ishex+copy(s,start,length(s));
|
|
end;
|
|
end;
|
|
|
|
function HexStrToInt(const S: string): Integer;
|
|
begin
|
|
result:=StrToint(ConvertHexStrToRealStr(s));
|
|
end;
|
|
|
|
function HexStrToInt64(const S: string): Int64;
|
|
begin
|
|
result:=StrToint64(ConvertHexStrToRealStr(s));
|
|
end;
|
|
|
|
function isjumporcall(address: dword; var addresstojumpto: dword): boolean;
|
|
var buf: array [0..31] of byte;
|
|
actualread: dword;
|
|
i,j: integer;
|
|
st: string;
|
|
offset: dword;
|
|
haserror: boolean;
|
|
begin
|
|
{$ifndef standalonetrainer}
|
|
result:=false;
|
|
|
|
if readprocessmemory(processhandle,pointer(address),@buf[0],32,actualread) then
|
|
begin
|
|
if buf[0] in [$0f,$70..$7f,$e3,$e8,$e9,$eb,$ff] then //possible
|
|
begin
|
|
case buf[0] of
|
|
$0f:
|
|
begin
|
|
if (not (buf[1] in [$80..$8f])) then exit; //not one of them
|
|
result:=true;
|
|
addresstojumpto:=address+plongint(@buf[2])^+6;
|
|
end;
|
|
|
|
$70..$7f,$e3,$eb: //(un)conditional jump (1 byte)
|
|
begin
|
|
result:=true;
|
|
addresstojumpto:=address+pshortint(@buf[1])^+2;
|
|
end;
|
|
|
|
$e8,$e9: //jump or call unconditional (4 byte)
|
|
begin
|
|
result:=true;
|
|
addresstojumpto:=address+plongint(@buf[1])^+5;
|
|
end;
|
|
|
|
$ff: //disassemble to see what it is
|
|
begin
|
|
st:=disassemble(address);
|
|
st:=copy(st,pos('-',st)+2,length(st));
|
|
st:=copy(st,pos('-',st)+2,length(st));
|
|
|
|
i:=pos('jmp',st);
|
|
j:=pos('call',st);
|
|
if (i=1) or (j=1) then
|
|
begin
|
|
//now determine where it jumps to
|
|
i:=pos('[',st);
|
|
if i>0 then
|
|
begin
|
|
st:=copy(st,i,pos(']',st)-i+1);
|
|
|
|
addresstojumpto:=symhandler.getAddressFromName(st, false, haserror); //the pointer interpreter code can do this
|
|
result:=not haserror;
|
|
end;
|
|
|
|
end;
|
|
end;
|
|
|
|
|
|
end;
|
|
end;
|
|
|
|
end;
|
|
{$endif}
|
|
|
|
end;
|
|
|
|
|
|
function readAndParseAddress(address: dword; variableType: TVariableType): string;
|
|
var buf: array [0..7] of byte;
|
|
x: dword;
|
|
check: boolean;
|
|
begin
|
|
result:='???';
|
|
case variableType of
|
|
vtByte:
|
|
begin
|
|
if ReadProcessMemory(processhandle,pointer(address),@buf[0],1,x) then
|
|
result:=inttostr(buf[0]);
|
|
end;
|
|
|
|
vtWord:
|
|
begin
|
|
if ReadProcessMemory(processhandle,pointer(address),@buf[0],2,x) then
|
|
result:=inttostr(pword(@buf[0])^);
|
|
end;
|
|
|
|
vtDWord:
|
|
begin
|
|
if ReadProcessMemory(processhandle,pointer(address),@buf[0],4,x) then
|
|
result:=inttostr(pdword(@buf[0])^);
|
|
end;
|
|
|
|
vtSingle:
|
|
begin
|
|
if ReadProcessMemory(processhandle,pointer(address),@buf[0],4,x) then
|
|
result:=floattostr(psingle(@buf[0])^);
|
|
end;
|
|
|
|
vtDouble:
|
|
begin
|
|
if ReadProcessMemory(processhandle,pointer(address),@buf[0],8,x) then
|
|
result:=floattostr(pdouble(@buf[0])^);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
const HEAP_NO_SERIALIZE =$00000001;
|
|
const HEAP_GROWABLE =$00000002;
|
|
const HEAP_GENERATE_EXCEPTIONS =$00000004;
|
|
const HEAP_ZERO_MEMORY =$00000008;
|
|
const HEAP_REALLOC_IN_PLACE_ONLY =$00000010;
|
|
const HEAP_TAIL_CHECKING_ENABLED =$00000020;
|
|
const HEAP_FREE_CHECKING_ENABLED =$00000040;
|
|
const HEAP_DISABLE_COALESCE_ON_FREE =$00000080;
|
|
const HEAP_CREATE_ALIGN_16 =$00010000;
|
|
const HEAP_CREATE_ENABLE_TRACING =$00020000;
|
|
const HEAP_CREATE_ENABLE_EXECUTE =$00040000;
|
|
const HEAP_MAXIMUM_TAG =$0FFF;
|
|
const HEAP_PSEUDO_TAG_FLAG =$8000;
|
|
const HEAP_TAG_SHIFT =18;
|
|
|
|
function heapflagstostring(heapflags: dword): string;
|
|
begin
|
|
result:='';
|
|
if (heapflags and HEAP_NO_SERIALIZE) > 0 then result:=result+'HEAP_NO_SERIALIZE+';
|
|
if (heapflags and HEAP_GROWABLE) > 0 then result:=result+'HEAP_GROWABLE+';
|
|
if (heapflags and HEAP_GENERATE_EXCEPTIONS) > 0 then result:='HEAP_GENERATE_EXCEPTIONS+';
|
|
if (heapflags and HEAP_ZERO_MEMORY) > 0 then result:=result+'HEAP_ZERO_MEMORY+';
|
|
if (heapflags and HEAP_REALLOC_IN_PLACE_ONLY) > 0 then result:=result+'HEAP_REALLOC_IN_PLACE_ONLY+';
|
|
if (heapflags and HEAP_TAIL_CHECKING_ENABLED) > 0 then result:=result+'HEAP_TAIL_CHECKING_ENABLED+';
|
|
if (heapflags and HEAP_FREE_CHECKING_ENABLED) > 0 then result:=result+'HEAP_FREE_CHECKING_ENABLED+';
|
|
if (heapflags and HEAP_DISABLE_COALESCE_ON_FREE) > 0 then result:=result+'HEAP_DISABLE_COALESCE_ON_FREE+';
|
|
if (heapflags and HEAP_CREATE_ALIGN_16) > 0 then result:=result+'HEAP_CREATE_ALIGN_16+';
|
|
if (heapflags and HEAP_CREATE_ENABLE_TRACING) > 0 then result:=result+'HEAP_CREATE_ENABLE_TRACING+';
|
|
if (heapflags and HEAP_CREATE_ENABLE_EXECUTE) > 0 then result:=result+'HEAP_CREATE_ENABLE_EXECUTE+';
|
|
if (heapflags and HEAP_PSEUDO_TAG_FLAG) > 0 then result:=result+'HEAP_PSEUDO_TAG_FLAG+';
|
|
|
|
|
|
if length(result)>0 then
|
|
result:=Copy(result,1,length(result)-1)+'('+inttohex(heapflags,1)+')';
|
|
end;
|
|
|
|
function allocationtypetostring(alloctype: dword): string;
|
|
begin
|
|
result:='';
|
|
if (alloctype and MEM_COMMIT) > 0 then result:='MEM_COMMIT+';
|
|
if (alloctype and MEM_RESERVE) > 0 then result:=result+'MEM_RESERVE+';
|
|
if (alloctype and MEM_RESET) > 0 then result:=result+'MEM_RESET+';
|
|
if (alloctype and MEM_TOP_DOWN) > 0 then result:=result+'MEM_TOP_DOWN+';
|
|
if (alloctype and $400000) > 0 then result:=result+'MEM_PHYSICAL+';
|
|
if (alloctype and $20000000) > 0 then result:=result+'MEM_LARGE_PAGES+';
|
|
|
|
if length(result)>0 then
|
|
result:=Copy(result,1,length(result)-1)+'('+inttohex(alloctype,1)+')';
|
|
end;
|
|
|
|
function allocationprotecttostring(protect: dword): string;
|
|
begin
|
|
result:='';
|
|
if (protect and PAGE_EXECUTE) > 0 then result:='PAGE_EXECUTE+';
|
|
if (protect and PAGE_EXECUTE_READ) > 0 then result:=result+'PAGE_EXECUTE_READ+';
|
|
if (protect and PAGE_EXECUTE_READWRITE) > 0 then result:=result+'PAGE_EXECUTE_READWRITE+';
|
|
if (protect and PAGE_EXECUTE_WRITECOPY) > 0 then result:=result+'PAGE_EXECUTE_WRITECOPY+';
|
|
if (protect and PAGE_NOACCESS) > 0 then result:=result+'PAGE_NOACCESS+';
|
|
if (protect and PAGE_READONLY) > 0 then result:=result+'PAGE_READONLY+';
|
|
if (protect and PAGE_READWRITE) > 0 then result:=result+'PAGE_READWRITE+';
|
|
if (protect and PAGE_WRITECOPY) > 0 then result:=result+'PAGE_WRITECOPY+';
|
|
if (protect and PAGE_GUARD) > 0 then result:=result+'PAGE_GUARD+';
|
|
if (protect and PAGE_NOCACHE) > 0 then result:=result+'PAGE_NOCACHE+';
|
|
if (protect and $400) > 0 then result:=result+'PAGE_WRITECOMBINE+';
|
|
|
|
if length(result)>0 then
|
|
result:=Copy(result,1,length(result)-1)+'('+inttohex(protect,1)+')';
|
|
end;
|
|
|
|
function freetypetostring(freetype: dword):string;
|
|
begin
|
|
result:='';
|
|
|
|
if (freetype and MEM_DECOMMIT) > 0 then result:='MEM_DECOMMIT+';
|
|
if (freetype and MEM_RELEASE) > 0 then result:='MEM_RELEASE+';
|
|
result:=Copy(result,1,length(result)-1)+'('+inttohex(freetype,1)+')';
|
|
end;
|
|
|
|
|
|
function isAddress(address: dword):boolean;
|
|
var mbi: TMemoryBasicInformation;
|
|
begin
|
|
result:=false;
|
|
if VirtualQueryEx(processhandle, pointer(address), mbi, sizeof(mbi))>0 then
|
|
result:=(mbi.State=MEM_COMMIT);// and (mbi.AllocationProtect<>PAGE_NOACCESS);
|
|
end;
|
|
|
|
function isExecutableAddress(address: dword):boolean;
|
|
var mbi: TMemoryBasicInformation;
|
|
begin
|
|
result:=false;
|
|
if VirtualQueryEx(processhandle, pointer(address), mbi, sizeof(mbi))>0 then
|
|
result:=(mbi.State=MEM_COMMIT) and (((mbi.Protect and PAGE_EXECUTE)=PAGE_EXECUTE) or ((mbi.Protect and PAGE_EXECUTE_READ)=PAGE_EXECUTE_READ) or ((mbi.Protect and PAGE_EXECUTE_READWRITE)=PAGE_EXECUTE_READWRITE) or ((mbi.Protect and PAGE_EXECUTE_WRITECOPY)=PAGE_EXECUTE_WRITECOPY) );
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
initialization
|
|
getmem(tempdir,256);
|
|
GetTempPath(256,tempdir);
|
|
GetWindir;
|
|
keysfilemapping:=0;
|
|
keys:=nil;
|
|
|
|
setlength(windowlist,0);
|
|
setlength(donthidelist,0);
|
|
allwindowsareback:=true;
|
|
stealthhook:=0;
|
|
iswin2kplus:=GetSystemType>=5;
|
|
|
|
flushthread:=TSaveDataThread.Create(false); //used for scanning, starts idled because the event isn't triggered
|
|
prefetchthread:=TPrefetchDataThread.create(false);
|
|
|
|
processhandler:=TProcessHandler.create;
|
|
|
|
finalization
|
|
if flushthread<>nil then
|
|
begin
|
|
flushthread.Terminate;
|
|
flushthread.dataavailable.SetEvent;
|
|
flushthread.WaitFor;
|
|
flushthread.free;
|
|
end;
|
|
|
|
if tempdir<>nil then
|
|
freemem(tempdir);
|
|
|
|
end.
|
|
|
|
|
|
|
|
|