Quantcast
Channel: CodeSection,代码区,网络安全 - CodeSec
Viewing all articles
Browse latest Browse all 12749

【技术分享】如何代码实现给fastboot发消息? 逆向aftool工具纪实

0
0
【技术分享】如何代码实现给fastboot发消息? 逆向aftool工具纪实

2017-07-04 12:16:33

阅读:390次
点赞(0)
收藏
来源: 安全客





【技术分享】如何代码实现给fastboot发消息? 逆向aftool工具纪实

作者:Yan_1_20





【技术分享】如何代码实现给fastboot发消息? 逆向aftool工具纪实

作者:Yan_1_20

预估稿费:300RMB

投稿方式:发送邮件至linwei#360.cn,或登陆网页版在线投稿


0x00 起因

学习android安全的朋友都应该熟悉adb,fastboot这两个工具,但是其实现方式网上却没有多少资料,在下对这些知识也非好奇,一次机会对某手机的售后刷机工具aftool进行对手机刷机时,发现了它的软件包里没有fastboot.exe,但是却执行了fastboot命令,猜测他可能自己实现了fastboot.exe的功能,就想对其进行逆向分析执行fastboot的命令的核心代码。

0x01 调试环境配置

工具:IDA ,Ollydbg,Wireshark,Source Insight3

Aftool download link:

http://pan.baidu.com/s/1c0AVz9I

Adb source code download link:

http://pan.baidu.com/s/1hrVZFxU

安装AF_UPGRADE_PKG.exe后,aftool.exe为目标文件

0x02 fastboot.exe 和fastboot 模式通信的数据包

我们手机进入fastboot, 使用wireshark 抓取usb数据包,观察数据包数量以及格式

进入fastboot的方法:

[1](命令)使用 adb reboot-bootloader [2](按键)音量减键+电源键
【技术分享】如何代码实现给fastboot发消息? 逆向aftool工具纪实

使用wireshark 捕获usb包

选择接口 android Bootloader interface


【技术分享】如何代码实现给fastboot发消息? 逆向aftool工具纪实

使用fastboot.exe 发送命令 fastboot reboot-bootloader


【技术分享】如何代码实现给fastboot发消息? 逆向aftool工具纪实

同时wireshark捕获到的数据包为:


【技术分享】如何代码实现给fastboot发消息? 逆向aftool工具纪实

URB_BULK out 的数据为:


【技术分享】如何代码实现给fastboot发消息? 逆向aftool工具纪实

URB_BULK in 的数据为:


【技术分享】如何代码实现给fastboot发消息? 逆向aftool工具纪实

可以大胆猜测 URB_BULK out 就是我们使用的fastboot的命令 fastboot reboot-bootloaderURB_BULK int 就是手机端给的回应

但是上面三个特殊的数据包 和我们发的数据没有任何关系,但是看其名称”Request,Response,Status”猜测可能是fastboot的通信协议的 建立协议的数据包

0x03 aftool.exe 和fastboot 模式通信的数据包

Aftool的使用方法:

[1]切换成高通手机 [2]点击选择按钮 加X520_recovery目录下的fastboot_flash_all.bat [3]点击下载按钮 开始执行fastboot_flash_all.bat里面的命令

对wireshark的处理方式和上面类型

捕获的数据包如下图


【技术分享】如何代码实现给fastboot发消息? 逆向aftool工具纪实

看来和fastboot的数据包格式一致,只是多发送了一条命令

现在的思路就是 Ollydbg 调试aftool ,假如执行了某个函数同时wireshark上有数据包产生那么这个函数就是通信使用的函数

0x04 逆向aftool.exe

这个工具是使用Qt编写,没有加壳子,没有加混淆,对我这种小白来说,最大的难题可能就是怎么在Qt的架构里找到”下载”按钮的处理函数了。

