Users browsing this thread: 1 Guest(s)
PCSX Modified for Sprite Ripping
#1
Here is a modified PCSX version: http://minus.com/lb0rni5snRrf00

It is geared towards sprite ripping. Using it is very easy. I will again use Beyond the Beyond as a typical example (just because it is one of the best jRPGs ever made!).

While Beyond the Beyond stores most graphics uncompressed 8-bit images, easy to get sheets, unfortunately *.DAT files (containing these big isometric sprites used in battle) are seems to be compressed.

So we have no choice but to reverse engineer the game. Play the game till the battle starts (save a state before it). Now hit V to view game RAM, you will see something like this:
[Image: bpset.jpg]

Obviously this is the place where game code unpacks the sheet, so shift-click right mouse button inside this sheet to set a write breakpoint. Now load the saved state we made just before this battle and go into battle again. In the console window you will notice a bunch of "WB: PC=XXXXXX" messages, that werent there before:
Code:
WB: PC=0x80011DB0
WB: PC=0x80011DB0
WB: PC=0x80011DB0
WB: PC=0x80011D3C
WB: PC=0x80011DA4
WB: PC=0x80011D88
WB: PC=0x80011DA4
WB: PC=0x80011D88
WB: PC=0x80011D88
WB: PC=0x80011DA4
...

Yay! We have found the unpacking routine and done with playing the game. Time to run IDA Pro (AFAIK, free version doesnt support MIPS). Open a game inside IDA (usually it is called like SCUS_947.02 or has an EXE extension). Do Jump -> Jump to Address and enter 0x80011DB0.

