首页
社区
课程
招聘
[原创]WM里蓝牙AVRCP的消息队列研究分析(问题已解决,笔记归档)
发表于: 2009-6-11 18:28 9774

[原创]WM里蓝牙AVRCP的消息队列研究分析(问题已解决,笔记归档)

2009-6-11 18:28
9774

折腾这破东西好几天了,目前还没得到进一步突破,不过已经知道了许多以前不知道的东西,写一下当前笔记。

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;

希望有高手能指点一下!


[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 7
支持
分享
最新回复 (7)
雪    币: 164
活跃值: (10)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
2
补充:问题解决了……关键还是在于btd.dll自身,有兴趣的朋友可以猜一下是怎么解决的,实际上解决方法已经夹杂在我反汇编的代码里了…………从我眼皮底下漏过去无数次,终于抓住了。

[15:57:56] 接收到AVRCP消息,OpId=44,OpCode=7c
[15:57:56] 接收到AVRCP消息,OpId=c4,OpCode=7c
[15:57:58] 接收到AVRCP消息,OpId=4c,OpCode=7c
[15:57:58] 接收到AVRCP消息,OpId=cc,OpCode=7c
[15:57:58] 接收到AVRCP消息,OpId=4b,OpCode=7c
[15:57:58] 接收到AVRCP消息,OpId=cb,OpCode=7c

TCPMP 0.72RC1 AVRCP蓝牙控制补丁 制作中
2009-6-12 15:33
0
雪    币: 2604
活跃值: (64)
能力值: (RANK:510 )
在线值:
发帖
回帖
粉丝
3
感谢小金介绍的知识和笔记。
2009-6-13 22:24
0
雪    币: 164
活跃值: (10)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
4
TCPMP蓝牙耳机控制(AVRCP)功能插件 v0.3 Alpha



源代码已提交CoreCodec团队的Beta_Boy。
2009-6-13 23:08
0
雪    币: 126
活跃值: (46)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
兄弟,我承认,很有执着精神.但是,请你看下PB好么?
帮助里没找到的话,你看下源代码吧。
在PB的根目录下,搜索AVRCP,你想要的什么东西都出来了,不用猜,也不用反汇编。
2009-6-14 00:27
0
雪    币: 164
活跃值: (10)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
6
哦,看来我要找时间下载个PB了。

我只是业余开发WM平台程序,并非专门搞CE的。

另外我百度和Google了都没找到AVRCP和CE和WM的实际可用资料,唯独MSDN提到过一个CE下的头文件以及AVRCP声明API和标准读取概念(Read from MsgQueue),但是没有任何细节,所以我才不得已IDA的。
2009-6-14 10:03
0
雪    币: 22
活跃值: (30)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
还是值得顶一下的,不过,要看源码的话可以下一个CE mobile 6的开发环境,CE 6以前的PB公布的是部分代码,直到现在的新CE 6,MS已经把100%的源码都公布了。
2009-6-14 13:31
0
雪    币: 202
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
还是兄弟你专业啊
2009-6-24 22:35
0
游客
登录 | 注册 方可回帖
返回
//