一开始我是没有思路的,由于不知道这个下载按钮里进行了操作,我给它下断点都不知道用什么函数下什么断点。但是想到了旁边还有一个”选择”按钮,加载bat文件肯定有文件读取的操作 于是对ReadFile 下了断点。果然断了下,然后通过回溯。找到了它的UI消息处理函数sub_4E22C0。

最后确定了sub_4E22C0 中调用的sub_4BFD30就是”下载”按钮响应事件,

在sub_4BFD30里分支比较多 但是ollydbg跟了几次之后 发现其执行的分支稳定执行

sub_4BBAF0


【技术分享】如何代码实现给fastboot发消息? 逆向aftool工具纪实

但是sub_4BBAF0的代码逻辑看起来很简单并没有多少值得注意的代码,但是在OD里跟着sub_4BBAF0 按F9就会跑起来,看来是这个函数没错,但是应该是错过了什么

在sub_4BBAF0里的下层函数sub_4B7DB0,以及sub_4B7DB0的下层函数sub_4A3F30找到了如下代码


【技术分享】如何代码实现给fastboot发消息? 逆向aftool工具纪实

可以的它开了一个线程

但是参考Qt QThread::start()的用法 这里传入的参数可能是ida的没有使用类的方式调用吧

直接用ollydbg动态调到他这里来。得到了v2[18]的值742D345e(742D345e不是定值)

接着有两个函数需要F7

742D34C2E851FFFFFFcallmsvcr90.742D3418 742D3430FF5054calldwordptrds:[eax+0x54] 恭喜最后来到了
004A411A.E8914B0000callAFTool.004A8CB0

sub_4A8CB0就是真正处理函数

接着在ollydbg IDA里跟了跟这个函数观察

//reboot-bootloader 004A908C|.E83F190000callAFTool.004AA9D0

发现AFTool.004AA9D0 这个函数就是给手机发数据的函数

004AA9D0 里最重要的就是下面的函数

