--[[ CE Lua Plugin: "AA Maker" Version 2.5.4 (64-bit compatible fix) [EN] Technical support : http://forum.cheatengine.org/viewtopic.php?p=5645967 [RU] Техническая поддержка: http://forum.gamehacklab.ru/index.php?/topic/1415-plugin-aa-maker-создание-аа-скриптов Authors: SnedS91, MasterGH, ++METHOS, Powered by A LLM Layout Beautification: community contribution Fix: Cheat Engine v7.x support Fix: 64-bit injection support, correct instruction length handling, original instructions preserved for execution ]] ------------------------------------------------------ local pluginVersion = '2.5.4' local stringSpaceBeforeinstruction = ' ' -- If you wish, add more characters SimpleCodeTemplate = [[ { Game : {$ProcessName} Version: 1.0 Date : {$Date} Author : [edit aamaker.lua and pastle Author] This script does blah blah blah Make by aamaker Lua plagin ;) } [ENABLE] {$AddressInjection}: {$CheatCode} [DISABLE] {$AddressInjection}: {$OriginalCode} {$PrintLog} ]] -- 修复:newMem 中先执行原指令,再执行用户代码,然后返回 AACodeTemplate = [[ { Game : {$ProcessName} Version: 1.0 Date : {$Date} Author : [open aamaker.lua and pastle Author] This script does blah blah blah Make by aamaker Lua plagin ;) } [ENABLE] alloc(newMem, 2048) label(returnHere) newMem: {$OriginalCode} {$CheatCode} ]]..stringSpaceBeforeinstruction..[[jmp returnHere {$AddressInjection}: ]]..stringSpaceBeforeinstruction..[[jmp newMem {$Nops} returnHere: [DISABLE] {$AddressInjection}: {$OriginalCode} dealloc(newMem) {$PrintLog} ]] -- 修复:aobscanmodule 使用纯模块名,newMem 中执行原指令 AOBSCANModuleCodeTemplate = [[ { Game : {$ProcessName} Version: 1.0 Date : {$Date} Author : [open aamaker.lua and pastle Author] This script does blah blah blah Make by aamaker Lua plagin ;) } [ENABLE] aobscanmodule(INJECT,{$ModuleName},{$ArrayOfbyte}) alloc(newmem,$1000) label(code) label(return) registersymbol(INJECT) newmem: code: {$OriginalCode} {$CheatCode} ]]..stringSpaceBeforeinstruction..[[jmp return INJECT: ]]..stringSpaceBeforeinstruction..[[jmp code {$Nops} return: [DISABLE] INJECT: {$OriginalCode} unregistersymbol(INJECT) dealloc(newmem) {$PrintLog} ]] -- 修复:stealth 模板同样处理 AOBSCANModuleStealthCodeTemplate = [[ { Game : {$ProcessName} Version: 1.0 Date : {$Date} Author : [open aamaker.lua and pastle Author] This script does blah blah blah Make by aamaker Lua plagin ;) Download stealthedit: http://www.cheatengine.org/temp/stealthedit2.4.zip } [ENABLE] aobscanmodule(INJECT,{$ModuleName},{$ArrayOfbyte}) alloc(newmem,2048,{$AddressInjection}) stealtheditex(stealth,INJECT,1) label(originalcode) label(returnhere) label(stealthedit) registersymbol(stealthedit) //====================================================== newmem: {$CheatCode} originalcode: {$OriginalCode} ]]..stringSpaceBeforeinstruction..[[jmp returnhere //enable: //db 0 //====================================================== stealth: stealthedit: ]]..stringSpaceBeforeinstruction..[[jmp newmem {$Nops} returnhere: [DISABLE] stealthedit: {$OriginalCode} unregistersymbol(stealthedit) dealloc(newmem) {$PrintLog} ]] ------------------------------------------------------ PATTERN = { ['inc'] = 'mov{$Type}[x],{$Value}', ['mov'] = 'mov{$Type}[x],{$Value}\r\n{$OriginalCode}', ['fld'] = 'mov{$Type}[x],{$Value}\r\n{$OriginalCode}', ['fstp'] = '{$OriginalCode}\r\n'..'mov{$Type}[x],{$Value}' } ------CODE--SECTION----------------------------------- local captionForm = 'AA Script Generator '.. pluginVersion local scriptName = '' local cheatType = '' local cheatName = '' local cheatValueType = '' local patternInjectAsmCode = '' local cheatCode = '' local originalCode = '' local originalBytes = '' local nops = '' local strSignature = '' local cheatValue = 0 local testBytes = 0 local origCodeType = 0 scriptCount = 0 ------------------------------------------------------ -- 布局尺寸(保持 v2.4.6 的宽松尺寸) local form = createForm(false) form.centerScreen() form.setSize(380, 408) form.Name = 'fmAdvCheat' form.Caption = captionForm setProperty(form,'BorderIcons','[biSystemMenu]') form.onClose = function() form.hide() end -- 修复 form_hide -- 脚本名称输入 local edCheatName = createEdit(form) edCheatName.setSize(320, 33) edCheatName.setPosition(30, 40) edCheatName.Name ='edCheatName' edCheatName.Text = '' local labelCheatName = createLabel(form) labelCheatName.setPosition(30, 10) labelCheatName.Caption = 'Script name (optional):' -- 脚本类型分组框(高度增加至 130,为复选框留出足够空间) local groupBox = createGroupBox(form) groupBox.setSize(320, 178) groupBox.setPosition(30, 75) groupBox.Caption = 'Script type' -- 类型下拉框(Y 位置保持不变) local cmbCheatType = createComboBox(groupBox) cmbCheatType.Name = 'cmbCheatType' cmbCheatType.setSize(290, 28) cmbCheatType.setPosition(15, 10) local items = cmbCheatType.getItems() items.add('Simple Script') items.add('Code Injection') items.add('NOP Fill') items.add('AOB Scan') items.add('Stealth AOB Scan') items.add('Disable CALL') setProperty(cmbCheatType, 'ReadOnly', true) cmbCheatType.setItemIndex(0) -- 复选框1:测试字节(Y 调至 60) local cbTestingBytes = createCheckBox(groupBox) cbTestingBytes.Name = 'cbTestingBytes' cbTestingBytes.setSize(150, 23) cbTestingBytes.setPosition(15, 60) cbTestingBytes.Caption = 'Test bytes (signature)' cbTestingBytes.Enabled = false -- 复选框2:原始代码字节显示(Y 调至 90,与上一个间隔 30px) local cbOrigCodeType = createCheckBox(groupBox) cbOrigCodeType.Name = 'cbOrigCodeType' cbOrigCodeType.setSize(180, 38) cbOrigCodeType.setPosition(15, 100) cbOrigCodeType.Caption = 'Show original code as bytes' -- 数值输入区域(位置不变,仍为 30, 215 等) local edValue = createEdit(form) edValue.setSize(110, 28) edValue.setPosition(30, 290) edValue.Name = 'edValue' edValue.Text = '100' local labelValue = createLabel(form) labelValue.setPosition(30, 257) labelValue.Caption = 'Value:' local cmbType = createComboBox(form) cmbType.Name = 'cmbType' cmbType.setSize(130, 28) cmbType.setPosition(170, 290) setProperty(cmbType, 'ReadOnly', true) local typevalitems = cmbType.Items typevalitems.add('Hexadecimal') typevalitems.add('Decimal') typevalitems.add('Float') cmbType.setItemIndex(1) local labelTypeValue = createLabel(form) labelTypeValue.setPosition(170, 257) labelTypeValue.Caption = 'Value type:' -- 生成按钮(位置不变) local btnOk = createButton(form) btnOk.Name = 'btnOk' btnOk.Caption = 'Generate Script' btnOk.setSize(320, 36) btnOk.setPosition(30, 347) setProperty(btnOk, 'Default', true) ------------------------------------------------------ function checkPattern() local address = dv_address1 if not address then local dv = getMemoryViewForm().DisassemblerView address = dv.SelectedAddress end if not address then return false end local _,opcode = splitDisassembledString(disassemble(address)) local choose = getProperty(cmbCheatType,"Text") if choose == 'Code Injection' or choose == 'AOB Scan' then for key,value in pairs(PATTERN) do if string.find(opcode,key) ~= nil then local _,_,x = string.find(opcode, '%[(.*)%]') if x ~= nil then patternInjectAsmCode = value return true end end end end patternInjectAsmCode = '{$OriginalCode}' return false end function getCheatCode(address, value, valueType) local _,opcode = splitDisassembledString(disassemble(address)) opcode = getAddressFromOpcode(opcode) local newCode = '' local opType = ' ' if checkPattern() then if string.find(opcode, " .* ptr ") ~= nil then opType = string.sub(opcode, string.find(opcode, ' .* ptr ')) end local _,_,x = string.find(opcode, '%[(.*)%]') if x ~= nil then newCode = string.gsub(patternInjectAsmCode,'{$Type}',opType) newCode = string.gsub(newCode,'%[x%]','['..x..']') newCode = string.gsub(newCode,'{$Value}',valueType..value) if string.find(opcode, '%],') ~= nil then if string.find(originalCode, '^.*\r?\n') ~= nil then newCode = string.gsub(newCode,'{$OriginalCode}',originalCode:gsub('^.*\r?\n','')) else newCode = string.gsub(newCode,'\r?\n*{$OriginalCode}','') end else newCode = string.gsub(newCode,'{$OriginalCode}',originalCode) end end else newCode = '\r\n'..originalCode end return stringSpaceBeforeinstruction..newCode end -- FIX: 修复地址累加错误(使用数值变量 currentAddr) function getOriginalCodeString(strAddress, length, typeNops) local sumBytes = 0 local nopsCount = 0 local originalCodeString = '' local originalBytesString = '' local nopsString = '' local address = strAddress local currentAddr = tonumber(strAddress) or getAddress(strAddress) if not currentAddr then print("Error: Unable to resolve starting address") return '', '', '' end repeat local InstructionSize = getInstructionSize(currentAddr) if InstructionSize == 0 then print("Error: Instruction size is 0, address may be invalid") break end local fullDisasm = disassemble(currentAddr) local _, opcode, bytes = splitDisassembledString(fullDisasm) opcode = getAddressFromOpcode(opcode) sumBytes = sumBytes + InstructionSize if sumBytes >= length then originalCodeString = originalCodeString .. stringSpaceBeforeinstruction .. opcode else originalCodeString = originalCodeString .. stringSpaceBeforeinstruction .. opcode .. '\r\n' end -- 收集原始字节(去除空格,后面统一格式化) local cleanBytes = string.gsub(bytes, '%s+', '') originalBytesString = originalBytesString .. cleanBytes currentAddr = currentAddr + InstructionSize until (sumBytes >= length) -- 计算 NOP 填充 if typeNops then nopsCount = sumBytes - length else nopsCount = length end if nopsCount > 0 then if nopsCount < 3 then for i = 1, nopsCount do if i == nopsCount then nopsString = nopsString .. stringSpaceBeforeinstruction .. "nop" else nopsString = nopsString .. stringSpaceBeforeinstruction .. "nop\r\n" end end else nopsString = stringSpaceBeforeinstruction .. 'db ' for i = 1, nopsCount do nopsString = nopsString .. "90" .. (i == nopsCount and '' or ' ') end end end -- FIX: 改进字节串格式化,确保偶数分组 if #originalBytesString > 0 then originalBytesString = stringSpaceBeforeinstruction .. 'db' .. string.gsub(originalBytesString, '(%x%x)', ' %1') else originalBytesString = '' end return originalCodeString, nopsString, originalBytesString end -- FIX: 修复 getAddressFromOpcode,不替换方括号内的地址 function getAddressFromOpcode(opcode) local instr, operands = string.match(opcode, "^(%a+)%s+(.*)$") if not operands then return opcode end -- 检查是否包含方括号(间接寻址) if string.find(operands, "%[") then -- 对于间接寻址,我们只替换独立地址(不在括号内),但此处简单起见直接返回原样 -- 因为大多数间接寻址的地址值在括号内,替换会导致语法错误 return opcode end -- 独立地址:替换所有十六进制数字(长度>5) local replaced = operands for addr in string.gmatch(operands, "%x+") do if #addr > 5 then local named = getNameFromAddress(addr) if named ~= addr then replaced = string.gsub(replaced, addr, named) end end end return instr .. " " .. replaced end function getReturnFromCall(strAddress) local address = strAddress local disasm = disassemble(address) local _, opcode = splitDisassembledString(disasm) local instr = string.match(opcode, "%a+") if instr ~= 'call' then return nil, nil, nil, "Not a CALL instruction" end local operands = string.match(opcode, "^%a+%s+(.*)$") if operands == nil then return nil, nil, nil, "Unable to parse operands" end -- 解析目标地址(优先使用 getAddress) local targetAddr = nil local isIndirect = string.find(operands, "%[") ~= nil if isIndirect then local ptrExpr = string.match(operands, "%[(.*)%]") if ptrExpr then local ptr = getAddress(ptrExpr) if ptr and ptr ~= 0 then targetAddr = readQword(ptr) end end if targetAddr == nil or targetAddr == 0 then local ptrStr = string.match(operands, "%[([%x]+)%]") if ptrStr then local ptr = tonumber(ptrStr, 16) if ptr and ptr ~= 0 then targetAddr = readQword(ptr) end end end else local addrStr = string.match(operands, "%x+$") if addrStr then targetAddr = tonumber(addrStr, 16) end end if targetAddr == nil or targetAddr == 0 then return nil, nil, nil, "Unable to resolve target address" end -- 查找 RET local searchAddr = targetAddr local maxAttempts = 100 local attempts = 0 local retInstr = nil local retAddr = nil repeat attempts = attempts + 1 if attempts > maxAttempts then return nil, nil, nil, "RET not found (possible loop)" end local size = getInstructionSize(searchAddr) if size == 0 then return nil, nil, nil, "Invalid address" end _, opcode, _, _ = splitDisassembledString(disassemble(searchAddr)) local currentInstr = string.match(opcode, "%a+") if currentInstr == 'ret' then retInstr = opcode retAddr = searchAddr break end searchAddr = searchAddr + size until (retInstr ~= nil) if retInstr == nil then return nil, nil, nil, "RET not found" end return targetAddr, retInstr, retAddr, nil end function getFullSignature(startAddress, stopAddress) local addr = startAddress local stop = stopAddress local str = '' local _str = '' local count = -1 local result = '' local num = 2 local minNum = 4 if testBytes then num = 8 minNum = 12 end str,addr = getBytesForAOB(addr, stop, stop) if #str > minNum then result = AOBScan(str, '+X-C-W') if result == nil then print("Error! Signature is not in code section. Not found! '+X-C-W' permission required") return '' end count = result.Count result.destroy() end while count ~= 1 do str = str.._str _str,addr = getBytesForAOB(addr, num) result = AOBScan(str.._str, '+X-C-W') if result == nil then print("AOBScan returned empty") return '' end count = result.Count result.destroy() end local numOflast = #string.gsub(_str,'x','')/2 while (numOflast > 1) do local nL = math.floor(numOflast/2) local nR = numOflast - nL local _strL, _strR if testBytes then _strL = string.match(_str,string.rep('x*%x+x+',nL)) _strR = string.match(_str,string.rep('%x+x*',nR),#_strL) else _strL = string.sub(_str,1,2*nL) _strR = string.sub(_str,2*nL+1) end local resultL = AOBScan(str.._strL, '+X-C-W') if resultL == nil then print("AOBScan refinement failed") return '' end if resultL.Count == 1 then _str = _strL numOflast = nL else str = str.._strL _str = _strR numOflast = nR end resultL.destroy() end str = str.._str if testBytes then str = string.lower(str) else str = str:gsub('(.)(.)', '%1%2 ') end str = str:gsub('x*%s*$','') return str end function getBytesForAOB(startAddress, num, stop) local addr = startAddress local str = '' for i = 1,num do local sizeInstruction = getInstructionSize(addr) local _,_,bytes = splitDisassembledString(disassemble(addr)) local fstBt, othBt = string.match(bytes,'^%x+'),string.match(bytes,' .+$') if testBytes then if othBt ~= nil then othBt = string.gsub(string.gsub(othBt,'%s',''),'%x','x') str = str..fstBt..othBt else str = str..string.gsub(fstBt,'%x','x') end else str = str..string.gsub(bytes,'%s','') end if addr == stop then addr = addr + sizeInstruction break end addr = addr + sizeInstruction end return str,addr end ------------------------------------------------------ function AddAARecord(script, sciptName) local addresslist = getAddressList() if not addresslist then print("Error: Unable to get address list") return nil end local newTableEntry = addresslist.createMemoryRecord() if not newTableEntry then print("Error: Failed to create memory record") return nil end newTableEntry.Description = sciptName newTableEntry.Type = vtAutoAssembler newTableEntry.Script = script return newTableEntry end function OpenAAEditor(newTableEntry) if not newTableEntry then return end local addresslist = getAddressList() addresslist.setSelectedRecord(newTableEntry) addresslist.doValueChange() end -------Add Item Menu in Disassembler------------------ function OnSelectionTracker(disassemblerviewLine, address, address2) dv_address1 = address dv_address2 = address2 if checkPattern() then edValue.Enabled = true cmbType.Enabled = true else edValue.Enabled = false cmbType.Enabled = false end end function AddItemMenuInMemoryViewForm(nameItemMenu, shortcut, functionItemClick, functionSelectiontracker) local mv = getMemoryViewForm() local dv = mv.DisassemblerView dv.OnSelectionChange = functionSelectiontracker dv_address1 = dv.SelectedAddress dv_address2 = dv.SelectedAddress2 local popupmenu = dv.PopupMenu if not popupmenu then print("Error: Disassembler popup menu is nil") return end local mi = createMenuItem(popupmenu) mi.Caption = nameItemMenu mi.onClick = functionItemClick mi.Shortcut = textToShortCut(shortcut) -- 修复快捷键 popupmenu.Items.add(mi) end function AddItemMenu(menuItem, nameItemMenu, shortcut, functionItemClick) local mi = createMenuItem(menuItem) mi.Caption = nameItemMenu mi.Shortcut = textToShortCut(shortcut) -- 修复快捷键 mi.onClick = functionItemClick menuItem.add(mi) end function AddItemWithSubMenusInMemoryViewForm(nameItemMenu, functionSelectiontracker) local mv = getMemoryViewForm() local dv = mv.DisassemblerView dv.OnSelectionChange = functionSelectiontracker dv_address1 = dv.SelectedAddress dv_address2 = dv.SelectedAddress2 local popupmenu = dv.PopupMenu if not popupmenu then print("Error: Disassembler popup menu is nil") return end local mi = createMenuItem(popupmenu) mi.Caption = nameItemMenu popupmenu.Items.add(mi) AddItemMenu(mi, 'Generate Simple Script', 'Ctrl+1', OnGenerateAASimpleClick) AddItemMenu(mi, 'Generate Code Injection', 'Ctrl+2', OnGenerateAAInjectionClick) AddItemMenu(mi, 'Generate NOP Fill', 'Ctrl+3', OnGenerateAANopClick) AddItemMenu(mi, 'Disable CALL', 'Ctrl+5', OnGenerateAADisableCallClick) AddItemMenu(mi, 'Generate AOB Scan', 'Ctrl+6', OnGenerateAAAobScanModuleClick) AddItemMenu(mi, 'Generate Stealth AOB Scan', 'Ctrl+7', OnGenerateAAAobScanModuleStealthClick) end function AddItemMenuSeparatorInMemoryViewForm(functionSelectiontracker) local mv = getMemoryViewForm() local dv = mv.DisassemblerView dv.OnSelectionChange = functionSelectiontracker local popupmenu = dv.PopupMenu if not popupmenu then print("Error: Disassembler popup menu is nil") return end local mi = createMenuItem(popupmenu) mi.Caption = '-' popupmenu.Items.add(mi) end ------------------------------------------------------ function generateAA(typeofcheat) setProperty(cmbCheatType,"Text", typeofcheat) cmbCheatTypeChange() btnOkClick() end function OnItemMenuCreateCheatClick(sender) form.show() end -- 修复 form_show function OnGenerateAASimpleClick(sender) generateAA('Simple Script') end function OnGenerateAAInjectionClick(sender) generateAA('Code Injection') end function OnGenerateAANopClick(sender) generateAA('NOP Fill') end function OnGenerateAADisableCallClick(sender) generateAA('Disable CALL') end function OnGenerateAAAobScanModuleClick(sender) generateAA('AOB Scan') end function OnGenerateAAAobScanModuleStealthClick(sender) generateAA('Stealth AOB Scan') end function OnItemMenuGetSignatureInfoClick(sender) print('--START--') local dv = getMemoryViewForm().DisassemblerView local addr1 = dv.SelectedAddress local addr2 = dv.SelectedAddress2 if addr1 == nil or addr2 == nil or (addr1 == 0 and addr2 == 0) then print('Error: No valid address selected. Please click a line in the disassembler first.') print('--END--') return end local address = math.min(addr1, addr2) local stop = math.max(addr1, addr2) if stop == address then stop = address + getInstructionSize(address) - 1 end print('Address: ' .. getNameFromAddress(address) .. ' or ' .. string.format('%08x', address)) local length = stop + getInstructionSize(stop) - address local bytestring = readBytes(address, length, true) local strSignature = '' local result local count = -1 local a2 = getPreviousOpcode(address) local a1 = getPreviousOpcode(a2) local a4 = address + getInstructionSize(address) local a5 = a4 + getInstructionSize(a4) print('') print('Original code view:') print(' ' .. disassemble(a1)) print(' ' .. disassemble(a2)) print(' ' .. disassemble(address) .. '<<<') print(' ' .. disassemble(a4)) print(' ' .. disassemble(a5)) print('') if length <= 5 then print('Sorry, you must select more than 5 bytes') return end for i=1, length do strSignature = strSignature .. string.format('%02X ', bytestring[i]) end print('Starting AOBScan using: '.. strSignature) result = AOBScan(strSignature, '+X-C-W') if result == nil then print(' ' ..'Error! Signature is not in code section. Not found! "+X-C-W" permission required') else count = result.Count result.destroy() print('') if (count == 1) then print(' ' ..'Signature is unique, good! :) ') else print(' ' ..string.format('Sorry, signature is not unique. Addresses found = %s', count)) end print('') strSignature = getBytesForAOB(address,length,stop) print('Test byte string: ' .. strSignature) print('') end print('Thanks for using AA Maker plugin, GameHackLab[RU], 2009-2013(C)') print('--END--') end ------------------------------------------------------ function btnOkClick() -- 优先使用全局变量 local addr1 = dv_address1 local addr2 = dv_address2 if addr1 == nil or addr2 == nil then local dv = getMemoryViewForm().DisassemblerView addr1 = dv.SelectedAddress addr2 = dv.SelectedAddress2 end if addr1 == nil or addr2 == nil or (addr1 == 0 and addr2 == 0) then print("Error: Please select a code line or region in the disassembler first.") return end dv_address1 = addr1 dv_address2 = addr2 local address = math.min(addr1, addr2) local stop = math.max(addr1, addr2) local length = stop + getInstructionSize(stop) - address cheatType = getProperty(cmbCheatType,"Text") cheatName = getProperty(edCheatName,"Text") cheatValue = getProperty(edValue,"Text") cheatValueType = getProperty(cmbType,"Text") testBytes = getProperty(cbTestingBytes,"Checked") origCodeType = getProperty(cbOrigCodeType,"Checked") if cheatValueType == 'Decimal' then cheatValueType = '#' elseif cheatValueType == 'Float' then cheatValueType = '(float)' else cheatValueType = '' end local script = '' local originalCode = '' local originalBytes = '' local nops = '' local cheatCode = '' local strSignature = '' local fullName = getNameFromAddress(address) -- 用于标签 local moduleName = string.match(fullName, "^([^+]+)") or process -- FIX: 提取模块名 if cheatType == 'Simple Script' then script = SimpleCodeTemplate originalCode,_,originalBytes = getOriginalCodeString(address, length) cheatCode = originalCode elseif cheatType == 'Code Injection' then script = AACodeTemplate originalCode, nops, originalBytes = getOriginalCodeString(address, 5, true) length = 5 cheatCode = getCheatCode(address, cheatValue,cheatValueType) elseif cheatType == 'NOP Fill' then script = SimpleCodeTemplate originalCode,cheatCode,originalBytes = getOriginalCodeString(address, length) elseif cheatType == 'AOB Scan' then script = AOBSCANModuleCodeTemplate if length < 8 then print("Error: Selected code length is too short (<8 bytes). AOB scan needs at least 8 bytes.") return end strSignature = getFullSignature(address, stop) if(strSignature == '') then print("Failed to get signature. Please check if the selected code is executable.") return end originalCode, nops, originalBytes = getOriginalCodeString(address, 5, true) length = 5 cheatCode = getCheatCode(address, cheatValue,cheatValueType) elseif cheatType == 'Stealth AOB Scan' then script = AOBSCANModuleStealthCodeTemplate if length < 8 then print("Error: Selected code length is too short (<8 bytes). AOB scan needs at least 8 bytes.") return end strSignature = getFullSignature(address, stop) if(strSignature == '') then print("Failed to get signature. Please check if the selected code is executable.") return end originalCode, nops, originalBytes = getOriginalCodeString(address, 5, true) length = 5 cheatCode = getCheatCode(address, cheatValue,cheatValueType) elseif cheatType == 'Disable CALL' then script = SimpleCodeTemplate local targetAddr, retInstr, retAddr, err = getReturnFromCall(address) if err then print("Disable CALL failed: " .. err) return end originalCode, _, originalBytes = getOriginalCodeString(address, length) local retSize = getInstructionSize(retAddr) local nopCount = length - retSize local nopStr = '' if nopCount > 0 then if nopCount < 3 then for i = 1, nopCount do nopStr = nopStr .. stringSpaceBeforeinstruction .. "nop\r\n" end else nopStr = stringSpaceBeforeinstruction .. 'db ' for i = 1, nopCount do nopStr = nopStr .. "90" .. (i == nopCount and '' or ' ') end nopStr = nopStr .. '\r\n' end end cheatCode = stringSpaceBeforeinstruction .. retInstr .. '\r\n' .. nopStr end if script == '' then print("Error: Generated script is empty. Please check if the selected code is valid.") return end -- 填充模板(增加模块名占位符替换) script = string.gsub(script, "{$ArrayOfbyte}", strSignature or '') script = string.gsub(script, "{$AddressInjection}", fullName) script = string.gsub(script, "{$ModuleName}", moduleName) -- FIX: 新增替换 script = string.gsub(script, "{$CheatCode}", cheatCode or '') script = string.gsub(script, "{$NscriptCount}", scriptCount) if origCodeType == true then script = string.gsub(script, "{$OriginalCode}", originalBytes or '') else script = string.gsub(script, "{$OriginalCode}", originalCode or '') end if nops and nops ~= '' then script = string.gsub(script, "{$Nops}", nops) else script = string.gsub(script, '\n?{$Nops}', '') end if cheatName ~= '' then scriptName = cheatName if string.find(cheatName, '^%d') ~= nil then cheatName = '_'..cheatName end else scriptName = 'New Script '..scriptCount cheatName = 'address'..scriptCount scriptCount = scriptCount + 1 end script = string.gsub(script,'{$Date}', string.gsub(os.date('%x'),'/','-')) script = string.gsub(script,'{$ProcessName}', process) script = string.gsub(script,'{$PrintLog}', GetLog(getNameFromAddress(address), getNameFromAddress(length + address))) local newTableEntry = AddAARecord(script,scriptName) if newTableEntry then OpenAAEditor(newTableEntry) end form.hide() -- 修复 form_hide end function GetLine(address) local rez = disassemble(address) mAddress, opcode, bytes, extrafield = splitDisassembledString(rez) rez = string.format("%s: %s - %s", getNameFromAddress(address), bytes, opcode) return rez end function GetLog(addressStart, addressEnd) local logCode = [[ { // ORIGINAL CODE - INJECTION POINT: {$INJECTPOINT} {$TOP} // ---------- INJECTING HERE ---------- {$MIDDLE} // ---------- DONE INJECTING ---------- {$BOTTOM} }]] local top = '' local midle = '' local bottom = '' local prevAddress = addressStart for i = 1,10 do prevAddress = getPreviousOpcode(prevAddress) end for i = 1,10 do if(i < 10) then top = top..GetLine(prevAddress)..'\r\n' else top = top..GetLine(prevAddress) end prevAddress = prevAddress + getInstructionSize(prevAddress) end local storyPrevAddress = prevAddress local andAddressDigit = getAddress(addressEnd) local countInstruction = 0 for i = 1,100 do if(prevAddress >= andAddressDigit) then break end countInstruction = countInstruction + 1 prevAddress = prevAddress + getInstructionSize(prevAddress) end prevAddress = storyPrevAddress for i = 1,countInstruction do if(i < countInstruction) then midle = midle..GetLine(prevAddress)..'\r\n' else midle = midle..GetLine(prevAddress) end prevAddress = prevAddress + getInstructionSize(prevAddress) end for i = 1,10 do if(i < 10) then bottom = bottom..GetLine(prevAddress)..'\r\n' else bottom = bottom..GetLine(prevAddress) end prevAddress = prevAddress + getInstructionSize(prevAddress) end logCode = string.gsub(logCode,'{$INJECTPOINT}', getNameFromAddress(addressStart)) logCode = string.gsub(logCode,'{$TOP}', top) logCode = string.gsub(logCode,'{$MIDDLE}', midle) logCode = string.gsub(logCode,'{$BOTTOM}', bottom) return logCode end function cmbCheatTypeChange(sender) cheatType = getProperty(cmbCheatType,"Text") if cheatType == 'NOP Fill' or cheatType == 'Disable CALL' then edValue.Enabled = false cmbType.Enabled = false else if checkPattern() then edValue.Enabled = true cmbType.Enabled = true end end if cheatType == 'AOB Scan' or cheatType == 'Stealth AOB Scan' then cbTestingBytes.Enabled = true else cbTestingBytes.Enabled = false end end function cbTestingBytesChange(sender) ------------------- end ------------------------------------------------------ setMethodProperty(cmbCheatType, 'OnChange', cmbCheatTypeChange) btnOk.OnClick = btnOkClick ------------------------------------------------------ AddItemMenuSeparatorInMemoryViewForm(OnSelectionTracker) AddItemWithSubMenusInMemoryViewForm('* Quick AA Generator', OnSelectionTracker) AddItemMenuInMemoryViewForm('* AA Generator Window', 'Ctrl+Z', OnItemMenuCreateCheatClick, OnSelectionTracker) AddItemMenuInMemoryViewForm('* Get Signature Info (AA Generator)', 'Ctrl+Shift+I', OnItemMenuGetSignatureInfoClick, OnSelectionTracker)