A1exdandy/checkm8-a5: Checkm8 Port For S5L8940X/S5L8942X ...

Skip to content Dismiss alert {{ message }} / checkm8-a5 Public
  • Notifications You must be signed in to change notification settings
  • Fork 145
  • Star 183
  • Code
  • Issues 19
  • Pull requests 1
  • Actions
  • Projects
  • Security
  • Insights
Additional navigation options  masterBranchesTagsGo to fileCode

Folders and files

NameNameLast commit messageLast commit date

Latest commit

 

History

1 Commit
LICENSELICENSE  
README.mdREADME.md  
checkm8-a5.inocheckm8-a5.ino  
constants.hconstants.h  
usb_host_library.patchusb_host_library.patch  
View all files

Repository files navigation

  • README
  • MIT license
A5/A5X checkm8

checkm8 port for S5L8940X/S5L8942X/S5L8945X based on Arduino and MAX3421E-based USB Host Shield

Building

Follow the instructions here. Note that the patch for USB Host Library Rev. 2.0 is different.

USB Host Library Rev. 2.0 installation and patching

cd path/to/Arduino/libraries git clone https://github.com/felis/USB_Host_Shield_2.0 cd USB_Host_Shield_2.0 git checkout cd87628af4a693eeafe1bf04486cf86ba01d29b8 git apply path/to/usb_host_library.patch

SoC selection

Before using the exploit change this line in the beginning of checkm8-a5.ino with target SoC CPID:

#define A5_8942

S5L8940X/S5L8942X/S5L8945X-specific exploitation notes

This article may be helpful for better understanding.

1. HOST2DEVICE control request without data phase processing

In newer SoCs this request is processed as follows. Note that there are different cases for request_handler_ret == 0 and request_handler_ret > 0:

