# This script was made by Eiffel2018, updated and modified for new ida and features by OblivionReign
import idc, ida_bytes, ida_search, struct, idautils, sys, ida_kernwin, ida_funcs, idaapi, ida_segment, math, os, ida_nalt, re
from idahelper import *
from keystone import *
SetDebug(True)
cheatCodes = masterCodes = restoreCodes = ''
english=''
is32bit=False
TID=BID=VER = RGN = None
TM='A'
TM2='F'
dataAddr = BADADDR if isGDB() else ida_segment.get_segm_by_name('.bss').end_ea
def SetAsmRegister(register):
global TM
TM = register
def SetPtrRegister(register):
global TM2
TM2 = register
def Addr2DWord(opAddr):
return "{:08X}".format(opAddr & 0xFFFFFFFF)
def Value2DWord(value):
if type(value) is str: value=int(value.replace(' ',''), 16)
return "{:08X}".format(value & 0xFFFFFFFF)
def Value2QWord(value):
if type(value) is str: value=int(value.replace(' ',''), 16)
return "{:08X} {:08X}".format(value // 0x100000000, value & 0xFFFFFFFF)
def Double2QWord(d):
return Value2QWord(struct.unpack('<Q', struct.pack('<d', d))[0])
def Float2DWord(f):
return Value2DWord(struct.unpack('<I', struct.pack('<f', f))[0])
def Char2DwordList(s):
i=0
result=[]
while i<len(s):
result.append(int(''.join('%02X'%ord(x) for x in reversed(s[i:i+4])),16))
i+=4
return result
def Char2QwordList(s):
i=0
result=[]
while i<len(s):
result.append(int(''.join('%02X'%ord(x) for x in reversed(s[i:i+8])),16))
i+=8
return result
def CheatCode(length,opAddr,value):
if opAddr>base and base>0x10000000: opAddr-=base
if type(value) not in (list,tuple):
if type(value) is str and re.match(r"^[0-9a-fA-F]{8}$", value[0:8]) is None: value=ASM(value)
# if type(value) is int and length==4: value=Value2DWord(value)
return '0{}0A0000 {} {}\n'.format(length,Addr2DWord(opAddr),Value2DWord(value) if length<=4 else Value2QWord(value))
lastInstruction = ResultCode = ''
for instruction in value:
if type(instruction) is str: instruction=instruction.replace('{there}',OperandAddr(opAddr)).replace('{here}',hex(opAddr))
if type(instruction) is str and re.match(r"^[0-9a-fA-F]{8}$", instruction[0:8]) is None: instruction=ASM(instruction)
if type(instruction) is int: instruction=Value2DWord(instruction)
if lastInstruction=='':
lastInstruction = instruction
else:
ResultCode += CheatCode(8,opAddr-4,instruction+lastInstruction)
lastInstruction = ''
opAddr+=4
if (lastInstruction != ''): ResultCode += CheatCode(4,opAddr-4,lastInstruction)
return ResultCode
def RestoreCode(length,opAddr):
if isGDB(): return ''
if length>=8: return CheatCode(length,opAddr,[ 0 if (opAddr+i>=GetCodeK() and opAddr+i<codeEnd) else (ida_bytes.get_dword(opAddr+i)) for i in range(0,length,4) ]) # IDA 9.2 Update
return CheatCode(length,opAddr,0 if (opAddr>=GetCodeK() and opAddr<codeEnd) else (GetBytes(length,opAddr) if length<=4 else GetQword(opAddr)))
def PointerCodeHeader(offsets,register=None,length=8): # offsets use tuples/list with at least 2 element
if isGDB(): return ''
if register == None: register = TM2
if type(offsets) not in (tuple, list): offsets=[offsets]
code = '5{}0{}0000 {:08X}\n'.format(length,register,offsets[0])
if len(offsets)>1: code += PointerCodeAddOffset(offsets[1:],register)
return code
def PointerCodeReadOffset(offset,register=None,length=8):
return PointerCodeAddOffset(offset,register,length)
def PointerCodeAddOffset(offsets,register=None,length=8):
if isGDB(): return ''
if register == None: register = TM2
if type(offsets) not in (tuple, list): offsets=[offsets]
if len(offsets)<1: return ''
code=''
if len(offsets)>1:
for offset in offsets[:-1]:
code += '5{}0{}1000 {:08X}\n'.format(8,register,offset)
code += '5{}0{}1000 {:08X}\n'.format(length,register,offsets[-1])
return code
def PointerCodeAddRegister(offset,register=None):
if isGDB(): return ''
return '780{}0000 {:08X}\n'.format(register,offset) if offset>=0 else '780{}1000 {:08X}\n'.format(register,-offset)
def PointerCodeSetValue(value,register='D',length=8):
if isGDB(): return ''
return '4{}0{}0000 {}\n'.format(length,register,Value2QWord(value))
def PointerCodeWrite(length, value, value2=None, register=None, use_D=True, increase=False):
if use_D==True: use_D='D'
if isGDB(): return ''
if register == None: register = TM2
if value2!=None and length==8:
code = '6{}0{}{}{}0 {} {}\n'.format(length, register,'1' if increase else '0','1'+use_D if use_D!=False else '00',Value2DWord(value2), Value2DWord(value))
else:
code = '6{}0{}{}{}0 {}\n'.format(length, register,'1' if increase else '0', '1'+use_D if use_D!=False else '00', Value2QWord(value))
return code
def PointerCodeBody(offset, length, value, value2=None, register=None):
if isGDB(): return ''
if register == None: register = TM2
return PointerCodeSetValue(offset) + PointerCodeWrite(length, value, value2, register)
def PointerCodeArithmetic(operater,r0=None,r1=None,r2=None,length=8): # Code Type 0x9
if isGDB(): return ''
if r0 == None: r0 = TM2
if r1 == None: r1 = TM2
operations = {'+':'0', '-':'1', '*':'2', '<<':'3', '>>':'4', 'and':'5', 'or':'6', 'not':'7', 'xor':'8', 'mov':'9'}
if r2==None or type(r2) is str: # 9TCRS0s0
if r2==None: r2='0'
result = '9{}{}{}{}0{}0\n'.format(length,operations[operater.lower()],r0,r1,r2)
else: # 9TCRS100 VVVVVVVV
result = '9{}{}{}{}100 {}\n'.format(length,operations[operater.lower()],r0,r1, Value2DWord(r2) if length<8 else Value2QWord(r2))
return result
def PointerCodeStoreRegisterValueToRegisterAddress(valueRegister='D', addrRegister=None, length=4, offset=0, increase=False): # Code Type 0xA A4SR1000
if isGDB(): return ''
if addrRegister == None: addrRegister = TM2
if offset==0:
return 'A{}{}{}{}000\n'.format(length,valueRegister, addrRegister, 1 if increase else 0)
elif type(offset) is str:
return 'A{}{}{}{}1{}0\n'.format(length,valueRegister, addrRegister, 1 if increase else 0, offset)
else:
return 'A{}{}{}{}200 {}\n'.format(length,valueRegister, addrRegister, 1 if increase else 0, Value2DWord(offset)) # seem buggy
def PointerCodeStoreRegisterValueToMemoryAddress(valueRegister=None, addr='B', length=4, offset=None, increase=False): # Code Type 0xA
if isGDB(): return ''
if valueRegister == None: valueRegister = TM2
if type(addr) is str and offset==None:
return 'A{}{}{}{}300\n'.format(length, valueRegister, addr, 1 if increase else 0)
elif type(addr) is not str:
return 'A{}{}0{}400 {:08X}\n'.format(length, valueRegister, 1 if increase else 0, addr)
else:
return 'A{}{}{}{}500 {:08X}\n'.format(length, valueRegister, addr, 1 if increase else 0, offset)
def PointerCodeCopyRegister(dest, source):
if isGDB(): return ''
return PointerCodeArithmetic('mov', dest, source)
def PointerCodeCondition(register,condition,value,length=4):
if isGDB(): return ''
Conditions={'>':'1', '>=':'2', '<':'3', '<=':'4', '==':'5', '=':'5', '!=':'6'}
if type(value) is str and len(value)==1:
return 'C0{}{}{}5{}0\n'.format(length,Conditions[condition],register,value)
else:
return 'C0{}{}{}400 {}\n'.format(length,Conditions[condition],register,Value2DWord(value) if length<8 else Value2QWord(value))
def PointerCodeEndBlock():
if isGDB(): return ''
return '20000000\n'
def PointerCodeElseBlock():
if isGDB(): return ''
return '21000000\n'
def PointerCodeStartLoop(size,register='C'):
if isGDB(): return ''
return '300{}0000 {:08X}\n'.format(register,size)
def PointerCodeEndLoop(register='C'):
if isGDB(): return ''
return '310{}0000\n'.format(register)
def PointerHack(offsets,values,length=4,useButton=None,default=None,appendCodes=None):
if isGDB(): return ''
codes=PointerCodeHeader(offsets[:-1])
if offsets[-1]>0: codes+=PointerCodeAddRegister(offsets[-1])
if type(values) not in (tuple, list): values=[values]
finalCode=''
useCombine=length==4 and len(values)>=2
if useCombine:
idx=0
while idx+1<len(values):
finalCode+=PointerCodeWrite(8,values[idx],values[idx+1],use_D=False,increase=True)
idx+=2
if idx<len(values):
finalCode+=PointerCodeWrite(4,values[idx],use_D=False,increase=True)
else:
for value in values:
finalCode+=PointerCodeWrite(length,value,use_D=False,increase=True)
if appendCodes!=None: finalCode+=appendCodes
defaultCode = '' if default==None else PointerCodeWrite(length,default,use_D=False)
if useButton != None: finalCode= defaultCode + ButtonCode(useButton,finalCode)
AddCheatCode(codes+finalCode)
def PointerCopyValue(dest,source,length=4):
common = []
for idx in range(len(source)):
if source[idx]!=dest[idx]: break
common.append(source[idx])
if len(common)==0:
codes = PointerCodeHeader(source[:-1],'F')
codes += PointerCodeHeader(dest[:-1],'A')
else:
codes = PointerCodeHeader(common,'F')
codes += PointerCodeCopyRegister('A','F')
codes += PointerCodeAddOffset(source[len(common):-1],'F')
codes += PointerCodeAddOffset(dest[len(common):-1],'A')
if length<=8:
codes += PointerCodeReadOffset(source[-1],'F',length)
codes += PointerCodeStoreRegisterValueToRegisterAddress('F', 'A', length, dest[-1])
else:
codes += PointerCodeCopyRegister('B','F')
sourceoffset=source[-1]
while length>0:
codes += PointerCodeReadOffset(sourceoffset,'F',length if length<8 else 8)
codes += PointerCodeStoreRegisterValueToRegisterAddress('F', 'A', length if length<8 else 8, dest[-1], increase=True)
sourceoffset+=8
length-=8
if length>0: codes += PointerCodeCopyRegister('F','B')
AddCheatCode(codes)
def PointerFillRange(basePointer, maxSize, value, length=4, condition=None, conditionValue=None):
codes = PointerCodeHeader(basePointer[:-1],'F')
if basePointer[-1]!=0: codes += PointerCodeAddRegister(basePointer[-1],'F')
codes += PointerCodeStartLoop(maxSize)
if condition!=None and conditionValue!=None:
codes += PointerCodeCopyRegister('B','F')
codes += PointerCodeReadOffset(0,'B',length)
codes += PointerCodeCondition('B',condition,conditionValue,length)
codes += PointerCodeWrite(length, value, None, 'F', use_D=False, increase=True)
if condition!=None and conditionValue!=None:
codes += PointerCodeElseBlock()
codes += PointerCodeAddRegister(0x8,'F')
codes += PointerCodeEndBlock()
codes += PointerCodeEndLoop()
AddCheatCode(codes)
def PointerFillArray(basePointer, maxSize, finalOffset, value, length=4, check=False, condition=None, conditionValue=None):
codes = PointerCodeHeader(basePointer,'F')
codes += PointerCodeAddRegister(0x18,'F')
codes += PointerCodeSetValue(finalOffset,'D')
if check:
codes += PointerCodeCopyRegister('A','F')
codes += PointerCodeReadOffset(0,'A',2)
codes += PointerCodeStartLoop(maxSize)
codes += PointerCodeAddRegister(0x8,'F')
if check:
codes += PointerCodeCondition('A','>',0,2)
codes += PointerCodeArithmetic('-','A','A',1,2)
if condition!=None and conditionValue!=None:
codes += PointerCodeCopyRegister('B','F')
codes += PointerCodeReadOffset(finalOffset,'B',length)
codes += PointerCodeCondition('B',condition,conditionValue,length)
codes += PointerCodeCopyRegister('B','F')
codes += PointerCodeAddOffset([0],'B')
codes += PointerCodeWrite(length, value, None, 'B')
if condition!=None and conditionValue!=None:
codes += PointerCodeEndBlock()
if check:
codes += PointerCodeEndBlock()
codes += PointerCodeEndLoop()
AddCheatCode(codes)
def ButtonCode(key,code=None,elseCode=None): # note: the ElseCode is not supported by Yuzu currently
if isGDB(): return ''
if type(key) in (tuple, list): key=MixButtons(key)
keymap={'a':0x1,'b':0x2,'x':0x4,'y':0x8,'l3':0x10,'r3':0x20,'l':0x40,'r':0x80,'zl':0x100,'zr':0x200,'+':0x400,'-':0x800,'left':0x1000,'up':0x2000,'right':0x4000,'down':0x8000,'l3left':0x10000,'l3up':0x20000,'l3right':0x40000,'l3down':0x80000,'r3left':0x100000,'r3up':0x200000,'r3right':0x400000,'r3down':0x800000,'sl':0x1000000,'sr':0x2000000}
if isinstance(key, str) and key.lower() in keymap: key=keymap[key.lower()]
key=key & 0xFFFFFFF
return '8{:07X}\n{}\n{}20000000\n'.format(key,code.strip('\n '),'' if elseCode==None else '21000000\n%s\n'%(elseCode.strip('\n '))) if code != None else '8%07X\n'%key
def MixButtons(keys):
if isGDB(): return ''
result=0
for key in keys:
result=result|int(ButtonCode(key),16)
return result
def ConditionCode(length,opAddr,value,commands,otherwise=None):
if isGDB(): return ''
if type(value) is str and re.match(r"^[0-9a-fA-F]{8}$", value[0:8]) is None: value=ASM(value)
result = '1%d050000 %s %s\n%s'%(length,Addr2DWord(opAddr),Value2DWord(value) if length<=4 else Value2QWord(value),commands)
if otherwise != None: result += '21000000\n%s'%(otherwise)
result += '20000000\n'
return result
def ToggleCode(button,length,opAddr,code1,code2=None):
if isGDB(): return ''
if code2==None: code2=RestoreCode(length,opAddr)
return ButtonCode(button,ConditionCode(length,opAddr,code2,CheatCode(length,opAddr,code1),CheatCode(length,opAddr,code2)))
def ASM(asm_code):
# IDA 9.2 Update: Corrected Keystone mode parameter
ks = Ks(KS_ARCH_ARM if is32bit else KS_ARCH_ARM64, KS_MODE_ARM if is32bit else KS_MODE_LITTLE_ENDIAN)
try:
bytecode, cnt = ks.asm(asm_code, as_bytes=True)
except:
idaapi.warning("Error in code: %s"%asm_code)
bytecode=b'FFFFFFFF'
if bytecode is None:
idaapi.warning("Error in code: %s"%asm_code);
return '????????'
return ''.join(map('{:02X}'.format, reversed(bytecode)))
def isEMU():
return isEMU;
def OperandAddr(addr): # return something like "B.NE 0x12345678" become "B 0x12345678"
if not isCode(addr): return '__ERROR__'
# IDA 9.2 Update
import ida_ua
cmd = ida_ua.insn_t()
if ida_ua.decode_insn(cmd, addr) == 0:
return '__ERROR__'
mnem = ida_ua.print_insn_mnem(addr).upper()
operand_index = 1
if mnem in ('B', 'BL', 'B.CC', 'B.HI', 'B.GE', 'B.LE', 'B.EQ', 'B.NE', 'CBNZ', 'CBZ'):
operand_index = 0
elif mnem in ('TBZ', 'TBNZ'):
operand_index = 2
target_addr = idc.get_operand_value(addr, operand_index)
return hex(target_addr - addr)
def Hack(pattern,codes,showRestoreCode=True,useButton=None,elseCode=None,returnCode=False,searchStart=codeStart,searchEnd=codeEnd):
if isGDB(): return
global cheatCodes, restoreCodes, masterCodes
output=''
cheatAddr=AOB(pattern,searchStart,searchEnd) if type(pattern) is str else pattern
if notFound(cheatAddr):
idaapi.warning(cheatName+': AOB broken!\n%s'%(pattern if type(pattern) is str else hex(pattern)))
else:
if type(codes) is str and re.match(r"^[0-9a-fA-F]{8} $", codes[0:9]) is not None: codes=list(reversed(codes.split(' ')))
if type(codes) is str or type(codes) is int: codes=[codes]
length = len(codes)*4
if showRestoreCode=='masterCodes':
masterCodes += RestoreCode(length,cheatAddr)
elif showRestoreCode and useButton==None:
restoreCodes += RestoreCode(length,cheatAddr)
output += CheatCode(length, cheatAddr, codes)
if useButton != None:
output=(RestoreCode(length,cheatAddr) if showRestoreCode and showRestoreCode!='masterCodes' else '') + ButtonCode(useButton,output,elseCode)
if not returnCode: cheatCodes += output
return output
def HackAll(pattern,codes,offset=0,showRestoreCode=True,useButton=None,elseCode=None,searchStart=codeStart,searchEnd=codeEnd,returnCode=False):
if isGDB(): return
global cheatCodes
output=''
cheatAddrs=AllOccur(pattern,offset,searchStart,searchEnd)
if len(cheatAddrs)<1:
idaapi.warning(cheatName+': AOB broken!')
else:
if useButton != None and showRestoreCode and elseCode == None:
for cheatAddr in cheatAddrs: output += RestoreCode(len(codes)*4,cheatAddr)
if useButton != None: output += ButtonCode(useButton) # Note: EMU cheat-vm does not support button activator on ASM codes
for cheatAddr in cheatAddrs: output += Hack(cheatAddr, codes, useButton == None and showRestoreCode and elseCode == None, None, returnCode=True)
if useButton != None and elseCode!=None: output += '21000000\n%s\n'%(elseCode.strip('\n '))
if useButton != None: output += '20000000\n'
if not returnCode: cheatCodes += output
return output
def CodeFunc(codes,retAddr=None,targetAddr=None):
global codeK
if isGDB(): return
ResultCode=lastInstruction=''
end=GetCodeK()
if type(codes) is str: idaapi.warning("Cannot be type of string: %s"%codes); return
for instruction in reversed(codes):
if type(instruction) is str: instruction = instruction.strip()
if not instruction: continue
codeK-=4
if type(instruction) is int: instruction='%08X'%instruction
instruction=instruction.replace('{here}',hex(codeK)).replace('{end}',hex(end-codeK)).replace('{start}',hex(end-len(codes)*4-codeK))
if retAddr!=None: instruction=instruction.replace('{back}',hex(retAddr-codeK))
if targetAddr!=None: instruction=instruction.replace('{there}',hex(targetAddr-codeK))
if re.match(r"^[0-9a-fA-F]{8}$", instruction[0:8]) is None: instruction=ASM(instruction)
if lastInstruction=='':
lastInstruction = instruction
else:
ResultCode += CheatCode(8,codeK,(lastInstruction)+(instruction))
lastInstruction = ''
if (lastInstruction != ''): ResultCode += CheatCode(4,codeK,(lastInstruction))
return ResultCode
def CodeCave(cheatAddr, codes, showRestoreCode=True, use_BL=True, returnCode=False, data_size=0):
if isGDB(): return ''
global cheatCodes, masterCodes, restoreCodes, codeK
output = CodeFunc(codes, cheatAddr + 4, idc.get_operand_value(cheatAddr, 0)) or ''
asm_start_addr = GetCodeK() # GetCodeK() now holds the start of the instructions
if not output:
idaapi.warning(cheatName+': CodeCave assembly failed!')
return ''
if showRestoreCode=="masterCodes":
masterCodes += RestoreCode(4,cheatAddr)
elif showRestoreCode:
restoreCodes += RestoreCode(4,cheatAddr)
hook_jump = ('BL ' if use_BL else 'B ') + hex(asm_start_addr - cheatAddr)
output += Hack(cheatAddr, hook_jump, False, None, returnCode=True)
if not returnCode: cheatCodes += output
return output
def GetCodeK():
if isGDB(): return BADADDR
return codeK
def SetCodeK(addr):
if isGDB(): return
global codeK
codeK=addr
def RegCodeK(size=4):
if isGDB(): return BADADDR
global codeK
codeK-=size
return codeK
def RegData(assignValue,size=4): # Reverted to simple data registration
if isGDB(): return ''
if type(assignValue) in (tuple, list): size=size*len(assignValue)
return CheatCode(size,RegCodeK(size),assignValue)
def DefineWriteableAddress(size=4):
if isGDB(): return BADADDR
global dataAddr
dataAddr-=size
return dataAddr
def Either(aob1,aob2):
if isGDB(): return
if type(aob1) is str: aob1=AOB(aob1)
if type(aob2) is str: aob2=AOB(aob2)
return aob1 if isFound(aob1) else aob2
def GetADRP(addr):
if notFound(addr): return BADADDR
# IDA 9.2 Update
register = idc.get_op_text(addr,1)[1:4].replace(',','')
baseAddr = SearchPrevASM(addr,'ADRP',register)
return idc.get_operand_value(baseAddr,1)+idc.get_operand_value(addr,1)
def WriteFile(filepath,content):
folder = os.path.dirname(filepath)
if not os.path.exists(folder): os.makedirs(folder)
with open(filepath, "w", encoding='utf-8') as out:
out.write(content)
def GetTID():
global TID
if isGDB(): return None
if TID is None:
TIDs = re.findall(r"[0-9a-fA-F]{16}", os.path.basename(idc.get_idb_path()).replace('800 ','000 ').replace('800]','000]'))
TID = TIDs[0] if len(TIDs)>0 else None
return TID
def GetBID(length=8):
global BID
if isGDB(): return None
if BID is None:
gnu=AOB("00 00 00 47 4E 55 00",dataStart,dataEnd)
# IDA 9.2 Update
BID = ''.join('%02X'%ida_bytes.get_byte(gnu+7+i) for i in range(length)) if isFound(gnu) else None
return BID
def SetBID(bid):
global BID
BID = bid
def SetTID(tid):
global TID
TID = tid
def SetVersion(ver):
global VER
VER = ver
def GetVersion():
global VER
if VER == None:
try:
VERs = re.findall('v\d[\d\.a-z]*',os.path.basename(idc.get_idb_path()))
VER=VERs[0] if len(VERs)>0 else None
except IndexError:
VER = None
return VER
def GetRegion():
global RGN
if RGN == None:
try:
RGNs = re.findall('[\[\(](US|GB|JP|AU|HK|PL|CN|TW|FR|KR|NL|NO|NZ|PE|PT|RU|SE|ZA|CZ|DE|DK|ES|FI|GR|HU|IT|MX|AR|AT|BE|CA|CL|CO)[\]\)]',os.path.basename(idc.get_idb_path()))
RGN = RGNs[0] if len(RGNs)>0 else None
except IndexError:
RGN = None
return RGN
def AddMasterCode(codes):
if isGDB(): return
global masterCodes
masterCodes+=codes
def AddCheatCode(codes):
if isGDB(): return
global cheatCodes
cheatCodes+=codes
def InsertCheatCode(line,codes):
if isGDB(): return
global cheatCodes
cheatlines=cheatCodes.split('\n')
cheatlines.insert(-line-1,codes[0:-1])
cheatCodes='\n'.join(cheatlines)
def AddRestoreCode(codes):
if isGDB(): return
global restoreCodes
restoreCodes+=codes
def AddCheat(nameEN,nameZH=None,newOption=0,isSuggest=False,showOption=True): # newOption=0(不是)/1(新)/2(接上)
if isGDB(): return
global cheatCnt, idx, cheatCodes, cheatName
cheatName=nameEN if english or nameZH==None else nameZH
if newOption<2:
cheatCnt+=1
idx=ord('a')
else:
idx+=1
title = '№%2d. %s'%(cheatCnt,cheatName) if newOption==0 else '№%2d%s %s'%(cheatCnt,chr(idx) if showOption else '',cheatName)
if isSuggest: title+=' ★'
Show(title)
cheatCodes += '\n[%s]\n'%title
def AddSection(nameEN,nameZH=None):
if isGDB(): return
global cheatCnt, idx, cheatCodes, cheatName
cheatName=nameEN if english or nameZH==None else nameZH
title = '--SectionStart:%s--'%(cheatName)
Show(title)
cheatCodes += '\n[%s]\n20000000\n'%title
return
def EndSection(nameEN,nameZH=None):
if isGDB(): return
global cheatCnt, idx, cheatCodes, cheatName
cheatName=nameEN if english or nameZH==None else nameZH
title = '--SectionEnd:%s--'%(cheatName)
Show(title)
cheatCodes += '\n[%s]\n20000001\n'%title
return
def HackComplete():
if isGDB(): return
header = ("[%s %s TID=%s BID=%s]\n"%(gameName,VER,TID,BID))
footer = ('[This set of cheats is created by All Credited, enjoy!]' if english else '[此套金手指由 OblivionReign 制作, 免費提供, 歡迎轉載, 敬請註明來源出處]')
if isEMU:
cheats=cheatCodes.replace('\r','').split('\n\n')
if masterCodes!='':
cheatfilename="# Master Code (include share functions)"
cheat = '{%s}\n%s'%(cheatfilename,masterCodes.strip('\n '))
cheats= [cheat]+cheats
for i in range(len(cheats)):
cheat=cheats[i]=cheats[i].strip('\n ')
if cheat=='': continue
cheatfilename=(cheat.split('\n'))[0].strip('{}[] ')
path='%s\\%s for Yuzu\\%s\\cheats\\%s.txt'%(os.path.dirname(idc.get_idb_path()),TID,cheatfilename,BID)
content = '%s\n'%cheat
if codeK<ida_segment.get_segm_by_name('.bss').end_ea: WriteFile(path,content) # skip Yuzu if using sdk code cave
path='%s\\%s for Ryujinx\\%s %s\\cheats\\%s.txt'%(os.path.dirname(idc.get_idb_path()),TID,gameName,VER,BID)
content = '%s\n'%('\n\n'.join(cheats))
WriteFile(path,content)
else:
if masterCodes != '':
header += (('\n{%s}\n'%('Master Code (includes share functions)' if english else '關鍵碼 (含共用函式)'))+masterCodes)
restoreCode = '' if restoreCodes=='' else '\n[%s]\n%s'%('Restore Code (Use after unchecking any cheats below)' if english else '還原碼 (當取消以下金手指時使用)', restoreCodes)
path='%s\\%s\\%s\\cheats\\%s.txt'%(os.path.dirname(idc.get_idb_path()),gameName,TID,BID)
content = '%s%s%s\n%s\n'%(header,restoreCode,cheatCodes,footer)
WriteFile(path,content)
cls()
print('ApplyPatch(\'\'\'\n'+header+cheatCodes+'\'\'\')')
def MarkLabel(name,type='Class'):
if isGDB():
addr=ptr(eval(name),returnResult=True)
if type=='Address':
MarkOffset(addr)
elif type=='Class':
MarkOffset(addr)
ApplyStruct(GetQword(addr), 'ObjHeader') # Ungine only
elif type=='Float':
MarkFloat(addr,4)
elif type=='Long':
MarkBytes(addr,8)
elif type=='DWord':
MarkBytes(addr,4)
elif type=='Word':
MarkBytes(addr,2)
elif type=='Byte':
MarkBytes(addr,1)
elif type=='Bits':
MarkBytes(addr,1)
Patch(GetQword(addr) if type in ('Class','Address') else addr,name)
def Init(enName,zhName=None,EMU=None, is64bit=True):
if isGDB(): return
cls()
global isEMU, english, TID, BID, VER, RGN, gameName, cheatCnt, cheatCodes, masterCodes, restoreCodes, is32bit
isNRO = '.nro.' in os.path.basename(idc.get_idb_path())
TID = GetTID()
if TID==None and not isNRO: TID=ida_kernwin.ask_str('', 11, "Please enter TID")
BID = GetBID()
if BID==None and not isNRO: BID=ida_kernwin.ask_str('', 11, "Please enter BID")
VER = GetVersion()
if VER==None and not isNRO: VER = ida_kernwin.ask_str('v0', 12, "Please enter VER")
RGN = GetRegion()
# if RGN==None: RGN = ida_kernwin.ask_str('US', 13, "Please enter Region")
isEMU = ida_kernwin.ask_yn(False, 'HIDECANCEL\nUse RyujinX / Yuzu?') if EMU == None else EMU
english = True if isEMU or zhName==None else ida_kernwin.ask_yn(True, 'HIDECANCEL\nUse english?')
gameName= (enName if english else zhName) + ('' if RGN==None else ' (%s)'%RGN)
cheatCnt=0
cheatCodes = masterCodes = restoreCodes = ''
SetCodeK(GetCodeEnd())
is32bit = not is64bit
def FpsCode(methods,SDK_FPS_Addr=None):
if type(methods) not in (tuple, list): methods=[methods]
cheatAddr1 = cheatAddr1b = cheatAddr1c = cheatAddr2 = cheatAddr3 = cheatAddr4 = cheatAddr5 = cheatAddr6 = cheatAddr7 = cheatAddr8 = BADADDR
if 1 in methods:
cheatAddr1=AOB('? ? ? 97 F4 00 00 34 68 3A 42 B9')
cheatAddr1b=Either('00 01 62 1E C8 09 E8 D2','00 03 62 1E 01 01 67 9E')
cheatAddr1c=Either('00 D8 61 5E 0A 18 61 1E','20 01 62 1E C9 09 E8 D2 21 01 67 9E 0A 18 61 1E')
if 2 in methods and SDK_FPS_Addr != None:
nnmusl_init_dso=AOB('? ? ? 94 80 ? ? B9 88 ? ? B9') #i.e. ida_segment.get_segm_by_name('.got.plt').start_ea + 0x18
cheatAddr2=GetADRP(idc.get_operand_value(nnmusl_init_dso,0)+4) if isFound(nnmusl_init_dso) else ida_segment.get_segm_by_name('.got.plt').start_ea + 0x18
# SDK_FPS_Addr = 0x7a66c # find in sdk: p( AOB("AB 26 4F B9") - get_name_ea(0,'__nnmusl_init_dso') )
if 3 in methods:
targetAddrs = AllOccur('88 01 00 34 ? ? ? 94 ? ? ? 94 ? ? ? ? 08 ? ? F9 08 01 40 B9 1F 01 00 6B E8 07 9F 1A 60 7A 68 BC ? ? ? ? ? ? ? ? C0 03 5F D6 E8 03 1F AA 60 7A 68 BC ? ? ? ? ? ? ? ? C0 03 5F D6')
cheatAddr3= GetADRP(SearchPrevASM(targetAddrs[1], 'LDR', 'X19', limit=0x40)) if len(targetAddrs)==2 else BADADDR
if 4 in methods:
temp=AOB('08 ? ? F9 01 01 40 F9 ? ? ? ? 08 ? ? F9 08 01 40 F9 A0 23 03 D1 00 01 3F D6 ? ? ? ? ? 02 40 B9 A0 23 03 D1 08 ? ? F9 08 01 40 F9 00 01 3F D6') # unity
if isFound(temp):
cheatAddr4=[GetQword(GetADRP(temp))]
else:
# temp=AOB('08 ? ? F9 01 01 40 F9 ? ? ? ? 08 ? ? F9 08 01 40 F9 A0 ? ? D1 00 01 3F D6 ? ? ? ? ? 02 40 B9 08 ? ? F9 08 01 40 F9 A0 ? ? D1 00 01 3F D6 ? ? ? ? 81 02 40 B9 08 ? ? F9 08 01 40 F9 A0 ? ? D1 00 01 3F D6') # old version unity
temp=AOB('08 ? ? F9 01 01 40 F9 ? ? ? ? 08 ? ? F9 08 01 40 F9 A0 ? ? D1 00 01 3F D6 ? ? ? ? ? 02 40 B9 A0 ? ? D1 08 ? ? F9 08 01 40 F9 00 01 3F D6') # old version unity
if isFound(temp): cheatAddr4=[GetQword(GetADRP(temp))]
if 5 in methods:
temp=AOB('1A ? ? F9 28 03 40 39')
if isFound(temp):
cheatAddr5=GetADRP(temp)
if 8 in methods:
temp=AOB('? ? ? ? ? ? ? 91 09 09 80 B9 C9 02 00 34 08 01 40 F9 0A 05 80 52')
if isFound(temp):
cheatAddr8=GetADRL(temp)
if 6 in methods: # search sysFps::m_flipSync
cheatAddr6=AOB('F3 03 00 2A ? ? ? 97 ? ? ? ? 08 ? ? F9')
if 7 in methods and SDK_FPS_Addr != None:
cheatAddr7=SDK_FPS_Addr
AddCheat('60 FPS',None,1)
if isFound(cheatAddr1):
Hack(cheatAddr1,'MOV W0, #1', False)
Hack(cheatAddr1b,'FMOV D0, #1.0', False)
Hack(cheatAddr1c,'FMOV D0, #1.0', False)
if isFound(cheatAddr2):
AddCheatCode(PointerCodeHeader((cheatAddr2)))
AddCheatCode(PointerCodeAddRegister(SDK_FPS_Addr))
AddCheatCode(PointerCodeWrite(4,ASM('MOV W11, #1'),use_D=False))
if isFound(cheatAddr3):
AddCheatCode(PointerCodeHeader((cheatAddr3)))
AddCheatCode(PointerCodeWrite(8,Float2DWord(60),Float2DWord(60),use_D=False))
if isFound(cheatAddr4):
AddCheatCode(PointerCodeHeader(cheatAddr4))
AddCheatCode(PointerCodeAddRegister(0xF14))
AddCheatCode(PointerCodeWrite(4,1,use_D=False))
if isFound(cheatAddr5):
AddCheatCode(PointerCodeHeader((cheatAddr5)))
AddCheatCode(PointerCodeWrite(8, 1, 1, use_D=False))
if isFound(cheatAddr8):
AddCheatCode(PointerCodeHeader((cheatAddr8)))
AddCheatCode(PointerCodeAddRegister(0x1F24))
AddCheatCode(PointerCodeWrite(4, 1, use_D=False))
if isFound(cheatAddr6):
Hack('62 6A 68 B8 08 26 86 52', 'MOV W2, #1', False)
Hack(cheatAddr6, 'MOV W0, #1', False)
Hack(GetQword(GetADRP(cheatAddr6+12)), 1, False)
if isFound(cheatAddr7):
Hack(SDK_FPS_Addr,'MOV W11, #1', False)
AddCheat('30 FPS',None,2)
if isFound(cheatAddr1):
Hack(cheatAddr1,'MOV W0, #2', False)
Hack(cheatAddr1b,'FMOV D0, #2.0', False)
Hack(cheatAddr1c,'FMOV D0, #2.0', False)
if isFound(cheatAddr2):
AddCheatCode(PointerCodeHeader((cheatAddr2)))
AddCheatCode(PointerCodeAddRegister(SDK_FPS_Addr))
AddCheatCode(PointerCodeWrite(4,ASM('MOV W11, #2'),use_D=False))
if isFound(cheatAddr3):
AddCheatCode(PointerCodeHeader((cheatAddr3)))
AddCheatCode(PointerCodeWrite(8,Float2DWord(30),Float2DWord(30),use_D=False))
# FPS method 3 if fail
# search 60 D2 4B BD check something like LDR S0, [X21,X8,LSL#2] or LDR S8, [X21,X8,LSL#2]
if isFound(cheatAddr4):
AddCheatCode(PointerCodeHeader(cheatAddr4))
AddCheatCode(PointerCodeAddRegister(0xF14))
AddCheatCode(PointerCodeWrite(4,2,use_D=False))
if isFound(cheatAddr5):
AddCheatCode(PointerCodeHeader((cheatAddr5)))
AddCheatCode(PointerCodeWrite(8, 2, 2, use_D=False))
if isFound(cheatAddr8):
AddCheatCode(PointerCodeHeader((cheatAddr8)))
AddCheatCode(PointerCodeAddRegister(0x1F24))
AddCheatCode(PointerCodeWrite(4, 2, use_D=False))
if isFound(cheatAddr6):
Hack('62 6A 68 B8 08 26 86 52', 'MOV W2, #2', False)
Hack(cheatAddr6, 'MOV W0, #2', False)
Hack(GetQword(GetADRP(cheatAddr6+12)), 2, False)
if isFound(cheatAddr7):
Hack(cheatAddr7,'MOV W11, #2', False)