You will end in the middle of unpacking subroutine (which in our case starts at 0x80011CE0):
Code:
TEXT:80011CE0  # =============== S U B R O U T I N E =======================================
TEXT:80011CE0
TEXT:80011CE0
TEXT:80011CE0 unpack:                                  # CODE XREF: sub_800356D4+A4p
TEXT:80011CE0                                          # sub_80035A4C+40p ...
TEXT:80011CE0
TEXT:80011CE0 var_6           = -6
TEXT:80011CE0
TEXT:80011CE0                 addiu   $sp, -0x18
TEXT:80011CE4                 move    $a2, $a1
TEXT:80011CE8                 lhu     $a1, 0x18+var_6($sp)
TEXT:80011CEC                 move    $v0, $zero
TEXT:80011CF0                 move    $v1, $a0
TEXT:80011CF4
TEXT:80011CF4 for_loop:                                # CODE XREF: unpack+D4j
TEXT:80011CF4                 srl     $t6, $v0, 1
TEXT:80011CF8
TEXT:80011CF8 for_loop2:                               # CODE XREF: unpack:if2j
TEXT:80011CF8                                          # unpack+C8j
TEXT:80011CF8                 andi    $v0, $t6, 0xFFFF
TEXT:80011CFC                 bnez    $v0, if1
TEXT:80011D00                 nop
TEXT:80011D04                 lhu     $a1, 0($a2)
TEXT:80011D08                 addiu   $a2, 2
TEXT:80011D0C                 li      $v0, 0x8000
TEXT:80011D10
TEXT:80011D10 if1:                                     # CODE XREF: unpack+1Cj
TEXT:80011D10                 lhu     $a3, 0($a2)
TEXT:80011D14                 and     $t8, $a1, $v0
TEXT:80011D18                 beqz    $t8, break
TEXT:80011D1C                 addiu   $a2, 2
TEXT:80011D20                 beqz    $a3, return
TEXT:80011D24                 andi    $t1, $a3, 0x1F
TEXT:80011D28                 srl     $t9, $a3, 5
TEXT:80011D2C                 sll     $t5, $t9, 1
TEXT:80011D30                 subu    $t3, $v1, $t5
TEXT:80011D34                 lhu     $t6, 0($t3)
TEXT:80011D38                 andi    $t4, $t1, 0xFFFF
TEXT:80011D3C                 sh      $t6, 0($v1)
TEXT:80011D40                 lhu     $t7, 2($t3)
TEXT:80011D44                 andi    $t8, $t4, 1
TEXT:80011D48                 andi    $t0, $t1, 0xFFFF
TEXT:80011D4C                 addiu   $v1, 4
TEXT:80011D50                 addiu   $t2, $t3, 4
TEXT:80011D54                 beqz    $t8, if2
TEXT:80011D58                 sh      $t7, -2($v1)
TEXT:80011D5C                 lhu     $t9, 0($t2)
TEXT:80011D60                 addiu   $t0, $t4, -1
TEXT:80011D64                 andi    $t5, $t0, 0xFFFF
TEXT:80011D68                 addiu   $v1, 2
TEXT:80011D6C                 addiu   $t2, 2
TEXT:80011D70                 move    $t0, $t5
TEXT:80011D74                 sh      $t9, -2($v1)
TEXT:80011D78
TEXT:80011D78 if2:                                     # CODE XREF: unpack+74j
TEXT:80011D78                 beqz    $t0, for_loop2
TEXT:80011D7C                 srl     $t6, $v0, 1
TEXT:80011D80
TEXT:80011D80 do_while:                                # CODE XREF: unpack+C0j
TEXT:80011D80                 lhu     $t6, 0($t2)
TEXT:80011D84                 addiu   $t0, -2
TEXT:80011D88                 sh      $t6, 0($v1)
TEXT:80011D8C                 lhu     $t7, 2($t2)
TEXT:80011D90                 andi    $t8, $t0, 0xFFFF
TEXT:80011D94                 addiu   $v1, 4
TEXT:80011D98                 addiu   $t2, 4
TEXT:80011D9C                 move    $t0, $t8
TEXT:80011DA0                 bnez    $t8, do_while
TEXT:80011DA4                 sh      $t7, -2($v1)
TEXT:80011DA8                 b       for_loop2
TEXT:80011DAC                 srl     $t6, $v0, 1
TEXT:80011DB0  # ---------------------------------------------------------------------------
TEXT:80011DB0
TEXT:80011DB0 break:                                   # CODE XREF: unpack+38j
TEXT:80011DB0                 sh      $a3, 0($v1)
TEXT:80011DB4                 b       for_loop
TEXT:80011DB8                 addiu   $v1, 2
TEXT:80011DBC  # ---------------------------------------------------------------------------
TEXT:80011DBC
TEXT:80011DBC return:                                  # CODE XREF: unpack+40j
TEXT:80011DBC                 subu    $v0, $v1, $a0
TEXT:80011DC0                 jr      $ra
TEXT:80011DC4                 addiu   $sp, 0x18
TEXT:80011DC4  # End of function unpack


After decompiling it into C/C++, you will get the following code, which is a simple LZ unpacker, you have probably already seen a thousand times:
Code:
// Typical LZ with mask word, that says which of the following words are backrefs
static int unpack(u2 *D, u2 *S) {
  u2 C, M, B, *R, *P = D;

  for (B=0; ; B>>=1) {
    if (!B) { // done this mask?
      M = *S++;
      B = 0x8000;
    }
    C = *S++;
    if (!(M&B)) { //non backref?
      *P++ = C;
      continue;
    }

    if (!C) break; // zero backref ends decoding

    R = P - (C>>5);
    C &= 0x1f;
    C+=2;
    while (C-- > 0) *P++ = *R++;
  }
  return (u1*)P - (u1*)D;


Now time for ImageMagic, which assembles all these small 256x256 battle sheets into one huge:


[MOD NOTE: Spoiler tagged the absurdly huge image for the sake of others' convenience. Try to do this for future images of similar size.]
Thanked by:
#2
It's possible to use it with Ojamajo Doremi Nijiro no Para-dice and Super Tokusatsu Wars 2001?
Thanked by:
#3
(08-25-2012, 08:38 PM)Toshio Wrote: It's possible to use it with Ojamajo Doremi Nijiro no Para-dice and Super Tokusatsu Wars 2001?
Some games use uncompressed graphics and breakpoint wont be triggered (DMA transfers dont trigger it). Just look for graphic files inside CD image.
Thanked by:


Forum Jump: