dumb question for cheat code

Longjumping-Topic708

New Member
OP
Newbie
Joined
Jul 21, 2024
Messages
4
Trophies
0
Age
51
XP
56
Country
Taiwan
for cheat code normally patch like this for example TOTK

from gdb monitor get info
Process: 0x51 (Application)
Program Id: 0x0100f2c0115b6000
Layout:
Alias: 0x1105c00000 - 0x2105bfffff
Heap: 0x2105c00000 - 0x2305bfffff
Aslr: 0x0008000000 - 0x7fffffffff
Stack: 0x1085c00000 - 0x1105bfffff
Modules:
0x0080000000 - 0x0080003fff nnrtld
0x0080004000 - 0x0084669fff EX-King.nss
0x008466a000 - 0x0084d12fff multimedia
0x0084d13000 - 0x0085a36fff nnSdk

[Item Pickup Multiplier (2x)]
040A0000 0162A408 52800041

040A0000 # ?? where is coming form dont know how atmosphere handle
016A408 # should be the offset finding from breeze/edizon or ghidra/gdb
52800041 # should be the opcode "mov w1, #2" in reverse order 41 00 80 52


[ Docked 720p ]
580F0000 04716F50
580F1000 00000090
780F0000 000000F0
680F01D0 00000360 00000600

for this example how to understand the cheat code how atmosphere or gdb dispatch for it
Post automatically merged:

Python:
```
import idaapi
import idc
import sys
import os
# cheatLib powered by Eiffel2018
from cheatLib import *

def add_bookmark(offset, comment, check_duplicate=True):
    """
    Add a bookmark at the specified address with a comment.
 
    :param offset: The address offset where the bookmark will be added.
    :param comment: The comment to associate with the bookmark.
    :param check_duplicate: If True, checks for existing bookmarks to avoid duplicates.
    """
    for bslot in range(0, 1024, 1):
        slotval = idc.get_bookmark(bslot)
        if check_duplicate:
            if slotval == offset:
                print(f"Bookmark already exists at address 0x{offset:X}")
                return

        if slotval == 0xffffffffffffffff:
            idc.put_bookmark(offset, 0, 0, 0, bslot, comment)
            print(f"Bookmark added at address 0x{offset:X} with comment: {comment}")
            break

def cheat_from_file(bid_file):
    if os.path.exists(bid_file):
        with open(bid_file, "r") as f:
            lines = f.readlines()
            current_cheat_name = None
            current_values = []

            for line in lines:
                line = line.strip()
             
                if not line:
                    continue  # Skip empty lines

                # Check if the line starts with a cheat name
                cheat_name_match = re.search(r'\[(.*?)\]', line)
                if cheat_name_match:
                    # Save the previous cheat's data before starting a new one
                    if current_cheat_name:
                        cheats.append((current_cheat_name, current_values))
                 
                    # Start a new cheat entry
                    current_cheat_name = cheat_name_match.group(1).strip()
                    current_values = []
                    continue
             
                # Check if the line starts with '040' for values
                if len(line)>=8:
                    parts = line.split()
                    if len(parts) >= 2:
                        values = parts[1:]  # Values after the prefix
                        current_values.append(values)

            # Append the last cheat entry after finishing the loop
            if current_cheat_name and current_values:
                cheats.append((current_cheat_name, current_values))

def patch_ida_comment(cheat_name, values):
    for address_offset, comment_text in values:
        # Convert offset to absolute address
        address_offset = int(address_offset,16)
        opcpde = f"[ {comment_text[::-1]} ]"
        # image_base = idaapi.get_imagebase()
        absolute_address = image_base + address_offset
        print(f"{absolute_address:x}")
        comment = "cheatcode_ "+cheat_name + " " + opcpde
        idc.set_cmt(absolute_address, comment, 1)
        add_bookmark(absolute_address, comment)


cheats = []

bid_file =GetBID()+".txt"
cheat_from_file(bid_file)
for cheat_name, values in cheats:
    if len(values) >0:
        print(cheat_name, values)
        patch_ida_comment(cheat_name, values)


```
what I'm try to do is easy for code understand on IDA
snap_0907_110719.png

Post automatically merged:

seems protocol a bit complex from breeze implementation
StoreStatic (3 DWORDs)
Instruction Format
: 0TMR00AA AAAAAAAA YYYYYYYY (YYYYYYYY)
  • T: Width of memory write (1, 2, 4, or 8 bytes)
  • M: Memory region (0 = Main NSO, 1 = Heap, 2 = Alias)
  • R: Register used as an offset
  • A: Immediate offset
  • YYYYYYYY: Value to be written
ControlLoop 3XRR0000 (VVVVVVVV) (R: Register to use as counter, X: 0=start 1=Stop )
EndConditionalBlock 2X000000 (X: End type (0 = End, 1 = Else))
LoadRegisterStatic 400R0000 VVVVVVVV VVVVVVVV
LoadRegisterMemory 5TMRI0AA AAAAAAAA
StoreStaticToAddress 6T0RIor0 VVVVVVVV VVVVVVVV
PerformArithmeticStatic 7T0RC000 VVVVVVVV
BeginKeypressConditionalBlock 8kkkkkkk
PerformArithmeticRegister 9TCRSIs0 (VVVVVVVV (VVVVVVVV))
StoreRegisterToAddress ATSRIOxa (aaaaaaaa)
...
more detail check breeze/source/assembleraction.cpp
maybe StoreStatic is good for me right now B-)
 
Last edited by Longjumping-Topic708,

Longjumping-Topic708

New Member
OP
Newbie
Joined
Jul 21, 2024
Messages
4
Trophies
0
Age
51
XP
56
Country
Taiwan
Screenshot 2024-09-09 112323.png

now it's much better with following code
```
Code:
from rich import print
from keystone import *
from capstone import Cs, CS_ARCH_ARM64, CS_MODE_ARM
import sys
import os

# thanks the decoder logic from breeze project

def opcode_asm(opcode,addr):
    asm_code = []
# Create a disassembler object for ARM64
    md = Cs(CS_ARCH_ARM64, CS_MODE_ARM)

    opcode_hex = int(opcode, 16)
    # in little endian
    opcode = opcode_hex.to_bytes(4, byteorder='little').hex()
    # print(f"Opcode: {opcode} {type(opcode)} {opcode_hex}")
    code = bytes.fromhex(opcode)
    for insn in md.disasm(code, addr):  # 0x1000 is the starting address
        # print(f"0x{insn.address:x}:\t{insn.mnemonic}\t{insn.op_str}")
        asm_code.append(f"0x{insn.address:x}:\t{insn.mnemonic}\t{insn.op_str}")
    return asm_code

def hex_0TMR00AA(hex_string):
    # Split the hex string into three 32-bit parts
    first_dword, second_dword, third_dword = hex_string.split()
   
    dasm=opcode_asm(third_dword,int(second_dword, 16))
    # Convert to integers
    first_dword = int(first_dword, 16)
    second_dword = int(second_dword, 16)
    third_dword = int(third_dword, 16)
   
    # Extract components from first_dword
    bit_width = (first_dword >> 24) & 0xF
    mem_type = (first_dword >> 20) & 0xF
    offset_register = (first_dword >> 16) & 0xF
    rel_address = ((first_dword & 0xFF) << 32) | second_dword
   
    # Extract value from third_dword
    value = third_dword
   
    # Define memory types
    mem_type_str = ["Main", "Heap", "Alias"]
   
    # Format the opcode components
    if bit_width == 8:
        opcode_str = f"[{mem_type_str[mem_type]}+R{offset_register}+0x{rel_address:010X}]=0x{value:016X}"
    elif bit_width == 4:
        opcode_str = f"[{mem_type_str[mem_type]}+R{offset_register}+0x{rel_address:010X}]=0x{value:08X}"
    elif bit_width == 2:
        opcode_str = f"[{mem_type_str[mem_type]}+R{offset_register}+0x{rel_address:010X}]=0x{value:04X}"
    elif bit_width == 1:
        opcode_str = f"[{mem_type_str[mem_type]}+R{offset_register}+0x{rel_address:010X}]=0x{value:02X}"
    else:
        raise ValueError("Invalid bit width")
 
    return opcode_str, dasm

def hex_5TMRI0AA(hex_string):
    if verbose:
        print("""
LoadRegisterMemory 5TMRI0AA AAAAAAAA                0, 15
T: Width of memory load (1, 2, 4, or 8 bytes)       1, 8
M: Memory region to load from 0 = Main NSO, 1 = Heap, 2 = Alias(not supported by atm)
R: Register to load                                 0, 15
I: Load from register                               0, 1
A: Immediate offset to use from memory region base, 0, 15
A: Immediate offset to use from memory region base, 0, 15
    """)
    # Split the hex string into two 32-bit parts
    first_dword, second_dword = hex_string.split()
   
    # Convert to integers
    first_dword = int(first_dword, 16)
    second_dword = int(second_dword, 16)
   
    # Extract the components from first_dword
    bit_width = (first_dword >> 24) & 0xF
    mem_type = (first_dword >> 20) & 0xF
    reg_index = (first_dword >> 16) & 0xF
    load_from_reg = (first_dword >> 12) & 0xF
    rel_address = ((first_dword & 0xFF) << 32) | second_dword
   
    # Format the opcode components
    if load_from_reg == 1:
        opcode_str = f"R{reg_index}=[R{reg_index}+0x{rel_address:010X}] W={bit_width}"
    elif load_from_reg == 2:
        mem_type_str = ["Main", "Heap", "Alias"][mem_type]
        opcode_str = f"R{reg_index}=[{mem_type_str}+R{reg_index}+0x{rel_address:010X}] W={bit_width}"
    else:
        mem_type_str = ["Main", "Heap", "Alias"][mem_type]
        opcode_str = f"R{reg_index}=[{mem_type_str}+0x{rel_address:010X}] W={bit_width}"
   
    return opcode_str

def hex_6T0RIor0(hex_string):
    if verbose:
        print("""
StoreStaticToAddress 6T0RIor0 VVVVVVVV VVVVVVVV
T: Width of memory write (1, 2, 4, or 8 bytes)
R: Register used as base memory address     0, 15
I: Increment register flag                  0, 1
o: Offset register enable flag              0, 1
r: Register used as offset when o is 1      0, 15
""")

    # Split the hex string into three 32-bit parts
    first_dword, second_dword, third_dword = hex_string.split()
    # Convert to integers
    first_dword = int(first_dword, 16)
    second_dword = int(second_dword, 16)
    third_dword = int(third_dword, 16)
    # Extract components from first_dword
    bit_width = (first_dword >> 24) & 0xF
    reg_index = (first_dword >> 16) & 0xF
    increment_reg = (first_dword >> 12) & 0xF
    add_offset_reg = (first_dword >> 8) & 0xF
    offset_reg_index = (first_dword >> 4) & 0xF
    # Combine second and third dword to form the full value
    value = ((second_dword << 32) | third_dword)
    # Format the opcode components
    if add_offset_reg:
        opcode_str = f"[R{reg_index}+R{offset_reg_index}]=0x{value:016X} W={bit_width}"
    else:
        opcode_str = f"[R{reg_index}]=0x{value:016X} W={bit_width}"
    if increment_reg:
        opcode_str += f" R{reg_index}+=W"
    return opcode_str



def hex_7T0RC000(hex_string):
    if verbose:
        print("""
PerformArithmeticStatic 7T0RC000 VVVVVVVV          0, 15
T: Width of memory write (1, 2, 4, or 8 bytes)     1, 8
R: Register to apply arithmetic to                 0, 15
C: Arithmetic operation to apply                   0, 4
    """)
    # Split the hex string into two 32-bit parts
    first_dword, second_dword = hex_string.split()
   
    # Convert to integers
    first_dword = int(first_dword, 16)
    second_dword = int(second_dword, 16)
   
    # Extract components from first_dword
    bit_width = (first_dword >> 24) & 0xF
    reg_index = (first_dword >> 16) & 0xF
    math_type = (first_dword >> 12) & 0xF
    value = second_dword
   
    # Define arithmetic operation strings
    math_str = ["", "+", "-", "*", "/"]  # Example, modify according to actual operations
   
    # Format the opcode components
    opcode_str = f"R{reg_index}=R{reg_index} {math_str[math_type]}0x{value:08X} W={bit_width}"
   
    return opcode_str

def decode_cheatcode(cheatcode):
    parts = cheatcode.split()
    if parts[0].startswith('0'):
        decoded,dasm = hex_0TMR00AA(cheatcode)
        print(f"Decoded 0TMR00AA -> [green]{cheatcode}[/green]")
        print(f"{decoded} -> {dasm[0]}")
       
    if parts[0].startswith('5'):
        decoded = hex_5TMRI0AA(cheatcode)
        print(f"Decoded 5TMRI0AA AAAAAAAA -> [green]{cheatcode}[/green]")
        print(decoded)

    if parts[0].startswith('6'):
        decoded = hex_6T0RIor0(cheatcode)
        print(f"Decoded 6T0RIor0 VVVVVVVV VVVVVVVV -> [green]{cheatcode}[/green]")
        print(decoded)
       
    if parts[0].startswith('7'):
        decoded = hex_7T0RC000(cheatcode)
        print(f"Decoded 7T0RC000 VVVVVVVV -> [green]{cheatcode}[/green]")
        print(decoded)

    if parts[0].startswith('['):
        print(f"[yellow]{cheatcode}[/yellow]")
 
verbose = False  # Set to True to enable verbose output

"""
cheatcode = ["580f0000 02cc5fe0",
             "780f0000 00005d90",
             "640f0000 00000000 00015b38",
             "04000000 010B9684 11001508",
             ]  # Hexadecimal instruction

ks = Ks(KS_ARCH_ARM64, KS_MODE_LITTLE_ENDIAN)
for instruction in cheatcode:
    decode_cheatcode(instruction)
    print("")

"""

ks = Ks(KS_ARCH_ARM64, KS_MODE_LITTLE_ENDIAN)
if len(sys.argv) > 1:
    cheatcode = sys.argv[1]
    with open(cheatcode, 'r') as f:
        cheatcode = f.read()
    for it in cheatcode.splitlines():
        if len(it) == 0: continue
        decode_cheatcode(it)

full infomation cheat sheet on Atmosphere cheats.md
 
Last edited by Longjumping-Topic708,

Site & Scene News

Popular threads in this forum

General chit-chat
Help Users
    K3Nv2 @ K3Nv2: Gotta lube up diidy to change characters +1