| 1 | unit CEFuncProc; |
|---|
| 2 | //This version of CEFuncProc has been COPIED to the server dir |
|---|
| 3 | //Cheat Engine regular WONT look at this |
|---|
| 4 | |
|---|
| 5 | interface |
|---|
| 6 | |
|---|
| 7 | uses Windows,StdCtrls,Classes,SysUtils,dialogs,tlhelp32,forms,messages, |
|---|
| 8 | Graphics, |
|---|
| 9 | ComCtrls, |
|---|
| 10 | reinit, |
|---|
| 11 | assemblerunit, |
|---|
| 12 | imagehlp, |
|---|
| 13 | registry, |
|---|
| 14 | |
|---|
| 15 | |
|---|
| 16 | netapis, |
|---|
| 17 | |
|---|
| 18 | NewKernelHandler, |
|---|
| 19 | |
|---|
| 20 | |
|---|
| 21 | hypermode, |
|---|
| 22 | firstscanhandler, |
|---|
| 23 | |
|---|
| 24 | |
|---|
| 25 | |
|---|
| 26 | math,syncobjs, shellapi, ProcessHandlerUnit; |
|---|
| 27 | |
|---|
| 28 | //memscan |
|---|
| 29 | type TScanOption=(soUnknownValue,soExactValue,soValueBetween,soBiggerThan,soSmallerThan, soIncreasedValue, soIncreasedValueBy, soDecreasedValue, soDecreasedValueBy, soChanged, soUnchanged, soSameAsFirst, soCustom); |
|---|
| 30 | type TScanType=(stNewScan, stFirstScan, stNextScan); |
|---|
| 31 | type TRoundingType=(rtRounded,rtExtremerounded,rtTruncated); |
|---|
| 32 | type TVariableType=(vtByte, vtWord, vtDword, vtQword, vtSingle, vtDouble, vtString, vtUnicodeString, vtByteArray, vtBinary, vtAll, vtCustom, vtPointer); |
|---|
| 33 | type TCustomScanType=(cstNone, cstAutoAssembler, cstCPP, cstDLLFunction); |
|---|
| 34 | |
|---|
| 35 | |
|---|
| 36 | type PUINT64 = ^uint64; |
|---|
| 37 | Type TBytes = array of integer; //An array that represents a row of byte. Ints are used to be able to represent wildcards (-1) |
|---|
| 38 | type tfloatscan=(rounded,extremerounded,truncated); |
|---|
| 39 | Type TMemoryRegion = record |
|---|
| 40 | BaseAddress: Dword; |
|---|
| 41 | MemorySize: Dword; |
|---|
| 42 | IsChild: boolean; //means there is a region before it |
|---|
| 43 | startaddress: pointer; //pointer to a spot in the whole memory copy, it means the start of this region |
|---|
| 44 | end; |
|---|
| 45 | type TMemoryRegions = array of TMemoryRegion; |
|---|
| 46 | type PMemoryRegions = ^TMemoryRegions; |
|---|
| 47 | |
|---|
| 48 | type TBitAddress = record |
|---|
| 49 | address: dword; |
|---|
| 50 | bit: dword; |
|---|
| 51 | end; |
|---|
| 52 | |
|---|
| 53 | type TBitAddressArray=array [0..0] of TBitAddress; |
|---|
| 54 | type PBitAddressArray=^TBitAddressArray; |
|---|
| 55 | |
|---|
| 56 | type TProcessListInfo=record |
|---|
| 57 | processID: dword; |
|---|
| 58 | processIcon: HICON; |
|---|
| 59 | end; |
|---|
| 60 | PProcessListInfo=^TProcessListInfo; |
|---|
| 61 | |
|---|
| 62 | type TFreememoryThread = class(tthread) |
|---|
| 63 | public |
|---|
| 64 | Bitscan: array of byte; |
|---|
| 65 | tempbits: array of byte; |
|---|
| 66 | FoundAddress: array of dword; |
|---|
| 67 | FoundValue1:Array of Byte; |
|---|
| 68 | FoundValue2:Array of word; |
|---|
| 69 | FoundValue3:Array of Dword; |
|---|
| 70 | FoundValue7:Array of Int64; |
|---|
| 71 | FoundValue8:array of byte; |
|---|
| 72 | FoundValue4:Array of Single; |
|---|
| 73 | FoundValue5:Array of Double; |
|---|
| 74 | foundValue6:Array of int64; //byte ????? |
|---|
| 75 | FoundValue1switch:Array of Byte; |
|---|
| 76 | FoundValue2switch:Array of word; |
|---|
| 77 | FoundValue3switch:Array of Dword; |
|---|
| 78 | FoundValue7switch:Array of Int64; |
|---|
| 79 | FoundValue8switch:array of byte; |
|---|
| 80 | FoundValue4switch:Array of Single; |
|---|
| 81 | FoundValue5switch:Array of Double; |
|---|
| 82 | foundValue6switch:Array of int64; |
|---|
| 83 | |
|---|
| 84 | foundaddressB: array of TBitAddress; |
|---|
| 85 | previousmemory: array of byte; |
|---|
| 86 | |
|---|
| 87 | SearchAddress: array of dword; |
|---|
| 88 | SearchAddressB: array of TBitAddress; |
|---|
| 89 | |
|---|
| 90 | previousmemory1: array of Byte; |
|---|
| 91 | previousmemory2: array of word; |
|---|
| 92 | previousmemory3: array of dword; |
|---|
| 93 | previousmemory4: array of Single; |
|---|
| 94 | previousmemory5: array of Double; |
|---|
| 95 | previousmemory6: array of int64; //Byte; |
|---|
| 96 | PreviousMemory7: Array of Int64; |
|---|
| 97 | PreviousMemory8: array of byte; |
|---|
| 98 | previousmemory1switch: array of Byte; |
|---|
| 99 | previousmemory2switch: array of word; |
|---|
| 100 | previousmemory3switch: array of dword; |
|---|
| 101 | previousmemory4switch: array of Single; |
|---|
| 102 | previousmemory5switch: array of Double; |
|---|
| 103 | previousmemory6switch: array of int64; //Byte; |
|---|
| 104 | PreviousMemory7switch: Array of Int64; |
|---|
| 105 | PreviousMemory8switch: array of byte; |
|---|
| 106 | |
|---|
| 107 | Memory: ^Byte; |
|---|
| 108 | memory2: ^byte; |
|---|
| 109 | bytes: array of integer; //-1=wildcard |
|---|
| 110 | bytearray: array of byte; |
|---|
| 111 | |
|---|
| 112 | procedure execute; override; |
|---|
| 113 | end; |
|---|
| 114 | |
|---|
| 115 | |
|---|
| 116 | |
|---|
| 117 | function ConvertHexStrToRealStr(const s: string): string; |
|---|
| 118 | function HexStrToInt(const S: string): Integer; |
|---|
| 119 | function HexStrToInt64(const S: string): Int64; |
|---|
| 120 | |
|---|
| 121 | function readAndParseAddress(address: dword; variableType: TVariableType): string; |
|---|
| 122 | function isjumporcall(address: dword; var addresstojumpto: dword): boolean; |
|---|
| 123 | |
|---|
| 124 | |
|---|
| 125 | |
|---|
| 126 | |
|---|
| 127 | procedure rewritecode(processhandle: thandle; address:dword; buffer: pointer; size:dword); |
|---|
| 128 | procedure rewritedata(processhandle: thandle; address:dword; buffer: pointer; size:dword); |
|---|
| 129 | |
|---|
| 130 | procedure GetProcessList(ProcessList: TListBox); overload; |
|---|
| 131 | procedure GetProcessList(ProcessList: TStrings); overload; |
|---|
| 132 | procedure GetWindowList(ProcessList: TListBox); |
|---|
| 133 | function AvailMem:dword; |
|---|
| 134 | function isreadable(address:dword):boolean; |
|---|
| 135 | |
|---|
| 136 | |
|---|
| 137 | procedure RemoveAddress(address: Dword;bit: Byte; vartype: Integer); |
|---|
| 138 | |
|---|
| 139 | function GetCEdir:string; |
|---|
| 140 | procedure Open_Process; |
|---|
| 141 | Procedure Shutdown; |
|---|
| 142 | function KeyToStr(key:word):string; |
|---|
| 143 | |
|---|
| 144 | function undolastscan(valtype: integer;hexadecimal:boolean): integer; |
|---|
| 145 | |
|---|
| 146 | procedure ConvertStringToBytes(scanvalue:string; hex:boolean;var bytes: TBytes); |
|---|
| 147 | function getbit(bitnr: integer; bt: dword):integer; |
|---|
| 148 | procedure setbit(bitnr: integer; var bt: Byte;state:integer); overload; |
|---|
| 149 | procedure setbit(bitnr: integer; var bt: dword;state:integer); overload; |
|---|
| 150 | |
|---|
| 151 | function eflags_setCF(flagvalue: dword; value: integer): DWORD; |
|---|
| 152 | function eflags_setPF(flagvalue: dword; value: integer): DWORD; |
|---|
| 153 | function eflags_setAF(flagvalue: dword; value: integer): DWORD; |
|---|
| 154 | function eflags_setZF(flagvalue: dword; value: integer): DWORD; |
|---|
| 155 | function eflags_setSF(flagvalue: dword; value: integer): DWORD; |
|---|
| 156 | function eflags_setTF(flagvalue: dword; value: integer): DWORD; |
|---|
| 157 | function eflags_setIF(flagvalue: dword; value: integer): DWORD; |
|---|
| 158 | function eflags_setDF(flagvalue: dword; value: integer): DWORD; |
|---|
| 159 | function eflags_setOF(flagvalue: dword; value: integer): DWORD; |
|---|
| 160 | function eflags_setIOPL(flagvalue: dword; value: integer): DWORD; |
|---|
| 161 | function eflags_setNT(flagvalue: dword; value: integer): DWORD; |
|---|
| 162 | function eflags_setRF(flagvalue: dword; value: integer): DWORD; |
|---|
| 163 | function eflags_setVM(flagvalue: dword; value: integer): DWORD; |
|---|
| 164 | function eflags_setAC(flagvalue: dword; value: integer): DWORD; |
|---|
| 165 | function eflags_setVIF(flagvalue: dword; value: integer): DWORD; |
|---|
| 166 | function eflags_setVIP(flagvalue: dword; value: integer): DWORD; |
|---|
| 167 | function eflags_setID(flagvalue: dword; value: integer): DWORD; |
|---|
| 168 | |
|---|
| 169 | |
|---|
| 170 | |
|---|
| 171 | |
|---|
| 172 | function ByteStringToText(s: string;hex: boolean):string; |
|---|
| 173 | function ByteStringToDouble(s: string;hex: boolean):double; |
|---|
| 174 | function ByteStringToSingle(s: string;hex: boolean):single; |
|---|
| 175 | function ByteStringToInt(s: string;hex: boolean):int64; |
|---|
| 176 | function VarToBytes(v: pointer; size: integer): string; |
|---|
| 177 | function RawToString(const buf: array of byte; vartype: integer;showashex: boolean; bufsize: integer):string; |
|---|
| 178 | function IntToBin(i: int64):string; |
|---|
| 179 | function BinToInt(s: string): int64; |
|---|
| 180 | |
|---|
| 181 | procedure decimal(var key: char); |
|---|
| 182 | procedure hexadecimal(var key: char); |
|---|
| 183 | |
|---|
| 184 | function GetSystemType: Integer; |
|---|
| 185 | |
|---|
| 186 | |
|---|
| 187 | procedure ToggleOtherWindows; |
|---|
| 188 | |
|---|
| 189 | Procedure InjectDll(dllname: string; functiontocall: string=''); |
|---|
| 190 | Function GetRelativeFilePath(filename: string):string; |
|---|
| 191 | |
|---|
| 192 | function GetCPUCount: integer; |
|---|
| 193 | function HasHyperthreading: boolean; |
|---|
| 194 | procedure SaveFormPosition(form: Tform; extra: array of integer); |
|---|
| 195 | function LoadFormPosition(form: Tform; var x: array of integer):boolean; |
|---|
| 196 | |
|---|
| 197 | function heapflagstostring(heapflags: dword): string; |
|---|
| 198 | function allocationtypetostring(alloctype: dword): string; |
|---|
| 199 | function allocationprotecttostring(protect: dword): string; |
|---|
| 200 | function freetypetostring(freetype: dword):string; |
|---|
| 201 | function isAddress(address: dword):boolean; |
|---|
| 202 | |
|---|
| 203 | |
|---|
| 204 | Procedure CreateCodeCave(address:dword; sourceaddress:dword; sizeofcave: integer); |
|---|
| 205 | |
|---|
| 206 | |
|---|
| 207 | procedure errorbeep; |
|---|
| 208 | |
|---|
| 209 | |
|---|
| 210 | |
|---|
| 211 | |
|---|
| 212 | procedure SetLanguage; |
|---|
| 213 | |
|---|
| 214 | |
|---|
| 215 | |
|---|
| 216 | |
|---|
| 217 | procedure DetachIfPossible; |
|---|
| 218 | |
|---|
| 219 | |
|---|
| 220 | procedure getexecutablememoryregionsfromregion(start: dword; stop:dword; var memoryregions: TMemoryRegions); |
|---|
| 221 | |
|---|
| 222 | const |
|---|
| 223 | Exact_value = 0; |
|---|
| 224 | Increased_value = 1; |
|---|
| 225 | Increased_value_by = 2; |
|---|
| 226 | Decreased_value = 3; |
|---|
| 227 | Decreased_value_by = 4; |
|---|
| 228 | Changed_value = 5; |
|---|
| 229 | Unchanged_value = 6; |
|---|
| 230 | Advanced_Scan = 7; |
|---|
| 231 | String_Scan = 8; |
|---|
| 232 | SmallerThan = 9; |
|---|
| 233 | BiggerThan = 10; |
|---|
| 234 | Userdefined = 11; //not used |
|---|
| 235 | ValueBetween = 12; |
|---|
| 236 | SameAsFirst = 13; |
|---|
| 237 | |
|---|
| 238 | splitvalue=400000; |
|---|
| 239 | number=600; //is my using the new value on my system arround 580000 |
|---|
| 240 | |
|---|
| 241 | WM_HOTKEY2=WM_USER+$800; |
|---|
| 242 | |
|---|
| 243 | type |
|---|
| 244 | MemoryRecordcet3 = record |
|---|
| 245 | Description : string[50]; |
|---|
| 246 | Address : dword; |
|---|
| 247 | VarType : byte; |
|---|
| 248 | Bit : Byte; |
|---|
| 249 | Frozen : boolean; |
|---|
| 250 | FrozenValue : Int64; |
|---|
| 251 | Group: Byte; |
|---|
| 252 | end; |
|---|
| 253 | |
|---|
| 254 | type TCEPointer=record |
|---|
| 255 | Address: Dword; //only used when last pointer in list |
|---|
| 256 | Interpretableaddress: string; //same as address |
|---|
| 257 | offset: integer; |
|---|
| 258 | end; |
|---|
| 259 | |
|---|
| 260 | type TCEAlloc=record |
|---|
| 261 | address: dword; |
|---|
| 262 | varname: string; |
|---|
| 263 | size: dword; |
|---|
| 264 | end; |
|---|
| 265 | type PCEAlloc=^TCEAlloc; |
|---|
| 266 | type TCEAllocArray=array of TCEAlloc; |
|---|
| 267 | |
|---|
| 268 | type |
|---|
| 269 | MemoryRecord = record |
|---|
| 270 | Description : string; |
|---|
| 271 | Address : dword; |
|---|
| 272 | interpretableaddress: string; |
|---|
| 273 | VarType : byte; |
|---|
| 274 | unicode : boolean; |
|---|
| 275 | IsPointer: Boolean; |
|---|
| 276 | pointers: array of TCEPointer; |
|---|
| 277 | Bit : Byte; |
|---|
| 278 | bitlength: integer; |
|---|
| 279 | Frozen : boolean; |
|---|
| 280 | FrozenValue : Int64; |
|---|
| 281 | OldValue: string; //not saved |
|---|
| 282 | Frozendirection: integer; //0=always freeze,1=only freeze when going up,2=only freeze when going down |
|---|
| 283 | Group: Byte; |
|---|
| 284 | ShowAsHex: boolean; |
|---|
| 285 | autoassemblescript: string; |
|---|
| 286 | allocs: TCEAllocArray; |
|---|
| 287 | end; |
|---|
| 288 | |
|---|
| 289 | type |
|---|
| 290 | MemoryRecordOld = record |
|---|
| 291 | Description : string[50]; |
|---|
| 292 | Address : dword; |
|---|
| 293 | VarType : byte; |
|---|
| 294 | Frozen : boolean; |
|---|
| 295 | FrozenValue : Dword; |
|---|
| 296 | end; |
|---|
| 297 | |
|---|
| 298 | type TDwordArray=array[0..100] of dword; |
|---|
| 299 | type PDwordArray=^TDwordArray; |
|---|
| 300 | |
|---|
| 301 | type TSingleArray=array[0..100] of single; |
|---|
| 302 | type PSingleArray=^TSingleArray; |
|---|
| 303 | |
|---|
| 304 | type TdoubleArray=array[0..100] of double; |
|---|
| 305 | type PdoubleArray=^TdoubleArray; |
|---|
| 306 | |
|---|
| 307 | type Tint64Array=array[0..100] of int64; |
|---|
| 308 | type Pint64Array=^Tint64Array; |
|---|
| 309 | |
|---|
| 310 | type Tuint64Array=array[0..100] of uint64; |
|---|
| 311 | type Puint64Array=^Tuint64Array; |
|---|
| 312 | |
|---|
| 313 | |
|---|
| 314 | |
|---|
| 315 | type TScanSettings = record |
|---|
| 316 | UseHyperscan: boolean; |
|---|
| 317 | scanning: boolean; |
|---|
| 318 | CEProcessID: dword; |
|---|
| 319 | CEMainThreadID: Dword; |
|---|
| 320 | applicantionhandle: thandle; |
|---|
| 321 | mainformHandle: THandle; |
|---|
| 322 | formscanningHandle: THandle; |
|---|
| 323 | hyperscanwindow: Thandle; |
|---|
| 324 | StartAddress: Dword; |
|---|
| 325 | StopAddress: Dword; |
|---|
| 326 | Scantype: Integer; |
|---|
| 327 | ValueType: Integer; |
|---|
| 328 | roundingtype: tfloatscan; |
|---|
| 329 | scan:byte; |
|---|
| 330 | readonly: boolean; |
|---|
| 331 | FastScan: boolean; |
|---|
| 332 | Hexadecimal: boolean; |
|---|
| 333 | unicode: boolean; |
|---|
| 334 | percentage: boolean; |
|---|
| 335 | LowMemoryUsage: boolean; |
|---|
| 336 | Skip_PAGE_NOCACHE:boolean; |
|---|
| 337 | scan_mem_private:boolean; |
|---|
| 338 | scan_mem_image:boolean; |
|---|
| 339 | scan_mem_mapped: boolean; |
|---|
| 340 | scanvalue: string[255]; |
|---|
| 341 | scanvalue2: string[255]; |
|---|
| 342 | CheatEngineDir: string[255]; |
|---|
| 343 | buffersize:dword; |
|---|
| 344 | priority:integer; |
|---|
| 345 | nrofbits:integer; |
|---|
| 346 | bitstring: string[255]; |
|---|
| 347 | bitoffsetchange: integer; |
|---|
| 348 | asktocontinue: boolean; |
|---|
| 349 | HookDirect3d: boolean; |
|---|
| 350 | HookOpenGL: boolean; |
|---|
| 351 | PacketEditor: boolean; |
|---|
| 352 | Stealthed: boolean; |
|---|
| 353 | hooknewprocesses: boolean; |
|---|
| 354 | end; |
|---|
| 355 | |
|---|
| 356 | type tspeedhackspeed=record |
|---|
| 357 | speed: single; |
|---|
| 358 | sleeptime: dword; |
|---|
| 359 | end; |
|---|
| 360 | |
|---|
| 361 | type TKeyCombo=array [0..4] of word; |
|---|
| 362 | type TKeys=record |
|---|
| 363 | configured: boolean; |
|---|
| 364 | CEDir: string[255]; |
|---|
| 365 | cewindow: thandle; |
|---|
| 366 | |
|---|
| 367 | callibrationmode: boolean; //false=no textureselect hud |
|---|
| 368 | callibrationkey: TKeycombo; |
|---|
| 369 | |
|---|
| 370 | setcallibration: boolean; |
|---|
| 371 | mousecallibrationhorizontal1point: single; |
|---|
| 372 | mousecallibrationvertical1point: single; |
|---|
| 373 | |
|---|
| 374 | mousecallibrationhorizontal2point: single; |
|---|
| 375 | mousecallibrationvertical2point: single; |
|---|
| 376 | |
|---|
| 377 | mousecallibrationhorizontal5point: single; |
|---|
| 378 | mousecallibrationvertical5point: single; |
|---|
| 379 | |
|---|
| 380 | mousecallibrationhorizontal10point: single; |
|---|
| 381 | mousecallibrationvertical10point: single; |
|---|
| 382 | |
|---|
| 383 | mousecallibrationhorizontal20point: single; |
|---|
| 384 | mousecallibrationvertical20point: single; |
|---|
| 385 | |
|---|
| 386 | mousecallibrationhorizontal40point: single; |
|---|
| 387 | mousecallibrationvertical40point: single; |
|---|
| 388 | |
|---|
| 389 | loadaimsettingsfile: tkeycombo; |
|---|
| 390 | saveaimsettingsfile: tkeycombo; |
|---|
| 391 | aimsettings1: string[255]; |
|---|
| 392 | Aimsettings2: string[255]; |
|---|
| 393 | Aimsettings3: string[255]; |
|---|
| 394 | |
|---|
| 395 | setaimsetting1: tkeycombo; |
|---|
| 396 | setaimsetting2: tkeycombo; |
|---|
| 397 | setaimsetting3: tkeycombo; |
|---|
| 398 | |
|---|
| 399 | nexttexture: tkeycombo; |
|---|
| 400 | previoustexture: tkeycombo; |
|---|
| 401 | locktexture: tkeycombo; |
|---|
| 402 | |
|---|
| 403 | IncreaseX: tkeycombo; |
|---|
| 404 | DecreaseX: TKeyCombo; |
|---|
| 405 | Increasey: tkeycombo; |
|---|
| 406 | Decreasey: TKeyCombo; |
|---|
| 407 | Increasez: tkeycombo; |
|---|
| 408 | Decreasez: TKeyCombo; |
|---|
| 409 | |
|---|
| 410 | HoldAutoaimtoggle: boolean; |
|---|
| 411 | autoshoot: boolean; |
|---|
| 412 | autoaimtoggle: tKeycombo; |
|---|
| 413 | increaselag: tkeycombo; |
|---|
| 414 | decreaselag: tkeycombo; |
|---|
| 415 | |
|---|
| 416 | zoomin,zoomout: TKeyCombo; |
|---|
| 417 | nozoom: tKeyCombo; |
|---|
| 418 | zoom1: tKeyCombo; |
|---|
| 419 | zoomlevel1: single; |
|---|
| 420 | zoom2: tkeycombo; |
|---|
| 421 | zoomlevel2: single; |
|---|
| 422 | zoom3: tkeycombo; |
|---|
| 423 | zoomlevel3: single; |
|---|
| 424 | zoom4: tkeycombo; |
|---|
| 425 | zoomlevel4: single; |
|---|
| 426 | zoom5: tkeycombo; |
|---|
| 427 | zoomlevel5: single; |
|---|
| 428 | |
|---|
| 429 | zoomdelta: single; |
|---|
| 430 | lagdelta: integer; |
|---|
| 431 | |
|---|
| 432 | setlag: boolean; |
|---|
| 433 | lagtoset: dword; |
|---|
| 434 | usefpslag: boolean; |
|---|
| 435 | |
|---|
| 436 | rotateleft: tKeycombo; |
|---|
| 437 | rotateright: tkeycombo; |
|---|
| 438 | rotateup: tkeycombo; |
|---|
| 439 | rotatedown: tkeycombo; |
|---|
| 440 | moveleft: tkeycombo; |
|---|
| 441 | moveright: tkeycombo; |
|---|
| 442 | moveup: tkeycombo; |
|---|
| 443 | movedown: tkeycombo; |
|---|
| 444 | moveforward: tkeycombo; |
|---|
| 445 | movebackwards: tkeycombo; |
|---|
| 446 | |
|---|
| 447 | movespeed: single; |
|---|
| 448 | rotatespeed: single; |
|---|
| 449 | |
|---|
| 450 | setcameraback: tkeycombo; |
|---|
| 451 | |
|---|
| 452 | zbuffer: tkeycombo; |
|---|
| 453 | fog: tkeycombo; |
|---|
| 454 | lighting: tkeycombo; |
|---|
| 455 | wireframe: tkeycombo; |
|---|
| 456 | |
|---|
| 457 | ShowKeylist: tkeycombo; |
|---|
| 458 | |
|---|
| 459 | SaveAlltextures: TKeycombo; |
|---|
| 460 | |
|---|
| 461 | selectedlagrecord: string[50]; |
|---|
| 462 | lagmemorytype: byte; |
|---|
| 463 | getlagfrommemory: boolean; |
|---|
| 464 | nrofoffsets: dword; |
|---|
| 465 | lagaddress: dword; |
|---|
| 466 | offset1: dword; |
|---|
| 467 | offset2: dword; |
|---|
| 468 | offset3: dword; |
|---|
| 469 | offset4: dword; |
|---|
| 470 | offset5: dword; |
|---|
| 471 | offset6: dword; |
|---|
| 472 | offset7: dword; |
|---|
| 473 | offset8: dword; |
|---|
| 474 | offset9: dword; |
|---|
| 475 | offset10: dword; |
|---|
| 476 | offset11: dword; |
|---|
| 477 | offset12: dword; |
|---|
| 478 | offset13: dword; |
|---|
| 479 | offset14: dword; |
|---|
| 480 | offset15: dword; |
|---|
| 481 | |
|---|
| 482 | |
|---|
| 483 | pollinginterval: integer; |
|---|
| 484 | end; |
|---|
| 485 | type PKeys= ^TKeys; |
|---|
| 486 | |
|---|
| 487 | type TKeys2=record |
|---|
| 488 | configured: boolean; |
|---|
| 489 | CEDir: string[255]; |
|---|
| 490 | cewindow: thandle; |
|---|
| 491 | |
|---|
| 492 | textures: tkeycombo; |
|---|
| 493 | lighting: tkeycombo; |
|---|
| 494 | depthtest: tkeycombo; |
|---|
| 495 | fog: tkeycombo; |
|---|
| 496 | |
|---|
| 497 | |
|---|
| 498 | zoomin,zoomout: TKeyCombo; |
|---|
| 499 | nozoom: tKeyCombo; |
|---|
| 500 | zoom1: tKeyCombo; |
|---|
| 501 | zoomlevel1: single; |
|---|
| 502 | zoom2: tkeycombo; |
|---|
| 503 | zoomlevel2: single; |
|---|
| 504 | zoom3: tkeycombo; |
|---|
| 505 | zoomlevel3: single; |
|---|
| 506 | zoom4: tkeycombo; |
|---|
| 507 | zoomlevel4: single; |
|---|
| 508 | zoom5: tkeycombo; |
|---|
| 509 | zoomlevel5: single; |
|---|
| 510 | |
|---|
| 511 | zoomdelta: single; |
|---|
| 512 | |
|---|
| 513 | |
|---|
| 514 | pollinginterval: integer; |
|---|
| 515 | end; |
|---|
| 516 | type PKeys2= ^TKeys2; |
|---|
| 517 | |
|---|
| 518 | |
|---|
| 519 | |
|---|
| 520 | function ConvertKeyComboToString(x: tkeycombo):string; |
|---|
| 521 | |
|---|
| 522 | |
|---|
| 523 | |
|---|
| 524 | |
|---|
| 525 | |
|---|
| 526 | function ProcessID: dword; |
|---|
| 527 | function ProcessHandle: THandle; |
|---|
| 528 | |
|---|
| 529 | //Global vars: |
|---|
| 530 | var |
|---|
| 531 | old8087CW: word; //you never know... |
|---|
| 532 | ProcessSelected: Boolean; |
|---|
| 533 | //ProcessID: Dword; //deperecated |
|---|
| 534 | //ProcessHandle: Thandle; |
|---|
| 535 | |
|---|
| 536 | Skip_PAGE_NOCACHE: boolean; |
|---|
| 537 | Scan_MEM_PRIVATE: boolean; |
|---|
| 538 | Scan_MEM_IMAGE: boolean; |
|---|
| 539 | Scan_MEM_MAPPED: boolean; |
|---|
| 540 | |
|---|
| 541 | CheatEngineDir: String; |
|---|
| 542 | WindowsDir: string; |
|---|
| 543 | GetProcessIcons: Boolean; |
|---|
| 544 | ProcessesWithIconsOnly: boolean; |
|---|
| 545 | |
|---|
| 546 | //scanhelpers |
|---|
| 547 | nrofbits: integer; |
|---|
| 548 | Bitscan: array of byte; |
|---|
| 549 | tempbits: array of byte; |
|---|
| 550 | |
|---|
| 551 | bitoffsetchange: integer; |
|---|
| 552 | |
|---|
| 553 | FoundValue1:Array of Byte; |
|---|
| 554 | FoundValue1switch:Array of Byte; |
|---|
| 555 | |
|---|
| 556 | FoundValue2:Array of word; |
|---|
| 557 | FoundValue2switch:Array of word; |
|---|
| 558 | |
|---|
| 559 | FoundValue3:Array of Dword; |
|---|
| 560 | FoundValue3switch:Array of Dword; |
|---|
| 561 | |
|---|
| 562 | FoundValue4:Array of Single; |
|---|
| 563 | FoundValue4switch:Array of Single; |
|---|
| 564 | |
|---|
| 565 | FoundValue5:Array of Double; |
|---|
| 566 | FoundValue5switch:Array of Double; |
|---|
| 567 | |
|---|
| 568 | foundValue6:Array of int64; |
|---|
| 569 | foundValue6switch:Array of int64; |
|---|
| 570 | |
|---|
| 571 | FoundValue7:Array of Int64; |
|---|
| 572 | FoundValue7switch:Array of Int64; |
|---|
| 573 | |
|---|
| 574 | FoundValue8:array of byte; |
|---|
| 575 | FoundValue8switch:array of byte; |
|---|
| 576 | |
|---|
| 577 | FoundAddress: array of dword; |
|---|
| 578 | FoundAddressSwitch: array of dword; |
|---|
| 579 | |
|---|
| 580 | foundaddressB: array of TBitAddress; |
|---|
| 581 | foundaddressBswitch: array of TBitAddress; |
|---|
| 582 | |
|---|
| 583 | |
|---|
| 584 | tempbytearray: array of byte; |
|---|
| 585 | tempwordarray: array of word; |
|---|
| 586 | tempdwordarray: array of dword; |
|---|
| 587 | tempsinglearray: array of single; |
|---|
| 588 | tempdoublearray: array of double; |
|---|
| 589 | tempint64array: array of int64; |
|---|
| 590 | |
|---|
| 591 | |
|---|
| 592 | //-------- |
|---|
| 593 | previousmemory: array of byte; |
|---|
| 594 | |
|---|
| 595 | SearchAddress: array of dword; |
|---|
| 596 | searchaddressswitch: array of dword; |
|---|
| 597 | |
|---|
| 598 | SearchAddressB: array of TBitAddress; |
|---|
| 599 | |
|---|
| 600 | previousmemory1,previousmemory1switch: array of Byte; |
|---|
| 601 | previousmemory2,previousmemory2switch: array of word; |
|---|
| 602 | previousmemory3,previousmemory3switch: array of dword; |
|---|
| 603 | previousmemory4,previousmemory4switch: array of Single; |
|---|
| 604 | previousmemory5,previousmemory5switch: array of Double; |
|---|
| 605 | previousmemory6,previousmemory6switch: array of int64; //Byte; |
|---|
| 606 | PreviousMemory7,previousmemory7switch: Array of Int64; |
|---|
| 607 | PreviousMemory8,previousmemory8switch: array of byte; |
|---|
| 608 | |
|---|
| 609 | //--------- |
|---|
| 610 | helpstr,helpstr2: string; |
|---|
| 611 | bytes: array of integer; //-1=wildcard |
|---|
| 612 | bytearray: array of byte; |
|---|
| 613 | |
|---|
| 614 | |
|---|
| 615 | |
|---|
| 616 | // MemoryRegion: array of TMemoryRegion; |
|---|
| 617 | // MemoryRegions: Integer; |
|---|
| 618 | |
|---|
| 619 | // Memory: Array of Byte; |
|---|
| 620 | Memory: ^Byte; |
|---|
| 621 | memory2: ^byte; |
|---|
| 622 | |
|---|
| 623 | |
|---|
| 624 | advanced: boolean; |
|---|
| 625 | //global files, so when an exception happens I can close them |
|---|
| 626 | addressfile, memoryfile: File; |
|---|
| 627 | newAddressfile,newmemoryfile: File; |
|---|
| 628 | |
|---|
| 629 | buffersize: dword; |
|---|
| 630 | overridedebug: boolean; |
|---|
| 631 | |
|---|
| 632 | totalbytes: dword; |
|---|
| 633 | currentbyte: dword; |
|---|
| 634 | |
|---|
| 635 | |
|---|
| 636 | //hide/show windows |
|---|
| 637 | windowlist: array of thandle; |
|---|
| 638 | lastforeground,lastactive: thandle; |
|---|
| 639 | donthidelist: array of string; |
|---|
| 640 | onlyfront: boolean; |
|---|
| 641 | allwindowsareback:boolean; |
|---|
| 642 | |
|---|
| 643 | HyperscanFileMapping: THandle; |
|---|
| 644 | HyperscanView: ^TScanSettings; |
|---|
| 645 | |
|---|
| 646 | hookedin:boolean; |
|---|
| 647 | keys: PKeys; |
|---|
| 648 | keys2: PKeys2; |
|---|
| 649 | keysfilemapping: THandle; |
|---|
| 650 | |
|---|
| 651 | //stealth globals |
|---|
| 652 | le: dword; |
|---|
| 653 | ownprocesshandle: THandle; |
|---|
| 654 | stealthhook: thandle; |
|---|
| 655 | |
|---|
| 656 | //windows version data |
|---|
| 657 | iswin2kplus: boolean; |
|---|
| 658 | scanpriority: TThreadPriority; |
|---|
| 659 | |
|---|
| 660 | |
|---|
| 661 | |
|---|
| 662 | hypermode: thypermode; |
|---|
| 663 | useAPCtoInjectDLL: boolean; |
|---|
| 664 | |
|---|
| 665 | |
|---|
| 666 | |
|---|
| 667 | tempdir: pchar; |
|---|
| 668 | |
|---|
| 669 | |
|---|
| 670 | processhandler: TProcessHandler; |
|---|
| 671 | |
|---|
| 672 | implementation |
|---|
| 673 | |
|---|
| 674 | |
|---|
| 675 | uses disassembler,debugger; |
|---|
| 676 | |
|---|
| 677 | |
|---|
| 678 | |
|---|
| 679 | |
|---|
| 680 | |
|---|
| 681 | uses disassembler,debugger,symbolhandler,frmProcessWatcherUnit,kerneldebugger; |
|---|
| 682 | |
|---|
| 683 | uses symbolhandler; |
|---|
| 684 | |
|---|
| 685 | |
|---|
| 686 | |
|---|
| 687 | |
|---|
| 688 | function ProcessID: dword; |
|---|
| 689 | begin |
|---|
| 690 | result:=ProcessHandler.Processid; |
|---|
| 691 | end; |
|---|
| 692 | |
|---|
| 693 | function ProcessHandle: THandle; |
|---|
| 694 | begin |
|---|
| 695 | result:=ProcessHandler.ProcessHandle; |
|---|
| 696 | end; |
|---|
| 697 | |
|---|
| 698 | |
|---|
| 699 | procedure TFreememorythread.execute; |
|---|
| 700 | begin |
|---|
| 701 | setlength(bitscan,0); |
|---|
| 702 | setlength(tempbits,0); |
|---|
| 703 | setlength(FoundAddress,0); |
|---|
| 704 | |
|---|
| 705 | setlength(FoundValue1,0); |
|---|
| 706 | setlength(FoundValue2,0); |
|---|
| 707 | setlength(FoundValue3,0); |
|---|
| 708 | setlength(FoundValue4,0); |
|---|
| 709 | setlength(FoundValue5,0); |
|---|
| 710 | setlength(foundValue6,0); |
|---|
| 711 | setlength(FoundValue7,0); |
|---|
| 712 | setlength(FoundValue8,0); |
|---|
| 713 | setlength(FoundValue1switch,0); |
|---|
| 714 | setlength(FoundValue2switch,0); |
|---|
| 715 | setlength(FoundValue3switch,0); |
|---|
| 716 | setlength(FoundValue4switch,0); |
|---|
| 717 | setlength(FoundValue5switch,0); |
|---|
| 718 | setlength(foundValue6switch,0); |
|---|
| 719 | setlength(FoundValue7switch,0); |
|---|
| 720 | setlength(FoundValue8switch,0); |
|---|
| 721 | |
|---|
| 722 | |
|---|
| 723 | //floating point notations |
|---|
| 724 | |
|---|
| 725 | |
|---|
| 726 | setlength(foundaddressB,0); |
|---|
| 727 | |
|---|
| 728 | setlength(previousmemory,0); |
|---|
| 729 | |
|---|
| 730 | setlength(SearchAddress,0); |
|---|
| 731 | setlength(SearchAddressB,0); |
|---|
| 732 | |
|---|
| 733 | setlength(previousmemory1,0); |
|---|
| 734 | setlength(previousmemory2,0); |
|---|
| 735 | setlength(previousmemory3,0); |
|---|
| 736 | setlength(previousmemory4,0); |
|---|
| 737 | setlength(previousmemory5,0); |
|---|
| 738 | setlength(previousmemory6,0); |
|---|
| 739 | setlength(PreviousMemory7,0); |
|---|
| 740 | setlength(PreviousMemory8,0); |
|---|
| 741 | |
|---|
| 742 | setlength(previousmemory1switch,0); |
|---|
| 743 | setlength(previousmemory2switch,0); |
|---|
| 744 | setlength(previousmemory3switch,0); |
|---|
| 745 | setlength(previousmemory4switch,0); |
|---|
| 746 | setlength(previousmemory5switch,0); |
|---|
| 747 | setlength(previousmemory6switch,0); |
|---|
| 748 | setlength(PreviousMemory7switch,0); |
|---|
| 749 | setlength(PreviousMemory8switch,0); |
|---|
| 750 | |
|---|
| 751 | if not advanced then //if the lastscan was a advanced, better not whipe the memory (yet!) |
|---|
| 752 | begin |
|---|
| 753 | if memory<>nil then freemem(memory); |
|---|
| 754 | memory:=nil; |
|---|
| 755 | |
|---|
| 756 | if memory2<>nil then freemem(memory2); |
|---|
| 757 | memory2:=nil; |
|---|
| 758 | end; |
|---|
| 759 | |
|---|
| 760 | setlength(bytes,0); |
|---|
| 761 | setlength(bytearray,0); |
|---|
| 762 | end; |
|---|
| 763 | |
|---|
| 764 | type TSaveDataThread=class(tthread) |
|---|
| 765 | public |
|---|
| 766 | buffer1: pointer; |
|---|
| 767 | buffer2: pointer; |
|---|
| 768 | buffersize1: dword; |
|---|
| 769 | buffersize2: dword; |
|---|
| 770 | file1: ^file; |
|---|
| 771 | file2: ^file; |
|---|
| 772 | datawritten: tevent; |
|---|
| 773 | dataavailable:tevent; |
|---|
| 774 | |
|---|
| 775 | procedure execute; override; |
|---|
| 776 | constructor create(suspended:boolean); |
|---|
| 777 | destructor destroy; override; |
|---|
| 778 | end; |
|---|
| 779 | |
|---|
| 780 | procedure TSaveDataThread.execute; |
|---|
| 781 | var ignore: dword; |
|---|
| 782 | begin |
|---|
| 783 | dataavailable.WaitFor(infinite); |
|---|
| 784 | while not terminated do |
|---|
| 785 | begin |
|---|
| 786 | blockwrite(file1^,buffer1^,buffersize1,ignore); |
|---|
| 787 | blockwrite(file2^,buffer2^,buffersize2,ignore); |
|---|
| 788 | |
|---|
| 789 | datawritten.SetEvent; //tell the others that you're ready to write again |
|---|
| 790 | dataavailable.WaitFor(infinite); //wait for the 'ready to write' event |
|---|
| 791 | end; |
|---|
| 792 | end; |
|---|
| 793 | |
|---|
| 794 | destructor TSaveDataThread.destroy; |
|---|
| 795 | begin |
|---|
| 796 | datawritten.Free; |
|---|
| 797 | dataavailable.free; |
|---|
| 798 | inherited destroy; |
|---|
| 799 | end; |
|---|
| 800 | |
|---|
| 801 | constructor TSaveDataThread.create(suspended:boolean); |
|---|
| 802 | begin |
|---|
| 803 | datawritten:=tevent.Create(nil,false,true,''); |
|---|
| 804 | dataavailable:=tevent.create(nil,false,false,''); |
|---|
| 805 | |
|---|
| 806 | inherited create(suspended); |
|---|
| 807 | end; |
|---|
| 808 | |
|---|
| 809 | var FlushThread:TSaveDataThread; |
|---|
| 810 | |
|---|
| 811 | procedure flushbuffer(var file1, file2:file; buffer1:pointer; buffer1size:integer; buffer2:pointer; buffer2size:integer); |
|---|
| 812 | begin |
|---|
| 813 | flushthread.datawritten.ResetEvent; |
|---|
| 814 | |
|---|
| 815 | flushthread.file1:=@file1; |
|---|
| 816 | flushthread.file2:=@file2; |
|---|
| 817 | flushthread.buffer1:=buffer1; |
|---|
| 818 | flushthread.buffer2:=buffer2; |
|---|
| 819 | flushthread.buffersize1:=buffer1size; |
|---|
| 820 | flushthread.buffersize2:=buffer2size; |
|---|
| 821 | flushthread.dataavailable.SetEvent; |
|---|
| 822 | end; |
|---|
| 823 | |
|---|
| 824 | procedure finishflushing; |
|---|
| 825 | begin |
|---|
| 826 | flushthread.datawritten.WaitFor(infinite); |
|---|
| 827 | flushthread.datawritten.SetEvent; |
|---|
| 828 | end; |
|---|
| 829 | |
|---|
| 830 | //------------------------------------ |
|---|
| 831 | |
|---|
| 832 | type TPrefetchDataThread=class(tthread) |
|---|
| 833 | public |
|---|
| 834 | buffer1: pointer; |
|---|
| 835 | buffer2: pointer; |
|---|
| 836 | buffersize1: dword; |
|---|
| 837 | buffersize2: dword; |
|---|
| 838 | file1: ^file; |
|---|
| 839 | file2: ^file; |
|---|
| 840 | dataread: tevent; |
|---|
| 841 | startreading:tevent; |
|---|
| 842 | |
|---|
| 843 | actualread: dword; |
|---|
| 844 | |
|---|
| 845 | procedure execute; override; |
|---|
| 846 | constructor create(suspended:boolean); |
|---|
| 847 | destructor destroy; override; |
|---|
| 848 | end; |
|---|
| 849 | |
|---|
| 850 | procedure TPrefetchDataThread.execute; |
|---|
| 851 | var ignore,tmp: dword; |
|---|
| 852 | begin |
|---|
| 853 | startreading.WaitFor(infinite); |
|---|
| 854 | |
|---|
| 855 | while not terminated do |
|---|
| 856 | begin |
|---|
| 857 | self.actualread:=0; |
|---|
| 858 | blockread(file1^,buffer1^,buffersize1,tmp); |
|---|
| 859 | blockread(file2^,buffer2^,buffersize2,ignore); |
|---|
| 860 | |
|---|
| 861 | self.actualread:=tmp; |
|---|
| 862 | |
|---|
| 863 | dataread.SetEvent; //tell the others that you're ready to read again |
|---|
| 864 | startreading.WaitFor(infinite); |
|---|
| 865 | end; |
|---|
| 866 | end; |
|---|
| 867 | |
|---|
| 868 | destructor TPrefetchDataThread.destroy; |
|---|
| 869 | begin |
|---|
| 870 | dataread.Free; |
|---|
| 871 | startreading.free; |
|---|
| 872 | inherited destroy; |
|---|
| 873 | end; |
|---|
| 874 | |
|---|
| 875 | constructor TPrefetchDataThread.create(suspended:boolean); |
|---|
| 876 | begin |
|---|
| 877 | dataread:=tevent.Create(nil,false,true,''); |
|---|
| 878 | startreading:=tevent.create(nil,false,false,''); |
|---|
| 879 | |
|---|
| 880 | inherited create(suspended); |
|---|
| 881 | end; |
|---|
| 882 | |
|---|
| 883 | var PrefetchThread:TPrefetchDataThread; |
|---|
| 884 | |
|---|
| 885 | procedure prefetchbuffer(var file1, file2:file; buffer1:pointer; buffer1size:integer; buffer2:pointer; buffer2size:integer); |
|---|
| 886 | begin |
|---|
| 887 | PrefetchThread.dataread.ResetEvent; |
|---|
| 888 | |
|---|
| 889 | PrefetchThread.file1:=@file1; |
|---|
| 890 | PrefetchThread.file2:=@file2; |
|---|
| 891 | PrefetchThread.buffer1:=buffer1; |
|---|
| 892 | PrefetchThread.buffer2:=buffer2; |
|---|
| 893 | PrefetchThread.buffersize1:=buffer1size; |
|---|
| 894 | PrefetchThread.buffersize2:=buffer2size; |
|---|
| 895 | PrefetchThread.startreading.SetEvent; |
|---|
| 896 | end; |
|---|
| 897 | |
|---|
| 898 | function finishprefetching:dword; |
|---|
| 899 | begin |
|---|
| 900 | PrefetchThread.dataread.WaitFor(infinite);//wait for the datread event to be set |
|---|
| 901 | result:=prefetchthread.actualread; |
|---|
| 902 | end; |
|---|
| 903 | |
|---|
| 904 | procedure errorbeep; |
|---|
| 905 | begin |
|---|
| 906 | beep; |
|---|
| 907 | sleep(100); |
|---|
| 908 | beep; |
|---|
| 909 | sleep(100); |
|---|
| 910 | beep; |
|---|
| 911 | sleep(100); |
|---|
| 912 | end; |
|---|
| 913 | |
|---|
| 914 | function isreadable(address:dword):boolean; |
|---|
| 915 | var mbi: _MEMORY_BASIC_INFORMATION; |
|---|
| 916 | begin |
|---|
| 917 | VirtualQueryEx(processhandle,pointer(address),mbi,sizeof(mbi)); |
|---|
| 918 | result:=mbi.State=mem_commit; |
|---|
| 919 | end; |
|---|
| 920 | |
|---|
| 921 | function RawToString(const buf: array of byte; vartype: integer;showashex: boolean; bufsize: integer):string; |
|---|
| 922 | var x: pchar; |
|---|
| 923 | i: integer; |
|---|
| 924 | begin |
|---|
| 925 | //buffsize has to match the type else error |
|---|
| 926 | if bufsize=0 then |
|---|
| 927 | begin |
|---|
| 928 | result:='???'; |
|---|
| 929 | exit; |
|---|
| 930 | end; |
|---|
| 931 | |
|---|
| 932 | try |
|---|
| 933 | case vartype of |
|---|
| 934 | 0: if bufsize<>1 then result:='???' else if showashex then result:=inttohex(buf[0],2) else result:=inttostr(buf[0]); |
|---|
| 935 | 1: if bufsize<>2 then result:='???' else if showashex then result:=inttohex(pshortint(@buf[0])^,2) else result:=inttostr(pshortint(@buf[0])^); |
|---|
| 936 | 2: if bufsize<>4 then result:='???' else if showashex then result:=inttohex(pint(@buf[0])^,4) else result:=inttostr(pint(@buf[0])^); |
|---|
| 937 | 3: if bufsize<>4 then result:='???' else result:=floattostr(psingle(@buf[0])^); |
|---|
| 938 | 4: if bufsize<>8 then result:='???' else result:=floattostr(pdouble(@buf[0])^); |
|---|
| 939 | 6: if bufsize<>4 then result:='???' else if showashex then result:=inttohex(pint64(@buf[0])^,8) else result:=inttostr(pint64(@buf[0])^); |
|---|
| 940 | 7: |
|---|
| 941 | begin |
|---|
| 942 | getmem(x,bufsize+1); |
|---|
| 943 | x[bufsize]:=#0; |
|---|
| 944 | result:=x; |
|---|
| 945 | freemem(x); |
|---|
| 946 | end; |
|---|
| 947 | |
|---|
| 948 | 8: //array of bytes |
|---|
| 949 | begin |
|---|
| 950 | result:=''; |
|---|
| 951 | for i:=0 to bufsize-1 do |
|---|
| 952 | result:=result+'-'+inttohex(buf[bufsize],2); |
|---|
| 953 | end; |
|---|
| 954 | |
|---|
| 955 | else result:='not supported in this version'; |
|---|
| 956 | end; |
|---|
| 957 | except |
|---|
| 958 | result:='Not convertable'; |
|---|
| 959 | end; |
|---|
| 960 | end; |
|---|
| 961 | |
|---|
| 962 | function ConvertKeyComboToString(x: tkeycombo):string; |
|---|
| 963 | var i: integer; |
|---|
| 964 | newstr: string; |
|---|
| 965 | begin |
|---|
| 966 | result:=''; |
|---|
| 967 | for i:=0 to 4 do |
|---|
| 968 | if x[i]=0 then |
|---|
| 969 | break |
|---|
| 970 | else |
|---|
| 971 | begin |
|---|
| 972 | newstr:=''; |
|---|
| 973 | case x[i] of |
|---|
| 974 | vk_lbutton: newstr:='Left MB'; |
|---|
| 975 | vk_mbutton: newstr:='Middle MB'; |
|---|
| 976 | vk_rbutton: newstr:='Right MB'; |
|---|
| 977 | VK_BACK : newstr:='Backspace'; |
|---|
| 978 | VK_SHIFT: newstr:='Shift'; |
|---|
| 979 | VK_CONTROL: newstr:='Ctrl'; |
|---|
| 980 | VK_MENU: newstr:='Alt'; |
|---|
| 981 | VK_TAB : newstr:='Tab'; |
|---|
| 982 | VK_CLEAR : newstr:='Clear'; |
|---|
| 983 | VK_RETURN : newstr:='Enter'; |
|---|
| 984 | VK_PAUSE : newstr:='Pause'; |
|---|
| 985 | VK_CAPITAL : newstr:='Caps Lock'; |
|---|
| 986 | VK_ESCAPE : newstr:='Esc'; |
|---|
| 987 | VK_SPACE : newstr:='Space bar'; |
|---|
| 988 | VK_PRIOR : newstr:='Page Up'; |
|---|
| 989 | VK_NEXT : newstr:='Page Down'; |
|---|
| 990 | VK_END : newstr:='End'; |
|---|
| 991 | VK_HOME : newstr:='Home'; |
|---|
| 992 | VK_LEFT : newstr:='Left Arrow'; |
|---|
| 993 | VK_UP : newstr:='Up Arrow'; |
|---|
| 994 | VK_RIGHT : newstr:='Right Arrow'; |
|---|
| 995 | VK_DOWN : newstr:='Down Arrow'; |
|---|
| 996 | VK_SELECT : newstr:='Select'; |
|---|
| 997 | VK_PRINT : newstr:='Print'; |
|---|
| 998 | VK_EXECUTE : newstr:='Execute'; |
|---|
| 999 | VK_SNAPSHOT : newstr:='Print Screen'; |
|---|
| 1000 | VK_INSERT : newstr:='Insert'; |
|---|
| 1001 | VK_DELETE : newstr:='Delete'; |
|---|
| 1002 | VK_HELP : newstr:='Help'; |
|---|
| 1003 | VK_LWIN : newstr:='Left Windows key'; |
|---|
| 1004 | VK_RWIN : newstr:='Right Windows key'; |
|---|
| 1005 | VK_APPS : newstr:='Applications key'; |
|---|
| 1006 | VK_NUMPAD0 : newstr:='numeric 0'; |
|---|
| 1007 | VK_NUMPAD1 : newstr:='numeric 1'; |
|---|
| 1008 | VK_NUMPAD2 : newstr:='numeric 2'; |
|---|
| 1009 | VK_NUMPAD3 : newstr:='numeric 3'; |
|---|
| 1010 | VK_NUMPAD4 : newstr:='numeric 4'; |
|---|
| 1011 | VK_NUMPAD5 : newstr:='numeric 5'; |
|---|
| 1012 | VK_NUMPAD6 : newstr:='numeric 6'; |
|---|
| 1013 | VK_NUMPAD7 : newstr:='numeric 7'; |
|---|
| 1014 | VK_NUMPAD8 : newstr:='numeric 8'; |
|---|
| 1015 | VK_NUMPAD9 : newstr:='numeric 9'; |
|---|
| 1016 | VK_MULTIPLY : newstr:='numeric *'; |
|---|
| 1017 | VK_ADD : newstr:='numeric +'; |
|---|
| 1018 | VK_SEPARATOR : newstr:='numeric Separator'; |
|---|
| 1019 | VK_SUBTRACT : newstr:='numeric -'; |
|---|
| 1020 | VK_DECIMAL : newstr:='numeric .'; |
|---|
| 1021 | VK_DIVIDE : newstr:='numeric /'; |
|---|
| 1022 | VK_F1 : newstr:='F1'; |
|---|
| 1023 | VK_F2 : newstr:='F2'; |
|---|
| 1024 | VK_F3 : newstr:='F3'; |
|---|
| 1025 | VK_F4 : newstr:='F4'; |
|---|
| 1026 | VK_F5 : newstr:='F5'; |
|---|
| 1027 | VK_F6 : newstr:='F6'; |
|---|
| 1028 | VK_F7 : newstr:='F7'; |
|---|
| 1029 | VK_F8 : newstr:='F8'; |
|---|
| 1030 | VK_F9 : newstr:='F9'; |
|---|
| 1031 | VK_F10 : newstr:='F10'; |
|---|
| 1032 | VK_F11 : newstr:='F11'; |
|---|
| 1033 | VK_F12 : newstr:='F12'; |
|---|
| 1034 | VK_F13 : newstr:='F13'; |
|---|
| 1035 | VK_F14 : newstr:='F14'; |
|---|
| 1036 | VK_F15 : newstr:='F15'; |
|---|
| 1037 | VK_F16 : newstr:='F16'; |
|---|
| 1038 | VK_F17 : newstr:='F17'; |
|---|
| 1039 | VK_F18 : newstr:='F18'; |
|---|
| 1040 | VK_F19 : newstr:='F19'; |
|---|
| 1041 | VK_F20 : newstr:='F20'; |
|---|
| 1042 | VK_F21 : newstr:='F21'; |
|---|
| 1043 | VK_F22 : newstr:='F22'; |
|---|
| 1044 | VK_F23 : newstr:='F23'; |
|---|
| 1045 | VK_F24 : newstr:='F24'; |
|---|
| 1046 | VK_NUMLOCK : newstr:='Num Lock'; |
|---|
| 1047 | VK_SCROLL : newstr:='Scroll Lock'; |
|---|
| 1048 | 48..57 : newstr:=chr(x[i]); |
|---|
| 1049 | 65..90 : newstr:=chr(x[i]); |
|---|
| 1050 | else newstr:='#'+inttostr(x[i]); |
|---|
| 1051 | end; |
|---|
| 1052 | |
|---|
| 1053 | result:=result+newstr+'+'; |
|---|
| 1054 | end; |
|---|
| 1055 | |
|---|
| 1056 | result:=copy(result,1,length(result)-1); |
|---|
| 1057 | end; |
|---|
| 1058 | |
|---|
| 1059 | procedure getexecutablememoryregionsfromregion(start: dword; stop:dword; var memoryregions: tmemoryregions); |
|---|
| 1060 | var address: dword; |
|---|
| 1061 | mbi: memory_basic_information; |
|---|
| 1062 | begin |
|---|
| 1063 | setlength(memoryregions,0); |
|---|
| 1064 | address:=start; |
|---|
| 1065 | while (address<stop) and (VirtualQueryEx(processhandle,pointer(address),mbi,sizeof(mbi))<>0) and ((address+mbi.RegionSize)>address) do |
|---|
| 1066 | begin |
|---|
| 1067 | if ((mbi.AllocationProtect and PAGE_EXECUTE)=PAGE_EXECUTE) or |
|---|
| 1068 | ((mbi.AllocationProtect and PAGE_EXECUTE_READ)=PAGE_EXECUTE_READ) or |
|---|
| 1069 | ((mbi.AllocationProtect and PAGE_EXECUTE_READWRITE)=PAGE_EXECUTE_READWRITE) or |
|---|
| 1070 | ((mbi.AllocationProtect and PAGE_EXECUTE_WRITECOPY)=PAGE_EXECUTE_WRITECOPY) then |
|---|
| 1071 | begin |
|---|
| 1072 | //executable |
|---|
| 1073 | setlength(memoryregions,length(memoryregions)+1); |
|---|
| 1074 | memoryregions[length(memoryregions)-1].BaseAddress:=dword(mbi.baseaddress); |
|---|
| 1075 | memoryregions[length(memoryregions)-1].MemorySize:=mbi.RegionSize; |
|---|
| 1076 | end; |
|---|
| 1077 | |
|---|
| 1078 | inc(address,mbi.RegionSize); |
|---|
| 1079 | end; |
|---|
| 1080 | |
|---|
| 1081 | end; |
|---|
| 1082 | |
|---|
| 1083 | |
|---|
| 1084 | |
|---|
| 1085 | procedure FillMemoryProcess(start:dword;count:dword;fillvalue:byte); |
|---|
| 1086 | var buf: array of byte; |
|---|
| 1087 | original,actualwritten:dword; |
|---|
| 1088 | begin |
|---|
| 1089 | setlength(buf,count); |
|---|
| 1090 | try |
|---|
| 1091 | fillmemory(@buf[0],count,fillvalue); |
|---|
| 1092 | rewritedata(processhandle,start,@buf[0],count); |
|---|
| 1093 | finally |
|---|
| 1094 | setlength(buf,0); |
|---|
| 1095 | end; |
|---|
| 1096 | end; |
|---|
| 1097 | |
|---|
| 1098 | |
|---|
| 1099 | Procedure CreateCodeCave(address:dword; sourceaddress:dword; sizeofcave: integer); |
|---|
| 1100 | var x,y: dword; |
|---|
| 1101 | i:integer; |
|---|
| 1102 | ignore,temp: string; |
|---|
| 1103 | replacedopcodes: array of string; |
|---|
| 1104 | jumpback: array [0..4] of byte; |
|---|
| 1105 | reassembledinstruction:tassemblerbytes; |
|---|
| 1106 | |
|---|
| 1107 | overwritesize: dword; |
|---|
| 1108 | begin |
|---|
| 1109 | x:=sourceaddress; |
|---|
| 1110 | |
|---|
| 1111 | while x<(sourceaddress+5) do |
|---|
| 1112 | begin |
|---|
| 1113 | setlength(replacedopcodes,length(replacedopcodes)+1); |
|---|
| 1114 | temp:=disassemble(x,ignore); |
|---|
| 1115 | temp:=copy(temp,pos('-',temp)+1,length(temp)); |
|---|
| 1116 | temp:=copy(temp,pos('-',temp)+2,length(temp)); |
|---|
| 1117 | |
|---|
| 1118 | replacedopcodes[length(replacedopcodes)-1]:=temp; |
|---|
| 1119 | end; |
|---|
| 1120 | |
|---|
| 1121 | overwritesize:=x-sourceaddress; |
|---|
| 1122 | |
|---|
| 1123 | x:=address+sizeofcave-5; |
|---|
| 1124 | y:=x; |
|---|
| 1125 | |
|---|
| 1126 | jumpback[0]:=$e9; |
|---|
| 1127 | pdword(@jumpback[1])^:=sourceaddress-x; |
|---|
| 1128 | |
|---|
| 1129 | virtualprotectex(processhandle,pointer(address),sizeofcave,PAGE_EXECUTE_READWRITE ,x); |
|---|
| 1130 | fillmemoryprocess(address,sizeofcave,$90); |
|---|
| 1131 | |
|---|
| 1132 | if sizeofcave>5 then |
|---|
| 1133 | writeprocessmemory(processhandle,pointer(y),@jumpback[0],5,x); |
|---|
| 1134 | |
|---|
| 1135 | x:=address; |
|---|
| 1136 | for i:=0 to length(replacedopcodes)-1 do |
|---|
| 1137 | begin |
|---|
| 1138 | assemble(replacedopcodes[i],x,reassembledinstruction); |
|---|
| 1139 | writeprocessmemory(processhandle,pointer(x),@reassembledinstruction[0],length(reassembledinstruction),y); |
|---|
| 1140 | inc(x,length(reassembledinstruction)); |
|---|
| 1141 | end; |
|---|
| 1142 | |
|---|
| 1143 | virtualprotectex(processhandle,pointer(sourceaddress),overwritesize,x,y); |
|---|
| 1144 | |
|---|
| 1145 | |
|---|
| 1146 | //now place the jmp |
|---|
| 1147 | setlength(reassembledinstruction,overwritesize); |
|---|
| 1148 | reassembledinstruction[0]:=$e9; |
|---|
| 1149 | pdword(@reassembledinstruction[1])^:=address-sourceaddress-5; |
|---|
| 1150 | |
|---|
| 1151 | for i:=5 to overwritesize-1 do |
|---|
| 1152 | reassembledinstruction[i]:=$90; |
|---|
| 1153 | |
|---|
| 1154 | RewriteData(processhandle,sourceaddress,@reassembledinstruction[0],overwritesize); |
|---|
| 1155 | end; |
|---|
| 1156 | |
|---|
| 1157 | |
|---|
| 1158 | |
|---|
| 1159 | |
|---|
| 1160 | |
|---|
| 1161 | procedure SetLanguage; |
|---|
| 1162 | begin |
|---|
| 1163 | if LoadNewResourceModule(LANG_GERMAN) <> 0 then ReinitializeForms |
|---|
| 1164 | if LoadNewResourceModule(LANG_RUSSIAN) <> 0 then ReinitializeForms |
|---|
| 1165 | if LoadNewResourceModule(LANG_DUTCH) <> 0 then ReinitializeForms |
|---|
| 1166 | end; |
|---|
| 1167 | |
|---|
| 1168 | |
|---|
| 1169 | |
|---|
| 1170 | |
|---|
| 1171 | //Returns a random threadid owned by the target process |
|---|
| 1172 | function getathreadid(processid:dword):dword; |
|---|
| 1173 | var i: integer; |
|---|
| 1174 | ths: thandle; |
|---|
| 1175 | tE: threadentry32; |
|---|
| 1176 | begin |
|---|
| 1177 | if frmProcessWatcher<>nil then |
|---|
| 1178 | begin |
|---|
| 1179 | //first find a processid using the processwatcher |
|---|
| 1180 | |
|---|
| 1181 | frmProcessWatcher.processesMREW.BeginRead; |
|---|
| 1182 | try |
|---|
| 1183 | for i:=0 to length(frmProcessWatcher.processes)-1 do |
|---|
| 1184 | if frmProcessWatcher.processes[i].processid=processid then |
|---|
| 1185 | begin |
|---|
| 1186 | if length(frmProcessWatcher.processes[i].threadlist)>0 then |
|---|
| 1187 | begin |
|---|
| 1188 | result:=frmProcessWatcher.processes[i].threadlist[0].threadid; |
|---|
| 1189 | exit; |
|---|
| 1190 | end; |
|---|
| 1191 | end; |
|---|
| 1192 | finally |
|---|
| 1193 | frmProcessWatcher.processesMREW.EndRead; |
|---|
| 1194 | end; |
|---|
| 1195 | |
|---|
| 1196 | end; |
|---|
| 1197 | |
|---|
| 1198 | //no exit yet, so use a enumeration of all threads and this processid |
|---|
| 1199 | ths:=CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD,0); |
|---|
| 1200 | if ths<>0 then |
|---|
| 1201 | begin |
|---|
| 1202 | te.dwSize:=sizeof(te); |
|---|
| 1203 | if Thread32First(ths,te) then |
|---|
| 1204 | begin |
|---|
| 1205 | repeat |
|---|
| 1206 | if te.th32OwnerProcessID=processid then |
|---|
| 1207 | begin |
|---|
| 1208 | result:=te.th32ThreadID; |
|---|
| 1209 | closehandle(ths); |
|---|
| 1210 | exit; |
|---|
| 1211 | end; |
|---|
| 1212 | |
|---|
| 1213 | |
|---|
| 1214 | until not thread32Next(ths,te); |
|---|
| 1215 | end; |
|---|
| 1216 | end; |
|---|
| 1217 | |
|---|
| 1218 | closehandle(ths); |
|---|
| 1219 | end; |
|---|
| 1220 | |
|---|
| 1221 | |
|---|
| 1222 | procedure DetachIfPossible; |
|---|
| 1223 | var crashcounter: integer; |
|---|
| 1224 | waitform: TForm; |
|---|
| 1225 | msg: tlabel; |
|---|
| 1226 | begin |
|---|
| 1227 | //detach the debugger |
|---|
| 1228 | |
|---|
| 1229 | waitform:=nil; |
|---|
| 1230 | crashcounter:=0; |
|---|
| 1231 | |
|---|
| 1232 | |
|---|
| 1233 | if debuggerthread=nil then |
|---|
| 1234 | begin |
|---|
| 1235 | if kdebugger.isactive then |
|---|
| 1236 | KDebugger.StopDebugger; |
|---|
| 1237 | |
|---|
| 1238 | exit; |
|---|
| 1239 | end |
|---|
| 1240 | else debuggerthread.Terminate; |
|---|
| 1241 | |
|---|
| 1242 | if @DebugActiveProcessStop=@DebugActiveProcessStopProstitute then //lets help it a hand if it cant detach gracefully |
|---|
| 1243 | terminateprocess(processhandle,0) |
|---|
| 1244 | else |
|---|
| 1245 | begin |
|---|
| 1246 | if debuggerthread<>nil then |
|---|
| 1247 | begin |
|---|
| 1248 | //show a window asking the user to wait and not to freak out and think CE crashed! |
|---|
| 1249 | waitform:=TForm.Create(nil); |
|---|
| 1250 | with waitform do |
|---|
| 1251 | begin |
|---|
| 1252 | waitform.Caption:='Detaching...'; |
|---|
| 1253 | msg:=TLabel.Create(waitform); |
|---|
| 1254 | msg.Caption:='Please wait while Cheat Engine tries to detach from the current process(This wont take longer than 30 seconds)'; |
|---|
| 1255 | |
|---|
| 1256 | waitform.Width:=msg.Width+20; |
|---|
| 1257 | waitform.clientHeight:=50; |
|---|
| 1258 | |
|---|
| 1259 | msg.Left:=7; |
|---|
| 1260 | msg.Top:=(waitform.ClientHeight div 2) - (msg.Height div 2); |
|---|
| 1261 | msg.Parent:=waitform; |
|---|
| 1262 | |
|---|
| 1263 | //waitform.Parent:=self; |
|---|
| 1264 | waitform.BorderStyle:=bsDialog; |
|---|
| 1265 | waitform.BorderIcons:=[]; |
|---|
| 1266 | |
|---|
| 1267 | waitform.Position:=poScreenCenter; |
|---|
| 1268 | waitform.Show; |
|---|
| 1269 | waitform.Repaint; |
|---|
| 1270 | end; |
|---|
| 1271 | end; |
|---|
| 1272 | end; |
|---|
| 1273 | |
|---|
| 1274 | while (debuggerthread<>nil) and (debuggerthread.attached) and (crashcounter<30) do |
|---|
| 1275 | begin |
|---|
| 1276 | inc(crashcounter); |
|---|
| 1277 | sleep(1000); |
|---|
| 1278 | end; |
|---|
| 1279 | |
|---|
| 1280 | if crashcounter=30 then messagedlg('Detaching failed!!! Your process is lost!',mtError,[mbok],0); |
|---|
| 1281 | |
|---|
| 1282 | if waitform<>nil then |
|---|
| 1283 | begin |
|---|
| 1284 | waitform.Hide; |
|---|
| 1285 | waitform.Free; |
|---|
| 1286 | waitform:=nil; |
|---|
| 1287 | end; |
|---|
| 1288 | |
|---|
| 1289 | |
|---|
| 1290 | |
|---|
| 1291 | |
|---|
| 1292 | end; |
|---|
| 1293 | |
|---|
| 1294 | |
|---|
| 1295 | |
|---|
| 1296 | Procedure InjectDll(dllname: string; functiontocall: string=''); |
|---|
| 1297 | var LoadLibraryPtr: pointer; |
|---|
| 1298 | GetProcAddressPtr: Pointer; |
|---|
| 1299 | |
|---|
| 1300 | |
|---|
| 1301 | h: Thandle; |
|---|
| 1302 | |
|---|
| 1303 | inject: array [0..4095] of byte; |
|---|
| 1304 | x:dword; |
|---|
| 1305 | |
|---|
| 1306 | outp:TAssemblerBytes; |
|---|
| 1307 | counter: integer; |
|---|
| 1308 | position,position2: dword; |
|---|
| 1309 | |
|---|
| 1310 | dllLocation: string; |
|---|
| 1311 | startaddresS: dword; |
|---|
| 1312 | functionloc: dword; |
|---|
| 1313 | injectionlocation: pointer; |
|---|
| 1314 | threadhandle: thandle; |
|---|
| 1315 | begin |
|---|
| 1316 | h:=LoadLibrary('Kernel32.dll'); |
|---|
| 1317 | if h=0 then raise exception.Create('No kernel32.dll loaded'); |
|---|
| 1318 | |
|---|
| 1319 | injectionlocation:=nil; |
|---|
| 1320 | try |
|---|
| 1321 | try |
|---|
| 1322 | getprocaddressptr:=pointer(symhandler.getAddressFromName('GetProcAddress',true)); |
|---|
| 1323 | except |
|---|
| 1324 | GetProcAddressPtr:=GetProcAddress(h,'GetProcAddress'); |
|---|
| 1325 | end; |
|---|
| 1326 | |
|---|
| 1327 | if getprocaddressptr=nil then raise exception.Create('GetProcAddress not found'); |
|---|
| 1328 | |
|---|
| 1329 | try |
|---|
| 1330 | LoadLibraryPtr:=pointer(symhandler.getAddressFromName('LoadLibraryA',true)); |
|---|
| 1331 | except |
|---|
| 1332 | //failed getting the address of LoadLibraryA, use old method |
|---|
| 1333 | LoadLibraryPtr:=GetProcAddress(h,'LoadLibraryA'); |
|---|
| 1334 | end; |
|---|
| 1335 | |
|---|
| 1336 | |
|---|
| 1337 | if LoadLibraryptr=nil then raise exception.Create('LoadLibraryA not found'); |
|---|
| 1338 | |
|---|
| 1339 | injectionlocation:=VirtualAllocEx(processhandle,nil,4096,MEM_COMMIT,PAGE_EXECUTE_READWRITE); |
|---|
| 1340 | |
|---|
| 1341 | if injectionlocation=nil then raise exception.Create('Failed to allocate memory'); |
|---|
| 1342 | |
|---|
| 1343 | dlllocation:=dllname; |
|---|
| 1344 | |
|---|
| 1345 | position:=dword(injectionlocation); |
|---|
| 1346 | position2:=0; |
|---|
| 1347 | copymemory(@inject[0],pchar(dllLocation+#0),length(dllLocation)+1); |
|---|
| 1348 | inc(position,length(dllLocation)+1); |
|---|
| 1349 | inc(position2,length(dllLocation)+1); |
|---|
| 1350 | |
|---|
| 1351 | functionloc:=position; |
|---|
| 1352 | copymemory(@inject[position2],pchar(functiontocall+#0),length(functiontocall)+1); |
|---|
| 1353 | inc(position,length(functiontocall)+1); |
|---|
| 1354 | inc(position2,length(functiontocall)+1); |
|---|
| 1355 | startaddress:=position; |
|---|
| 1356 | |
|---|
| 1357 | //loadlibrary(cehook); |
|---|
| 1358 | assemble('PUSH '+IntToHex(dword(injectionlocation),8),position,outp); |
|---|
| 1359 | copymemory(@inject[position2],outp,length(outp)); |
|---|
| 1360 | inc(position,length(outp)); |
|---|
| 1361 | inc(position2,length(outp)); |
|---|
| 1362 | |
|---|
| 1363 | assemble('CALL '+IntToHex(dword(LoadLibraryPtr),8),position,outp); |
|---|
| 1364 | copymemory(@inject[position2],outp,length(outp)); |
|---|
| 1365 | inc(position,length(outp)); |
|---|
| 1366 | inc(position2,length(outp)); |
|---|
| 1367 | |
|---|
| 1368 | |
|---|
| 1369 | //safetycode, test if the dll was actually loaded and skip if not |
|---|
| 1370 | assemble('TEST EAX,EAX',position,outp); |
|---|
| 1371 | copymemory(@inject[position2],outp,length(outp)); |
|---|
| 1372 | inc(position,length(outp)); |
|---|
| 1373 | inc(position2,length(outp)); |
|---|
| 1374 | |
|---|
| 1375 | assemble('JNE '+inttohex(position+3+5,8),position,outp); //jump over the ret |
|---|
| 1376 | copymemory(@inject[position2],outp,length(outp)); |
|---|
| 1377 | inc(position,length(outp)); |
|---|
| 1378 | inc(position2,length(outp)); |
|---|
| 1379 | |
|---|
| 1380 | assemble('MOV EAX,2',position,outp); //exitcode=2 |
|---|
| 1381 | copymemory(@inject[position2],outp,length(outp)); |
|---|
| 1382 | inc(position,length(outp)); |
|---|
| 1383 | inc(position2,length(outp)); |
|---|
| 1384 | |
|---|
| 1385 | assemble('RET',position,outp); |
|---|
| 1386 | copymemory(@inject[position2],outp,length(outp)); |
|---|
| 1387 | inc(position,length(outp)); |
|---|
| 1388 | inc(position2,length(outp)); |
|---|
| 1389 | |
|---|
| 1390 | |
|---|
| 1391 | if functiontocall<>'' then |
|---|
| 1392 | begin |
|---|
| 1393 | //getprocaddress |
|---|
| 1394 | assemble('PUSH '+IntToHex(functionloc,8),position,outp); |
|---|
| 1395 | copymemory(@inject[position2],outp,length(outp)); |
|---|
| 1396 | inc(position,length(outp)); |
|---|
| 1397 | inc(position2,length(outp)); |
|---|
| 1398 | |
|---|
| 1399 | assemble('PUSH EAX',position,outp); |
|---|
| 1400 | copymemory(@inject[position2],outp,length(outp)); |
|---|
| 1401 | inc(position,length(outp)); |
|---|
| 1402 | inc(position2,length(outp)); |
|---|
| 1403 | |
|---|
| 1404 | assemble('CALL '+IntToHex(dword(GetProcAddressPtr),8),position,outp); |
|---|
| 1405 | copymemory(@inject[position2],outp,length(outp)); |
|---|
| 1406 | inc(position,length(outp)); |
|---|
| 1407 | inc(position2,length(outp)); |
|---|
| 1408 | |
|---|
| 1409 | assemble('TEST EAX,EAX',position,outp); |
|---|
| 1410 | copymemory(@inject[position2],outp,length(outp)); |
|---|
| 1411 | inc(position,length(outp)); |
|---|
| 1412 | inc(position2,length(outp)); |
|---|
| 1413 | |
|---|
| 1414 | assemble('JNE '+inttohex(position+3+5,8),position,outp); |
|---|
| 1415 | copymemory(@inject[position2],outp,length(outp)); |
|---|
| 1416 | inc(position,length(outp)); |
|---|
| 1417 | inc(position2,length(outp)); |
|---|
| 1418 | |
|---|
| 1419 | assemble('MOV EAX,3',position,outp); //exitcode=3 |
|---|
| 1420 | copymemory(@inject[position2],outp,length(outp)); |
|---|
| 1421 | inc(position,length(outp)); |
|---|
| 1422 | inc(position2,length(outp)); |
|---|
| 1423 | |
|---|
| 1424 | assemble('RET',position,outp); |
|---|
| 1425 | copymemory(@inject[position2],outp,length(outp)); |
|---|
| 1426 | inc(position,length(outp)); |
|---|
| 1427 | inc(position2,length(outp)); |
|---|
| 1428 | |
|---|
| 1429 | //call function |
|---|
| 1430 | assemble('CALL EAX',position,outp); |
|---|
| 1431 | copymemory(@inject[position2],outp,length(outp)); |
|---|
| 1432 | inc(position,length(outp)); |
|---|
| 1433 | inc(position2,length(outp)); |
|---|
| 1434 | end; |
|---|
| 1435 | |
|---|
| 1436 | |
|---|
| 1437 | assemble('MOV EAX,1',position,outp); //causes the exitcode of the thread be 1 |
|---|
| 1438 | copymemory(@inject[position2],outp,length(outp)); |
|---|
| 1439 | inc(position,length(outp)); |
|---|
| 1440 | inc(position2,length(outp)); |
|---|
| 1441 | |
|---|
| 1442 | assemble('RET',position,outp); |
|---|
| 1443 | copymemory(@inject[position2],outp,length(outp)); |
|---|
| 1444 | inc(position,length(outp)); |
|---|
| 1445 | inc(position2,length(outp)); |
|---|
| 1446 | |
|---|
| 1447 | |
|---|
| 1448 | //call the routine |
|---|
| 1449 | |
|---|
| 1450 | if not writeprocessmemory(processhandle,injectionlocation,@inject[0],position2,x) then raise exception.Create('Failed to inject the dll loader'); |
|---|
| 1451 | |
|---|
| 1452 | |
|---|
| 1453 | |
|---|
| 1454 | |
|---|
| 1455 | useapctoinjectdll:=false; |
|---|
| 1456 | if useapctoinjectdll then |
|---|
| 1457 | begin |
|---|
| 1458 | showmessage('injected code at:'+inttohex(startaddress,8)); |
|---|
| 1459 | |
|---|
| 1460 | //suspend , message, resume is needed to prevent a crash when it is in a message loop |
|---|
| 1461 | ntsuspendprocess(processid); |
|---|
| 1462 | x:=getathreadid(processid); |
|---|
| 1463 | PostThreadMessage(x,wm_paint,0,0); |
|---|
| 1464 | CreateRemoteAPC(x,pointer(startaddress)); |
|---|
| 1465 | ntresumeprocess(processid); |
|---|
| 1466 | end |
|---|
| 1467 | else |
|---|
| 1468 | |
|---|
| 1469 | |
|---|
| 1470 | |
|---|
| 1471 | begin |
|---|
| 1472 | threadhandle:=createremotethread(processhandle,nil,0,pointer(startaddress),nil,0,x); |
|---|
| 1473 | if threadhandle=0 then raise exception.Create('Failed to execute the dll loader'); |
|---|
| 1474 | |
|---|
| 1475 | counter:=10000 div 10; |
|---|
| 1476 | while (waitforsingleobject(threadhandle,10)=WAIT_TIMEOUT) and (counter>0) do |
|---|
| 1477 | begin |
|---|
| 1478 | if GetCurrentThreadID = MainThreadID then |
|---|
| 1479 | CheckSynchronize; //handle sychronize calls while it's waiting |
|---|
| 1480 | |
|---|
| 1481 | dec(counter); |
|---|
| 1482 | end; |
|---|
| 1483 | |
|---|
| 1484 | if (counter=0) then |
|---|
| 1485 | raise exception.Create('The injection thread took longer than 10 seconds to execute. Injection routine not freed'); |
|---|
| 1486 | |
|---|
| 1487 | if getexitcodethread(threadhandle,x) then |
|---|
| 1488 | begin |
|---|
| 1489 | case x of |
|---|
| 1490 | 1: ;//success |
|---|
| 1491 | 2: raise exception.Create('Failed injecting the DLL'); |
|---|
| 1492 | 3: raise exception.Create('Failed executing the function of the dll'); |
|---|
| 1493 | else raise exception.Create('Unknown error during injection'); |
|---|
| 1494 | end; |
|---|
| 1495 | end; //else unsure, did it work or not , or is it crashing? |
|---|
| 1496 | |
|---|
| 1497 | end; |
|---|
| 1498 | finally |
|---|
| 1499 | FreeLibrary(h); |
|---|
| 1500 | if injectionlocation<>nil then |
|---|
| 1501 | virtualfreeex(processhandle,injectionlocation,0,MEM_RELEASE ); |
|---|
| 1502 | end; |
|---|
| 1503 | |
|---|
| 1504 | end; |
|---|
| 1505 | |
|---|
| 1506 | procedure ToggleOtherWindows; |
|---|
| 1507 | type Tprocesslistitem = record |
|---|
| 1508 | processid: dword; |
|---|
| 1509 | processname: string; |
|---|
| 1510 | end; |
|---|
| 1511 | var winhandle: Hwnd; |
|---|
| 1512 | winprocess: Dword; |
|---|
| 1513 | i,j: integer; |
|---|
| 1514 | SNAPHandle: THandle; |
|---|
| 1515 | ProcessEntry: ProcessEntry32; |
|---|
| 1516 | Check: Boolean; |
|---|
| 1517 | processlist: array of Tprocesslistitem; |
|---|
| 1518 | hideall,hidethisone: boolean; |
|---|
| 1519 | begin |
|---|
| 1520 | hideall:=false; |
|---|
| 1521 | |
|---|
| 1522 | allwindowsareback:=false; |
|---|
| 1523 | |
|---|
| 1524 | if length(windowlist)<>0 then |
|---|
| 1525 | begin |
|---|
| 1526 | for i:=0 to length(windowlist)-1 do |
|---|
| 1527 | showwindow(windowlist[i],SW_SHOW); |
|---|
| 1528 | |
|---|
| 1529 | setlength(windowlist,0); |
|---|
| 1530 | allwindowsareback:=true; |
|---|
| 1531 | exit; |
|---|
| 1532 | end; |
|---|
| 1533 | |
|---|
| 1534 | lastactive:=getactivewindow; |
|---|
| 1535 | lastforeground:=GetForegroundWindow; |
|---|
| 1536 | |
|---|
| 1537 | if onlyfront then |
|---|
| 1538 | begin |
|---|
| 1539 | GetWindowThreadProcessId(lastforeground,addr(winprocess)); |
|---|
| 1540 | if getcurrentprocessid=winprocess then |
|---|
| 1541 | begin |
|---|
| 1542 | beep; |
|---|
| 1543 | sleep(100); |
|---|
| 1544 | beep; |
|---|
| 1545 | sleep(100); |
|---|
| 1546 | exit; |
|---|
| 1547 | end; |
|---|
| 1548 | |
|---|
| 1549 | setlength(windowlist,1); |
|---|
| 1550 | windowlist[0]:=lastforeground; |
|---|
| 1551 | showwindow(lastforeground,sw_hide); |
|---|
| 1552 | exit; |
|---|
| 1553 | end; |
|---|
| 1554 | |
|---|
| 1555 | |
|---|
| 1556 | if length(donthidelist)>0 then |
|---|
| 1557 | begin |
|---|
| 1558 | //first get a process list |
|---|
| 1559 | SNAPHandle:=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0); |
|---|
| 1560 | If SnapHandle>0 then |
|---|
| 1561 | begin |
|---|
| 1562 | ProcessEntry.dwSize:=SizeOf(ProcessEntry); |
|---|
| 1563 | Check:=Process32First(SnapHandle,ProcessEntry); |
|---|
| 1564 | while check do |
|---|
| 1565 | begin |
|---|
| 1566 | if processentry.th32ProcessID<>0 then |
|---|
| 1567 | begin |
|---|
| 1568 | setlength(processlist,length(processlist)+1); |
|---|
| 1569 | processlist[length(processlist)-1].processid:=processentry.th32ProcessID; |
|---|
| 1570 | processlist[length(processlist)-1].processname:=lowercase(ExtractFilename(processentry.szExeFile)); |
|---|
| 1571 | end; |
|---|
| 1572 | check:=Process32Next(SnapHandle,ProcessEntry); |
|---|
| 1573 | end; |
|---|
| 1574 | end else hideall:=true; //else sorry dude, but no exceptions for you, say goodbye to ALL your windows |
|---|
| 1575 | end else hideall:=true; |
|---|
| 1576 | |
|---|
| 1577 | winhandle:=getwindow(GetForegroundWindow,GW_HWNDFIRST); |
|---|
| 1578 | |
|---|
| 1579 | while winhandle<>0 do |
|---|
| 1580 | begin |
|---|
| 1581 | GetWindowThreadProcessId(winhandle,addr(winprocess)); |
|---|
| 1582 | |
|---|
| 1583 | if (winprocess<>getCurrentProcessID) {and (winprocess<>3600) }then |
|---|
| 1584 | begin |
|---|
| 1585 | if isWindowVisible(winhandle) then |
|---|
| 1586 | begin |
|---|
| 1587 | hidethisone:=true; |
|---|
| 1588 | if not hideall then |
|---|
| 1589 | begin |
|---|
| 1590 | //see if you can hide it or not |
|---|
| 1591 | //check this window process with the process list |
|---|
| 1592 | //and then see if the processname equals an item from the donthide list |
|---|
| 1593 | for i:=0 to length(processlist)-1 do |
|---|
| 1594 | if processlist[i].processid=winprocess then |
|---|
| 1595 | begin |
|---|
| 1596 | //found the process id, now check if the processname of this process equals an item from the list |
|---|
| 1597 | for j:=0 to length(donthidelist)-1 do |
|---|
| 1598 | if processlist[i].processname=donthidelist[j] then //it's in so do not hide |
|---|
| 1599 | begin |
|---|
| 1600 | hidethisone:=false; |
|---|
| 1601 | break; |
|---|
| 1602 | end; |
|---|
| 1603 | break; |
|---|
| 1604 | end; |
|---|
| 1605 | end; |
|---|
| 1606 | |
|---|
| 1607 | |
|---|
| 1608 | |
|---|
| 1609 | if hidethisone then |
|---|
| 1610 | begin |
|---|
| 1611 | showwindow(winhandle,SW_HIDE); |
|---|
| 1612 | // 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); |
|---|
| 1613 | setlength(windowlist,length(windowlist)+1); |
|---|
| 1614 | windowlist[length(windowlist)-1]:=winhandle; |
|---|
| 1615 | end; |
|---|
| 1616 | // showwindow(winhandle,sw_show); //remove this for real version |
|---|
| 1617 | end; |
|---|
| 1618 | end; |
|---|
| 1619 | |
|---|
| 1620 | winhandle:=getwindow(winhandle,GW_HWNDNEXT); |
|---|
| 1621 | end; |
|---|
| 1622 | |
|---|
| 1623 | // application.BringToFront; |
|---|
| 1624 | end; |
|---|
| 1625 | |
|---|
| 1626 | function GetSystemType: Integer; //from Stuart Johnson with a little change by me |
|---|
| 1627 | const |
|---|
| 1628 | |
|---|
| 1629 | |
|---|
| 1630 | cOsUnknown = 999999; |
|---|
| 1631 | cOsWin95 = 0; |
|---|
| 1632 | cOsWin98 = 1; |
|---|
| 1633 | cOsWin98SE = 2; |
|---|
| 1634 | cOsWinME = 3; |
|---|
| 1635 | cOsWinNT = 4; |
|---|
| 1636 | cOsWin2000 = 5; |
|---|
| 1637 | cOsWinXP = 6; |
|---|
| 1638 | cOsNewer = 7; |
|---|
| 1639 | |
|---|
| 1640 | var |
|---|
| 1641 | osVerInfo : TOSVersionInfo; |
|---|
| 1642 | majorVer, minorVer : Integer; |
|---|
| 1643 | |
|---|
| 1644 | begin |
|---|
| 1645 | if overridedebug then |
|---|
| 1646 | begin |
|---|
| 1647 | result:=cOsWinXP; |
|---|
| 1648 | exit; |
|---|
| 1649 | end; |
|---|
| 1650 | |
|---|
| 1651 | |
|---|
| 1652 | osVerInfo.dwOSVersionInfoSize := SizeOf(TOSVersionInfo); |
|---|
| 1653 | if GetVersionEx(osVerInfo) then |
|---|
| 1654 | begin |
|---|
| 1655 | majorVer := osVerInfo.dwMajorVersion; |
|---|
| 1656 | minorVer := osVerInfo.dwMinorVersion; |
|---|
| 1657 | case osVerInfo.dwPlatformId of |
|---|
| 1658 | VER_PLATFORM_WIN32_NT : |
|---|
| 1659 | begin |
|---|
| 1660 | if majorVer <= 4 then |
|---|
| 1661 | result := cOsWinNT |
|---|
| 1662 | else |
|---|
| 1663 | if (majorVer = 5) AND (minorVer= 0) then |
|---|
| 1664 | result := cOsWin2000 |
|---|
| 1665 | else |
|---|
| 1666 | if (majorVer = 5) AND (minorVer = 1) then |
|---|
| 1667 | result := cOsWinXP |
|---|
| 1668 | else if (majorver > 5) then result:=cOsNewer |
|---|
| 1669 | else |
|---|
| 1670 | result := cOsUnknown; |
|---|
| 1671 | end; |
|---|
| 1672 | VER_PLATFORM_WIN32_WINDOWS : |
|---|
| 1673 | begin |
|---|
| 1674 | if (majorVer = 4) AND (minorVer = 0) then |
|---|
| 1675 | result := cOsWin95 |
|---|
| 1676 | else |
|---|
| 1677 | if (majorVer = 4) AND (minorVer = 10) then |
|---|
| 1678 | begin |
|---|
| 1679 | if osVerInfo.szCSDVersion[1] = 'A' then |
|---|
| 1680 | result := cOsWin98SE |
|---|
| 1681 | else |
|---|
| 1682 | result := cOsWin98; |
|---|
| 1683 | end |
|---|
| 1684 | else |
|---|
| 1685 | if (majorVer = 4) AND (minorVer = 90) then |
|---|
| 1686 | result := cOsWinME |
|---|
| 1687 | else |
|---|
| 1688 | result := cOsUnknown; |
|---|
| 1689 | end; |
|---|
| 1690 | else |
|---|
| 1691 | result := cOsUnknown; |
|---|
| 1692 | end; |
|---|
| 1693 | end |
|---|
| 1694 | else |
|---|
| 1695 | result := cOsUnknown; |
|---|
| 1696 | end; |
|---|
| 1697 | |
|---|
| 1698 | |
|---|
| 1699 | |
|---|
| 1700 | function KeyToStr(key:word):string; |
|---|
| 1701 | begin |
|---|
| 1702 | case key of |
|---|
| 1703 | VK_BACK : result:='Backspace'; |
|---|
| 1704 | VK_TAB : result:='Tab'; |
|---|
| 1705 | VK_CLEAR : result:='Clear'; |
|---|
| 1706 | VK_RETURN : result:='Enter'; |
|---|
| 1707 | VK_PAUSE : result:='Pause'; |
|---|
| 1708 | VK_CAPITAL : result:='Caps Lock'; |
|---|
| 1709 | VK_ESCAPE : result:='Esc'; |
|---|
| 1710 | VK_SPACE : result:='Space bar'; |
|---|
| 1711 | VK_PRIOR : result:='Page Up'; |
|---|
| 1712 | VK_NEXT : result:='Page Down'; |
|---|
| 1713 | VK_END : result:='End'; |
|---|
| 1714 | VK_HOME : result:='Home'; |
|---|
| 1715 | VK_LEFT : result:='Left Arrow'; |
|---|
| 1716 | VK_UP : result:='Up Arrow'; |
|---|
| 1717 | VK_RIGHT : result:='Right Arrow'; |
|---|
| 1718 | VK_DOWN : result:='Down Arrow'; |
|---|
| 1719 | VK_SELECT : result:='Select'; |
|---|
| 1720 | VK_PRINT : result:='Print'; |
|---|
| 1721 | VK_EXECUTE : result:='Execute'; |
|---|
| 1722 | VK_SNAPSHOT : result:='Print Screen'; |
|---|
| 1723 | VK_INSERT : result:='Insert'; |
|---|
| 1724 | VK_DELETE : result:='Delete'; |
|---|
| 1725 | VK_HELP : result:='Help'; |
|---|
| 1726 | VK_LWIN : result:='Left Windows key'; |
|---|
| 1727 | VK_RWIN : result:='Right Windows key'; |
|---|
| 1728 | VK_APPS : result:='Applications key'; |
|---|
| 1729 | VK_NUMPAD0 : result:='numeric 0'; |
|---|
| 1730 | VK_NUMPAD1 : result:='numeric 1'; |
|---|
| 1731 | VK_NUMPAD2 : result:='numeric 2'; |
|---|
| 1732 | VK_NUMPAD3 : result:='numeric 3'; |
|---|
| 1733 | VK_NUMPAD4 : result:='numeric 4'; |
|---|
| 1734 | VK_NUMPAD5 : result:='numeric 5'; |
|---|
| 1735 | VK_NUMPAD6 : result:='numeric 6'; |
|---|
| 1736 | VK_NUMPAD7 : result:='numeric 7'; |
|---|
| 1737 | VK_NUMPAD8 : result:='numeric 8'; |
|---|
| 1738 | VK_NUMPAD9 : result:='numeric 9'; |
|---|
| 1739 | VK_MULTIPLY : result:='numeric *'; |
|---|
| 1740 | VK_ADD : result:='numeric +'; |
|---|
| 1741 | VK_SEPARATOR : result:='numeric Separator'; |
|---|
| 1742 | VK_SUBTRACT : result:='numeric -'; |
|---|
| 1743 | VK_DECIMAL : result:='numeric .'; |
|---|
| 1744 | VK_DIVIDE : result:='numeric /'; |
|---|
| 1745 | VK_F1 : result:='F1'; |
|---|
| 1746 | VK_F2 : result:='F2'; |
|---|
| 1747 | VK_F3 : result:='F3'; |
|---|
| 1748 | VK_F4 : result:='F4'; |
|---|
| 1749 | VK_F5 : result:='F5'; |
|---|
| 1750 | VK_F6 : result:='F6'; |
|---|
| 1751 | VK_F7 : result:='F7'; |
|---|
| 1752 | VK_F8 : result:='F8'; |
|---|
| 1753 | VK_F9 : result:='F9'; |
|---|
| 1754 | VK_F10 : result:='F10'; |
|---|
| 1755 | VK_F11 : result:='F11'; |
|---|
| 1756 | VK_F12 : result:='F12'; |
|---|
| 1757 | VK_F13 : result:='F13'; |
|---|
| 1758 | VK_F14 : result:='F14'; |
|---|
| 1759 | VK_F15 : result:='F15'; |
|---|
| 1760 | VK_F16 : result:='F16'; |
|---|
| 1761 | VK_F17 : result:='F17'; |
|---|
| 1762 | VK_F18 : result:='F18'; |
|---|
| 1763 | VK_F19 : result:='F19'; |
|---|
| 1764 | VK_F20 : result:='F20'; |
|---|
| 1765 | VK_F21 : result:='F21'; |
|---|
| 1766 | VK_F22 : result:='F22'; |
|---|
| 1767 | VK_F23 : result:='F23'; |
|---|
| 1768 | VK_F24 : result:='F24'; |
|---|
| 1769 | VK_NUMLOCK : result:='Num Lock'; |
|---|
| 1770 | VK_SCROLL : result:='Scroll Lock'; |
|---|
| 1771 | 48..57 : result:=chr(key); |
|---|
| 1772 | 65..90 : result:=chr(key); |
|---|
| 1773 | else result:='#'+IntToStr(key); |
|---|
| 1774 | end; |
|---|
| 1775 | |
|---|
| 1776 | end; |
|---|
| 1777 | |
|---|
| 1778 | procedure decimal(var key: char); //removed |
|---|
| 1779 | begin |
|---|
| 1780 | |
|---|
| 1781 | |
|---|
| 1782 | |
|---|
| 1783 | |
|---|
| 1784 | |
|---|
| 1785 | |
|---|
| 1786 | |
|---|
| 1787 | |
|---|
| 1788 | end; |
|---|
| 1789 | |
|---|
| 1790 | procedure hexadecimal(var key: char); //removed |
|---|
| 1791 | begin |
|---|
| 1792 | |
|---|
| 1793 | |
|---|
| 1794 | |
|---|
| 1795 | |
|---|
| 1796 | |
|---|
| 1797 | |
|---|
| 1798 | |
|---|
| 1799 | |
|---|
| 1800 | end; |
|---|
| 1801 | |
|---|
| 1802 | function ByteStringToText(s: string;hex: boolean):string; |
|---|
| 1803 | var temp: tbytes; |
|---|
| 1804 | i,j: integer; |
|---|
| 1805 | begin |
|---|
| 1806 | ConvertStringToBytes(s,hex,temp); |
|---|
| 1807 | result:=''; |
|---|
| 1808 | |
|---|
| 1809 | for i:=0 to length(temp)-1 do |
|---|
| 1810 | if temp[i]>$13 then |
|---|
| 1811 | result:=result+chr(temp[i]); |
|---|
| 1812 | end; |
|---|
| 1813 | |
|---|
| 1814 | |
|---|
| 1815 | function ByteStringToDouble(s: string;hex: boolean):double; |
|---|
| 1816 | var temp: tbytes; |
|---|
| 1817 | temp2: double; |
|---|
| 1818 | p: ^byte; |
|---|
| 1819 | i,j: integer; |
|---|
| 1820 | begin |
|---|
| 1821 | ConvertStringToBytes(s,hex,temp); |
|---|
| 1822 | p:=@temp2; |
|---|
| 1823 | |
|---|
| 1824 | if length(temp)<8 then |
|---|
| 1825 | begin |
|---|
| 1826 | j:=length(temp); |
|---|
| 1827 | setlength(temp,8); |
|---|
| 1828 | for i:=j to 7 do |
|---|
| 1829 | temp[i]:=0; |
|---|
| 1830 | end; |
|---|
| 1831 | |
|---|
| 1832 | for i:=0 to length(temp)-1 do |
|---|
| 1833 | begin |
|---|
| 1834 | if temp[i]=-1 then temp[i]:=0; |
|---|
| 1835 | |
|---|
| 1836 | p^:=byte(temp[i]); |
|---|
| 1837 | inc(p); |
|---|
| 1838 | end; |
|---|
| 1839 | |
|---|
| 1840 | result:=temp2; |
|---|
| 1841 | end; |
|---|
| 1842 | |
|---|
| 1843 | |
|---|
| 1844 | function ByteStringToSingle(s: string;hex: boolean):single; |
|---|
| 1845 | var temp: tbytes; |
|---|
| 1846 | temp2: single; |
|---|
| 1847 | p: ^byte; |
|---|
| 1848 | i,j: integer; |
|---|
| 1849 | begin |
|---|
| 1850 | ConvertStringToBytes(s,hex,temp); |
|---|
| 1851 | p:=@temp2; |
|---|
| 1852 | |
|---|
| 1853 | if length(temp)<4 then |
|---|
| 1854 | begin |
|---|
| 1855 | j:=length(temp); |
|---|
| 1856 | setlength(temp,4); |
|---|
| 1857 | for i:=j to 3 do |
|---|
| 1858 | temp[i]:=0; |
|---|
| 1859 | end; |
|---|
| 1860 | |
|---|
| 1861 | for i:=0 to length(temp)-1 do |
|---|
| 1862 | begin |
|---|
| 1863 | if temp[i]=-1 then temp[i]:=0; |
|---|
| 1864 | |
|---|
| 1865 | p^:=byte(temp[i]); |
|---|
| 1866 | inc(p); |
|---|
| 1867 | end; |
|---|
| 1868 | |
|---|
| 1869 | result:=temp2; |
|---|
| 1870 | end; |
|---|
| 1871 | |
|---|
| 1872 | function ByteStringToInt(s: string;hex: boolean):int64; |
|---|
| 1873 | var temp: tbytes; |
|---|
| 1874 | i: integer; |
|---|
| 1875 | power: integer; |
|---|
| 1876 | |
|---|
| 1877 | begin |
|---|
| 1878 | ConvertStringToBytes(s,hex,temp); |
|---|
| 1879 | power:=0; |
|---|
| 1880 | result:=0; |
|---|
| 1881 | |
|---|
| 1882 | for i:=0 to length(temp)-1 do |
|---|
| 1883 | begin |
|---|
| 1884 | result:=result+(temp[i]*trunc(math.power(256,power))); |
|---|
| 1885 | inc(power); |
|---|
| 1886 | end; |
|---|
| 1887 | end; |
|---|
| 1888 | |
|---|
| 1889 | function VarToBytes(v: pointer; size: integer): string; |
|---|
| 1890 | var p: ^byte; |
|---|
| 1891 | j,k: integer; |
|---|
| 1892 | res: array of string; |
|---|
| 1893 | begin |
|---|
| 1894 | result:=''; |
|---|
| 1895 | p:=v; |
|---|
| 1896 | |
|---|
| 1897 | setlength(res,size); |
|---|
| 1898 | |
|---|
| 1899 | for k:=0 to size-1 do |
|---|
| 1900 | begin |
|---|
| 1901 | res[k]:=inttohex(p^,2); |
|---|
| 1902 | inc(p); |
|---|
| 1903 | end; |
|---|
| 1904 | |
|---|
| 1905 | j:=size; |
|---|
| 1906 | for k:=size-1 to 1 do |
|---|
| 1907 | if res[k]='00' then dec(j); |
|---|
| 1908 | |
|---|
| 1909 | for k:=0 to j-1 do |
|---|
| 1910 | result:=result+res[k]+' '; |
|---|
| 1911 | |
|---|
| 1912 | result:=copy(result,1,length(result)-1); |
|---|
| 1913 | end; |
|---|
| 1914 | |
|---|
| 1915 | function BinToInt(s: string): int64; |
|---|
| 1916 | var i: integer; |
|---|
| 1917 | begin |
|---|
| 1918 | result:=0; |
|---|
| 1919 | for i:=length(s) downto 1 do |
|---|
| 1920 | if s[i]='1' then result:=result+trunc(power(2,length(s)-i )); |
|---|
| 1921 | end; |
|---|
| 1922 | |
|---|
| 1923 | function Inttobin(i: int64): string; |
|---|
| 1924 | var temp,temp2: string; |
|---|
| 1925 | j: integer; |
|---|
| 1926 | begin |
|---|
| 1927 | temp:=''; |
|---|
| 1928 | while i>0 do |
|---|
| 1929 | begin |
|---|
| 1930 | if (i mod 2)>0 then temp:=temp+'1' |
|---|
| 1931 | else temp:=temp+'0'; |
|---|
| 1932 | i:=i div 2; |
|---|
| 1933 | end; |
|---|
| 1934 | |
|---|
| 1935 | temp2:=''; |
|---|
| 1936 | for j:=length(temp) downto 1 do |
|---|
| 1937 | temp2:=temp2+temp[j]; |
|---|
| 1938 | result:=temp2; |
|---|
| 1939 | end; |
|---|
| 1940 | |
|---|
| 1941 | |
|---|
| 1942 | |
|---|
| 1943 | function getbit(bitnr: integer; bt: dword):integer; |
|---|
| 1944 | begin |
|---|
| 1945 | result:=(bt shr bitnr) and 1; |
|---|
| 1946 | end; |
|---|
| 1947 | |
|---|
| 1948 | procedure setbit(bitnr: integer; var bt: dword;state:integer); overload; |
|---|
| 1949 | |
|---|
| 1950 | |
|---|
| 1951 | |
|---|
| 1952 | |
|---|
| 1953 | |
|---|
| 1954 | |
|---|
| 1955 | begin |
|---|
| 1956 | bt:=bt and (not (1 shl bitnr)); |
|---|
| 1957 | bt:=bt or (state shl bitnr); |
|---|
| 1958 | end; |
|---|
| 1959 | |
|---|
| 1960 | procedure setbit(bitnr: integer; var bt: Byte;state:integer); overload; |
|---|
| 1961 | |
|---|
| 1962 | |
|---|
| 1963 | |
|---|
| 1964 | |
|---|
| 1965 | |
|---|
| 1966 | |
|---|
| 1967 | var d: dword; |
|---|
| 1968 | begin |
|---|
| 1969 | d:=bt; |
|---|
| 1970 | setbit(bitnr,d,state); |
|---|
| 1971 | bt:=d; |
|---|
| 1972 | end; |
|---|
| 1973 | |
|---|
| 1974 | function eflags_setCF(flagvalue: dword; value: integer): DWORD; |
|---|
| 1975 | begin |
|---|
| 1976 | result:=flagvalue and (not (1 shl 0)) or (value shl 0); |
|---|
| 1977 | end; |
|---|
| 1978 | |
|---|
| 1979 | function eflags_setPF(flagvalue: dword; value: integer): DWORD; |
|---|
| 1980 | begin |
|---|
| 1981 | result:=flagvalue and (not (1 shl 2)) or (value shl 2); |
|---|
| 1982 | end; |
|---|
| 1983 | |
|---|
| 1984 | function eflags_setAF(flagvalue: dword; value: integer): DWORD; |
|---|
| 1985 | begin |
|---|
| 1986 | result:=flagvalue and (not (1 shl 4)) or (value shl 4); |
|---|
| 1987 | end; |
|---|
| 1988 | |
|---|
| 1989 | function eflags_setZF(flagvalue: dword; value: integer): DWORD; |
|---|
| 1990 | begin |
|---|
| 1991 | result:=flagvalue and (not (1 shl 6)) or (value shl 6); |
|---|
| 1992 | end; |
|---|
| 1993 | |
|---|
| 1994 | function eflags_setSF(flagvalue: dword; value: integer): DWORD; |
|---|
| 1995 | begin |
|---|
| 1996 | result:=flagvalue and (not (1 shl 7)) or (value shl 7); |
|---|
| 1997 | end; |
|---|
| 1998 | |
|---|
| 1999 | function eflags_setTF(flagvalue: dword; value: integer): DWORD; |
|---|
| 2000 | begin |
|---|
| 2001 | result:=flagvalue and (not (1 shl 8)) or (value shl 8); |
|---|
| 2002 | end; |
|---|
| 2003 | |
|---|
| 2004 | function eflags_setIF(flagvalue: dword; value: integer): DWORD; |
|---|
| 2005 | begin |
|---|
| 2006 | result:=flagvalue and (not (1 shl 9)) or (value shl 9); |
|---|
| 2007 | end; |
|---|
| 2008 | |
|---|
| 2009 | function eflags_setDF(flagvalue: dword; value: integer): DWORD; |
|---|
| 2010 | begin |
|---|
| 2011 | result:=flagvalue and (not (1 shl 10)) or (value shl 10); |
|---|
| 2012 | end; |
|---|
| 2013 | |
|---|
| 2014 | function eflags_setOF(flagvalue: dword; value: integer): DWORD; |
|---|
| 2015 | begin |
|---|
| 2016 | result:=flagvalue and (not (1 shl 11)) or (value shl 11); |
|---|
| 2017 | end; |
|---|
| 2018 | |
|---|
| 2019 | function eflags_setIOPL(flagvalue: dword; value: integer): DWORD; |
|---|
| 2020 | begin |
|---|
| 2021 | result:=flagvalue and (not (3 shl 12)) or (value shl 12); |
|---|
| 2022 | end; |
|---|
| 2023 | |
|---|
| 2024 | function eflags_setNT(flagvalue: dword; value: integer): DWORD; |
|---|
| 2025 | begin |
|---|
| 2026 | result:=flagvalue and (not (1 shl 14)) or (value shl 14); |
|---|
| 2027 | end; |
|---|
| 2028 | |
|---|
| 2029 | function eflags_setRF(flagvalue: dword; value: integer): DWORD; |
|---|
| 2030 | begin |
|---|
| 2031 | result:=flagvalue and (not (1 shl 16)) or (value shl 16); |
|---|
| 2032 | end; |
|---|
| 2033 | |
|---|
| 2034 | function eflags_setVM(flagvalue: dword; value: integer): DWORD; |
|---|
| 2035 | begin |
|---|
| 2036 | result:=flagvalue and (not (1 shl 17)) or (value shl 17); |
|---|
| 2037 | end; |
|---|
| 2038 | |
|---|
| 2039 | function eflags_setAC(flagvalue: dword; value: integer): DWORD; |
|---|
| 2040 | begin |
|---|
| 2041 | result:=flagvalue and (not (1 shl 18)) or (value shl 18); |
|---|
| 2042 | end; |
|---|
| 2043 | |
|---|
| 2044 | function eflags_setVIF(flagvalue: dword; value: integer): DWORD; |
|---|
| 2045 | begin |
|---|
| 2046 | result:=flagvalue and (not (1 shl 19)) or (value shl 19); |
|---|
| 2047 | end; |
|---|
| 2048 | |
|---|
| 2049 | function eflags_setVIP(flagvalue: dword; value: integer): DWORD; |
|---|
| 2050 | begin |
|---|
| 2051 | result:=flagvalue and (not (1 shl 20)) or (value shl 20); |
|---|
| 2052 | end; |
|---|
| 2053 | |
|---|
| 2054 | function eflags_setID(flagvalue: dword; value: integer): DWORD; |
|---|
| 2055 | begin |
|---|
| 2056 | result:=flagvalue and (not (1 shl 21)) or (value shl 21); |
|---|
| 2057 | end; |
|---|
| 2058 | |
|---|
| 2059 | function undolastscan(valtype: integer;hexadecimal:boolean): integer; |
|---|
| 2060 | begin |
|---|
| 2061 | deletefile(CheatEngineDir+'Memory.tmp'); |
|---|
| 2062 | deletefile(CheatEngineDir+'Addresses.tmp'); |
|---|
| 2063 | |
|---|
| 2064 | renamefile(CheatEngineDir+'Memory.UNDO',CheatEngineDir+'Memory.tmp'); |
|---|
| 2065 | renamefile(CheatEngineDir+'Addresses.UNDO',CheatEngineDir+'Addresses.tmp'); |
|---|
| 2066 | |
|---|
| 2067 | assignfile(addressfile,CheatEngineDir+'Addresses.tmp'); |
|---|
| 2068 | assignfile(memoryfile,CheatEngineDir+'Memory.tmp'); |
|---|
| 2069 | end; |
|---|
| 2070 | |
|---|
| 2071 | function AvailMem:dword; |
|---|
| 2072 | var x: _MEMORYSTATUS; |
|---|
| 2073 | begin |
|---|
| 2074 | x.dwLength:=sizeof(x); |
|---|
| 2075 | GlobalMemoryStatus(x); |
|---|
| 2076 | |
|---|
| 2077 | if x.dwAvailVirtual>(x.dwAvailPhys+x.dwAvailPageFile) then |
|---|
| 2078 | result:=x.dwAvailPhys+x.dwAvailPageFile |
|---|
| 2079 | else |
|---|
| 2080 | result:=x.dwAvailVirtual; |
|---|
| 2081 | |
|---|
| 2082 | end; |
|---|
| 2083 | |
|---|
| 2084 | procedure RemoveAddress(address: Dword;bit: Byte; vartype: Integer); |
|---|
| 2085 | type bitaddress = record |
|---|
| 2086 | address: dword; |
|---|
| 2087 | bit: dword; |
|---|
| 2088 | end; |
|---|
| 2089 | |
|---|
| 2090 | var |
|---|
| 2091 | |
|---|
| 2092 | Addresses: Array [1..number] of Dword; |
|---|
| 2093 | BAddress: Array [1..number] of BitAddress; |
|---|
| 2094 | Memory: Array [1..8*number] of Byte; |
|---|
| 2095 | i,j: Integer; |
|---|
| 2096 | |
|---|
| 2097 | str: pchar; |
|---|
| 2098 | |
|---|
| 2099 | found: boolean; |
|---|
| 2100 | check,check2: Integer; |
|---|
| 2101 | |
|---|
| 2102 | |
|---|
| 2103 | begin |
|---|
| 2104 | assignfile(memoryfile,CheatEngineDir+'Memory.TMP'); |
|---|
| 2105 | assignfile(addressfile,CheatEngineDir+'Addresses.TMP'); |
|---|
| 2106 | reset(memoryfile,1); |
|---|
| 2107 | reset(addressfile,1); |
|---|
| 2108 | |
|---|
| 2109 | assignfile(newmemoryfile,CheatEngineDir+'Memory2.TMP'); |
|---|
| 2110 | assignfile(newaddressfile,CheatEngineDir+'Address2.TMP'); |
|---|
| 2111 | rewrite(newmemoryfile,1); |
|---|
| 2112 | rewrite(newaddressfile,1); |
|---|
| 2113 | |
|---|
| 2114 | blockread(addressfile,memory,7,check); |
|---|
| 2115 | blockwrite(newaddressfile,memory,7,check); |
|---|
| 2116 | |
|---|
| 2117 | found:=false; |
|---|
| 2118 | i:=0; |
|---|
| 2119 | |
|---|
| 2120 | if vartype=7 then //text scan |
|---|
| 2121 | begin |
|---|
| 2122 | i:=filesize(memoryfile); |
|---|
| 2123 | |
|---|
| 2124 | getmem(str,i+1); |
|---|
| 2125 | blockread(memoryfile,pointer(str)^,i,check); |
|---|
| 2126 | str[i]:=chr(0); |
|---|
| 2127 | blockwrite(newmemoryfile,pointer(str)^,i,check); |
|---|
| 2128 | |
|---|
| 2129 | check:=4*number; |
|---|
| 2130 | while (check=4*number) do |
|---|
| 2131 | begin |
|---|
| 2132 | blockread(addressfile,addresses,4*number,check); |
|---|
| 2133 | i:=0; |
|---|
| 2134 | j:=0; |
|---|
| 2135 | while (i<check div 4) do |
|---|
| 2136 | begin |
|---|
| 2137 | inc(i); |
|---|
| 2138 | if addresses[i]<>address then //if it's not the selected address write it else dont write it. |
|---|
| 2139 | blockwrite(newaddressfile,addresses[i],4,check2); |
|---|
| 2140 | end; |
|---|
| 2141 | end; |
|---|
| 2142 | end |
|---|
| 2143 | else |
|---|
| 2144 | if vartype<>5 then |
|---|
| 2145 | begin |
|---|
| 2146 | check:=4*number; |
|---|
| 2147 | while ((not found) and (check=4*number)) do |
|---|
| 2148 | begin |
|---|
| 2149 | blockread(addressfile,addresses,4*number,check); |
|---|
| 2150 | i:=0; |
|---|
| 2151 | while (not found) and (i<(check div 4)) do |
|---|
| 2152 | begin |
|---|
| 2153 | inc(i); |
|---|
| 2154 | if addresses[i]=address then |
|---|
| 2155 | begin |
|---|
| 2156 | found:=true; |
|---|
| 2157 | break; |
|---|
| 2158 | end; |
|---|
| 2159 | end; |
|---|
| 2160 | |
|---|
| 2161 | if not found then |
|---|
| 2162 | begin |
|---|
| 2163 | blockwrite(newaddressfile,addresses,4*number,check2); |
|---|
| 2164 | case vartype of |
|---|
| 2165 | 0: begin //byte |
|---|
| 2166 | blockread(memoryfile,memory,number,check2); |
|---|
| 2167 | blockwrite(newmemoryfile,memory,check2,check2); |
|---|
| 2168 | end; |
|---|
| 2169 | |
|---|
| 2170 | 1: begin //word |
|---|
| 2171 | blockread(memoryfile,memory,2*number,check2); |
|---|
| 2172 | blockwrite(newmemoryfile,memory,check2,check2); |
|---|
| 2173 | end; |
|---|
| 2174 | |
|---|
| 2175 | 2: begin //dword |
|---|
| 2176 | blockread(memoryfile,memory,4*number,check2); |
|---|
| 2177 | blockwrite(newmemoryfile,memory,check2,check2); |
|---|
| 2178 | end; |
|---|
| 2179 | |
|---|
| 2180 | |
|---|
| 2181 | 3: begin //float |
|---|
| 2182 | blockread(memoryfile,memory,4*number,check2); |
|---|
| 2183 | blockwrite(newmemoryfile,memory,check2,check2); |
|---|
| 2184 | end; |
|---|
| 2185 | |
|---|
| 2186 | 4: begin //double |
|---|
| 2187 | blockread(memoryfile,memory,8*number,check2); |
|---|
| 2188 | blockwrite(newmemoryfile,memory,check2,check2); |
|---|
| 2189 | end; |
|---|
| 2190 | |
|---|
| 2191 | 6: begin //int64 |
|---|
| 2192 | blockread(memoryfile,memory,8*number,check2); |
|---|
| 2193 | blockwrite(newmemoryfile,memory,check2,check2); |
|---|
| 2194 | end; |
|---|
| 2195 | |
|---|
| 2196 | |
|---|
| 2197 | //bit doesnt come here |
|---|
| 2198 | end; |
|---|
| 2199 | end; |
|---|
| 2200 | end; |
|---|
| 2201 | |
|---|
| 2202 | if found then |
|---|
| 2203 | begin |
|---|
| 2204 | for j:=i to number-1 do |
|---|
| 2205 | addresses[j]:=addresses[j+1]; |
|---|
| 2206 | |
|---|
| 2207 | blockwrite(newaddressfile,addresses,check-4,check2); |
|---|
| 2208 | |
|---|
| 2209 | case vartype of |
|---|
| 2210 | 0: begin //byte |
|---|
| 2211 | blockread(memoryfile,memory,number,check2); |
|---|
| 2212 | for j:=i to number-1 do memory[j]:=memory[j+1]; |
|---|
| 2213 | blockwrite(newmemoryfile,memory,check2-1,check2); |
|---|
| 2214 | end; |
|---|
| 2215 | |
|---|
| 2216 | 1: begin //word |
|---|
| 2217 | blockread(memoryfile,memory,2*number,check2); |
|---|
| 2218 | for j:=i to number-4 do |
|---|
| 2219 | begin |
|---|
| 2220 | memory[j]:=memory[j+2]; |
|---|
| 2221 | memory[j+1]:=memory[j+3]; |
|---|
| 2222 | end; |
|---|
| 2223 | blockwrite(newmemoryfile,memory,check2-2,check2); |
|---|
| 2224 | end; |
|---|
| 2225 | |
|---|
| 2226 | 2: begin //dword |
|---|
| 2227 | blockread(memoryfile,memory,4*number,check2); |
|---|
| 2228 | for j:=i to number-8 do |
|---|
| 2229 | begin |
|---|
| 2230 | memory[j]:=memory[j+4]; |
|---|
| 2231 | memory[j+1]:=memory[j+5]; |
|---|
| 2232 | memory[j+2]:=memory[j+6]; |
|---|
| 2233 | memory[j+3]:=memory[j+7]; |
|---|
| 2234 | end; |
|---|
| 2235 | |
|---|
| 2236 | blockwrite(newmemoryfile,memory,check2-4,check2); |
|---|
| 2237 | end; |
|---|
| 2238 | |
|---|
| 2239 | |
|---|
| 2240 | 3: begin //float |
|---|
| 2241 | blockread(memoryfile,memory,4*number,check2); |
|---|
| 2242 | for j:=i to number-8 do |
|---|
| 2243 | begin |
|---|
| 2244 | memory[j]:=memory[j+4]; |
|---|
| 2245 | memory[j+1]:=memory[j+5]; |
|---|
| 2246 | memory[j+2]:=memory[j+6]; |
|---|
| 2247 | memory[j+3]:=memory[j+7]; |
|---|
| 2248 | end; |
|---|
| 2249 | blockwrite(newmemoryfile,memory,check2-4,check2); |
|---|
| 2250 | end; |
|---|
| 2251 | |
|---|
| 2252 | 4: begin //double |
|---|
| 2253 | blockread(memoryfile,memory,8*number,check2); |
|---|
| 2254 | for j:=i to number-16 do |
|---|
| 2255 | begin |
|---|
| 2256 | memory[j]:=memory[j+8]; |
|---|
| 2257 | memory[j+1]:=memory[j+9]; |
|---|
| 2258 | memory[j+2]:=memory[j+10]; |
|---|
| 2259 | memory[j+3]:=memory[j+11]; |
|---|
| 2260 | memory[j+4]:=memory[j+12]; |
|---|
| 2261 | memory[j+5]:=memory[j+13]; |
|---|
| 2262 | memory[j+6]:=memory[j+14]; |
|---|
| 2263 | memory[j+7]:=memory[j+15]; |
|---|
| 2264 | end; |
|---|
| 2265 | blockwrite(newmemoryfile,memory,check2-8,check2); |
|---|
| 2266 | end; |
|---|
| 2267 | |
|---|
| 2268 | 6: begin //Int64 |
|---|
| 2269 | blockread(memoryfile,memory,8*number,check2); |
|---|
| 2270 | for j:=i to number-16 do |
|---|
| 2271 | begin |
|---|
| 2272 | memory[j]:=memory[j+8]; |
|---|
| 2273 | memory[j+1]:=memory[j+9]; |
|---|
| 2274 | memory[j+2]:=memory[j+10]; |
|---|
| 2275 | memory[j+3]:=memory[j+11]; |
|---|
| 2276 | memory[j+4]:=memory[j+12]; |
|---|
| 2277 | memory[j+5]:=memory[j+13]; |
|---|
| 2278 | memory[j+6]:=memory[j+14]; |
|---|
| 2279 | memory[j+7]:=memory[j+15]; |
|---|
| 2280 | end; |
|---|
| 2281 | blockwrite(newmemoryfile,memory,check2-8,check2); |
|---|
| 2282 | end; |
|---|
| 2283 | |
|---|
| 2284 | |
|---|
| 2285 | end; |
|---|
| 2286 | |
|---|
| 2287 | //and now just copy the addresses till the end |
|---|
| 2288 | check:=4*number; |
|---|
| 2289 | while (check=4*number) do |
|---|
| 2290 | begin |
|---|
| 2291 | blockread(addressfile,addresses,4*number,check); |
|---|
| 2292 | blockwrite(newaddressfile,addresses,check,check); |
|---|
| 2293 | end; |
|---|
| 2294 | |
|---|
| 2295 | //and same for memory |
|---|
| 2296 | check:=4*number; |
|---|
| 2297 | while (check=4*number) do |
|---|
| 2298 | begin |
|---|
| 2299 | blockread(memoryfile,addresses,4*number,check); |
|---|
| 2300 | blockwrite(newaddressfile,addresses,check,check); |
|---|
| 2301 | end; |
|---|
| 2302 | end; |
|---|
| 2303 | |
|---|
| 2304 | end; |
|---|
| 2305 | |
|---|
| 2306 | closefile(memoryfile); |
|---|
| 2307 | closefile(addressfile); |
|---|
| 2308 | closefile(newmemoryfile); |
|---|
| 2309 | closefile(newaddressfile); |
|---|
| 2310 | |
|---|
| 2311 | deletefile(CheatEngineDir+'Memory.UNDO'); |
|---|
| 2312 | deletefile(CheatEngineDir+'Addresses.UNDO'); |
|---|
| 2313 | renamefile(CheatEngineDir+'Memory.tmp',cheatenginedir+'Memory.UNDO'); |
|---|
| 2314 | renamefile(CheatEngineDir+'Addresses.tmp',CheatEngineDir+'Addresses.UNDO'); |
|---|
| 2315 | renamefile(CheatEngineDir+'Memory2.tmp',CheatEngineDir+'Memory.TMP'); |
|---|
| 2316 | Renamefile(CheatengineDir+'Address2.TMP',CheatEngineDir+'Addresses.TMP'); |
|---|
| 2317 | |
|---|
| 2318 | |
|---|
| 2319 | end; |
|---|
| 2320 | |
|---|
| 2321 | procedure Open_Process; |
|---|
| 2322 | begin |
|---|
| 2323 | {$ifndef netclient} |
|---|
| 2324 | ProcessHandler.ProcessHandle:=NewKernelHandler.OpenProcess(PROCESS_ALL_ACCESS,false,ProcessID); |
|---|
| 2325 | le:=GetLastError; |
|---|
| 2326 | {$endif} |
|---|
| 2327 | end; |
|---|
| 2328 | { |
|---|
| 2329 | function MakeAddressWritable(address: dword):boolean; |
|---|
| 2330 | var buf,x:dword; |
|---|
| 2331 | begin |
|---|
| 2332 | result:=false; |
|---|
| 2333 | if ReadProcessMemory(processhandle,pointeR(address),@buf,4,x) then |
|---|
| 2334 | begin |
|---|
| 2335 | if ReadProcessMemory(processhandle,pointer(((address div $1000)*4)+$c0000000),@buf,4,x) then |
|---|
| 2336 | begin |
|---|
| 2337 | if copyonwrite then |
|---|
| 2338 | buf:=(buf or $200) //when you write to it it will copy the page and give that to the process in writable state |
|---|
| 2339 | else |
|---|
| 2340 | buf:=(buf or $2); //just make it writable, even if it is shared |
|---|
| 2341 | |
|---|
| 2342 | result:=WriteProcessMemory(processhandle,pointer(((address div $1000)*4)+$c0000000),@buf,4,x); |
|---|
| 2343 | end; |
|---|
| 2344 | end; |
|---|
| 2345 | end; |
|---|
| 2346 | } |
|---|
| 2347 | |
|---|
| 2348 | { |
|---|
| 2349 | procedure quicksortmemoryregions(lo,hi: integer); |
|---|
| 2350 | var i,j: integer; |
|---|
| 2351 | x,h: TMemoryRegion; |
|---|
| 2352 | begin |
|---|
| 2353 | i:=lo; |
|---|
| 2354 | j:=hi; |
|---|
| 2355 | |
|---|
| 2356 | x:=memoryregion[(lo+hi) div 2]; |
|---|
| 2357 | |
|---|
| 2358 | repeat |
|---|
| 2359 | while (memoryregion[i].BaseAddress<x.BaseAddress) do inc(i); |
|---|
| 2360 | while (memoryregion[j].BaseAddress>x.BaseAddress) do dec(j); |
|---|
| 2361 | |
|---|
| 2362 | if i<=j then |
|---|
| 2363 | begin |
|---|
| 2364 | h:=memoryregion[i]; |
|---|
| 2365 | memoryregion[i]:=memoryregion[j]; |
|---|
| 2366 | memoryregion[j]:=h; |
|---|
| 2367 | inc(i); |
|---|
| 2368 | dec(j); |
|---|
| 2369 | end; |
|---|
| 2370 | |
|---|
| 2371 | until i>j; |
|---|
| 2372 | |
|---|
| 2373 | if (lo<j) then quicksortmemoryregions(lo,j); |
|---|
| 2374 | if (i<hi) then quicksortmemoryregions(i,hi); |
|---|
| 2375 | end; |
|---|
| 2376 | } |
|---|
| 2377 | |
|---|
| 2378 | { |
|---|
| 2379 | procedure GetProcessListSmall(ProcessList: TListBox); |
|---|
| 2380 | Var SNAPHandle: THandle; |
|---|
| 2381 | ProcessEntry: ProcessEntry32; |
|---|
| 2382 | Check: Boolean; |
|---|
| 2383 | begin |
|---|
| 2384 | processlist.clear; |
|---|
| 2385 | |
|---|
| 2386 | processlist.Sorted:=false; |
|---|
| 2387 | SNAPHandle:=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0); |
|---|
| 2388 | If SnapHandle>0 then |
|---|
| 2389 | begin |
|---|
| 2390 | ProcessEntry.dwSize:=SizeOf(ProcessEntry); |
|---|
| 2391 | Check:=Process32First(SnapHandle,ProcessEntry); |
|---|
| 2392 | while check do |
|---|
| 2393 | begin |
|---|
| 2394 | if processentry.th32ProcessID<>0 then |
|---|
| 2395 | ProcessList.Items.Add(ExtractFilename(processentry.szExeFile)); |
|---|
| 2396 | |
|---|
| 2397 | check:=Process32Next(SnapHandle,ProcessEntry); |
|---|
| 2398 | end; |
|---|
| 2399 | end else raise exception.Create('I can''t get the process list. You are propably using windows NT. Use the window list instead!'); |
|---|
| 2400 | end; } |
|---|
| 2401 | |
|---|
| 2402 | |
|---|
| 2403 | procedure GetProcessList(ProcessList: TListBox); |
|---|
| 2404 | var sl: tstringlist; |
|---|
| 2405 | i: integer; |
|---|
| 2406 | begin |
|---|
| 2407 | sl:=tstringlist.create; |
|---|
| 2408 | try |
|---|
| 2409 | processlist.Sorted:=false; |
|---|
| 2410 | for i:=0 to processlist.Items.count-1 do |
|---|
| 2411 | if processlist.Items.Objects[i]<>nil then |
|---|
| 2412 | freemem(pointer(processlist.Items.Objects[i])); |
|---|
| 2413 | |
|---|
| 2414 | processlist.Items.Clear; |
|---|
| 2415 | |
|---|
| 2416 | |
|---|
| 2417 | GetProcessList(sl); |
|---|
| 2418 | processlist.Items.AddStrings(sl); |
|---|
| 2419 | finally |
|---|
| 2420 | sl.free; |
|---|
| 2421 | end; |
|---|
| 2422 | end; |
|---|
| 2423 | |
|---|
| 2424 | |
|---|
| 2425 | function GetFirstModuleName(processid: dword): string; |
|---|
| 2426 | var |
|---|
| 2427 | SNAPHandle: THandle; |
|---|
| 2428 | check: boolean; |
|---|
| 2429 | ModuleEntry: MODULEENTRY32; |
|---|
| 2430 | begin |
|---|
| 2431 | SNAPHandle:=CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,processid); |
|---|
| 2432 | if SNAPHandle<>0 then |
|---|
| 2433 | begin |
|---|
| 2434 | ModuleEntry.dwSize:=sizeof(moduleentry); |
|---|
| 2435 | if Module32First(snaphandle,ModuleEntry) then |
|---|
| 2436 | result:=moduleentry.szExePath |
|---|
| 2437 | else |
|---|
| 2438 | result:=''; |
|---|
| 2439 | |
|---|
| 2440 | closehandle(SNAPHandle); |
|---|
| 2441 | end; |
|---|
| 2442 | end; |
|---|
| 2443 | |
|---|
| 2444 | procedure GetProcessList(ProcessList: TStrings); |
|---|
| 2445 | Var SNAPHandle: THandle; |
|---|
| 2446 | ProcessEntry: ProcessEntry32; |
|---|
| 2447 | Check: Boolean; |
|---|
| 2448 | |
|---|
| 2449 | HI: HICON; |
|---|
| 2450 | ProcessListInfo: PProcessListInfo; |
|---|
| 2451 | i: integer; |
|---|
| 2452 | s: string; |
|---|
| 2453 | begin |
|---|
| 2454 | HI:=0; |
|---|
| 2455 | |
|---|
| 2456 | for i:=0 to processlist.count-1 do |
|---|
| 2457 | if processlist.Objects[i]<>nil then |
|---|
| 2458 | freemem(pointer(processlist.Objects[i])); |
|---|
| 2459 | |
|---|
| 2460 | processlist.clear; |
|---|
| 2461 | |
|---|
| 2462 | |
|---|
| 2463 | SNAPHandle:=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0); |
|---|
| 2464 | If SnapHandle>0 then |
|---|
| 2465 | begin |
|---|
| 2466 | ProcessEntry.dwSize:=SizeOf(ProcessEntry); |
|---|
| 2467 | Check:=Process32First(SnapHandle,ProcessEntry); |
|---|
| 2468 | while check do |
|---|
| 2469 | begin |
|---|
| 2470 | if getprocessicons then |
|---|
| 2471 | begin |
|---|
| 2472 | HI:=ExtractIcon(hinstance,ProcessEntry.szExeFile,0); |
|---|
| 2473 | if HI=0 then |
|---|
| 2474 | begin |
|---|
| 2475 | //alternative method: |
|---|
| 2476 | if processentry.th32ProcessID>0 then |
|---|
| 2477 | begin |
|---|
| 2478 | s:=GetFirstModuleName(processentry.th32ProcessID); |
|---|
| 2479 | HI:=ExtractIcon(hinstance,pchar(s),0); |
|---|
| 2480 | end; |
|---|
| 2481 | end; |
|---|
| 2482 | end; |
|---|
| 2483 | |
|---|
| 2484 | |
|---|
| 2485 | if not (ProcessesWithIconsOnly and (hi=0)) then |
|---|
| 2486 | begin |
|---|
| 2487 | if processentry.th32ProcessID<>0 then |
|---|
| 2488 | begin |
|---|
| 2489 | // processinfo |
|---|
| 2490 | getmem(ProcessListInfo,sizeof(TProcessListInfo)); |
|---|
| 2491 | ProcessListInfo.processID:=processentry.th32ProcessID; |
|---|
| 2492 | ProcessListInfo.processIcon:=HI; |
|---|
| 2493 | |
|---|
| 2494 | ProcessList.AddObject(IntTohex(processentry.th32ProcessID,8)+'-'+ExtractFilename(processentry.szExeFile), TObject(ProcessListInfo)); |
|---|
| 2495 | end; |
|---|
| 2496 | end; |
|---|
| 2497 | |
|---|
| 2498 | check:=Process32Next(SnapHandle,ProcessEntry); |
|---|
| 2499 | end; |
|---|
| 2500 | closehandle(snaphandle); |
|---|
| 2501 | end else raise exception.Create('I can''t get the process list. You are propably using windows NT. Use the window list instead!'); |
|---|
| 2502 | end; |
|---|
| 2503 | |
|---|
| 2504 | procedure GetWindowList(ProcessList: TListBox{; var ArrIcons: TBytes}); |
|---|
| 2505 | var previouswinhandle, winhandle: Hwnd; |
|---|
| 2506 | winprocess: Dword; |
|---|
| 2507 | temp: Pchar; |
|---|
| 2508 | wintitle: string; |
|---|
| 2509 | |
|---|
| 2510 | x: tstringlist; |
|---|
| 2511 | i:integer; |
|---|
| 2512 | |
|---|
| 2513 | ProcessListInfo: PProcessListInfo; |
|---|
| 2514 | begin |
|---|
| 2515 | getmem(temp,101); |
|---|
| 2516 | try |
|---|
| 2517 | x:=tstringlist.Create; |
|---|
| 2518 | |
|---|
| 2519 | for i:=0 to processlist.items.count-1 do |
|---|
| 2520 | if processlist.items.Objects[i]<>nil then |
|---|
| 2521 | freemem(pointer(processlist.items.Objects[i])); |
|---|
| 2522 | processlist.clear; |
|---|
| 2523 | |
|---|
| 2524 | winhandle:=getwindow(getforegroundwindow,GW_HWNDFIRST); |
|---|
| 2525 | |
|---|
| 2526 | i:=0; |
|---|
| 2527 | while (winhandle<>0) and (i<10000) do |
|---|
| 2528 | begin |
|---|
| 2529 | GetWindowThreadProcessId(winhandle,addr(winprocess)); |
|---|
| 2530 | temp[0]:=#0; |
|---|
| 2531 | getwindowtext(winhandle,temp,100); |
|---|
| 2532 | temp[100]:=#0; |
|---|
| 2533 | wintitle:=temp; |
|---|
| 2534 | |
|---|
| 2535 | if length(wintitle)>0 then |
|---|
| 2536 | begin |
|---|
| 2537 | getmem(ProcessListInfo,sizeof(TProcessListInfo)); |
|---|
| 2538 | ProcessListInfo.processID:=winprocess; |
|---|
| 2539 | ProcessListInfo.processIcon:=SendMessage(winhandle,WM_GETICON,ICON_SMALL,0); |
|---|
| 2540 | if ProcessListInfo.processIcon=0 then |
|---|
| 2541 | ProcessListInfo.processIcon:=SendMessage(winhandle,WM_GETICON,ICON_BIG,0); |
|---|
| 2542 | |
|---|
| 2543 | x.AddObject(IntTohex(winprocess,8)+'-'+wintitle,TObject(ProcessListInfo)); |
|---|
| 2544 | end; |
|---|
| 2545 | |
|---|
| 2546 | previouswinhandle:=winhandle; |
|---|
| 2547 | winhandle:=getwindow(winhandle,GW_HWNDNEXT); |
|---|
| 2548 | |
|---|
| 2549 | if winhandle=previouswinhandle then break; |
|---|
| 2550 | |
|---|
| 2551 | inc(i); |
|---|
| 2552 | end; |
|---|
| 2553 | |
|---|
| 2554 | x.Sort; |
|---|
| 2555 | processlist.Items.Assign(x); |
|---|
| 2556 | finally |
|---|
| 2557 | freemem(temp); |
|---|
| 2558 | end; |
|---|
| 2559 | end; |
|---|
| 2560 | |
|---|
| 2561 | function GetCEdir:string; |
|---|
| 2562 | begin |
|---|
| 2563 | CheatEngineDir:=ExtractFilePath(application.ExeName); |
|---|
| 2564 | result:=CheatEngineDir; |
|---|
| 2565 | end; |
|---|
| 2566 | |
|---|
| 2567 | function GetWinDir:string; |
|---|
| 2568 | var x: pchar; |
|---|
| 2569 | begin |
|---|
| 2570 | getmem(x,200); |
|---|
| 2571 | if GetWindowsDirectory(x,200)>0 then |
|---|
| 2572 | begin |
|---|
| 2573 | result:=x; |
|---|
| 2574 | WindowsDir:=x; |
|---|
| 2575 | end; |
|---|
| 2576 | freemem(x); |
|---|
| 2577 | end; |
|---|
| 2578 | |
|---|
| 2579 | Procedure Shutdown; |
|---|
| 2580 | //This will erase the temporary files and close the processhandle (In case it doesnt happen automatically) |
|---|
| 2581 | begin |
|---|
| 2582 | deletefile(CheatEngineDir+'Memory.TMP'); |
|---|
| 2583 | deletefile(CheatEngineDir+'Addresses.TMP'); |
|---|
| 2584 | deletefile(CheatEngineDir+'Memory.UNDO'); |
|---|
| 2585 | deletefile(CheatEngineDir+'Addresses.UNDO'); |
|---|
| 2586 | freemem(memory); |
|---|
| 2587 | // Closehandle(processhandle); |
|---|
| 2588 | |
|---|
| 2589 | end; |
|---|
| 2590 | |
|---|
| 2591 | procedure ConvertStringToBytes(scanvalue:string; hex:boolean;var bytes: TBytes); |
|---|
| 2592 | { |
|---|
| 2593 | Converts a given string into a array of TBytes. |
|---|
| 2594 | TBytes are not pure bytes, they can hold -1, which indicates a wildcard |
|---|
| 2595 | } |
|---|
| 2596 | var i,j,k: integer; |
|---|
| 2597 | helpstr:string; |
|---|
| 2598 | begin |
|---|
| 2599 | setlength(bytes,0); |
|---|
| 2600 | if length(scanvalue)=0 then exit; |
|---|
| 2601 | |
|---|
| 2602 | while scanvalue[length(scanvalue)]=' ' do |
|---|
| 2603 | scanvalue:=copy(scanvalue,1,length(scanvalue)-1); |
|---|
| 2604 | |
|---|
| 2605 | if (pos('-',scanvalue)>0) or (pos(' ',scanvalue)>0) then |
|---|
| 2606 | begin |
|---|
| 2607 | //syntax is xx-xx-xx or xx xx xx |
|---|
| 2608 | j:=1; |
|---|
| 2609 | k:=0; |
|---|
| 2610 | scanvalue:=scanvalue+' '; |
|---|
| 2611 | |
|---|
| 2612 | for i:=1 to length(scanvalue) do |
|---|
| 2613 | begin |
|---|
| 2614 | if (scanvalue[i]=' ') or (scanvalue[i]='-') then |
|---|
| 2615 | begin |
|---|
| 2616 | helpstr:=copy(scanvalue,j,i-j); |
|---|
| 2617 | j:=i+1; |
|---|
| 2618 | setlength(bytes,k+1); |
|---|
| 2619 | try |
|---|
| 2620 | if hex then bytes[k]:=strtoint('$'+helpstr) |
|---|
| 2621 | else bytes[k]:=strtoint(helpstr); |
|---|
| 2622 | except |
|---|
| 2623 | bytes[k]:=-1; |
|---|
| 2624 | //if it is not a '-' or ' ' or a valid value then I assume it is a wildcard.(I know, retarded) |
|---|
| 2625 | end; |
|---|
| 2626 | inc(k); |
|---|
| 2627 | end; |
|---|
| 2628 | end; |
|---|
| 2629 | end else |
|---|
| 2630 | begin |
|---|
| 2631 | //syntax is xxxxxx |
|---|
| 2632 | k:=0; |
|---|
| 2633 | j:=1; |
|---|
| 2634 | for i:=1 to length(scanvalue) do |
|---|
| 2635 | begin |
|---|
| 2636 | if (i mod 2)=0 then |
|---|
| 2637 | begin |
|---|
| 2638 | helpstr:=copy(scanvalue,j,i-j+1); |
|---|
| 2639 | j:=i+1; |
|---|
| 2640 | setlength(bytes,k+1); |
|---|
| 2641 | try |
|---|
| 2642 | bytes[k]:=strtoint('$'+helpstr); |
|---|
| 2643 | except |
|---|
| 2644 | bytes[k]:=-1; |
|---|
| 2645 | end; |
|---|
| 2646 | inc(k); |
|---|
| 2647 | end; |
|---|
| 2648 | end; |
|---|
| 2649 | end; |
|---|
| 2650 | end; |
|---|
| 2651 | |
|---|
| 2652 | |
|---|
| 2653 | |
|---|
| 2654 | procedure rewritedata(processhandle: thandle; address:dword; buffer: pointer; size:dword); |
|---|
| 2655 | var written: dword; |
|---|
| 2656 | original,a: dword; |
|---|
| 2657 | begin |
|---|
| 2658 | //make writable, write, restore, flush |
|---|
| 2659 | VirtualProtectEx(processhandle, pointer(address),size,PAGE_EXECUTE_READWRITE,original); |
|---|
| 2660 | writeprocessmemory(processhandle,pointer(address),buffer,size,written); |
|---|
| 2661 | VirtualProtectEx(processhandle,pointer(address),size,original,a); |
|---|
| 2662 | end; |
|---|
| 2663 | |
|---|
| 2664 | procedure rewritecode(processhandle: thandle; address:dword; buffer: pointer; size:dword); |
|---|
| 2665 | begin |
|---|
| 2666 | rewritedata(processhandle,address,buffer,size); |
|---|
| 2667 | FlushInstructionCache(processhandle,pointer(address),size); |
|---|
| 2668 | end; |
|---|
| 2669 | |
|---|
| 2670 | function HasHyperthreading: boolean; |
|---|
| 2671 | var a,b,c,d: dword; |
|---|
| 2672 | begin |
|---|
| 2673 | result:=false; |
|---|
| 2674 | asm |
|---|
| 2675 | pushad |
|---|
| 2676 | mov eax,0 |
|---|
| 2677 | cpuid |
|---|
| 2678 | mov a,eax |
|---|
| 2679 | mov b,ebx |
|---|
| 2680 | mov c,ecx |
|---|
| 2681 | mov d,edx |
|---|
| 2682 | popad |
|---|
| 2683 | end; |
|---|
| 2684 | |
|---|
| 2685 | if (b=$756e6547) and (d=$49656e69) and (c=$6c65746e) then |
|---|
| 2686 | begin |
|---|
| 2687 | //intel cpu |
|---|
| 2688 | asm |
|---|
| 2689 | pushad |
|---|
| 2690 | mov eax,1 |
|---|
| 2691 | cpuid |
|---|
| 2692 | mov a,eax |
|---|
| 2693 | mov b,ebx |
|---|
| 2694 | mov c,ecx |
|---|
| 2695 | mov d,edx |
|---|
| 2696 | popad |
|---|
| 2697 | end; |
|---|
| 2698 | |
|---|
| 2699 | if ((d shr 28) and 1)=1 then |
|---|
| 2700 | result:=true; //it has hyperthreading |
|---|
| 2701 | end; |
|---|
| 2702 | |
|---|
| 2703 | |
|---|
| 2704 | end; |
|---|
| 2705 | |
|---|
| 2706 | function GetCPUCount: integer; |
|---|
| 2707 | { |
|---|
| 2708 | this function will return how many active cpu cores there are at your disposal |
|---|
| 2709 | } |
|---|
| 2710 | var cpucount: integer; |
|---|
| 2711 | PA,SA: dword; |
|---|
| 2712 | begin |
|---|
| 2713 | //get the cpu and system affinity mask, only processmask is used |
|---|
| 2714 | GetProcessAffinityMask(getcurrentprocess,PA,SA); |
|---|
| 2715 | |
|---|
| 2716 | cpucount:=0; |
|---|
| 2717 | while pa>0 do |
|---|
| 2718 | begin |
|---|
| 2719 | if (pa mod 2)=1 then inc(cpucount); |
|---|
| 2720 | pa:=pa div 2; |
|---|
| 2721 | end; |
|---|
| 2722 | |
|---|
| 2723 | result:=cpucount; |
|---|
| 2724 | |
|---|
| 2725 | if result=0 then result:=1; |
|---|
| 2726 | end; |
|---|
| 2727 | |
|---|
| 2728 | function LoadFormPosition(form: Tform; var x: array of integer):boolean; |
|---|
| 2729 | var reg: tregistry; |
|---|
| 2730 | s: string; |
|---|
| 2731 | buf: array of integer; |
|---|
| 2732 | buf2: array [0..100] of byte; |
|---|
| 2733 | i: integer; |
|---|
| 2734 | z: integer; |
|---|
| 2735 | begin |
|---|
| 2736 | result:=false; |
|---|
| 2737 | reg:=tregistry.create; |
|---|
| 2738 | try |
|---|
| 2739 | Reg.RootKey := HKEY_CURRENT_USER; |
|---|
| 2740 | if Reg.OpenKey('\Software\Cheat Engine',false) then |
|---|
| 2741 | begin |
|---|
| 2742 | if reg.valueexists('Save window positions') then |
|---|
| 2743 | if reg.readbool('Save window positions') = false then exit; |
|---|
| 2744 | end; |
|---|
| 2745 | |
|---|
| 2746 | if Reg.OpenKey('\Software\Cheat Engine\Window Positions',false) then |
|---|
| 2747 | begin |
|---|
| 2748 | s:=form.Name; |
|---|
| 2749 | s:=s+' Position'; |
|---|
| 2750 | |
|---|
| 2751 | if reg.ValueExists(s) then |
|---|
| 2752 | begin |
|---|
| 2753 | |
|---|
| 2754 | setlength(buf,4+length(x)); //for some reason it checks if |
|---|
| 2755 | |
|---|
| 2756 | z:=reg.ReadBinaryData(s,buf[0],length(buf)*sizeof(integer)); |
|---|
| 2757 | |
|---|
| 2758 | form.position:=poDesigned; |
|---|
| 2759 | form.top:=buf[0]; |
|---|
| 2760 | form.Left:=buf[1]; |
|---|
| 2761 | form.width:=buf[2]; |
|---|
| 2762 | form.height:=buf[3]; |
|---|
| 2763 | |
|---|
| 2764 | for i:=0 to length(x)-1 do |
|---|
| 2765 | x[i]:=buf[4+i]; |
|---|
| 2766 | |
|---|
| 2767 | setlength(buf,0); |
|---|
| 2768 | |
|---|
| 2769 | result:=true; |
|---|
| 2770 | end; |
|---|
| 2771 | end; |
|---|
| 2772 | finally |
|---|
| 2773 | reg.free; |
|---|
| 2774 | end; |
|---|
| 2775 | end; |
|---|
| 2776 | |
|---|
| 2777 | procedure SaveFormPosition(form: Tform; extra: array of integer); |
|---|
| 2778 | { |
|---|
| 2779 | This function will save the position and the optional data in extra to an array element in the registry |
|---|
| 2780 | } |
|---|
| 2781 | var reg: tregistry; |
|---|
| 2782 | buf: tmemorystream; |
|---|
| 2783 | temp: integer; |
|---|
| 2784 | i: integer; |
|---|
| 2785 | s: string; |
|---|
| 2786 | begin |
|---|
| 2787 | //save window pos |
|---|
| 2788 | reg:=tregistry.create; |
|---|
| 2789 | try |
|---|
| 2790 | Reg.RootKey := HKEY_CURRENT_USER; |
|---|
| 2791 | |
|---|
| 2792 | //make sure the option to save is enabled |
|---|
| 2793 | if Reg.OpenKey('\Software\Cheat Engine',false) then |
|---|
| 2794 | begin |
|---|
| 2795 | if reg.valueexists('Save window positions') then |
|---|
| 2796 | if reg.readbool('Save window positions') = false then exit; |
|---|
| 2797 | end; |
|---|
| 2798 | |
|---|
| 2799 | |
|---|
| 2800 | if Reg.OpenKey('\Software\Cheat Engine\Window Positions',true) then |
|---|
| 2801 | begin |
|---|
| 2802 | //registry is open, gather data |
|---|
| 2803 | buf:=tmemorystream.Create; |
|---|
| 2804 | try |
|---|
| 2805 | temp:=form.top; |
|---|
| 2806 | buf.Write(temp,sizeof(temp)); |
|---|
| 2807 | |
|---|
| 2808 | temp:=form.left; |
|---|
| 2809 | buf.Write(temp,sizeof(temp)); |
|---|
| 2810 | |
|---|
| 2811 | temp:=form.width; |
|---|
| 2812 | buf.Write(temp,sizeof(temp)); |
|---|
| 2813 | |
|---|
| 2814 | temp:=form.height; |
|---|
| 2815 | buf.Write(temp,sizeof(temp)); |
|---|
| 2816 | |
|---|
| 2817 | |
|---|
| 2818 | //save extra data |
|---|
| 2819 | for i:=0 to length(extra)-1 do |
|---|
| 2820 | buf.Write(extra[i],sizeof(extra[i])); |
|---|
| 2821 | |
|---|
| 2822 | //and now save buf to the registry |
|---|
| 2823 | s:=form.Name; |
|---|
| 2824 | s:=s+' Position'; |
|---|
| 2825 | |
|---|
| 2826 | reg.WriteBinaryData(s,buf.Memory^,buf.Size); |
|---|
| 2827 | finally |
|---|
| 2828 | buf.free; |
|---|
| 2829 | end; |
|---|
| 2830 | end; |
|---|
| 2831 | finally |
|---|
| 2832 | reg.free; |
|---|
| 2833 | end; |
|---|
| 2834 | end; |
|---|
| 2835 | |
|---|
| 2836 | function GetRelativeFilePath(filename: string):string; |
|---|
| 2837 | begin |
|---|
| 2838 | result:=filename; |
|---|
| 2839 | if pos(uppercase(CheatEngineDir),uppercase(filename))=1 then |
|---|
| 2840 | result:='.\'+copy(filename,length(CheatEnginedir)+1,length(filename)); |
|---|
| 2841 | end; |
|---|
| 2842 | |
|---|
| 2843 | function ConvertHexStrToRealStr(const s: string): string; |
|---|
| 2844 | { |
|---|
| 2845 | Converts a string meant to be a hexadeimcal string to the real way delphi reads |
|---|
| 2846 | it |
|---|
| 2847 | e.g: |
|---|
| 2848 | 123 > $123 |
|---|
| 2849 | -123 > -$123 |
|---|
| 2850 | +123 > +$123 |
|---|
| 2851 | #123 > 123 |
|---|
| 2852 | +#123 > +123 |
|---|
| 2853 | } |
|---|
| 2854 | var ishex: string; |
|---|
| 2855 | start: integer; |
|---|
| 2856 | i,j,k: integer; |
|---|
| 2857 | |
|---|
| 2858 | bytes: string; |
|---|
| 2859 | t: string; |
|---|
| 2860 | f: single; |
|---|
| 2861 | d: double; |
|---|
| 2862 | begin |
|---|
| 2863 | if s='' then |
|---|
| 2864 | begin |
|---|
| 2865 | result:=s; |
|---|
| 2866 | exit; |
|---|
| 2867 | end; |
|---|
| 2868 | start:=1; |
|---|
| 2869 | |
|---|
| 2870 | ishex:='$'; |
|---|
| 2871 | for i:=start to length(s) do |
|---|
| 2872 | case s[i] of |
|---|
| 2873 | '''' , '"' : |
|---|
| 2874 | begin |
|---|
| 2875 | //char |
|---|
| 2876 | if (i+2)<=length(s) then |
|---|
| 2877 | begin |
|---|
| 2878 | bytes:=''; |
|---|
| 2879 | for j:=i+2 to length(s) do |
|---|
| 2880 | if s[j] in ['''','"'] then |
|---|
| 2881 | begin |
|---|
| 2882 | bytes:=copy(s,i+1,j-(i+1)); |
|---|
| 2883 | |
|---|
| 2884 | result:='$'; |
|---|
| 2885 | for k:=length(bytes) downto 1 do |
|---|
| 2886 | result:=result+inttohex(byte(bytes[k]),2); |
|---|
| 2887 | |
|---|
| 2888 | //result := '$'+inttohex(byte(s[i+1]),2); |
|---|
| 2889 | exit; //this is it, no further process required, or appreciated... |
|---|
| 2890 | |
|---|
| 2891 | end; |
|---|
| 2892 | |
|---|
| 2893 | |
|---|
| 2894 | |
|---|
| 2895 | end; |
|---|
| 2896 | end; |
|---|
| 2897 | |
|---|
| 2898 | '#' : |
|---|
| 2899 | begin |
|---|
| 2900 | ishex:=''; |
|---|
| 2901 | start:=2; |
|---|
| 2902 | break; |
|---|
| 2903 | end; |
|---|
| 2904 | |
|---|
| 2905 | '(' : |
|---|
| 2906 | begin |
|---|
| 2907 | if copy(s,1,5)='(INT)' then |
|---|
| 2908 | begin |
|---|
| 2909 | t:=copy(s,6,length(s)); |
|---|
| 2910 | val(t, k,j); |
|---|
| 2911 | if j=0 then |
|---|
| 2912 | begin |
|---|
| 2913 | result:='$'+inttohex(k,8); |
|---|
| 2914 | |
|---|
| 2915 | if s[1]='-' then |
|---|
| 2916 | result:='-'+result; |
|---|
| 2917 | |
|---|
| 2918 | if s[1]='+' then |
|---|
| 2919 | result:='+'+result; |
|---|
| 2920 | |
|---|
| 2921 | exit; |
|---|
| 2922 | end; |
|---|
| 2923 | end; |
|---|
| 2924 | |
|---|
| 2925 | if copy(s,1,8)='(DOUBLE)' then |
|---|
| 2926 | begin |
|---|
| 2927 | t:=copy(s,9,length(s)); |
|---|
| 2928 | val(t, d,j); |
|---|
| 2929 | if j=0 then |
|---|
| 2930 | begin |
|---|
| 2931 | result:='$'+inttohex(PINT64(@d)^,8); |
|---|
| 2932 | |
|---|
| 2933 | if s[1]='-' then |
|---|
| 2934 | result:='-'+result; |
|---|
| 2935 | |
|---|
| 2936 | if s[1]='+' then |
|---|
| 2937 | result:='+'+result; |
|---|
| 2938 | |
|---|
| 2939 | exit; |
|---|
| 2940 | end; |
|---|
| 2941 | end; |
|---|
| 2942 | |
|---|
| 2943 | if copy(s,1,7)='(FLOAT)' then |
|---|
| 2944 | begin |
|---|
| 2945 | t:=copy(s,8,length(s)); |
|---|
| 2946 | val(t, f,j); |
|---|
| 2947 | if j=0 then |
|---|
| 2948 | begin |
|---|
| 2949 | result:='$'+inttohex(pdword(@f)^,8); |
|---|
| 2950 | |
|---|
| 2951 | if s[1]='-' then |
|---|
| 2952 | result:='-'+result; |
|---|
| 2953 | |
|---|
| 2954 | if s[1]='+' then |
|---|
| 2955 | result:='+'+result; |
|---|
| 2956 | |
|---|
| 2957 | exit; |
|---|
| 2958 | end; |
|---|
| 2959 | end; |
|---|
| 2960 | end; |
|---|
| 2961 | end; |
|---|
| 2962 | |
|---|
| 2963 | |
|---|
| 2964 | if s[1]='-' then |
|---|
| 2965 | begin |
|---|
| 2966 | result:='-'+ishex+copy(s,start+1,length(s)) |
|---|
| 2967 | end |
|---|
| 2968 | else |
|---|
| 2969 | if s[1]='+' then |
|---|
| 2970 | begin |
|---|
| 2971 | result:='+'+ishex+copy(s,start+1,length(s)); |
|---|
| 2972 | end |
|---|
| 2973 | else |
|---|
| 2974 | begin |
|---|
| 2975 | result:=ishex+copy(s,start,length(s)); |
|---|
| 2976 | end; |
|---|
| 2977 | end; |
|---|
| 2978 | |
|---|
| 2979 | function HexStrToInt(const S: string): Integer; |
|---|
| 2980 | begin |
|---|
| 2981 | result:=StrToint(ConvertHexStrToRealStr(s)); |
|---|
| 2982 | end; |
|---|
| 2983 | |
|---|
| 2984 | function HexStrToInt64(const S: string): Int64; |
|---|
| 2985 | begin |
|---|
| 2986 | result:=StrToint64(ConvertHexStrToRealStr(s)); |
|---|
| 2987 | end; |
|---|
| 2988 | |
|---|
| 2989 | function isjumporcall(address: dword; var addresstojumpto: dword): boolean; |
|---|
| 2990 | var buf: array [0..31] of byte; |
|---|
| 2991 | actualread: dword; |
|---|
| 2992 | i,j: integer; |
|---|
| 2993 | st: string; |
|---|
| 2994 | offset: dword; |
|---|
| 2995 | haserror: boolean; |
|---|
| 2996 | begin |
|---|
| 2997 | {$ifndef standalonetrainer} |
|---|
| 2998 | result:=false; |
|---|
| 2999 | |
|---|
| 3000 | if readprocessmemory(processhandle,pointer(address),@buf[0],32,actualread) then |
|---|
| 3001 | begin |
|---|
| 3002 | if buf[0] in [$0f,$70..$7f,$e3,$e8,$e9,$eb,$ff] then //possible |
|---|
| 3003 | begin |
|---|
| 3004 | case buf[0] of |
|---|
| 3005 | $0f: |
|---|
| 3006 | begin |
|---|
| 3007 | if (not (buf[1] in [$80..$8f])) then exit; //not one of them |
|---|
| 3008 | result:=true; |
|---|
| 3009 | addresstojumpto:=address+plongint(@buf[2])^+6; |
|---|
| 3010 | end; |
|---|
| 3011 | |
|---|
| 3012 | $70..$7f,$e3,$eb: //(un)conditional jump (1 byte) |
|---|
| 3013 | begin |
|---|
| 3014 | result:=true; |
|---|
| 3015 | addresstojumpto:=address+pshortint(@buf[1])^+2; |
|---|
| 3016 | end; |
|---|
| 3017 | |
|---|
| 3018 | $e8,$e9: //jump or call unconditional (4 byte) |
|---|
| 3019 | begin |
|---|
| 3020 | result:=true; |
|---|
| 3021 | addresstojumpto:=address+plongint(@buf[1])^+5; |
|---|
| 3022 | end; |
|---|
| 3023 | |
|---|
| 3024 | $ff: //disassemble to see what it is |
|---|
| 3025 | begin |
|---|
| 3026 | st:=disassemble(address); |
|---|
| 3027 | st:=copy(st,pos('-',st)+2,length(st)); |
|---|
| 3028 | st:=copy(st,pos('-',st)+2,length(st)); |
|---|
| 3029 | |
|---|
| 3030 | i:=pos('jmp',st); |
|---|
| 3031 | j:=pos('call',st); |
|---|
| 3032 | if (i=1) or (j=1) then |
|---|
| 3033 | begin |
|---|
| 3034 | //now determine where it jumps to |
|---|
| 3035 | i:=pos('[',st); |
|---|
| 3036 | if i>0 then |
|---|
| 3037 | begin |
|---|
| 3038 | st:=copy(st,i,pos(']',st)-i+1); |
|---|
| 3039 | |
|---|
| 3040 | addresstojumpto:=symhandler.getAddressFromName(st, false, haserror); //the pointer interpreter code can do this |
|---|
| 3041 | result:=not haserror; |
|---|
| 3042 | end; |
|---|
| 3043 | |
|---|
| 3044 | end; |
|---|
| 3045 | end; |
|---|
| 3046 | |
|---|
| 3047 | |
|---|
| 3048 | end; |
|---|
| 3049 | end; |
|---|
| 3050 | |
|---|
| 3051 | end; |
|---|
| 3052 | {$endif} |
|---|
| 3053 | |
|---|
| 3054 | end; |
|---|
| 3055 | |
|---|
| 3056 | |
|---|
| 3057 | function readAndParseAddress(address: dword; variableType: TVariableType): string; |
|---|
| 3058 | var buf: array [0..7] of byte; |
|---|
| 3059 | x: dword; |
|---|
| 3060 | check: boolean; |
|---|
| 3061 | begin |
|---|
| 3062 | result:='???'; |
|---|
| 3063 | case variableType of |
|---|
| 3064 | vtByte: |
|---|
| 3065 | begin |
|---|
| 3066 | if ReadProcessMemory(processhandle,pointer(address),@buf[0],1,x) then |
|---|
| 3067 | result:=inttostr(buf[0]); |
|---|
| 3068 | end; |
|---|
| 3069 | |
|---|
| 3070 | vtWord: |
|---|
| 3071 | begin |
|---|
| 3072 | if ReadProcessMemory(processhandle,pointer(address),@buf[0],2,x) then |
|---|
| 3073 | result:=inttostr(pword(@buf[0])^); |
|---|
| 3074 | end; |
|---|
| 3075 | |
|---|
| 3076 | vtDWord: |
|---|
| 3077 | begin |
|---|
| 3078 | if ReadProcessMemory(processhandle,pointer(address),@buf[0],4,x) then |
|---|
| 3079 | result:=inttostr(pdword(@buf[0])^); |
|---|
| 3080 | end; |
|---|
| 3081 | |
|---|
| 3082 | vtSingle: |
|---|
| 3083 | begin |
|---|
| 3084 | if ReadProcessMemory(processhandle,pointer(address),@buf[0],4,x) then |
|---|
| 3085 | result:=floattostr(psingle(@buf[0])^); |
|---|
| 3086 | end; |
|---|
| 3087 | |
|---|
| 3088 | vtDouble: |
|---|
| 3089 | begin |
|---|
| 3090 | if ReadProcessMemory(processhandle,pointer(address),@buf[0],8,x) then |
|---|
| 3091 | result:=floattostr(pdouble(@buf[0])^); |
|---|
| 3092 | end; |
|---|
| 3093 | end; |
|---|
| 3094 | end; |
|---|
| 3095 | |
|---|
| 3096 | const HEAP_NO_SERIALIZE =$00000001; |
|---|
| 3097 | const HEAP_GROWABLE =$00000002; |
|---|
| 3098 | const HEAP_GENERATE_EXCEPTIONS =$00000004; |
|---|
| 3099 | const HEAP_ZERO_MEMORY =$00000008; |
|---|
| 3100 | const HEAP_REALLOC_IN_PLACE_ONLY =$00000010; |
|---|
| 3101 | const HEAP_TAIL_CHECKING_ENABLED =$00000020; |
|---|
| 3102 | const HEAP_FREE_CHECKING_ENABLED =$00000040; |
|---|
| 3103 | const HEAP_DISABLE_COALESCE_ON_FREE =$00000080; |
|---|
| 3104 | const HEAP_CREATE_ALIGN_16 =$00010000; |
|---|
| 3105 | const HEAP_CREATE_ENABLE_TRACING =$00020000; |
|---|
| 3106 | const HEAP_CREATE_ENABLE_EXECUTE =$00040000; |
|---|
| 3107 | const HEAP_MAXIMUM_TAG =$0FFF; |
|---|
| 3108 | const HEAP_PSEUDO_TAG_FLAG =$8000; |
|---|
| 3109 | const HEAP_TAG_SHIFT =18; |
|---|
| 3110 | |
|---|
| 3111 | function heapflagstostring(heapflags: dword): string; |
|---|
| 3112 | begin |
|---|
| 3113 | result:=''; |
|---|
| 3114 | if (heapflags and HEAP_NO_SERIALIZE) > 0 then result:=result+'HEAP_NO_SERIALIZE+'; |
|---|
| 3115 | if (heapflags and HEAP_GROWABLE) > 0 then result:=result+'HEAP_GROWABLE+'; |
|---|
| 3116 | if (heapflags and HEAP_GENERATE_EXCEPTIONS) > 0 then result:='HEAP_GENERATE_EXCEPTIONS+'; |
|---|
| 3117 | if (heapflags and HEAP_ZERO_MEMORY) > 0 then result:=result+'HEAP_ZERO_MEMORY+'; |
|---|
| 3118 | if (heapflags and HEAP_REALLOC_IN_PLACE_ONLY) > 0 then result:=result+'HEAP_REALLOC_IN_PLACE_ONLY+'; |
|---|
| 3119 | if (heapflags and HEAP_TAIL_CHECKING_ENABLED) > 0 then result:=result+'HEAP_TAIL_CHECKING_ENABLED+'; |
|---|
| 3120 | if (heapflags and HEAP_FREE_CHECKING_ENABLED) > 0 then result:=result+'HEAP_FREE_CHECKING_ENABLED+'; |
|---|
| 3121 | if (heapflags and HEAP_DISABLE_COALESCE_ON_FREE) > 0 then result:=result+'HEAP_DISABLE_COALESCE_ON_FREE+'; |
|---|
| 3122 | if (heapflags and HEAP_CREATE_ALIGN_16) > 0 then result:=result+'HEAP_CREATE_ALIGN_16+'; |
|---|
| 3123 | if (heapflags and HEAP_CREATE_ENABLE_TRACING) > 0 then result:=result+'HEAP_CREATE_ENABLE_TRACING+'; |
|---|
| 3124 | if (heapflags and HEAP_CREATE_ENABLE_EXECUTE) > 0 then result:=result+'HEAP_CREATE_ENABLE_EXECUTE+'; |
|---|
| 3125 | if (heapflags and HEAP_PSEUDO_TAG_FLAG) > 0 then result:=result+'HEAP_PSEUDO_TAG_FLAG+'; |
|---|
| 3126 | |
|---|
| 3127 | |
|---|
| 3128 | if length(result)>0 then |
|---|
| 3129 | result:=Copy(result,1,length(result)-1)+'('+inttohex(heapflags,1)+')'; |
|---|
| 3130 | end; |
|---|
| 3131 | |
|---|
| 3132 | function allocationtypetostring(alloctype: dword): string; |
|---|
| 3133 | begin |
|---|
| 3134 | result:=''; |
|---|
| 3135 | if (alloctype and MEM_COMMIT) > 0 then result:='MEM_COMMIT+'; |
|---|
| 3136 | if (alloctype and MEM_RESERVE) > 0 then result:=result+'MEM_RESERVE+'; |
|---|
| 3137 | if (alloctype and MEM_RESET) > 0 then result:=result+'MEM_RESET+'; |
|---|
| 3138 | if (alloctype and MEM_TOP_DOWN) > 0 then result:=result+'MEM_TOP_DOWN+'; |
|---|
| 3139 | if (alloctype and $400000) > 0 then result:=result+'MEM_PHYSICAL+'; |
|---|
| 3140 | if (alloctype and $20000000) > 0 then result:=result+'MEM_LARGE_PAGES+'; |
|---|
| 3141 | |
|---|
| 3142 | if length(result)>0 then |
|---|
| 3143 | result:=Copy(result,1,length(result)-1)+'('+inttohex(alloctype,1)+')'; |
|---|
| 3144 | end; |
|---|
| 3145 | |
|---|
| 3146 | function allocationprotecttostring(protect: dword): string; |
|---|
| 3147 | begin |
|---|
| 3148 | result:=''; |
|---|
| 3149 | if (protect and PAGE_EXECUTE) > 0 then result:='PAGE_EXECUTE+'; |
|---|
| 3150 | if (protect and PAGE_EXECUTE_READ) > 0 then result:=result+'PAGE_EXECUTE_READ+'; |
|---|
| 3151 | if (protect and PAGE_EXECUTE_READWRITE) > 0 then result:=result+'PAGE_EXECUTE_READWRITE+'; |
|---|
| 3152 | if (protect and PAGE_EXECUTE_WRITECOPY) > 0 then result:=result+'PAGE_EXECUTE_WRITECOPY+'; |
|---|
| 3153 | if (protect and PAGE_NOACCESS) > 0 then result:=result+'PAGE_NOACCESS+'; |
|---|
| 3154 | if (protect and PAGE_READONLY) > 0 then result:=result+'PAGE_READONLY+'; |
|---|
| 3155 | if (protect and PAGE_READWRITE) > 0 then result:=result+'PAGE_READWRITE+'; |
|---|
| 3156 | if (protect and PAGE_WRITECOPY) > 0 then result:=result+'PAGE_WRITECOPY+'; |
|---|
| 3157 | if (protect and PAGE_GUARD) > 0 then result:=result+'PAGE_GUARD+'; |
|---|
| 3158 | if (protect and PAGE_NOCACHE) > 0 then result:=result+'PAGE_NOCACHE+'; |
|---|
| 3159 | if (protect and $400) > 0 then result:=result+'PAGE_WRITECOMBINE+'; |
|---|
| 3160 | |
|---|
| 3161 | if length(result)>0 then |
|---|
| 3162 | result:=Copy(result,1,length(result)-1)+'('+inttohex(protect,1)+')'; |
|---|
| 3163 | end; |
|---|
| 3164 | |
|---|
| 3165 | function freetypetostring(freetype: dword):string; |
|---|
| 3166 | begin |
|---|
| 3167 | result:=''; |
|---|
| 3168 | |
|---|
| 3169 | if (freetype and MEM_DECOMMIT) > 0 then result:='MEM_DECOMMIT+'; |
|---|
| 3170 | if (freetype and MEM_RELEASE) > 0 then result:='MEM_RELEASE+'; |
|---|
| 3171 | result:=Copy(result,1,length(result)-1)+'('+inttohex(freetype,1)+')'; |
|---|
| 3172 | end; |
|---|
| 3173 | |
|---|
| 3174 | |
|---|
| 3175 | function isAddress(address: dword):boolean; |
|---|
| 3176 | var mbi: TMemoryBasicInformation; |
|---|
| 3177 | begin |
|---|
| 3178 | result:=false; |
|---|
| 3179 | if VirtualQueryEx(processhandle, pointer(address), mbi, sizeof(mbi))>0 then |
|---|
| 3180 | result:=(mbi.State=MEM_COMMIT);// and (mbi.AllocationProtect<>PAGE_NOACCESS); |
|---|
| 3181 | end; |
|---|
| 3182 | |
|---|
| 3183 | |
|---|
| 3184 | |
|---|
| 3185 | initialization |
|---|
| 3186 | getmem(tempdir,256); |
|---|
| 3187 | GetTempPath(256,tempdir); |
|---|
| 3188 | GetWindir; |
|---|
| 3189 | keysfilemapping:=0; |
|---|
| 3190 | keys:=nil; |
|---|
| 3191 | |
|---|
| 3192 | setlength(windowlist,0); |
|---|
| 3193 | setlength(donthidelist,0); |
|---|
| 3194 | allwindowsareback:=true; |
|---|
| 3195 | stealthhook:=0; |
|---|
| 3196 | iswin2kplus:=GetSystemType>=5; |
|---|
| 3197 | |
|---|
| 3198 | flushthread:=TSaveDataThread.Create(false); //used for scanning, starts idled because the event isn't triggered |
|---|
| 3199 | prefetchthread:=TPrefetchDataThread.create(false); |
|---|
| 3200 | |
|---|
| 3201 | processhandler:=TProcessHandler.create; |
|---|
| 3202 | |
|---|
| 3203 | finalization |
|---|
| 3204 | if flushthread<>nil then |
|---|
| 3205 | begin |
|---|
| 3206 | flushthread.Terminate; |
|---|
| 3207 | flushthread.dataavailable.SetEvent; |
|---|
| 3208 | flushthread.WaitFor; |
|---|
| 3209 | flushthread.free; |
|---|
| 3210 | end; |
|---|
| 3211 | |
|---|
| 3212 | if tempdir<>nil then |
|---|
| 3213 | freemem(tempdir); |
|---|
| 3214 | |
|---|
| 3215 | end. |
|---|
| 3216 | |
|---|
| 3217 | |
|---|
| 3218 | |
|---|