SPU Isolated Modules Reverse Engineering: Difference between revisions

From PS3 Developer wiki
Jump to navigation Jump to search
No edit summary
 
(38 intermediate revisions by 16 users not shown)
Line 1: Line 1:
== anergistic ==
Using a static analysis (IDA) could give you a good view of what the program does, but sometimes you want to know what a program does in real time and how it reacts to different parameters, this is where anergistics becomes a powerful tool. It simulates the SPU including its communication, and storage.
=== Current repos===
*https://github.com/kraiskil/anergistic.git
*http://git.gitbrew.org/ps3/anergistic.git/
*https://github.com/psfree/anergistic
*<span style="text-decoration: line-through;">http://foxbrew.org/git/anergistic.git/</span>
*<span style="text-decoration: line-through;">http://git.fail0verflow.com/?p=anergistic.git</span>
=== Usage ===
anergistic can be launched in two different modes, one that '''only emulates''' (runs) the program through the SPU and the the other that lets you '''debug''' the process through gdb
==== only emulate ====
{{keyboard|content=<syntaxhighlight lang="bash">./anergistic spu_elf_name.elf</syntaxhighlight>}}
this mode runs an elf with all the parameters and actions defined on main.c, channel.c a
==== debug ====
terminal 1
{{keyboard|content=<syntaxhighlight lang="bash">./anergistic -g1234 spu_elf_name.elf</syntaxhighlight>}}
simulate debug server in the local host on port 1234
terminal 2
{{keyboard|content=<syntaxhighlight lang="bash">
spu-gdb spu_elf_name.elf
(gdb)target remote :1234
</syntaxhighlight>}}
connect to the local host on port 1234
(gdb)help will give you information of the command available
==== Documentation ====
*http://publib.boulder.ibm.com/infocenter/ieduasst/stgv1r0/topic/com.ibm.iea.cbe/cbe/1.0/LinuxOnCell/L2T1H1_31_LinuxonCellToolchainGDB.pdf
*SPU specific commands
**http://sourceware.org/gdb/onlinedocs/gdb/SPU.html
this mode performs the same as above but lets you debug the process through gdb
=== Customizations ===
See example below.
'''Running in aim_spu_module anergistic'''
=== Problems ===
==== Connection problem ====
when in debugger mode
<pre>
Waiting for gdb to connect...
Client connected.
recv failed: Success
</pre>
==== Solution ====
Use spu-gdb.
=== Tools ===
[http://pastie.org/2810870 gnuify_ida.pl][http://paste.ubuntu.com/25615421/ mirror]
Use this to convert IDA disassembly into a format suitable for GNU AS. Literals in IDA are unsigned while AS expects signed literals. Conversion of literals is a work in progress.
== Loading Isolated Modules in GameOS ==
This code kinda represents how GameOS applications load and execute isolated SPU SELFs. For example: psp emulator.
<source lang="C">
  sys_spu_initialize(1,1);
  syscall(230, sys_spu_t *id,img &iso_spuSCEself,void *arg,0,0,0); //sys_isolated_spu_create
  sys_ppu_thread_create(sys_ppu_thread_t *thread_id,void* iso_spu_handler,sys_spu_t *id, 0x64, 0x1000, 2,"iso_spu_handler");
  syscall(233, sys_spu_t *id,2,0,sys_interrupt_tag_t intrtag);  //sys_iso_spu_create_interrupt_tag
  sys_interrupt_thread_establish(sys_interrupt_thread_handle_t *ih,sys_interrupt_tag_t intrtag,sys_ppu_thread_t t_id,
  sys_spu_t id,0);
  syscall(234, sys_spu_t *id,2,7); //sys_iso_spu_set_int_mask
  syscall(232, sys_spu_t *id);    //sys_iso_spu_start
  ...
  iso_spu_handler(...) {
  syscall(237, sys_spu_t id,2,void *out1);  // sys_iso_spu_get_int_stat
  syscall(240, void *out2, out1);          // sys_iso_spu_mmio_read / sys_isolated_spu_read_puint_mb ?
  syscall(236, sys_spu_t id,2, out1)        // sys_iso_spu_set_int_stat
  sys_interrupt_thread_eoi()
  }
</source>
== aim_spu_module ==
== aim_spu_module ==
It is used to retrieve the device type, device id, open psid and the pscode from the EID data that is passed in.
 
It is used to retrieve the device type, Device Id, OpenPSID and the PsCode from the EID0 data that is passed in.


=== Debug messages ===
=== Debug messages ===
{| class="wikitable"
! colspan="2" | Address !! rowspan="2" | Message
|-
! ?&nbsp;3.41&nbsp;? !! 355&nbsp;CEX
|-
| 0x36f0 || 0x3570 || "(spu)start aim spu module!\n"
|-
| 0x3710 || 0x3590 || "(spu) PU DMA area start address is not align 16byte\n"
|-
| 0x3750 || 0x35d0 || "(spu) PU EID area start address is not align 16byte\n"
|-
| 0x3790 || 0x3610 || "(spu) PU DMA area size is not equall to AIM_DMA_SIZE\n"
|}
These messages are sent via DMA to the PPU if a debug output address is specified.
=== Data ===
{| class="wikitable"
{| class="wikitable"
| Address || Message
! colspan="2" | Address !! rowspan="2" | Message
|-
|-
| 0x36f0 || "(spu)start aim spu module!\n"
! ?&nbsp;3.41&nbsp;? !! 355&nbsp;CEX
|-
|-
| 0x3710 || "(spu) PU DMA area start address is not align 16byte\n"
| 0x37e0 || - || Reference Tool fallback IDPS
|-
|-
| 0x3750 || "(spu) PU EID area start address is not align 16byte\n"
| 0x37f0 - ... || 0x3650 - ... || Start of [[Keys#aim_spu_module_Keys|aim_spu_module keys]]
|-
|-
| 0x3790 || "(spu) PU DMA area size is not equall to AIM_DMA_SIZE\n"
| 0x3ac0 || 0x3870 || AES sbox (16*16 bytes)
|-
| 0x3c70 || 0x3a20 || AES inverse sbox (16*16 bytes)
|}
|}


=== Functions ===
=== Functions ===
{| class="wikitable"
{| class="wikitable"
| Address || Name || Parameters || Info
! colspan="2" | Address !! rowspan="2" | Name !! rowspan="2" | Parameters !! rowspan="2" | Info
|-
! &nbsp;3.41&nbsp; CEX/DEX !! 355&nbsp;CEX
|-
| 0x9e0 ||  || stop_func || unknown || Stops the module execution with various stop codes.
|-
| 0xa18 ||  || main_func || unknown || Main routine.
|-
| 0xf18 ||  || response || unknown || Sends response to ppu over DMA.
|-
| 0x1158 ||  || process_eid || unknown || Decrypts EID0.
|-
|-
| 0x1440 || debug_print || unknown || As the name already states...
| 0x1438 || || prepare_print || unknown || Prepares debug output.
|-
|-
| 0x30c0 || do_dma || ls_addr:$4, dma_effective_addr:$5, size:$6, tag_id:$7, unk0:$8, unk1:$9 || Used to dma data in and out of the isolated module's LS.
| 0x1440 || || debug_print || unknown || As the name already states... (this outputs over DMA)
|-
|-
| 0x3168 || write_tag_mask_bit || mask_bit:$4 || Used to set a specific bit in MFC_WrTagMask.
| 0x17f0 ||  || - || - || AES 1 Part of aes implementation.
|-
| 0x1c48 ||  || aes_encrypt_ecb || - || AES 2 Part of aes implementation.
|-
| 0x1df0 ||  || cellCryptoSpuAesCbcCfb128Decrypt || - || AES 3 Probably part of aes implementation.
|-
| 0x20f0 ||  || aes_omac1 || - || AES 4 Probably part of aes implementation.
|-
| 0x2300 ||  || aes_set_key_dec || - || AES 5 Probably part of aes implementation.
|-
| 0x2418 ||  || aes_decrypt_ecb || - || AES 6 Part of aes implementation.
|-
| 0x2608 ||  || aes_decrypt_ecb_aligned || - || AES 7 Part of aes implementation.
|-
| 0x30c0 ||  || do_dma || ls_addr:$4, dma_effective_addr:$5, size:$6, tag_id:$7, unk0:$8, unk1:$9 || Used to dma data in and out of the isolated module's LS.
|-
| 0x3168 ||  || write_tag_mask_bit || mask_bit:$4 || Used to set a specific bit in MFC_WrTagMask.
|}
|}


Line 30: Line 176:
The complete disassembly is available at [http://pastebin.com/7vArGweJ].
The complete disassembly is available at [http://pastebin.com/7vArGweJ].


===== do_dma =====
== Decrypting EID ==
From 0x30c0 to 0x3130 it just checks if the parameters are ok (ls_addr != 0, dma_effective_addr != 0, size-1 < 0x3fff, tag_id < 32) else it will jump to 0x3160.
 
=== Dumper iso.self ===
 
Is there one ?
 
=== Dumper Payload ===
 
* [https://web.archive.org/web/20150912102728/http://pastie.org/pastes/2101977 Dumper payload code]
* [http://paste.ubuntu.com/25615310/ mirror]
 
=== Running aim_spu_module in anergistic ===
 
* [https://web.archive.org/web/20150912053633/http://pastie.org/2000330 Partial code modified to run aim_spu_module]
* [http://paste.ubuntu.com/25615344/ mirror]
 
== isoldr ==
 
Loads, decrypts, runs isolated modules, and creates through AES the required key in LS 0x0.
 
=== Debug messages ===
 
This module doesn't contain debug messages.
 
=== Data ===
 
{| class="wikitable"
! colspan="2" | Address !! rowspan="2" | Message
|-
! ?&nbsp;3.41&nbsp;? !! 355&nbsp;CEX
|-
|-
| 0x34C40 - ... || 0x34d10 || Start of isoldr keys [[Keys#Modules]]
|-
| 0x35130 || 0x35050 || AES sbox (16*16 bytes)
|-
| 0x35300 || 0x35220 || AES inverse sbox (16*16 bytes)
|}
 
=== Functions ===
 
{| class="wikitable"
! colspan="2" | Address !! rowspan="2" | Name !! rowspan="2" | Parameters !! rowspan="2" | Info
|-
! ?&nbsp;3.41&nbsp;? !! 355&nbsp;CEX
|-
| 0x259E0 ||  || cleanup_jump_code || unknown || cleans all the registers and jump to the loader
|-
| 0x259E0 ||  || main_func || unknown || Main routine.
|-
| 0x346B0 ||  || write_tag_mask_bit || mask_bit:$4 || Used to set a specific bit in MFC_WrTagMask.
|-
| 0x27438 || || aes128_cbc_decrypt || ||
|-
| 0x27508 || || aes128_cbc_encrypt || ||
|-
| 0x29DC0 || || aes_ctr || ||
|-
| 0x2BB28 || || aes_set_key_enc || ||
|-
| 0x2C0D0 || || cellCryptoSpuAesCbcCfb128Encrypt || ||
|-
| 0x2C240 || || cellCryptoSpuAesCbcCfb128Decrypt || ||
|-
| 0x2C540 || || cellCryptoSpuAesCtr || ||
|-
| 0x2C8D0 || || aes_omac1 || ||
|-
| 0x2CAE0 || || sha1_buffer || ||
|-
| 0x2CB70 || || sha1_hmac_init || ||
|-
| 0x2CC70 || || sha1_hmac_update || ||
|-
| 0x2CC90 || || sha1_hmac_final || ||
|-
| 0x2CD28 || || sha1_hmac_buffer || ||
|-
| 0x2CDC8 || || aes_set_key_dec || ||
|-
| 0x2CEE0 || || aes_encrypt_ecb_aligned || ||
|-
| 0x2D7C0 || || aes_decrypt_ecb || ||
|-
| 0x2D9B0 || || aes_decrypt_ecb_aligned || ||
|-
| 0x2E450 || || sha1_init || ||
|-
| 0x2E4C8 || || sha1_update || ||
|-
| 0x2E700 || || sha1_final || ||
|-
| 0x2EA88 || || sha1_process || ||
|}
 
* [https://web.archive.org/web/20141118195818/http://pastie.org/2774207 REed functions names from FW 3.41 isoldr] (offsets relative to segment start).
* [http://paste.ubuntu.com/25615363/ mirror]


//(ls_addr:$4, dma_effective_addr:$5, size:$6, tag_id:$7, unk0:$8, unk1:$9)
//...
{
  //3134: 21 a0 08 0a wrch $MFC_LSA,$10
  wrch(MFC_LSA, ls_addr);
  //3138: 21 a0 08 85 wrch $MFC_EAH,$5
  wrch(MFC_EAH, dma_effective_addr);
  //313c: 3f e1 02 8a shlqbyi $10,$5,4
  //3140: 21 a0 09 0a wrch $MFC_EAL,$10
  wrch(MFC_EAL, dma_effective_addr << 4);
  //3144: 21 a0 09 86 wrch $MFC_Size,$6
  wrch(MFC_Size, size);
  //3148: 21 a0 0a 07 wrch $MFC_TagID,$7
  wrch(MFC_TagID, tag_id);
  //314c: 0f 64 04 06 shli $6,$8,16
  //3150: 08 22 43 05 or $5,$6,$9
  //3154: 21 a0 0a 85 wrch $MFC_Cmd,$5
  wrch(MFC_Cmd, (unk0 << 16) | unk1);
  //3158: 40 80 00 03 il $3,0
  //315c: 35 00 00 00 bi $lr
  return 0; //0 is probably success
  err:;
  //3160: 40 80 04 83 il $3,9
  //3164: 35 00 00 00 bi $lr
  return 9; //9 is probably failure
}


===== write_tag_mask_bit =====
{{Reverse engineering}}<noinclude>[[Category:Main]]</noinclude>
//(tag_mask_bit:$4)
{
  //3168: 40 80 00 02 il $2,0 //Update immediately, unconditional.
  //316c: 21 a0 0b 82 wrch $MFC_WrTagUpdate,$2
  wrch(MFC_WrTagUpdate, 0);
  //3170: 01 e0 0b 83 rchcnt $3,$MFC_WrTagUpdate
  //3174: 7c 00 41 85 ceqi $5,$3,1
  //3178: 20 7f ff 05 brz $5,0x3170 # 3170
  while(rchcnt(MFC_WrTagUpdate) != 1);
  //317c: 01 a0 0c 02 rdch $2,$MFC_RdTagStat
  $2 = rdch(MFC_RdTagStat);
  //3180: 0b 61 01 86 shl $6,$3,$4
  //3184: 21 a0 0b 06 wrch $MFC_WrTagMask,$6
  wrch(MFC_WrTagMask, 1 << tag_mask_bit);
  //3188: 40 80 01 03 il $3,2 //Update tag status if or when all enabled tag groups have “no outstanding operation” status.
  //318c: 21 a0 0b 83 wrch $MFC_WrTagUpdate,$3
  wrch(MFC_WrTagUpdate, 2);
  //3190: 01 a0 0c 02 rdch $2,$MFC_RdTagStat
  $2 = rdch(MFC_RdTagStat);
  //3194: 35 00 00 00 bi $lr
  return;
}

Latest revision as of 17:47, 15 September 2021

anergistic[edit | edit source]

Using a static analysis (IDA) could give you a good view of what the program does, but sometimes you want to know what a program does in real time and how it reacts to different parameters, this is where anergistics becomes a powerful tool. It simulates the SPU including its communication, and storage.

Current repos[edit | edit source]

Usage[edit | edit source]

anergistic can be launched in two different modes, one that only emulates (runs) the program through the SPU and the the other that lets you debug the process through gdb

only emulate[edit | edit source]

Type This
./anergistic spu_elf_name.elf

this mode runs an elf with all the parameters and actions defined on main.c, channel.c a

debug[edit | edit source]

terminal 1

Type This
./anergistic -g1234 spu_elf_name.elf

simulate debug server in the local host on port 1234

terminal 2

Type This
spu-gdb spu_elf_name.elf 
(gdb)target remote :1234

connect to the local host on port 1234

(gdb)help will give you information of the command available

Documentation[edit | edit source]

this mode performs the same as above but lets you debug the process through gdb

Customizations[edit | edit source]

See example below.

Running in aim_spu_module anergistic

Problems[edit | edit source]

Connection problem[edit | edit source]

when in debugger mode

Waiting for gdb to connect...
Client connected.
recv failed: Success

Solution[edit | edit source]

Use spu-gdb.

Tools[edit | edit source]

gnuify_ida.plmirror

Use this to convert IDA disassembly into a format suitable for GNU AS. Literals in IDA are unsigned while AS expects signed literals. Conversion of literals is a work in progress.

Loading Isolated Modules in GameOS[edit | edit source]

This code kinda represents how GameOS applications load and execute isolated SPU SELFs. For example: psp emulator.

  sys_spu_initialize(1,1);
  syscall(230, sys_spu_t *id,img &iso_spuSCEself,void *arg,0,0,0); //sys_isolated_spu_create
  sys_ppu_thread_create(sys_ppu_thread_t *thread_id,void* iso_spu_handler,sys_spu_t *id, 0x64, 0x1000, 2,"iso_spu_handler");
  syscall(233, sys_spu_t *id,2,0,sys_interrupt_tag_t intrtag);   //sys_iso_spu_create_interrupt_tag
  sys_interrupt_thread_establish(sys_interrupt_thread_handle_t *ih,sys_interrupt_tag_t intrtag,sys_ppu_thread_t t_id, 
  sys_spu_t id,0);
  syscall(234, sys_spu_t *id,2,7); //sys_iso_spu_set_int_mask
  syscall(232, sys_spu_t *id);     //sys_iso_spu_start
  ...

  iso_spu_handler(...) {
  syscall(237, sys_spu_t id,2,void *out1);  // sys_iso_spu_get_int_stat
  syscall(240, void *out2, out1);           // sys_iso_spu_mmio_read / sys_isolated_spu_read_puint_mb ?
  syscall(236, sys_spu_t id,2, out1)        // sys_iso_spu_set_int_stat
  sys_interrupt_thread_eoi()
  }

aim_spu_module[edit | edit source]

It is used to retrieve the device type, Device Id, OpenPSID and the PsCode from the EID0 data that is passed in.

Debug messages[edit | edit source]

Address Message
? 3.41 ? 355 CEX
0x36f0 0x3570 "(spu)start aim spu module!\n"
0x3710 0x3590 "(spu) PU DMA area start address is not align 16byte\n"
0x3750 0x35d0 "(spu) PU EID area start address is not align 16byte\n"
0x3790 0x3610 "(spu) PU DMA area size is not equall to AIM_DMA_SIZE\n"

These messages are sent via DMA to the PPU if a debug output address is specified.

Data[edit | edit source]

Address Message
? 3.41 ? 355 CEX
0x37e0 - Reference Tool fallback IDPS
0x37f0 - ... 0x3650 - ... Start of aim_spu_module keys
0x3ac0 0x3870 AES sbox (16*16 bytes)
0x3c70 0x3a20 AES inverse sbox (16*16 bytes)

Functions[edit | edit source]

Address Name Parameters Info
 3.41  CEX/DEX 355 CEX
0x9e0 stop_func unknown Stops the module execution with various stop codes.
0xa18 main_func unknown Main routine.
0xf18 response unknown Sends response to ppu over DMA.
0x1158 process_eid unknown Decrypts EID0.
0x1438 prepare_print unknown Prepares debug output.
0x1440 debug_print unknown As the name already states... (this outputs over DMA)
0x17f0 - - AES 1 Part of aes implementation.
0x1c48 aes_encrypt_ecb - AES 2 Part of aes implementation.
0x1df0 cellCryptoSpuAesCbcCfb128Decrypt - AES 3 Probably part of aes implementation.
0x20f0 aes_omac1 - AES 4 Probably part of aes implementation.
0x2300 aes_set_key_dec - AES 5 Probably part of aes implementation.
0x2418 aes_decrypt_ecb - AES 6 Part of aes implementation.
0x2608 aes_decrypt_ecb_aligned - AES 7 Part of aes implementation.
0x30c0 do_dma ls_addr:$4, dma_effective_addr:$5, size:$6, tag_id:$7, unk0:$8, unk1:$9 Used to dma data in and out of the isolated module's LS.
0x3168 write_tag_mask_bit mask_bit:$4 Used to set a specific bit in MFC_WrTagMask.

Disasm[edit | edit source]

The complete disassembly is available at [1].

Decrypting EID[edit | edit source]

Dumper iso.self[edit | edit source]

Is there one ?

Dumper Payload[edit | edit source]

Running aim_spu_module in anergistic[edit | edit source]

isoldr[edit | edit source]

Loads, decrypts, runs isolated modules, and creates through AES the required key in LS 0x0.

Debug messages[edit | edit source]

This module doesn't contain debug messages.

Data[edit | edit source]

Address Message
? 3.41 ? 355 CEX
0x34C40 - ... 0x34d10 Start of isoldr keys Keys#Modules
0x35130 0x35050 AES sbox (16*16 bytes)
0x35300 0x35220 AES inverse sbox (16*16 bytes)

Functions[edit | edit source]

Address Name Parameters Info
? 3.41 ? 355 CEX
0x259E0 cleanup_jump_code unknown cleans all the registers and jump to the loader
0x259E0 main_func unknown Main routine.
0x346B0 write_tag_mask_bit mask_bit:$4 Used to set a specific bit in MFC_WrTagMask.
0x27438 aes128_cbc_decrypt
0x27508 aes128_cbc_encrypt
0x29DC0 aes_ctr
0x2BB28 aes_set_key_enc
0x2C0D0 cellCryptoSpuAesCbcCfb128Encrypt
0x2C240 cellCryptoSpuAesCbcCfb128Decrypt
0x2C540 cellCryptoSpuAesCtr
0x2C8D0 aes_omac1
0x2CAE0 sha1_buffer
0x2CB70 sha1_hmac_init
0x2CC70 sha1_hmac_update
0x2CC90 sha1_hmac_final
0x2CD28 sha1_hmac_buffer
0x2CDC8 aes_set_key_dec
0x2CEE0 aes_encrypt_ecb_aligned
0x2D7C0 aes_decrypt_ecb
0x2D9B0 aes_decrypt_ecb_aligned
0x2E450 sha1_init
0x2E4C8 sha1_update
0x2E700 sha1_final
0x2EA88 sha1_process