void __fastcall usb_core_handle_usb_control_receive(void *ep0_rx_buffer, __int64 is_setup, __int64 data_rcvd, bool *data_phase) { ... // get interface control request handler request_handler = ep.registered_interfaces[(unsigned __int16)setup_request.wIndex]->request_handler; if ( !request_handler ) goto error_handling; // call to interface control request handler // set global buffer pointer request_handler_ret = request_handler(&g_setup_request, &ep0_data_phase_buffer); if ( !(g_setup_request.bmRequestType & 0x80000000) ) { // HOST2DEVICE if ( request_handler_ret >= 1 ) { // set global data phase length and ifnum ep0_data_phase_length = request_handler_ret; ep0_data_phase_if_num = intf_num; goto continue; } if ( !request_handler_ret ) { // acknowledge transaction with zlp, do not touch global state usb_core_send_zlp(); goto continue; } ... }

But in our target SoCs this request is processed slightly different:

unsigned int __fastcall usb_core_handle_usb_control_receive(unsigned int rx_buffer, int is_setup, unsigned int data_received, int *data_phase) { ... if ( is_setup ) { v11 = memmove((unsigned int)&g_setup_packet, rx_buffer, 8); if ( g_setup_packet.bmRequestType & 0x60 ) { if ( (g_setup_packet.bmRequestType & 0x60) != 0x20 || (g_setup_packet.bmRequestType & 0x1F) != 1 || (v29 = LOBYTE(g_setup_packet.wIndex) | (HIBYTE(g_setup_packet.wIndex) << 8), v29 >= ep_size) || (request_handler = *(int (__fastcall **)(setup_req *, _DWORD *))(ep_array[LOBYTE(g_setup_packet.wIndex) | (HIBYTE(g_setup_packet.wIndex) << 8)] + 32)) == 0 || (request_handler_ret = request_handler(&g_setup_packet, &ep0_data_phase_buffer), request_handler_ret < 0) ) { // error handling rx_buffer = sub_2E7C(0x80, 1); v10 = 0; goto LABEL_103; } // if request_handler_ret >= 0, then data phase length will be touched anyway ep0_data_phase_length = request_handler_ret; ep0_data_phase_if_num = v29; *data_phase = 1; goto continue; } ... }

So, if we send any HOST2DEVICE control request without data phase, then ep0_data_phase_length will be reset to zero. Because of this we can't use ctrlReq(0x21,4,0) to reenter DFU. But there is another way to reenter DFU:

  1. ctrlReq(bmRequestType = 0x21,bRequest = 1,wLength = 0x40) with any data
  2. ctrlReq(0x21,1,0)
  3. ctrlReq(0xa1,3,1)
  4. ctrlReq(0xa1,3,1)
  5. USB bus reset

So, to be able to write to the freed io_buffer, we do steps 1-4, then send an incomplete HOST2DEVICE control transaction to set global state, then trigger bus reset. This algorithm is fully described here by littlelailo.

But, if we use any normal OS with default USB stack for exploitation, then we can't avoid standard device requests (e.g. SET_ADDRESS, see this for more info) sent by OS before we can work with device. Because of it in our PoC we use Arduino and MAX3421E to control early initialization of USB.

2. Zero length packet processing

In newer SoCs data packets are processed as follows. Note that in case of zero length packet processing is not performed.

void __fastcall usb_core_handle_usb_control_receive(void *ep0_rx_buffer, __int64 is_setup, __int64 data_rcvd, bool *data_phase) { ... if ( !(is_setup & 1) ) { if ( !(_DWORD)data_rcvd ) // check for zero length packet return; if ( ep0_data_phase_rcvd + (unsigned int)data_rcvd <= ep0_data_phase_length ) { if ( ep0_data_phase_length - ep0_data_phase_rcvd >= (unsigned int)data_rcvd ) to_copy = (unsigned int)data_rcvd; else to_copy = ep0_data_phase_length - ep0_data_phase_rcvd; memmove(ep0_data_phase_buffer, ep0_rx_buffer, to_copy);// copy received data to IO-buffer ep0_data_phase_buffer += (unsigned int)to_copy;// update global buffer pointer ep0_data_phase_rcvd += to_copy; // update received counter *data_phase = 1; // stop transfer if received expected number of bytes // or received less then 0x40 bytes packet if ( (_DWORD)data_rcvd == 0x40 ) end_of_transfer = ep0_data_phase_rcvd == ep0_data_phase_length; else end_of_transfer = 1; ... }

But in our target SoCs zero length packets are processed in the same way as non-zero length packets.

unsigned int __fastcall usb_core_handle_usb_control_receive(unsigned int rx_buffer, int is_setup, unsigned int data_received, int *data_phase) { ... // data packet processing starts here rx_buffer = ep0_data_phase_buffer; if ( !ep0_data_phase_buffer ) return rx_buffer; if ( data_received + ep0_data_phase_rcvd > ep0_data_phase_length ) { rx_buffer = sub_2E7C(128, 1); reset_global_state: v10 = 0; ep0_data_phase_rcvd = 0; ep0_data_phase_length = 0; ep0_data_phase_buffer = 0; ep0_data_phase_if_num = -2; LABEL_103: *v6 = v10; return rx_buffer; } if ( data_received >= ep0_data_phase_length - ep0_data_phase_rcvd ) v7 = ep0_data_phase_length - ep0_data_phase_rcvd; else v7 = data_received; memmove(ep0_data_phase_buffer, rx_buffer_1, v7); end_of_transfer = data_received_1 != 0x40; // in case of zero length packet `end_of_transfer` will be `true` // and global state will be reseted ep0_data_phase_buffer += v7; ep0_data_phase_rcvd += v7; rx_buffer = ep0_data_phase_rcvd; *v6 = 1; if ( rx_buffer == ep0_data_phase_length ) end_of_transfer = 1; if ( end_of_transfer ) { if ( (int)ep0_data_phase_if_num >= 0 && ep0_data_phase_if_num < ep_size ) { v9 = *(void (**)(void))(ep_array[ep0_data_phase_if_num] + 36); if ( v9 ) { v9(); rx_buffer = usb_core_send_zlp(); } } goto reset_global_state; } return rx_buffer; }

As in the previous case, if we use normal OS with default USB stack, we can't avoid sending of zero length packets in status phase of standard device USB controll requests.

Important notes

  • Do not use any cables with embedded USB hubs (DCSD/Kong/Kanzi/etc.), as it might prevent a device from being recognized by the program. Normal USB-cables will do the trick just fine
  • This exploit demotes your device by default, so SWD-debugging will be available. But that also makes your device use development KBAG when decrypting Image3s. Keep that in mind if you're going to use this to decrypt firmware components

Authors

  • a1exdandy
  • nyan_satan

License

This project is licensed under the MIT License - see the LICENSE file for details

About

checkm8 port for S5L8940X/S5L8942X/S5L8945X

Resources

Readme

License

MIT license

Uh oh!

There was an error while loading. Please reload this page.

Activity

Stars

183 stars

Watchers

14 watching

Forks

145 forks Report repository

Releases

No releases published

Packages

Uh oh!

There was an error while loading. Please reload this page.

Contributors 1

  • @a1exdandy a1exdandy Alexey Kovrizhnykh

Languages

  • C 67.9%
  • C++ 32.1%
You can’t perform that action at this time.

Từ khóa » Checkm8-a5 Github