折腾这破东西好几天了,目前还没得到进一步突破,不过已经知道了许多以前不知道的东西,写一下当前笔记。
AVRCP(Audio/Video Remote Control Profile)是一种在蓝牙协议栈A2DP/AVCTP上实现的控制技术,通俗点说,就是你用蓝牙耳机听歌时按一下拨号键它会暂停,按下选曲它会切换,这就是AVRCP的功劳。
A2DP和AVRCP是一对兄弟,A2DP里WM设备是控制端,蓝牙耳机是接收端,AVRCP反之,这里说的就是WM如何接收蓝牙耳机发送的AVRCP并处理的过程。
WM里AVRCP是在L2CAP层上的扩展协议,它由AVCTP负责传输,这些规范请去看蓝牙协议文档,这里不说了。
WM里AVRCP是通过一个btd.dll驱动实现的,根据IDA静态分析得知,该驱动实现了一个接口AVCT_EstablishDeviceContext,这个接口建立起一个AVCTP协议的Callback结构,当蓝牙耳机发送一个AVRCP指令时经过底层蓝牙堆栈的处理后提交到L2CAP层,再由AVCTP协议分析处理,这个分析就是在AVCT_EstablishDeviceContext建立的Callback回调函数里进行的。
WM是一个基于消息队列的系统,可以说它的内部到处都是MsgQueue,而不知道是不是微软和蓝牙规定的协议还是通用协议里也指定了,蓝牙堆栈的消息是通过消息队列传输的,因此,微软就不在WM里专门提供一个处理AVRCP的接口函数了,这就造成了今天的局面:业余开发者们都不知道怎么实现它!(专门的开发厂商有微软提供技术支持,实现起来当然简单,交学费就行……)
而MSDN上提到的那个RequestBluetoothNotifications是只对蓝牙连接和配对等消息队列起反应的,虽然里面写着它是“Handling Events from Bluetooth Stack”,但是实际上它能得到的Event并不包括AVRCP,就算你手工把1到65535的dwClass结构全写满也没用,仍然只接收BTE_CLASS_CONNECTIONS | BTE_CLASS_DEVICE | BTE_CLASS_PAIRING,不能不说在这方面微软狠狠的涮了开发者一把。
所以要弄懂AVRCP怎么跑到接收程序里的,就得分析btd.dll了。
在IDA里可以看到AVCT_EstablishDeviceContext创建了多个过程调用,最后跑去执行本体
.text:03CA4A4C BL memset
.text:03CA4A50 LDR R4, =sub_3CA3ED4
.text:03CA4A54 LDR LR, =sub_3CA49A4
.text:03CA4A58 LDR R3, =sub_3CA490C
.text:03CA4A5C LDR R2, =sub_3CA4958
.text:03CA4A60 STR R4, [SP,#0x60+var_28]
.text:03CA4A64 LDR R4, [SP,#0x60+var_4C]
.text:03CA4A68 LDR R5, =loc_3CA3EDC
.text:03CA4A6C LDR R6, =loc_3CA3EE4
.text:03CA4A70 LDR R7, =loc_3CA3EEC
..............................
.text:03CA4AC8 BL AVCT_EstablishDeviceContext
注意这个调用:LDR LR, =sub_3CA49A4,看下去会发现它就是AVRCP队列的关键调用
在经过七跳八跳后,我们来到sub_3CA4208
STMFD SP!, {R4-R6,LR}
SUB SP, SP, #0x14
MOV R4, R0
LDR R0, =aAvrcpmsg
MOV R3, #0x14
MOV R2, #0
MOV LR, #5
MOV R5, #0x64
MOV R6, #0
ADD R1, SP, #0x24+var_24
STR R3, [SP,#0x24+var_24]
STR R2, [SP,#0x24+var_20]
STR LR, [SP,#0x24+var_1C]
STR R5, [SP,#0x24+var_18]
STR R6, [SP,#0x24+var_14]
BL CreateMsgQueue
可以看出这里建立了一个消息队列,里面最大保存5条数据!
继续看下去,到sub_3CA4274这里:
SUB SP, SP, #0x1C
MOV R4, R1
MOV R5, R0
MOV R2, #0x18
MOV R1, #0
ADD R0, SP, #0x2C+var_28
BL memset
LDR R0, [R5,#0x10]
MOV LR, #0x7C
MOV R6, #0
MOV R3, #0x32
MOV R2, #0x18
ADD R1, SP, #0x2C+var_28
STR LR, [SP,#0x2C+var_28]
STR R4, [SP,#0x2C+var_24]
STR R6, [SP,#0x2C+var_2C]
BL WriteMsgQueue
很明显这里就是把AVRCP指令写到消息队列中了,至此btd.dll的流程结束。
然后,微软在WM5以上提供了一个A2DP补丁以及一个WMP的AVRCP插件avrcp_mpplugin.dll,把它丢进IDA,跟到CreateMsgQueue:
SUB SP, SP, #0x60
MOV R5, R0
LDR R0, =(dword_3D97020+0x10)
MOV R3, #0x14
MOV R2, #2
MOV LR, #5
MOV R4, #0x64
MOV R6, #1
ADD R1, SP, #0x84+var_64
STR R3, [SP,#0x84+var_64]
STR R2, [SP,#0x84+var_60]
STR LR, [SP,#0x84+var_5C]
STR R4, [SP,#0x84+var_58]
STR R6, [SP,#0x84+var_54]
BL CreateMsgQueue
这里很明显又建立了一个和btd.dll里对应的消息队列结构,都是最大接收5条数据的结构,然后CreateEvent,再WaitForMultiObjects,最后我们来到一个循环:
LDR R0, [R4,#0xC]
ADD R3, SP, #0x40+var_38
MOV R2, #0x18
ADD R1, SP, #0x40+var_28
STR R5, [SP,#0x40+var_3C]
STR R6, [SP,#0x40+var_40]
BL ReadMsgQueue
这里便是把btd.dll写入的消息队列读取出来的部分,然后这个COM服务器形式的UI插件查找Windows Media窗口(类名WMP for Mobile Devices),并PostMessage发送一条WM_USER+1(0x8001)的消息过去,param里就是指示当前蓝牙耳机按下了什么按钮的编码。
然后……分析暂时就到此了……阅读IDA反汇编的能力有限-_-
目前重现的难点在于:
1.CreateMsgQueue的结构是什么?
2.ReadMsgQueue的参数?
因为只有这两个都与btd.dll创建的实例一样了,它才能“识别”到这个消息队列并实现处理,做过MSMQ的人应该都不会陌生,而我是MSMQ的门外汉……
从MSDN里找到一些AVRCP的声明:
typedef enum {
UNITINFO_T = 0x30,
SUBUNITINFO_T,
PASSTHRU_T = 0x7C
} AVCOpCodes;
typedef struct _AvrcpMsg {
UINT OpCode;
UINT OpId;
UINT Reserved[4];
} AvrcpMsg;
typedef enum {
SELECT_T = 0x00,
UP_T,
DOWN_T,
LEFT_T,
RIGHT_T,
RIGHTUP_T,
RIGHTDOWN_T,
LEFTUP_T,
LEFTDOWN_T,
ROOTMENU_T,
SETUPMENU_T,
CONTENTSMENU_T,
FAVMENU_T,
EXIT_T,
CHANNELUP_T,
CHANNELDOWN_T,
PREVCHANNEL_T,
SOUNDSEL_T,
INPUTSEL_T,
DISPLAYINFO_T,
HELP_T,
PAGEUP_T,
PAGEDOWN_T,
POWER_T,
VOLUP_T,
VOLDOWN_T,
MUTE_T,
PLAY_T,
STOP_T,
PAUSE_T,
RECORD_T,
REWIND_T,
FASTFWD_T,
EJECT_T,
FORWARD_T,
BACKWARD_T,
} PassThruOpId;
希望有高手能指点一下!
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!