Sonic Dissasembly Reseach Lua Tricks

Discussion in 'Engineering & Reverse Engineering' started by Cokie, Jun 26, 2022.

  1. Cokie


    C. Okie Member
    I wanted to share some LUA script tricks/ methods I do to better help understand the sonic dissasemblies. Feedback welcome. Also, if these
    methods can be simplified to achieve similar goal, would much appreciate any advice on that as well.

    A scenario sometimes is that I want to print all the instructions and its coresponding address that read/wrote to a particular address in RAM. Additionally, I may want to print it only one time (and not every occurrence), as well as print the particular instruction.

    I would write a lua scipt with the Emulator BizHawk since it allows to fetch the assembly instruction.
    Gens Rerecord / Gens r57shell could do this besides print the instruction afaik. The script tracks what instruction/address we already printed to avoid duplicates.

    readword = mainmemory.read_u16_be
    onmemorywrite = event.onmemorywrite
    getregister = emu.getregister

    OFF_SonicY = 0xFFFFB00C

    instr_addr = {}

    function tohex(val) return string.format("%0x",val) end

    function is_new_inst_addr(PC)

    local found_new = true

    for i,v in ipairs(instr_addr) do
    if v == PC then
    found_new = false

    return found_new

    local PC = getregister("M68K PC")

    if is_new_inst_addr(PC) == true then
    local out_str = "\nAddress: " .. tohex(PC) .. " " .. tostring(emu.disassemble( PC))

    This would print each pair of address / instruction that wrote to Sonics Y position in Sonic 2. The output looks like this:

    Address: 1a078 { disasm = 0268 andi.w #$7FF, ($C,A0), length = 6 }: -1481166473

    Address: 1aae2 { disasm = 5A68 addq.w #5, ($C,A0), length = 4 }: 1501105241

    Address: 163a6 { disasm = 2143 move.l D3, ($C,A0), length = 4 }: -1753659296

    .... etc

    A scenario similiar in that it involves state. If you wanted to do something when the game wrote a value to an address that
    was different from its previous address. For instance, when camera/sonic coordinate change, sonics status ( rolling jumping ) changes.
    A Gens Rerecord / r57 script that loads the debugger and breaks ( so you can inspect stuff) writes a value to the camera y pos different from
    its previous might look like:

    readword = memory.readword
    cam_y_pos={} = 0xFFEE04
    cam_y_pos.current = readword(
    cam_y_pos.prev = cam_y_pos

    -- update previous and current
    cam_y_pos.prev = cam_y_pos.current
    cam_y_pos.current = readword(

    -- if game wrote value != previous then load breakpoint debugger, breaking
    if cam_y_pos.current ~= cam_y_pos.prev then gens.breakpoint() end

    More posts on way.