004AAA58|.52|pushedx 004AAA59|.8B542434|movedx,dwordptrss:[esp+0x34];AFTool.0052D4B8 004AAA5D|.8D4C2418|leaecx,dwordptrss:[esp+0x18] 004AAA61|.51|pushecx 004AAA62|.50|pusheax 004AAA63|.8B4208|moveax,dwordptrds:[edx+0x8] 004AAA66|.55|pushebp 004AAA67|.50|pusheax 004AAA68|.FF151CC05000|calldwordptrds:[<&AdbWinApi.AdbWrite>;AdbWinAp.AdbWriteEndpointSync

堆栈如图:

esp->09A2F97800000008 09A2F97C09A2FD1CASCII"reboot-bootloader" 09A2F98000000011 09A2F98409A2F9A0 09A2F9880000027C

<注意:这个函数执行之前Wireshark里已经有了那三条特殊的数据包了,这个函数执行之后Wireshark会增加 URB_BULK out >

所以发送命令API函数就是 AdbWinAPi.dll里的导出函数 AdbWriteEndpointSync

类似的找到了发出别的4条数据包的具体函数(其实三条特殊数据包的是一个函数发的)


AdbGetSerialNumber------>GETDESCRIPTORRequestSTRING ------>GETDESCRIPTORResponseSTRING ------>GETDESCRIPTORStatus AdbReadEndpointSync------>URB_BULKin

0x05 API调用分析

现在找到了API接下来就是参考源码对这些API传入正确参数并调用了。

我们一开始假设的是前三条数据包是建立协议链接 类似socket编程accept函数返回的sock

然后AdbWriteEndpointSync 类似 send函数 使用这个sock进行通信

在源码里找了AdbWriteEndpointSync 声明(使用dll里的导出函数),调用

声明:


【技术分享】如何代码实现给fastboot发消息? 逆向aftool工具纪实

调用:


【技术分享】如何代码实现给fastboot发消息? 逆向aftool工具纪实

在usb_write 下面就是 usb_read的定义


【技术分享】如何代码实现给fastboot发消息? 逆向aftool工具纪实

通过上面的代码可以看出AdbWriteEndpointSync,AdbReadEndpointSync使用的第一个参数都是同一个结构体里的不同成员变量

这个结构体的声明如下


【技术分享】如何代码实现给fastboot发消息? 逆向aftool工具纪实

接着关于adb_write_pipe和adb_read_pipe变量的赋值

但是搜索无果,搜索调用函数usb_write的函数时,能搜索到,但是没有找到他的参数传递


【技术分享】如何代码实现给fastboot发消息? 逆向aftool工具纪实

换了一个思路对AdbGetSerialNumber调用进行了寻找


【技术分享】如何代码实现给fastboot发消息? 逆向aftool工具纪实

比起这个调用,上面的do_usb_open函数返回的handle则是引起了我的兴趣,其定义如下。


【技术分享】如何代码实现给fastboot发消息? 逆向aftool工具纪实

通过其定义可以看出,do_usb_open 里完成了对结构体usb_handle的分配已经赋值。

通过do_usb_open 返回的关键性结构体,我们就可以对AdbWriteEndpointSync 进行调用。

至于do_usb_open的参数来源 则是 上面的API AdbNextInterface进行的赋值


【技术分享】如何代码实现给fastboot发消息? 逆向aftool工具纪实

所以我们已经在源码里找到了我们需要的API的调用参数的来源。

0x06 整合代码

通过整合。得了如下的代码

<注意:一定要把AdbWinApi.dll AdbWinUsbApi.dll放到这个项目里编译>

//adb_test.cpp:定义控制台应用程序的入口点。 // #include"stdafx.h" #include<windows.h> #defineADB_MUTEX_INITIALIZERPTHREAD_MUTEX_INITIALIZER typedefvoid*ADBAPIHANDLE; typedefstruct_AdbInterfaceInfo{ ///Inteface'sclassid(seeSP_DEVICE_INTERFACE_DATAfordetails) GUIDclass_id; ///Interfaceflags(seeSP_DEVICE_INTERFACE_DATAfordetails) unsignedlongflags; ///Devicenamefortheinterface(seeSP_DEVICE_INTERFACE_DETAIL_DATA ///fordetails) wchar_tdevice_name[1]; }AdbInterfaceInfo; structusb_handle{ ///Previousentryinthelistofopenedusbhandles usb_handle*prev; ///Nextentryinthelistofopenedusbhandles usb_handle*next; ///HandletoUSBinterface ADBAPIHANDLEadb_interface; ///HandletoUSBreadpipe(endpoint) ADBAPIHANDLEadb_read_pipe; ///HandletoUSBwritepipe(endpoint) ADBAPIHANDLEadb_write_pipe; ///Interfacename char*interface_name; ///Maskfordeterminingwhentousezerolengthpackets unsignedzero_mask; }; typedefenum_AdbOpenAccessType{ ///Opensforreadandwriteaccess. AdbOpenAccessTypeReadWrite, ///Opensforreadonlyaccess. AdbOpenAccessTypeRead, ///Opensforwriteonlyaccess. AdbOpenAccessTypeWrite, ///Opensforqueryinginformation. AdbOpenAccessTypeQueryInfo, }AdbOpenAccessType; typedefenum_AdbOpenSharingMode{ ///Sharesreadandwrite. AdbOpenSharingModeReadWrite, ///Sharesonlyread. AdbOpenSharingModeRead, ///Sharesonlywrite. AdbOpenSharingModeWrite, ///Opensexclusive. AdbOpenSharingModeExclusive, }AdbOpenSharingMode; #defineANDROID_USB_CLASS_ID\ {0xf72fe0d4,0xcbcb,0x407d,{0x88,0x14,0x9e,0xd6,0x73,0xd0,0xdd,0x6b}}; structusb_ifc_info { unsigned__int16dev_vendor; unsigned__int16dev_product; unsigned__int8dev_class; unsigned__int8dev_subclass; unsigned__int8dev_protocol; unsigned__int8ifc_class; unsigned__int8ifc_subclass; unsigned__int8ifc_protocol; unsigned__int8has_bulk_in; unsigned__int8has_bulk_out; unsigned__int8writable; charserial_number[256]; chardevice_path[256]; }; typedefstruct_USB_DEVICE_DESCRIPTOR{ UCHARbLength; UCHARbDescriptorType; USHORTbcdUSB; UCHARbDeviceClass; UCHARbDeviceSubClass; UCHARbDeviceProtocol; UCHARbMaxPacketSize0; USHORTidVendor; USHORTidProduct; USHORTbcdDevice; UCHARiManufacturer; UCHARiProduct; UCHARiSerialNumber; UCHARbNumConfigurations; }USB_DEVICE_DESCRIPTOR,*PUSB_DEVICE_DESCRIPTOR; typedefstruct_USB_INTERFACE_DESCRIPTOR{ UCHARbLength; UCHARbDescriptorType; UCHARbInterfaceNumber; UCHARbAlternateSetting; UCHARbNumEndpoints; UCHARbInterfaceClass; UCHARbInterfaceSubClass; UCHARbInterfaceProtocol; UCHARiInterface; }USB_INTERFACE_DESCRIPTOR,*PUSB_INTERFACE_DESCRIPTOR; typedefint(*AdbWriteEndpointSync_)(ADBAPIHANDLE,char*,int,int*,int); typedefvoid*(*AdbCreateInterfaceByName_)(constwchar_t*); typedefvoid*(*AdbOpenDefaultBulkWriteEndpoint_)(ADBAPIHANDLE,AdbOpenAccessType,AdbOpenSharingMode); typedefbool(*AdbNextInterface_)(ADBAPIHANDLE,AdbInterfaceInfo*,unsignedlong*size); typedefvoid*(*AdbEnumInterfaces_)(GUID,bool,bool,bool); typedefADBAPIHANDLE(*AdbOpenDefaultBulkReadEndpoint_)(ADBAPIHANDLE,AdbOpenAccessType,AdbOpenSharingMode); typedefbool(*AdbGetInterfaceName_)(ADBAPIHANDLEadb_interface, void*buffer, unsignedlong*buffer_char_size, boolansi); typedefbool(*AdbCloseHandle_)(ADBAPIHANDLEadb_handle); typedefbool(*AdbGetUsbDeviceDescriptor_)(ADBAPIHANDLE,USB_DEVICE_DESCRIPTOR*); typedefbool(*AdbGetUsbInterfaceDescriptor_)(ADBAPIHANDLE,USB_INTERFACE_DESCRIPTOR*); typedefbool(*AdbGetSerialNumber_)(ADBAPIHANDLE,void*,unsignedlong*,bool); typedefbool(*AdbReadEndpointSync_)(ADBAPIHANDLE, void*, unsignedlong, unsignedlong*, unsignedlong); AdbWriteEndpointSync_AdbWriteEndpointSync; AdbCreateInterfaceByName_AdbCreateInterfaceByName; AdbOpenDefaultBulkWriteEndpoint_AdbOpenDefaultBulkWriteEndpoint; AdbNextInterface_AdbNextInterface; AdbEnumInterfaces_AdbEnumInterfaces; AdbOpenDefaultBulkReadEndpoint_AdbOpenDefaultBulkReadEndpoint; AdbGetInterfaceName_AdbGetInterfaceName; AdbCloseHandle_AdbCloseHandle; AdbGetUsbDeviceDescriptor_AdbGetUsbDeviceDescriptor; AdbGetUsbInterfaceDescriptor_AdbGetUsbInterfaceDescriptor; AdbGetSerialNumber_AdbGetSerialNumber; AdbReadEndpointSync_AdbReadEndpointSync; usb_handle*do_usb_open(constwchar_t*interface_name); voidusb_cleanup_handle(usb_handle*handle); intrecognized_device(usb_handle*handle); intmain() { intd; chargetvar[]="getvar:product"; charrebootbl[]="reboot-bootloader"; HMODULEa=LoadLibrary(L"AdbWinApi.dll"); AdbWriteEndpointSync=(AdbWriteEndpointSync_)GetProcAddress(a,"AdbWriteEndpointSync"); AdbCreateInterfaceByName=(AdbCreateInterfaceByName_)GetProcAddress(a,"AdbCreateInterfaceByName"); AdbOpenDefaultBulkWriteEndpoint=(AdbOpenDefaultBulkWriteEndpoint_)GetProcAddress(a,"AdbOpenDefaultBulkWriteEndpoint"); AdbNextInterface=(AdbNextInterface_)GetProcAddress(a,"AdbNextInterface"); AdbEnumInterfaces=(AdbEnumInterfaces_)GetProcAddress(a,"AdbEnumInterfaces"); AdbOpenDefaultBulkReadEndpoint=(AdbOpenDefaultBulkReadEndpoint_)GetProcAddress(a,"AdbOpenDefaultBulkReadEndpoint"); AdbGetInterfaceName=(AdbGetInterfaceName_)GetProcAddress(a,"AdbGetInterfaceName"); AdbCloseHandle=(AdbCloseHandle_)GetProcAddress(a,"AdbCloseHandle"); AdbGetUsbDeviceDescriptor=(AdbGetUsbDeviceDescriptor_)GetProcAddress(a,"AdbGetUsbDeviceDescriptor"); AdbGetUsbInterfaceDescriptor=(AdbGetUsbInterfaceDescriptor_)GetProcAddress(a,"AdbGetUsbInterfaceDescriptor"); AdbGetSerialNumber=(AdbGetSerialNumber_)GetProcAddress(a,"AdbGetSerialNumber"); AdbReadEndpointSync=(AdbReadEndpointSync_)GetProcAddress(a,"AdbReadEndpointSync"); usb_handle*handle=NULL; charentry_buffer[2048]; charinterf_name[2048]; charread[2048]; intArgList; AdbInterfaceInfo*next_interface=(AdbInterfaceInfo*)(&entry_buffer[0]); unsignedlongentry_buffer_size=sizeof(entry_buffer); char*copy_name; staticconstGUIDusb_class_id=ANDROID_USB_CLASS_ID; //Enumerateallpresentandactiveinterfaces. ADBAPIHANDLEenum_handle= AdbEnumInterfaces(usb_class_id,true,true,true); while(AdbNextInterface(enum_handle,next_interface,&entry_buffer_size)){ constwchar_t*wchar_name=next_interface->device_name; for(copy_name=interf_name; L'\0'!=*wchar_name; wchar_name++,copy_name++){ *copy_name=(char)(*wchar_name); } *copy_name='\0'; handle=do_usb_open(next_interface->device_name); if(recognized_device(handle)){ printf("addinganewdevice%s\n",interf_name); charserial_number[512]; unsignedlongserial_number_len=sizeof(serial_number); if(AdbGetSerialNumber(handle->adb_interface,serial_number,&serial_number_len,true)) { memset(read,0,sizeof(read)); AdbWriteEndpointSync(handle->adb_write_pipe,getvar,strlen(rebootbl),&d,0x26c); Sleep(3000); AdbReadEndpointSync(handle->adb_read_pipe,read,4096,(unsignedlong*)&ArgList,0x26c); read[strlen(read)]='\0'; printf("%s:\n",read); memset(read,0,sizeof(read)); AdbWriteEndpointSync(handle->adb_write_pipe,rebootbl,strlen(rebootbl),&d,0x26c); Sleep(3000); AdbReadEndpointSync(handle->adb_read_pipe,read,4096,(unsignedlong*)&ArgList,0x26c); read[strlen(read)]='\0'; printf("%s:\n",read); } } } //AdbWriteEndpointSync(ret->adb_write_pipe,rebootbl,strlen(rebootbl),&d,0x26c); return0; } intrecognized_device(usb_handle*handle){ if(NULL==handle) return0; //Checkvendorandproductidfirst USB_DEVICE_DESCRIPTORdevice_desc; if(!AdbGetUsbDeviceDescriptor(handle->adb_interface, &device_desc)){ return0; } //Thencheckinterfaceproperties USB_INTERFACE_DESCRIPTORinterf_desc; if(!AdbGetUsbInterfaceDescriptor(handle->adb_interface, &interf_desc)){ return0; } //Musthavetwoendpoints if(2!=interf_desc.bNumEndpoints){ return0; } //if(is_adb_interface(device_desc.idVendor,device_desc.idProduct, //interf_desc.bInterfaceClass,interf_desc.bInterfaceSubClass,interf_desc.bInterfaceProtocol)){ //if(interf_desc.bInterfaceProtocol==0x01){ //AdbEndpointInformationendpoint_info; ////assumingzeroisavalidbulkendpointID //if(AdbGetEndpointInformation(handle->adb_interface,0,&endpoint_info)){ //handle->zero_mask=endpoint_info.max_packet_size-1; //} //} return1; } voidusb_cleanup_handle(usb_handle*handle){ if(NULL!=handle){ if(NULL!=handle->interface_name) free(handle->interface_name); if(NULL!=handle->adb_write_pipe) AdbCloseHandle(handle->adb_write_pipe); if(NULL!=handle->adb_read_pipe) AdbCloseHandle(handle->adb_read_pipe); if(NULL!=handle->adb_interface) AdbCloseHandle(handle->adb_interface); handle->interface_name=NULL; handle->adb_write_pipe=NULL; handle->adb_read_pipe=NULL; handle->adb_interface=NULL; } } usb_handle*do_usb_open(constwchar_t*interface_name){ //Allocateourhandle usb_handle*ret=(usb_handle*)malloc(sizeof(usb_handle)); if(NULL==ret) returnNULL; //Setlinkersbacktothehandle ret->next=ret; ret->prev=ret; //Createinterface. ret->adb_interface=AdbCreateInterfaceByName(interface_name); //if(NULL==ret->adb_interface){ //free(ret); //errno=GetLastError(); //returnNULL; //} //Openreadpipe(endpoint) ret->adb_read_pipe= AdbOpenDefaultBulkReadEndpoint(ret->adb_interface, AdbOpenAccessTypeReadWrite, AdbOpenSharingModeReadWrite); //Openwritepipe(endpoint) ret->adb_write_pipe= AdbOpenDefaultBulkWriteEndpoint(ret->adb_interface, AdbOpenAccessTypeReadWrite, AdbOpenSharingModeReadWrite); //Saveinterfacename unsignedlongname_len=0; //Firstgetexpectednamelength AdbGetInterfaceName(ret->adb_interface, NULL, &name_len, true); if(0!=name_len){ ret->interface_name=(char*)malloc(name_len); if(NULL!=ret->interface_name){ //Nowsavethename if(AdbGetInterfaceName(ret->adb_interface, ret->interface_name, &name_len, true)){ //We'redoneatthispoint returnret; } } else{ SetLastError(ERROR_OUTOFMEMORY); } } //Somethingwentwrong. intsaved_errno=GetLastError(); usb_cleanup_handle(ret); free(ret); SetLastError(saved_errno); returnNULL; }

0x07 代码运行结果


【技术分享】如何代码实现给fastboot发消息? 逆向aftool工具纪实

其中 OKAYMSM8916是其CUP型号,为fastboot命令 getvar product的返回,OKAY是reboot-bootloader的返回,并且手机重启进入fastboot模式。说明得到的代码是完全能执行命令的核心API。




【技术分享】如何代码实现给fastboot发消息? 逆向aftool工具纪实
【技术分享】如何代码实现给fastboot发消息? 逆向aftool工具纪实
本文由 安全客 原创发布,如需转载请注明来源及本文地址。
本文地址:http://bobao.360.cn/learning/detail/4060.html

Viewing all articles
Browse latest Browse all 12749

Latest Images

Trending Articles





Latest Images