local selfProcess; local INITIALIZATION_INJECT = createStringlist() local is64bit = cheatEngineIs64Bit(); if is64bit then -- this might be prune again in the future.... if (getAddressSafe("cheatengine-x86_64.exe",true,true)) then selfProcess = "cheatengine-x86_64.exe" elseif getAddressSafe("cheatengine-x86_64-SSE4-AVX2.exe",true,true) then selfProcess = "cheatengine-x86_64-SSE4-AVX2.exe" end INITIALIZATION_INJECT.Text = [==[ //**********Initialization************************************************************************// aobscanmodule(deleteHotkey_searchedAOB,%baseAddress%,48 8B 48 38 E8 * * * * 48 8B 8B * * * * E8 * * * * 48 89 C1 E8 * * * * 66 90 90) aobscanmodule(editHotkey_searchedAOB1,%baseAddress%,48 8B 83 * * * * 48 89 46 * 66 8B 83) aobscanmodule(editHotkey_searchedAOB2,%baseAddress%,48 8B 55 * 48 8D 4E * E8 * * * * 48 8B 8B * * * * 48 8D * * E8 * * * * 48 * * * 48 * * * E8 * * * * 48 * * E8) aobscanmodule(addHotkey_searchedAOB,%baseAddress%,49 89 F9 E8 * * * * 48 89 C6) registersymbol(deleteHotkey_searchedAOB) registersymbol(editHotkey_searchedAOB1) registersymbol(editHotkey_searchedAOB2) registersymbol(addHotkey_searchedAOB) aobscanmodule(isSelected_searchedAOB,%baseAddress%,C6 80 * * * * 01 48 8B 8B * * * * E8 * * * * 48 * * E8) aobscanmodule(HotkeyListOffset_searchedAOB,%baseAddress%,C7 40 * FF FF FF FF 48 8B 45 * 48 8B 55 * 48 89 50 * 48 8B 45 * 48 8B 40) registersymbol(isSelected_searchedAOB) registersymbol(HotkeyListOffset_searchedAOB) ]==] else selfProcess = getAddress("cheatengine-i386.exe",true) and 'cheatengine-i386.exe' INITIALIZATION_INJECT.Text = [==[ //**********Initialization************************************************************************// aobscanmodule(deleteHotkey_searchedAOB,%baseAddress%,8b 40 1c e8 ?? ?? ?? ?? 8b 83 ?? ?? ?? ?? e8 ?? ?? ?? ?? e8 ?? ?? ?? ?? 8d) aobscanmodule(editHotkey_searchedAOB1,%baseAddress%,8b 87 ?? ?? ?? ?? 89 43 ?? 8b 87 ?? ?? ?? ?? 89 43 ?? 66 8b 87) aobscanmodule(editHotkey_searchedAOB2,%baseAddress%,8b 55 ?? 8d 43 ?? e8 ?? ?? ?? ?? 8b 87 ?? ?? ?? ?? 8d ?? ?? e8 ?? ?? ?? ?? 8b) //aobscanmodule(addHotkey_searchedAOB,%baseAddress%,ff ?? ?? 89 f8 e8 ?? ?? ?? ?? 88 c1) aobscanmodule(addHotkey_searchedAOB,%baseAddress%,e8 ?? ?? ?? ?? 89 ?? 8b 87 ?? ?? ?? ?? 8b 97) registersymbol(deleteHotkey_searchedAOB) registersymbol(editHotkey_searchedAOB1) registersymbol(editHotkey_searchedAOB2) registersymbol(addHotkey_searchedAOB) aobscanmodule(isSelected_searchedAOB,%baseAddress%,c6 80 ?? ?? ?? ?? 01 8b 14 24 8b 82) //aobscanmodule(HotkeyListOffset_searchedAOB,%baseAddress%,?? ?? ?? 8b ?? ?? c7 40 ?? FF FF FF FF 8b 45 ?? 8b 55 ?? 89 50 ?? 8b 45 ?? 8b 40) //gotta offset the address a bit so the matching aobscanmodule(HotkeyListOffset_searchedAOB,%baseAddress%,8b 40 ?? 8b 55 ?? e8 ?? ?? ?? ?? 8b 45 ?? 66 c7) //hopefully will stay reliable registersymbol(isSelected_searchedAOB) registersymbol(HotkeyListOffset_searchedAOB) ]==] end if (not selfProcess) then -- error('Couldnt get ce base address symbol, did you rename CE name?'); return; end autoAssemble(INITIALIZATION_INJECT.Text:gsub("%%baseAddress%%",selfProcess),true); local MAIN_INJECT,TAddressList = createStringlist(),getAddressList() if (is64bit) then --Local Functions Declaration local convertUIntToInt function convertUIntToInt(int) if (int >> 31) == 1 then return int - math.floor(2^32) end return int end --Main---------------------------------------------------------------------------------------------- MAIN_INJECT.Text = [==[ //**********Shared Resources**********************************************************************// alloc(rax_bak,8) alloc(rbx_bak,8) alloc(rcx_bak,8) alloc(rdx_bak,8) alloc(r8_bak,8) alloc(r9_bak,8) alloc(r10_bak,8) alloc(r11_bak,8) alloc(rsp_plus_20_bak,8) alloc(TAddressList,8) alloc(selectedMemoryRecordAddress,8) alloc(selectedHotkeyAddress,8) alloc(selectedHotkeyIndex,8) alloc(loopIndex,8) alloc(loopCount,8) alloc(loopArray,$1000) //registersymbol(rax_bak) //registersymbol(rbx_bak) //registersymbol(rcx_bak) //registersymbol(rdx_bak) //registersymbol(r8_bak) //registersymbol(r9_bak) //registersymbol(r10_bak) //registersymbol(r11_bak) //registersymbol(rsp_plus_20_bak) //registersymbol(TAddressList) //registersymbol(selectedMemoryRecordAddress) //registersymbol(selectedHotkeyAddress) //registersymbol(selectedHotkeyIndex) //registersymbol(loopIndex) //registersymbol(loopCount) //registersymbol(loopArray) loopIndex: dd 00 loopCount: dd 00 loopArray: dd 00 TAddressList: %REPLACE1% alloc(libraryFunc_newmem,$1000,"%baseAddress%") label(getListViewSelectedIndex) label(getListViewSelectedIndex_loop) label(getListViewSelectedIndex_break) label(getSelectedRecordsHotkey) label(getSelectedRecordsHotkey_loop) label(getSelectedRecordsHotkey_nextChild_continue) label(getSelectedRecordsHotkey_nextElement_continue) label(getSelectedRecordsHotkey_exit) label(getSelectedRecords) label(getSelectedRecords_loop) label(getSelectedRecords_nextChild_continue) label(getSelectedRecords_nextElement_continue) label(getSelectedRecords_exit) //registersymbol(libraryFunc_newmem) //registersymbol(getListViewSelectedIndex) //registersymbol(getListViewSelectedIndex_loop) //registersymbol(getListViewSelectedIndex_break) //registersymbol(getSelectedRecordsHotkey) //registersymbol(getSelectedRecordsHotkey_loop) //registersymbol(getSelectedRecordsHotkey_nextChild_continue) //registersymbol(getSelectedRecordsHotkey_nextElement_continue) //registersymbol(getSelectedRecordsHotkey_exit) //registersymbol(getSelectedRecords) //registersymbol(getSelectedRecords_loop) //registersymbol(getSelectedRecords_nextChild_continue) //registersymbol(getSelectedRecords_nextElement_continue) //registersymbol(getSelectedRecords_exit) libraryFunc_newmem: getListViewSelectedIndex: mov r8,[selectedHotkeyAddress] //mov rax,[rbx+848] //Selected.TMemoryRecord %REPLACE6% mov [selectedMemoryRecordAddress],rax //mov rax,[rax+48] %REPLACE8% mov rax,[rax+8] mov ebx,[rax+10] //sizeof(TMemoryRecord.Hotkey[]) mov rax,[rax+8] //TMemoryRecord.Hotkey[] xor rcx,rcx getListViewSelectedIndex_loop: //Loop through Hotkey[] n times, not more then sizeof(Hotkey[]) cmp rcx,rbx jae short getListViewSelectedIndex_break mov rdx,[rax+rcx*8] add rcx,#1 cmp r8,rdx jne short getListViewSelectedIndex_loop getListViewSelectedIndex_break: mov [selectedHotkeyIndex],rcx ret getSelectedRecordsHotkey: mov rax,[TAddressList] //TAddressList lea rax,[rax+F50-48] //TMemoryRecord[] getSelectedRecordsHotkey_loop: mov rax,[rax+48] //TMemoryRecord[i] Next Linked List Element mov rbx,[rax+28] //TMemoryRecord cmp rbx,[selectedMemoryRecordAddress] //Check if is selected memory record je short getSelectedRecordsHotkey_nextChild_continue //cmp byte ptr [rbx+180],#1 //TMemoryRecord.isSelected type:boolean %REPLACE7% jne short getSelectedRecordsHotkey_nextChild_continue //mov rbx,[rbx+48] %REPLACE9% mov rbx,[rbx+8] mov ecx,[rbx+10] //sizeof(TMemoryRecord.Hotkey[]) mov rdx,[selectedHotkeyIndex] cmp rcx,rdx jb short getSelectedRecordsHotkey_nextChild_continue //Skips if memory record has less hotkeys than the selected index sub rdx,#1 mov rbx,[rbx+8] //TMemoryRecord.Hotkey[] mov rbx,[rbx+rdx*8] //TMemoryRecord.Hotkey mov rcx,[loopCount] mov [loopArray+rcx*8],rbx add [loopCount],#1 getSelectedRecordsHotkey_nextChild_continue: cmp dword ptr [rax+24],#0 //Check if has child records je short getSelectedRecordsHotkey_nextElement_continue mov rax,[rax+40] mov rax,[rax] //Get first child TMemoryRecord[] Element jmp getSelectedRecordsHotkey_loop+4 getSelectedRecordsHotkey_nextElement_continue: cmp [rax+48],#0 //Check if next element is valid jne short getSelectedRecordsHotkey_loop cmp [rax+60],#0 //Check if has parent record je short getSelectedRecordsHotkey_exit mov rax,[rax+60] //Return to parent record jmp getSelectedRecordsHotkey_nextElement_continue getSelectedRecordsHotkey_exit: ret getSelectedRecords: mov rax,[TAddressList] //TAddressList lea rax,[rax+F50-48] //TMemoryRecord[] getSelectedRecords_loop: mov rax,[rax+48] //TMemoryRecord[i] Next Linked List Element mov rbx,[rax+28] //TMemoryRecord cmp rbx,[rcx_bak] //Check if is primary selected memory record je short getSelectedRecords_nextChild_continue //cmp byte ptr [rbx+180],#1 //TMemoryRecord.isSelected type:boolean %REPLACE7% jne short getSelectedRecords_nextChild_continue mov rcx,[loopCount] mov [loopArray+rcx*8],rbx add [loopCount],#1 getSelectedRecords_nextChild_continue: cmp dword ptr [rax+24],#0 //Check if has child records je short getSelectedRecords_nextElement_continue mov rax,[rax+40] mov rax,[rax] //Get first child TMemoryRecord[] Element jmp getSelectedRecords_loop+4 getSelectedRecords_nextElement_continue: cmp [rax+48],#0 //Check if next element is valid jne short getSelectedRecords_loop cmp [rax+60],#0 //Check if has parent record je short getSelectedRecords_exit mov rax,[rax+60] //Return to parent record jmp getSelectedRecords_nextElement_continue getSelectedRecords_exit: ret //**********deleteHotkey**************************************************************************// alloc(deleteHotkey_newmem,$1000,deleteHotkey_searchedAOB) label(deleteHotkey_loop) label(deleteHotkey_originalcode) label(deleteHotkey_return) //registersymbol(deleteHotkey_newmem) //registersymbol(deleteHotkey_loop) //registersymbol(deleteHotkey_originalcode) //registersymbol(deleteHotkey_return) deleteHotkey_newmem: //Reset loop counters mov [loopIndex],#0 mov [loopCount],#0 //Backup registers mov [rax_bak],rax mov [rbx_bak],rbx mov [rcx_bak],rcx mov [rdx_bak],rdx mov [r8_bak],r8 mov [r9_bak],r9 mov [r10_bak],r10 mov [r11_bak],r11 mov [selectedHotkeyAddress],rcx call getListViewSelectedIndex call getSelectedRecordsHotkey //Add Original HotkeyRecord (RAX/RCX) to loopArray mov rcx,[loopCount] push rax mov rax,[rcx_bak] mov [loopArray+rcx*8],rax pop rax add [loopCount],#1 deleteHotkey_loop: //Get selected memory record hotkey addresses mov rax,[loopIndex] mov rcx,[loopArray+rax*8] mov rax,rcx add [loopIndex],#1 //Restore registers mov rbx,[rbx_bak] mov rdx,[rdx_bak] mov r8,[r8_bak] mov r9,[r9_bak] mov r10,[r10_bak] mov r11,[r11_bak] //call cheatengine-x86_64.exe+107A0 //Original Code %REPLACE2% push rax mov rax,[loopIndex] cmp rax,[loopCount] pop rax jb short deleteHotkey_loop deleteHotkey_originalcode: jmp deleteHotkey_return deleteHotkey_searchedAOB+4: jmp deleteHotkey_newmem deleteHotkey_return: //**********editHotkey****************************************************************************// //**********editHotkey Start**********// alloc(editHotkey_newmem1,$1000,editHotkey_searchedAOB1) label(editHotkey_loop) label(editHotkey_originalcode1) label(editHotkey_return1) registersymbol(editHotkey_newmem1) registersymbol(editHotkey_loop) registersymbol(editHotkey_originalcode1) registersymbol(editHotkey_return1) editHotkey_newmem1: //Reset loop counters mov [loopIndex],#0 mov [loopCount],#0 //Backup registers mov [rax_bak],rax mov [rbx_bak],rbx mov [rcx_bak],rcx mov [rdx_bak],rdx mov [r8_bak],r8 mov [r9_bak],r9 mov [r10_bak],r10 mov [r11_bak],r11 mov [selectedHotkeyAddress],rsi call getListViewSelectedIndex call getSelectedRecordsHotkey //Add Original HotkeyRecord (RSI) to loopArray mov rcx,[loopCount] mov [loopArray+rcx*8],rsi add [loopCount],#1 editHotkey_loop: //Get selected memory record hotkey addresses mov rax,[loopIndex] mov rsi,[loopArray+rax*8] add [loopIndex],#1 //Restore registers mov rax,[rax_bak] mov rbx,[rbx_bak] mov rcx,[rcx_bak] mov rdx,[rdx_bak] mov r8,[r8_bak] mov r9,[r9_bak] mov r10,[r10_bak] mov r11,[r11_bak] editHotkey_originalcode1: //mov rax,[rbx+00000850] %REPLACE5% jmp editHotkey_return1 editHotkey_searchedAOB1: jmp editHotkey_newmem1 nop nop editHotkey_return1: //**********editHotkey End**********// alloc(editHotkey_newmem2,$1000,editHotkey_searchedAOB2) label(editHotkey_originalcode2) label(editHotkey_return2) registersymbol(editHotkey_newmem2) registersymbol(editHotkey_originalcode2) registersymbol(editHotkey_return2) editHotkey_newmem2: //call cheatengine-x86_64.exe+AFE0 //Original Code %REPLACE3% push rax mov rax,[loopIndex] cmp rax,[loopCount] pop rax jb editHotkey_loop editHotkey_originalcode2: jmp editHotkey_return2 editHotkey_searchedAOB2+8: jmp editHotkey_newmem2 editHotkey_return2: //**********addHotkey*****************************************************************************// alloc(addHotkey_newmem,$1000,addHotkey_searchedAOB) label(addHotkey_loop) label(addHotkey_originalcode) label(addHotkey_return) registersymbol(addHotkey_newmem) registersymbol(addHotkey_loop) registersymbol(addHotkey_originalcode) registersymbol(addHotkey_return) addHotkey_newmem: //Reset loop counters mov [loopIndex],#0 mov [loopCount],#0 //Backup registers mov [rax_bak],rax mov [rbx_bak],rbx mov [rcx_bak],rcx mov [rdx_bak],rdx mov [r8_bak],r8 mov [r9_bak],r9 mov [r10_bak],r10 mov [r11_bak],r11 mov rax,[rsp+20] mov [rsp_plus_20_bak],rax call getSelectedRecords cmp [loopCount],0 //Skips if only one selected memory record je short addHotkey_originalcode addHotkey_loop: //Get selected memory record addresses mov rax,[loopIndex] mov rcx,[loopArray+rax*8] add [loopIndex],1 //Restore registers mov rax,[rsp_plus_20_bak] mov [rsp+20],rax mov rax,[rax_bak] mov rbx,[rbx_bak] mov rdx,[rdx_bak] mov r8,[r8_bak] mov r9,[r9_bak] mov r10,[r10_bak] mov r11,[r11_bak] //call cheatengine-x86_64.exe+1BF540 //Original Code %REPLACE4% mov rax,[loopIndex] cmp rax,[loopCount] jb short addHotkey_loop addHotkey_originalcode: //Restore registers mov rax,[rsp_plus_20_bak] mov [rsp+20],rax mov rax,[rax_bak] mov rbx,[rbx_bak] mov rcx,[rcx_bak] mov rdx,[rdx_bak] mov r8,[r8_bak] mov r9,[r9_bak] mov r10,[r10_bak] mov r11,[r11_bak] //call cheatengine-x86_64.exe+1BF540 //Original Code %REPLACE4% jmp addHotkey_return addHotkey_searchedAOB+3: jmp addHotkey_newmem addHotkey_return: ]==] --Grab and fill in offsets and calls, for CE version compatibility MAIN_INJECT.Text = MAIN_INJECT.Text:gsub("%%REPLACE1%%",string.format(" dq %X",userDataToInteger(TAddressList))) local searchedAddr,machineCode,callAddr --Calls searchedAddr = getAddress("deleteHotkey_searchedAOB",true) machineCode = readIntegerLocal(searchedAddr+5) callAddr = searchedAddr+convertUIntToInt(machineCode)+9 MAIN_INJECT.Text = MAIN_INJECT.Text:gsub("%%REPLACE2%%",string.format("call %X",callAddr)) searchedAddr = getAddress("editHotkey_searchedAOB2",true) machineCode = readIntegerLocal(searchedAddr+9) callAddr = searchedAddr+convertUIntToInt(machineCode)+13 MAIN_INJECT.Text = MAIN_INJECT.Text:gsub("%%REPLACE3%%",string.format("call %X",callAddr)) searchedAddr = getAddress("addHotkey_searchedAOB",true) machineCode = readIntegerLocal(searchedAddr+4) -- gotta tweak it for the 32bit version callAddr = searchedAddr+convertUIntToInt(machineCode)+8 MAIN_INJECT.Text = MAIN_INJECT.Text:gsub("%%REPLACE4%%",string.format("call %X",callAddr)) --Offsets searchedAddr = getAddress("editHotkey_searchedAOB1",true) machineCode = readIntegerLocal(searchedAddr+3) MAIN_INJECT.Text = MAIN_INJECT.Text:gsub("%%REPLACE5%%",string.format("mov rax,[rbx+%X]",machineCode)) searchedAddr = getAddress("addHotkey_searchedAOB",true) machineCode = readIntegerLocal(searchedAddr-4) -- puurrfect MAIN_INJECT.Text = MAIN_INJECT.Text:gsub("%%REPLACE6%%",string.format("mov rax,[rbx+%X]",machineCode)) searchedAddr = getAddress("isSelected_searchedAOB",true) machineCode = readIntegerLocal(searchedAddr+2) MAIN_INJECT.Text = MAIN_INJECT.Text:gsub("%%REPLACE7%%",string.format("cmp byte ptr [rbx+%X],#1",machineCode)) searchedAddr = getAddress("HotkeyListOffset_searchedAOB",true) -- machineCode = readIntegerLocal(searchedAddr+0x1E) -- possibly a typo? machineCode = readBytesLocal(searchedAddr+0x1E,1) -- fetch the offset, I guess it could change, in the comments it used to be 48 now its 50... MAIN_INJECT.Text = MAIN_INJECT.Text:gsub("%%REPLACE8%%",string.format("mov rax,[rax+%X]",machineCode)) MAIN_INJECT.Text = MAIN_INJECT.Text:gsub("%%REPLACE9%%",string.format("mov rbx,[rbx+%X]",machineCode)) else -- 32 bit section MAIN_INJECT.Text = [==[ //**********Shared Resources**********************************************************************// // modifying a bit... alloc(TAddressList,8) alloc(selectedMemoryRecordAddress,8) alloc(selectedHotkeyAddress,8) alloc(selectedHotkeyIndex,8) alloc(loopIndex,8) alloc(loopCount,8) alloc(loopArray,$1000) alloc(eax_bak,4) alloc(ebx_bak,4) alloc(ecx_bak,4) alloc(edx_bak,4) alloc(ebp_2c,4) alloc(ebp_30,4) loopIndex: dd 00 loopCount: dd 00 loopArray: dd 00 TAddressList: %REPLACE1% alloc(libraryFunc_newmem,$1000,"%baseAddress%") label(getListViewSelectedIndex) label(getListViewSelectedIndex_loop) label(getListViewSelectedIndex_break) label(getSelectedRecordsHotkey) label(getSelectedRecordsHotkey_loop) label(getSelectedRecordsHotkey_nextChild_continue) label(getSelectedRecordsHotkey_nextElement_continue) label(getSelectedRecordsHotkey_exit) label(getSelectedRecords) label(getSelectedRecords_loop) label(getSelectedRecords_nextChild_continue) label(getSelectedRecords_nextElement_continue) label(getSelectedRecords_exit) //registersymbol(libraryFunc_newmem) //registersymbol(getListViewSelectedIndex) //registersymbol(getListViewSelectedIndex_loop) //registersymbol(getListViewSelectedIndex_break) //registersymbol(getSelectedRecordsHotkey) //registersymbol(getSelectedRecordsHotkey_loop) //registersymbol(getSelectedRecordsHotkey_nextChild_continue) //registersymbol(getSelectedRecordsHotkey_nextElement_continue) //registersymbol(getSelectedRecordsHotkey_exit) //registersymbol(getSelectedRecords) //registersymbol(getSelectedRecords_loop) //registersymbol(getSelectedRecords_nextChild_continue) //registersymbol(getSelectedRecords_nextElement_continue) //registersymbol(getSelectedRecords_exit) libraryFunc_newmem: getListViewSelectedIndex: push eax push ebx push ecx push edx push esi mov esi,[selectedHotkeyAddress] //mov eax,[edi+52c] //Selected.TMemoryRecord %REPLACE6% mov [selectedMemoryRecordAddress],eax //mov eax,[eax+50] %REPLACE8% mov eax,[eax+4] mov ebx,[eax+8] //sizeof(TMemoryRecord.Hotkey[]) mov eax,[eax+4] //TMemoryRecord.Hotkey[] xor ecx,ecx getListViewSelectedIndex_loop: //Loop through Hotkey[] n times, not more then sizeof(Hotkey[]) cmp ecx,ebx jae short getListViewSelectedIndex_break mov edx,[eax+ecx*4] add ecx,#1 cmp esi,edx jne short getListViewSelectedIndex_loop getListViewSelectedIndex_break: mov [selectedHotkeyIndex],ecx pop esi pop edx pop ecx pop ebx pop eax ret getSelectedRecordsHotkey: /* better to keep with how it was Addresslist+18)+4)+0)+514 possible but will not register until something happens (a click maybe? or table being loaded..) Addresslist+C)+398)+514 Addresslist+18)+4)+0)+3a4 */ push eax push ebx push ecx push edx mov eax,[TAddressList] //TAddressList //lea rax,[rax+F50-48] //TMemoryRecord[] //seems we cannot find a quick and easy pointer mov eax,[eax+18] mov eax,[eax+4] mov eax,[eax] mov eax,[eax+514] //if addresslist is empty, this will be null avoid crash... test eax,eax je getSelectedRecordsHotkey_exit //mov eax,[eax] // get first mr... jmp short +3 // skip next instruction getSelectedRecordsHotkey_loop: mov eax,[eax+30] //TMemoryRecord[i] Next Linked List Element mov ebx,[eax+18] //TMemoryRecord cmp ebx,[selectedMemoryRecordAddress] //Check if is selected memory record je short getSelectedRecordsHotkey_nextChild_continue //cmp byte ptr [ebx+dc],#1 //TMemoryRecord.isSelected type:boolean %REPLACE7% jne short getSelectedRecordsHotkey_nextChild_continue //mov ebx,[ebx+50] %REPLACE9% mov ebx,[ebx+4] mov ecx,[ebx+8] //sizeof(TMemoryRecord.Hotkey[]) mov edx,[selectedHotkeyIndex] cmp ecx,edx jb short getSelectedRecordsHotkey_nextChild_continue //Skips if memory record has less hotkeys than the selected index sub edx,#1 mov ebx,[ebx+4] //TMemoryRecord.Hotkey[] mov ebx,[ebx+edx*4] //TMemoryRecord.Hotkey mov ecx,[loopCount] mov [loopArray+ecx*4],ebx add [loopCount],#1 getSelectedRecordsHotkey_nextChild_continue: cmp dword ptr [eax+14],#0 //Check if has child records je short getSelectedRecordsHotkey_nextElement_continue mov eax,[eax+2c] mov eax,[eax] //Get first child TMemoryRecord[] Element jmp getSelectedRecordsHotkey_loop+3 getSelectedRecordsHotkey_nextElement_continue: cmp [eax+30],#0 //Check if next element is valid jne short getSelectedRecordsHotkey_loop cmp [eax+3c],#0 //Check if has parent record je short getSelectedRecordsHotkey_exit mov eax,[eax+3c] //Return to parent record jmp getSelectedRecordsHotkey_nextElement_continue getSelectedRecordsHotkey_exit: pop edx pop ecx pop ebx pop eax ret getSelectedRecords: push eax push ebx push ecx mov eax,[TAddressList] //TAddressList mov eax,[eax+18] mov eax,[eax+4] mov eax,[eax] mov eax,[eax+514] test eax,eax //in case addresslist is empty je getSelectedRecords_exit jmp short +3 // skip next instruction getSelectedRecords_loop: mov eax,[eax+30] //TMemoryRecord[i] Next Linked List Element mov ebx,[eax+18] //TMemoryRecord cmp ebx,[eax_bak] //Check if is primary selected memory record je short getSelectedRecords_nextChild_continue //cmp byte ptr [ebx+DC],#1 //TMemoryRecord.isSelected type:boolean %REPLACE7% jne short getSelectedRecords_nextChild_continue mov ecx,[loopCount] mov [loopArray+ecx*4],ebx add [loopCount],#1 getSelectedRecords_nextChild_continue: cmp dword ptr [eax+14],#0 //Check if has child records je short getSelectedRecords_nextElement_continue mov eax,[eax+2c] mov eax,[eax] //Get first child TMemoryRecord[] Element jmp getSelectedRecords_loop+3 getSelectedRecords_nextElement_continue: cmp [eax+30],#0 //Check if next element is valid jne short getSelectedRecords_loop cmp [eax+3c],#0 //Check if has parent record je short getSelectedRecords_exit mov eax,[eax+3c] //Return to parent record jmp getSelectedRecords_nextElement_continue getSelectedRecords_exit: pop ecx pop ebx pop eax ret //**********deleteHotkey**************************************************************************// alloc(deleteHotkey_newmem,$1000,deleteHotkey_searchedAOB) label(deleteHotkey_loop) label(deleteHotkey_originalcode) label(deleteHotkey_return) //registersymbol(deleteHotkey_newmem) //registersymbol(deleteHotkey_loop) //registersymbol(deleteHotkey_originalcode) //registersymbol(deleteHotkey_return) deleteHotkey_newmem: //Reset loop counters mov [loopIndex],#0 mov [loopCount],#0 mov [eax_bak],eax mov [ebx_bak],ebx mov [ecx_bak],ecx mov [edx_bak],edx mov [selectedHotkeyAddress],eax push edi mov edi,ebx call getListViewSelectedIndex call getSelectedRecordsHotkey pop edi //Add Original HotkeyRecord (RAX/RCX) to loopArray mov ecx,[loopCount] //mov eax,[eax_bak] mov [loopArray+ecx*4],eax add [loopCount],#1 deleteHotkey_loop: mov ebx,[ebx_bak] mov ecx,[ecx_bak] mov edx,[edx_bak] //Get selected memory record hotkey addresses mov eax,[loopIndex] mov eax,[loopArray+eax*4] add [loopIndex],#1 //call cheatengine-i386.exe+F840 //Original Code reassemble(deleteHotkey_searchedAOB+3) push eax mov eax,[loopIndex] cmp eax,[loopCount] pop eax jb short deleteHotkey_loop deleteHotkey_originalcode: jmp deleteHotkey_return deleteHotkey_searchedAOB+3: jmp deleteHotkey_newmem deleteHotkey_return: //**********editHotkey****************************************************************************// //**********editHotkey Start**********// alloc(editHotkey_newmem1,$1000,editHotkey_searchedAOB1) label(editHotkey_loop) label(editHotkey_originalcode1) label(editHotkey_return1) registersymbol(editHotkey_newmem1) registersymbol(editHotkey_loop) registersymbol(editHotkey_originalcode1) registersymbol(editHotkey_return1) editHotkey_newmem1: //Reset loop counters mov [loopIndex],#0 mov [loopCount],#0 mov [eax_bak],eax mov [ebx_bak],ebx mov [ecx_bak],ecx mov [edx_bak],edx mov [selectedHotkeyAddress],ebx call getListViewSelectedIndex call getSelectedRecordsHotkey //Add Original HotkeyRecord (RSI) to loopArray mov ecx,[loopCount] mov [loopArray+ecx*4],ebx add [loopCount],#1 editHotkey_loop: mov eax,[eax_bak] mov ecx,[ecx_bak] mov edx,[edx_bak] //Get selected memory record hotkey addresses mov ebx,[loopIndex] mov ebx,[loopArray+ebx*4] add [loopIndex],#1 editHotkey_originalcode1: //mov eax,[edi+00000520] %REPLACE5% jmp editHotkey_return1 editHotkey_searchedAOB1: jmp editHotkey_newmem1 nop editHotkey_return1: //**********editHotkey End**********// alloc(editHotkey_newmem2,$1000,editHotkey_searchedAOB2) label(editHotkey_originalcode2) label(editHotkey_return2) registersymbol(editHotkey_newmem2) registersymbol(editHotkey_originalcode2) registersymbol(editHotkey_return2) editHotkey_newmem2: //call cheatengine-i386.exe+A8B0 //Original Code reassemble(editHotkey_searchedAOB2+6) push eax mov eax,[loopIndex] cmp eax,[loopCount] pop eax jb editHotkey_loop editHotkey_originalcode2: jmp editHotkey_return2 editHotkey_searchedAOB2+6: jmp editHotkey_newmem2 editHotkey_return2: //**********addHotkey*****************************************************************************// alloc(addHotkey_newmem,$1000,addHotkey_searchedAOB) label(addHotkey_loop) label(addHotkey_originalcode) label(addHotkey_return) registersymbol(addHotkey_newmem) registersymbol(addHotkey_loop) registersymbol(addHotkey_originalcode) registersymbol(addHotkey_return) addHotkey_newmem: //Reset loop counters mov [loopIndex],#0 mov [loopCount],#0 //Backup registers mov [eax_bak],eax //primary mr mov [ebx_bak],ebx mov [ecx_bak],ecx mov [edx_bak],edx //mov rax,[rsp+20] --> push [ebp-2c] mov eax,[ebp-2c] mov [ebp_2c],eax mov eax,[ebp-30] mov [ebp_30],eax call getSelectedRecords cmp [loopCount],0 //Skips if only one selected memory record je short addHotkey_originalcode addHotkey_loop: mov eax,[ebp_2c] mov [ebp-2c],eax mov eax,[ebp_30] mov [ebp-30],eax mov eax,[loopIndex] mov eax,[loopArray+eax*4] add [loopIndex],1 mov ebx,[ebx_bak] mov ecx,[ecx_bak] mov edx,[edx_bak] //call cheatengine-i386.exe+1E40D0 //Original Code reassemble(addHotkey_searchedAOB) //push for the next loop / original code run push [ebp_2c] push [ebp_30] mov eax,[loopIndex] cmp eax,[loopCount] jb short addHotkey_loop addHotkey_originalcode: mov eax,[eax_bak] mov ebx,[ebx_bak] mov ecx,[ecx_bak] mov edx,[edx_bak] //call cheatengine-i386.exe+1E40D0 //Original Code reassemble(addHotkey_searchedAOB) jmp addHotkey_return addHotkey_searchedAOB: jmp addHotkey_newmem addHotkey_return: ]==]local getAddr,readInt,readByt = getAddress,readIntegerLocal,readBytesLocal replaceTable = { REPLACE1 = ("dq %X"):format(userDataToInteger(TAddressList)), REPLACE5 = ("mov eax,[edi+%X]"):format(readInt(getAddr("editHotkey_searchedAOB1",true)+2)), REPLACE6 = ("mov eax,[edi+%X]"):format(readInt(getAddr("addHotkey_searchedAOB",true)-4)), REPLACE7 = ("cmp byte ptr [ebx+%X],#1"):format(readInt(getAddr("isSelected_searchedAOB",true)+2)), REPLACE8 = ("mov eax,[eax+%X]"):format(readByt(getAddr("HotkeyListOffset_searchedAOB",true)+2,1)), REPLACE9 = ("mov ebx,[ebx+%X]"):format(readByt(getAddr("HotkeyListOffset_searchedAOB",true)+2,1)), } MAIN_INJECT.Text = MAIN_INJECT.Text:gsub("%%(REPLACE%d)%%",function(s)return replaceTable[s] end) end autoAssemble(MAIN_INJECT.Text:gsub('%%baseAddress%%',selfProcess),true) autoAssemble([[ //**********Cleanup*******************************************************************************// unregistersymbol(deleteHotkey_searchedAOB) unregistersymbol(editHotkey_searchedAOB1) unregistersymbol(editHotkey_searchedAOB2) unregistersymbol(addHotkey_searchedAOB) unregistersymbol(isSelected_searchedAOB) unregistersymbol(HotkeyListOffset_searchedAOB) ]],true)