Jump to content

Tux

Member
  • Posts

    54
  • Joined

  • Last visited

  • Days Won

    1

Posts posted by Tux

  1. That's okay :)

    So do you know what happens if the setlines are overwritten? Also, does that mean that you never need to use them when writing your own scripts?

    It's only debugging info iirc.

    Pokémon xD has a debugging menu disabled on retail. I've made a code to make it appear a while ago, but it was PAL only and doesn't work on latest Dolphin releases.

    Basically it just displays timers, currently running functions on each task with the lines, and the free stack space for each task.

  2. Sorry for not reponding ^^'

    In particular have you discovered any more classes/class functions? I've identified a handful more from what was in the repo last time I checked (like giving the player items and triggering battles) and thought I could help add to the list if you haven't discovered them yet.

    I didn't made any research on xD for some time; however I've identified some other classes (Shadow Pokémon handling, party handling) but the problem is that I'm missing the significance of many of their methods... feel free to PR though.

    I was also wondering if you knew the significance of the "setline" that appears throughout the scripts because it's just about the only thing I don't understand at this point.

    It's debugging information, and it's most likely a remnant of a higher-level language being assembled.

  3. I've been doing some research about PBR since yesterday, and found some really interesting stuff.

    The save file, which is location is "nand:/title/00010000/52504250/data/GeniusPbr/PbrSaveData" is made of two contiguous "save slots" ("current" and "backup"), each one being 0x1c0000 bytes of size. It turns out that they are encrypted the same way xD save slots are.

    The encryption/decryption/checksum calculation routines can be here.

    Without further ado, here is what I know about the various structures.

    Save slots (0x1c0000 bytes):

    /* struct SaveSlot (size = 0x1c0000) */
    
    0x00: u16 encryptionKeys[4]
    ****************ENCRYPTED DATA**************** (refer to decryptSaveSlotAndCheckChecksums for more details)
    
    ** Start of game config data **
    /* 
    Checksum from 0x00 to 0x100. 
    Refer to decryptSaveSlotAndCheckChecksums for more details.
    */
    0x08: u32 configChecksum[16] 
    
    ... unknown data ...
    
    0x1c: u8 isBackup (computed at runtime from saveCount)
    
    ... unknown data ...
    
    0x4c: u32 saveCount
    
    ... unknown data ...
    
    ** End of game config data **
    
    0x100 to 0x37f: unknown 
    
    
    0x380: SaveSubSlots subSlots[4] (each one is 0x6ff00 of size and is associated to a particular NDS save file (probably by the TID/SID))
    
    0x1bff80 (= end - 0x80): u32 checksum[16] (of the whole structure (i.e. 0 to 0x1c0000)) (refer to decryptSaveSlotAndCheckChecksums for more details)
    
    0x1bffc0 -- end: probably padding

    Pokémon: 140 bytes. I don't know anything else about these.

    Trainer cards: 0x738 bytes. When sent to/received from Wiimotes, 8 bytes of encryption keys and 64 bytes of checksum (same algorithms as before) are prepended. You can actually trigger a buffer overflow vulnerability (by playing with the trainer's name), but that's not really something exploitable.

  4. I made a tool exploiting this vulnerability : http://www.mediafire.com/download/10xm5gjb8yo299s/pkmgchax.zip (all NTSC-U/PAL versions supported, tested on PAL; I'm lacking the address of in-battle Pokémon for Japanese versions).

    You need to copy your save file under the name "save.gci", and the code you want to be executed upon entering a Pokémon battle (NOTE: its location in RAM may is only known at runtime) under the name "payload.bin", in the same folder as the executable.

  5. Looks like there is a buffer overflow vulnerability in the implementation of the script version of printf:

    ROM:801BE670 # int __fastcall scriptPrintf(void *format, void *args)
    ROM:801BE670 scriptPrintf:                           # CODE XREF: scriptStdFunctions2Handler+270p
    ROM:801BE670
    ROM:801BE670 .set var_12C, -0x12C
    ROM:801BE670 .set sprintf_buffer, -0x128
    ROM:801BE670 .set var_28, -0x28
    ROM:801BE670 .set var_1C, -0x1C
    ROM:801BE670 .set lr,  4
    ROM:801BE670
    ROM:801BE670                 stwu      r1, -0x130(r1)
    ROM:801BE674                 mflr      r0
    ROM:801BE678                 stw       r0, 0x130+lr(r1)
    ROM:801BE67C                 stmw      r25, 0x130+var_1C(r1)
    ROM:801BE680                 mr        r26, r3
    ROM:801BE684                 mr        r29, r4
    
    # ... NOTE: this function refers to "script error line[%d] : printf argument %d error \n"
    
    ROM:801BE840 loc_801BE840:                           # CODE XREF: scriptPrintf+1C4j
    ROM:801BE840                 add       r3, r29, r27  # var
    ROM:801BE844                 lha       r0, 0(r3)
    ROM:801BE848                 cmpwi     r0, 3
    ROM:801BE84C                 bne       loc_801BE884
    ROM:801BE850                 lwz       r4, 0x954(r26) # dst
    ROM:801BE854                 bne       loc_801BE860
    ROM:801BE858                 lwz       r6, 4(r3)
    ROM:801BE85C                 b         loc_801BE868
    ROM:801BE860 # ---------------------------------------------------------------------------
    ROM:801BE860
    ROM:801BE860 loc_801BE860:                           # CODE XREF: scriptPrintf+1E4j
    ROM:801BE860                 bl        scriptConvertToString
    ROM:801BE864                 mr        r6, r3
    ROM:801BE868
    ROM:801BE868 loc_801BE868:                           # CODE XREF: scriptPrintf+1ECj
    ROM:801BE868                 addi      r3, r1, 0x130+sprintf_buffer # str
    ROM:801BE86C                 addi      r4, r2, -0x56E8 # aSS # format
    ROM:801BE870                 mr        r5, r3
    ROM:801BE874                 crclr     4*cr1+eq
    ROM:801BE878                 bl        sprintf       # "%s%s" # BOOOOOOOOOOOOOOOOOOOOOOOOOOOOOM
    ROM:801BE87C                 mr        r25, r3
    ROM:801BE880                 b         loc_801BEA20
    
    # ...
    # the buffer is cleared IFF '\\n' is encountered
    ROM:801BEA2C # ---------------------------------------------------------------------------
    ROM:801BEA2C
    ROM:801BEA2C loc_801BEA2C:                           # CODE XREF: scriptPrintf+80j
    ROM:801BEA2C                 cmpwi     r0, 0x5C      # '\'
    ROM:801BEA30                 bne       loc_801BEAB8
    ROM:801BEA34                 addi      r30, r30, 1
    ROM:801BEA38                 lbz       r0, 0(r30)
    ROM:801BEA3C                 extsb     r0, r0
    ROM:801BEA40                 cmpwi     r0, 'n'       # '\n'
    ROM:801BEA44                 bne       loc_801BEA94
    ROM:801BEA48                 addi      r3, r1, 0x130+sprintf_buffer # str
    ROM:801BEA4C                 addi      r4, r2, -0x56D8 # aS_0 # format
    ROM:801BEA50                 mr        r5, r3
    ROM:801BEA54                 crclr     4*cr1+eq
    ROM:801BEA58                 bl        sprintf
    ROM:801BEA5C                 addi      r3, r1, 0x130+sprintf_buffer # msg
    ROM:801BEA60                 crclr     4*cr1+eq
    ROM:801BEA64                 bl        sendToLog     # '%s\n'
    ROM:801BEA68                 li        r5, 0
    ROM:801BEA6C                 li        r0, 0x100
    ROM:801BEA70                 addi      r3, r1, 0x130+sprintf_buffer
    ROM:801BEA74                 li        r4, 0
    ROM:801BEA78                 mtctr     r0
    ROM:801BEA7C
    ROM:801BEA7C loc_801BEA7C:                           # CODE XREF: scriptPrintf+418j
    ROM:801BEA7C                 stb       r4, 0(r3)     # clear temporary buffer
    ROM:801BEA80                 addi      r5, r5, 1
    ROM:801BEA84                 addi      r3, r3, 1
    ROM:801BEA88                 bdnz      loc_801BEA7C
    ROM:801BEA8C                 li        r25, 0
    ROM:801BEA90                 b         loc_801BEAC4
    
    # ...
    
    ROM:801BEAB8
    ROM:801BEAB8 loc_801BEAB8:                           # CODE XREF: scriptPrintf+3C0j
    ROM:801BEAB8                 addi      r3, r1, 0x130+sprintf_buffer
    ROM:801BEABC                 stbx      r0, r3, r25
    ROM:801BEAC0                 addi      r25, r25, 1
    ROM:801BEAC4
    ROM:801BEAC4 loc_801BEAC4:                           # CODE XREF: scriptPrintf+3B8j
    ROM:801BEAC4                                         # scriptPrintf+420j ...
    ROM:801BEAC4                 addi      r30, r30, 1
    ROM:801BEAC8
    ROM:801BEAC8 loc_801BEAC8:                           # CODE XREF: scriptPrintf+74j
    ROM:801BEAC8                 lbz       r3, 0(r30)
    ROM:801BEACC                 extsb     r0, r3
    ROM:801BEAD0                 cmpwi     r0, 0
    ROM:801BEAD4                 bne       loc_801BE6E8
    ROM:801BEAD8                 addi      r3, r1, 0x130+sprintf_buffer # msg
    ROM:801BEADC                 lbzx      r0, r3, r25
    ROM:801BEAE0                 extsb     r0, r0
    ROM:801BEAE4                 cmpwi     r0, 0xA       # '\n'
    ROM:801BEAE8                 beq       loc_801BEB04
    ROM:801BEAEC                 cmpwi     r25, 0
    ROM:801BEAF0                 beq       loc_801BEB04
    ROM:801BEAF4                 li        r0, 0xA
    ROM:801BEAF8                 stbx      r0, r3, r25   # msg
    ROM:801BEAFC                 crclr     4*cr1+eq
    ROM:801BEB00                 bl        sendToLog
    ROM:801BEB04
    ROM:801BEB04 loc_801BEB04:                           # CODE XREF: scriptPrintf+478j
    ROM:801BEB04                                         # scriptPrintf+480j
    ROM:801BEB04                 li        r3, 0         # empty string
    ROM:801BEB08
    ROM:801BEB08 loc_801BEB08:                           # CODE XREF: scriptPrintf+11Cj
    ROM:801BEB08                                         # scriptPrintf+1BCj ...
    ROM:801BEB08                 lmw       r25, 0x130+var_1C(r1)
    ROM:801BEB0C                 lwz       r0, 0x130+lr(r1)
    ROM:801BEB10                 mtlr      r0
    ROM:801BEB14                 addi      r1, r1, 0x130
    ROM:801BEB18                 blr
    ROM:801BEB18 # End of function scriptPrintf

  6. td;dr: So, it is basically possible to run arbitrary code on Pokémon Colosseum and xD, provided you can load modified save files. (even if it's actually useless ...)

    CSWIe3hWsAAo5AO.png:large

    How it works: On Pokémon Colosseum and xD, text, and especially Pokémon names, is stored as UTF-16 null-terminated strings (well, not UTF-16 exactly, but almost). When sending a Pokémon in battle, the games copies its name on a stack-allocated buffer, without proper bound-checking.

    # Pokémon , PAL
    ROM:8023B034 # =============== S U B R O U T I N E =======================================
    ROM:8023B034
    ROM:8023B034
    ROM:8023B034 sub_8023B034:                           # CODE XREF: sub_80238CF0+58p
    ROM:8023B034                                         # sub_8023AFE4+14p ...
    ROM:8023B034
    ROM:8023B034 .set var_7C, -0x7C
    ROM:8023B034 .set var_78, -0x78
    ROM:8023B034 .set var_4C, -0x4C
    ROM:8023B034 .set pkmNameBuffer, -0x48
    ROM:8023B034 .set var_1F, -0x1F
    ROM:8023B034 .set var_1B, -0x1B
    ROM:8023B034 .set var_C, -0xC
    ROM:8023B034 .set arg_4,  4
    ROM:8023B034
    ROM:8023B034                 stwu      r1, -0x80(r1)
    ROM:8023B038                 mflr      r0
    ROM:8023B03C                 stw       r0, 0x80+arg_4(r1)
    ROM:8023B040                 stmw      r29, 0x80+var_C(r1)
    ROM:8023B044                 mr        r29, r5
    ROM:8023B048                 mr        r31, r3
    ROM:8023B04C                 mr        r30, r7
    ROM:8023B050                 mr        r5, r6
    ROM:8023B054                 bl        sub_8023B16C
    ROM:8023B058                 mr        r0, r3
    ROM:8023B05C                 mr        r3, r31       # pkm
    ROM:8023B060                 mr        r31, r0
    ROM:8023B064                 addi      r4, r1, 0x80+pkmNameBuffer # dstName
    ROM:8023B068                 bl        copyPkmInfoForBattle # this will copy the Pokémon name into r4, WITHOUT CHECKING BOUNDARIES
    
    #etc.....................................................................................
    #.......................................................................................
    
    ROM:8023B0FC
    ROM:8023B0FC loc_8023B0FC:                           # CODE XREF: sub_8023B034+70j
    ROM:8023B0FC                 lmw       r29, 0x80+var_C(r1)
    ROM:8023B100                 lwz       r0, 0x80+arg_4(r1)
    ROM:8023B104                 mtlr      r0
    ROM:8023B108                 addi      r1, r1, 0x80
    ROM:8023B10C                 blr
    ROM:8023B10C # End of function sub_8023B034

    That means, if you fill your Pokémon's name (located at offset 0x4e (xD) or 0x2e (Colo) in the Pokémon data structure) with 76 (xD) or 124 (Colosseum) bytes of anything but not 00 00 or FF FF, followed by an address, the game will jump to that address.

    Now, what makes it actually exploitable is that the address of in-battle Pokémon is always the same for a given version. (804DC708 for PAL xD etc...).

    After jumping to the Pokémon data address (knowing its address), we can then jump to the PC data in a region-independent way:

    # 
    
    lwz       r3, -0x4720(r13) # This is the saved data structure
    addi      r3, r3, 0xAD0	# PC data address
    mtctr	  r3
    bctrl	  
    
    # Colosseum
    
    lwz       r3, -0x5A58(r13) # This is the saved data structure
    addi      r3, r3, 0xB88	# PC data address
    mtctr	  r3
    bctrl	  

    This eventually enable us to execute at most 0xbc50 (xD) or 0x7198 (Colosseum) bytes of code.

  7. Sounds good. So I've been looking at some of the disassembled scripts and I think I'm starting to get a feel for how it all works. For class methods like Party::recieveGiftOrEventPkm(id) or Character::setVisibility did you find out what they do by trial and error and did you name them yourself?

    Named them myself (see FunctionInfo for the "whole" list).

    For Party::recieveGiftOrEvent I already knew the function that was used to generate never-shiny-if-shadow/can-be-shiny-if-not Pokémon, and for Character::setVisibility it was indeed by trial and error when debugging.

  8. I've not tried to modify anything ... but looking at the code, you can lift the restriction on Shadow Pkms in the Daycare (w/o adding any instruction, just by modifiying the existing ones), and I'm sure you can change the Pokémon given by Duking (+ Elekid, + the Johto starters) (again w/o adding anything), refer to Party::recieveGiftOrEventPkm(id)

  9. No, it can just disassemble.

    If you want to modify the script, you will have to do this by hand. Since all code offsets (in FTBL, HEAD, jumps and calls) are absolute, the easiest way to add code to an existing function, though a little bit hackish, is to add the code at the end of the CODE section, jump to this portion, and jump back (as well as updating the script total size (offset 4), and the CODE section size (CODE offset 4)).

  10. I've figured out how scripts work in Pokémon xD, and therefore wrote a script disassembler (in Python 3.x). Sorry if it's a mess.

    There are basically two scripts run at the same time: the "common" script, used for a lot of things, loaded after the "Health and safety" screen, and the current map's own script.

    I don't know where the common script is stored, so I've dumped it from RAM (you can find it in in the link below, along with the disassembler). This common script seems to do strange things anyways. For everything else, refer to the disassembler various docstrings.

    I consider the Daycare's script (M3_houseD_1F.fsys/1) to be a good script to begin with. The test script (in Script_test.fsys) is interesting too.

    Download link (download the source code, since it's Python): https://github.com/TuxSH/XDscriptTools/releases/tag/v0.1

  11. I have the following hard-coded function, not sure if it is called (after using your AR code):

    ROM:80154060 # =============== S U B R O U T I N E =======================================

    ROM:80154060

    ROM:80154060

    ROM:80154060 # int __fastcall recieveEventJolteon(void *partyData, __int8 unused)

    ROM:80154060 recieveEventJolteon: # CODE XREF: scriptRecieveSpecialPkm+60p

    ROM:80154060

    ROM:80154060 .set var_D8, -0xD8

    ROM:80154060 .set var_8, -8

    ROM:80154060 .set var_4, -4

    ROM:80154060 .set arg_4, 4

    ROM:80154060

    ROM:80154060 stwu r1, -0xE0(r1)

    ROM:80154064 mflr r0

    ROM:80154068 li r4, 2

    ROM:8015406C li r5, 0

    ROM:80154070 stw r0, 0xE0+arg_4(r1)

    ROM:80154074 stw r31, 0xE0+var_4(r1)

    ROM:80154078 stw r30, 0xE0+var_8(r1)

    ROM:8015407C mr r30, r3

    ROM:80154080 bl getPlayerDataField

    ROM:80154084 mr r0, r3

    ROM:80154088 li r3, 0 # baseAddress

    ROM:8015408C mr r31, r0

    ROM:80154090 li r4, 1 # what

    ROM:80154094 bl getVersionInfo

    ROM:80154098 mr r6, r3 # versionInfo

    ROM:8015409C addi r3, r1, 0xE0+var_D8 # pkmData

    ROM:801540A0 li r4, 0x87 # species

    ROM:801540A4 li r5, 0x1A # level

    ROM:801540A8 bl initStdPkmCreation

    ROM:801540AC addi r3, r1, 0xE0+var_D8

    ROM:801540B0 li r4, 0

    ROM:801540B4 li r5, 0x62

    ROM:801540B8 bl sub_80142A40

    ROM:801540BC addi r3, r1, 0xE0+var_D8

    ROM:801540C0 li r4, 1

    ROM:801540C4 li r5, 0x1C

    ROM:801540C8 bl sub_80142A40

    ROM:801540CC addi r3, r1, 0xE0+var_D8

    ROM:801540D0 li r4, 2

    ROM:801540D4 li r5, 0x10E

    ROM:801540D8 bl sub_80142A40

    ROM:801540DC addi r3, r1, 0xE0+var_D8

    ROM:801540E0 li r4, 3

    ROM:801540E4 li r5, 0x54

    ROM:801540E8 bl sub_80142A40

    ROM:801540EC mr r7, r31 # SIDTID

    ROM:801540F0 addi r3, r1, 0xE0+var_D8 # pkmData

    ROM:801540F4 li r4, 0 # wantedGender

    ROM:801540F8 li r5, -1 # wantedNature

    ROM:801540FC li r6, 0 # wantedShininess

    ROM:80154100 bl generatePIDWithConstraints # (Male, any nature, never shiny)

    ROM:80154104 mr r0, r3

    ROM:80154108 addi r3, r1, 0xE0+var_D8 # pkmData

    ROM:8015410C mr r7, r0 # value

    ROM:80154110 li r4, 0 # unk

    ROM:80154114 li r5, 0x6F # action

    ROM:80154118 li r6, 0 # optVal

    ROM:8015411C bl setPkmAttribute

    ROM:80154120 addi r3, r1, 0xE0+var_D8 # pkmData

    ROM:80154124 li r4, 0 # unk

    ROM:80154128 li r5, 0x79 # action

    ROM:8015412C li r6, 0 # optVal

    ROM:80154130 li r7, 0x4A6F # value

    ROM:80154134 bl setPkmAttribute

    ROM:80154138 addi r3, r1, 0xE0+var_D8 # pkmData

    ROM:8015413C li r4, 0 # unk

    ROM:80154140 li r5, 0x99 # action

    ROM:80154144 li r6, 0 # optVal

    ROM:80154148 li r7, 0xDC # value

    ROM:8015414C bl setPkmAttribute

    ROM:80154150 addi r3, r1, 0xE0+var_D8 # pkmData

    ROM:80154154 bl updateAllPkmStats

    ROM:80154158 mr r3, r30

    ROM:8015415C addi r4, r1, 0xE0+var_D8

    ROM:80154160 li r5, 0x259

    ROM:80154164 li r6, 4

    ROM:80154168 li r7, 0

    ROM:8015416C bl sub_8014E820

    ROM:80154170 lwz r0, 0xE0+arg_4(r1)

    ROM:80154174 lwz r31, 0xE0+var_4(r1)

    ROM:80154178 lwz r30, 0xE0+var_8(r1)

    ROM:8015417C mtlr r0

    ROM:80154180 addi r1, r1, 0xE0

    ROM:80154184 blr

    ROM:80154184 # End of function recieveEventJolteon

  12. Nice ;)

    Btw, is your patch based on the NTSC or the PAL version of the game ?

    About the beta starters, are they the male-only shiny locked ? I think about the ones received through the implementation of the script built-in fuction Party::receieveGiftOrEventPkm(id) (here id could be equal to 1 or 2). Look at 801C9FCC for PAL, otherwise look for the following sequence :

    94 21 FF 70 7C 08 02 A6 90 01 00 94 BF 61 00 7C

    7C 7B 1B 78 38 60 00 00 38 80 00 02 48 00 6A A5

×
×
  • Create New...