-
Poking around.
09/25/2018 at 16:55 • 0 commentsfirst look at firmware `.bin`s:
- appears to be compressed or encrypted with >0.9 entropy almost all over in binwalk.
- ~42KB each - are loaded into SRAM when flashing?
42012 Jun 2 2017 8Bitdo_NesMini_RR_Firmware_V1.06.dat 42012 Sep 30 2017 8Bitdo_NesMini_RR_Firmware_V1.07.dat 42524 Dec 5 2017 8Bitdo_NesMini_RR_Firmware_V1.08.dat 44572 Mar 15 2018 8Bitdo_NesMini_RR_Firmware_V1.11.dat 42012 Mar 6 2017 8Bitdo_NesMini_RR_Firmware_V105_beta3.dat
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)
- Symbols seem to be complete, fairly concise 200kb elf executable - seem like lower hanging fruit than 2mb win32 exe.
- Interesting symbols might shed light on format
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.