问题描述:在逆向一个app,研究环境是一台红米2,需要使用jdwp接口,也就是ddms下面这个界面:
但神奇的是,同一台主机上,模拟器的进程可以显示在ddms界面上,红米2确一个进程都没有显示出来。cmd里使用 adb jdwp 命令,也没有显示任何接口。
通过简单搜索发现,一个app进程要能被jdwp客户端调试,要不就是编译的时候主配置文件需要开启 android:debuggable="true" ,要不就是系统 boot.img 里的一个文件 default.pro 里的 ro.debuggable 需要值为 1, 后者可以使所有app 进程可以调试, 根据网上的做法用 apktool 工具反编译目标 app,将其主配置文件加上 android:debuggable="true" 再重新打包,然后安装到红米2 ,然而 adb jdwp 依然显示没有接口。
遇到这种情况,就需要研究下 adb 和 jdwp 的原理了,根据android源码 system/core/adb/jdwp_service.c 的注释的说明,基本了解了adb 和 jdwp 是什么回事,大概是这样的,adb 有3种角色(代码是一套,编译选项和运行选项有不同):adbd,adb client, adb server, adb client 最简单的就是调试时在 cmd 里敲入的 adb 命令,这时候跑的就是 adb client 的代码,另外,ddms 或者 eclipse 或者 android studio 里的 debug 界面,其实也是一种 adb client , 它们都是接受用户的命令,然后发送给 adb server. adb server 是调试端(如PC端)的一个服务进程,它接受 adb client 的命令,然后发送给设备或模拟器里的 adbd 进程。 另外,设备里根据配置可能会启动一个 adbd daemon 进程,这个进程负责响应adb server的命令,向android系统请求各种数据后返回给adb server,adbd 与adb server的交互可以用 tcp 的方式或者 usb 的方式。 jdwp 是一种java调试协议,在android的实现里边,如果开启了调试(前面说的两种情况至少满足一种),则进程内部虚拟机会启动一个 JDWP 线程,然后这个线程会跟 adbd 进程有一个unix socket的交互,交互的结果就是adbd内部维护了一个可以调试的目标app 进程列表,这样当 adb client 敲入 adb jdwp 后, adb server 将命令传给 adbd , adbd 就可以返回一个进程列表给 adb client 显示了。
adb client (debugger) , adb server, adbd, jdwp 4 者关系如下:
jdwp 线程和adbd 的 unix socket 连接可以通过命令查看:
了解了上述原理之后,首先可以确定一下,设备内部的jdwp调试路径是否正常,方法就是先安装原生的app(没有开启调试), 然后 busybox netstat -xa | grep jdwp 查看,发现果然没有连接,接着,用 apktool 反编译,修改后再打包安装,再用同样的命令查看,发现出来几个连接了,这时候可以基本判断,app 的修改是有效的,而且内部启动了jdwp线程且已经注册到了 adbd 进程内。
接下去的问题就是,为什么PC端的 Adb client 在跟 Adbd 请求的时候没有能返回列表,而如果请求的是模拟器,又是正常的。
红米2真机和模拟器的区别,主要就是 Adb server 和 adbd 的连接方式不一样,前者是USB的方式,后者是tcp的方式,而且有一个现象是,连接红米2后,adb devices 会提示出现两个设备,明明只有一个设备嘛! 既然有两个设备,就看一下设备管理器是什么情况,果然有发现:
android phone 设备下有两个驱动,搜索一下 xiaomi mdb ,果然有情况 :
原来小米/红米有一套 mdb 方案,可以实现小米助手在手机不开usb调试的情况下仍能连接手机(之前安装过小米助手,不确定mdb驱动是不是那时候安装的),不管三七二十一,在设备里找到 mdbd 进程,杀死它,发现能自动重启,又回到PC里边,把 MDB 驱动卸载了,重启系统之后,再次 Adb devices 发现只有一个设备了,再 adb jdwp ,发现居然能显示列表了:
打开ddms也能正常连接了,看来果然是小米的 mdb 驱动造成的。