Close

Poking around.

A project log for Reversing The 8Bitdo Retro Receiver

A small study on the internals of 8Bitdo's Retro Receiver for SNES Classic. Tear Down and BOM

zvoddzvodd 09/25/2018 at 16:550 Comments

first look at firmware `.bin`s:

Unsure of the format, should search around for a possible standard format before... 

Radare2 into ~updatesTools~/MacOS/8Bitdo_Retro_Receiver_Tools_For_Update. ( literally first time running radare)

0x1000055d0 : sym._SendFirmwareHeader
0x1000045c0 : sym._SendFirmwarePacket
0x1000051d0 : sym._Send_FirmwareDataPacket
0x1000054e0 : sym._Set_ApplicationEncodeID
0x1000044b0 : sym._VerificationId
0x100005290 : sym._WriteFlash_Packet
0x1000049a0 : sym._WriteHid
0x100006690 : sym.___hex_dump
0x100000000 : sym.__mh_execute_header
0x100007090 : sym._add_callback
0x10001c1a0 : sym._app_key_index
0x10001c34c : sym._cur_devVersion
0x10001c340 : sym._data_status
0x10001c350 : sym._firmware_type
0x10001c354 : sym._g_firmware_update_state
0x10001c190 : sym._gamepad_type
0x100006940 : sym._getCurrentPath
0x10001c1e8 : sym._help_text
0x1000067a0 : sym._hex_dump_log
0x100006670 : sym._input_callback
0x10001c338 : sym._m_FilePathName
0x10001c358 : sym._m_firmwareHeader
0x10001c378 : sym._m_handleFirmeWare
 __hex_dump: takes a string, checks length? prints things? might just be for dev debuging (possibly for dumping hex :P ).
           | mov qword [local_8h], rdi                          |           
           | ; arg2                                             |           
           | mov qword [local_10h], rsi                         |           
           | ; arg3                                             |           
           | mov dword [local_14h], edx                         |           
           | mov dword [local_18h], 0                           |           
           | cmp qword [local_8h], 0                            |           
           | je 0x1000066d5;[ga]                                |           
           `----------------------------------------------------'           
                   | |                                                      
                   | '----------------------.                               
      .------------'                        |                               
      |                                     |                               
      |                                     |                               
  .--------------------------------.    .--------------------------------.  
  |  0x1000066b8 [ge]              |    |  0x1000066d5 [ga]              |  
  | ; 0x100012f0e                  |    | ; 0x100012f1b                  |  
  | ; "\n%s size=%d\n"             |    | ; "\nsize=%d\n"                |  
  | lea rdi, str.s_size__d         |    | lea rdi, str.size__d           |  
  | mov rsi, qword [local_8h]      |    | mov esi, dword [local_14h]     |  
  | mov edx, dword [local_14h]     |    | mov al, 0                      |  
  | mov al, 0                      |    | call sym.imp.printf;[gc]       |  
  | call sym.imp.printf;[gc]       |    | mov dword [local_20h], eax     |  
  | mov dword [local_1ch], eax     |    `--------------------------------'  
  | jmp 0x1000066e9;[gd]           |        |                               
  `--------------------------------'        |                               
      |                                     |                               
      '------------.                        |                               
                   | .----------------------'                               
                   | |                                                      
                   | |                                                      
             .------------------------------------------------.             
             |  0x1000066e9 [gd]                              |             
             | ; CODE XREF from 0x1000066d0 (sym.___hex_dump) |             
             | mov dword [local_18h], 0                       |             
             `------------------------------------------------'             
We should try and start with the start of the bin files in more relevant functions:  `_m_firmwareHeader` `_firmware_type` ...later.
fw `.bin` headers:
v105:
0x00000000  6900 0000 0034 0008 00a4 0000 0000 0000  i....4..........
0x00000010  0000 0000 0000 0000 0000 0000 4375 28d4  ............Cu(.

v106:
0x00000000  6a00 0000 0034 0008 00a4 0000 0000 0000  j....4..........
0x00000010  0000 0000 0000 0000 0000 0000 a374 28d4  .............t(.

v107:
0x00000000  6b00 0000 0034 0008 00a4 0000 0000 0000  k....4..........
0x00000010  0000 0000 0000 0000 0000 0000 a374 28d4  .............t(.

v108:
0x00000000  6c00 0000 0034 0008 00a6 0000 0000 0000  l....4..........
0x00000010  0000 0000 0000 0000 0000 0000 ab74 28d4  .............t(.

v111:
0x00000000  6f00 0000 0034 0008 00ae 0000 0000 0000  o....4..........
0x00000010  0000 0000 0000 0000 0000 0000 8b76 28d4  .............v(.

 Well i guess we know what the first byte is.

Checks for a vendor ID for the Retro Receiver

# sym._IOHIDDevice_GetVendorID (int arg1);
# 0x100006908      lea rax, str.cstr.VendorID                ; 0x100017760

I am running on the assumption the RR is running a custom bootloader that accepts firmware updates on some custom format.


`SendFirmwarePacket` seems pretty obvious, place to look for packet sending.

[ 0x1000045c0 ]
;-- func.1000045c0:
(fcn) sym._SendFirmwarePacket 980
  sym._SendFirmwarePacket (int arg6, int arg5, int arg1, int arg2);

  lots of magic numbers being checked here.

 0x10000474a [gd]                                     
; CODE XREF from 0x1000046fc (sym._SendFirmwarePacket)
; 135                                                 
mov eax, 0x87                                         
movzx ecx, byte [local_425h]                          
cmp eax, ecx                                          
jne 0x100004763;[gf]                                  

0x100004763 [gf]            
; 151                        
mov eax, 0x97                
movzx ecx, byte [local_425h] 
cmp eax, ecx                 
jne 0x100004951;[gi]         

0x100004777 [gk]             
movzx eax, byte [local_426h]  
cmp eax, 0                    
jne 0x1000048b2;[gj]          

Looks like its loading values into `_usb_send_packet` struct ? Then we see a `call sym._WriteHid;[gs] `. This looks like it'll reveal a good deal about the fw update process. Deep analysis could be worth while.

 0x1000048b2 [gj]              
; 0x10001c490                  
lea rax, sym._usb_send_packet  
mov rcx, rax                   
add rcx, 1                     
; '?'                          
; 63                           
mov edx, 0x3f                  
mov esi, edx                   
lea rdi, [local_410h]          
mov edx, dword [local_43ch]    
mov r8b, dl                    
mov byte [rax], r8b            
movsxd rdx, dword [local_43ch] 
mov qword [local_478h], rdi    
mov rdi, rcx                   
mov rax, qword [local_478h]    
mov qword [local_480h], rsi    
mov rsi, rax                   
mov rcx, qword [local_480h]    
call sym.imp.__memcpy_chk;[gc] 
; 0x10001c490                  
lea rsi, sym._usb_send_packet  
mov rdi, qword [local_420h]    
mov r9d, dword [local_43ch]    
mov r8b, r9b                   
movzx r9d, r8b                 
add r9d, 1                     
mov r8b, r9b                   
movzx edx, r8b                 
mov qword [local_488h], rax    
call sym._WriteHid;[gs]        
mov dword [local_414h], eax    
jmp 0x100004960;[gx]           

All this would be a lot easier with a device in hand to capture USB traffic.

TODO : Possibly spoof Vendor/Device ID to allow dummy fw update.

Discussions