使用Smalidea对无源码APK调试简介

   2017-01-06 0
核心提示:阅读:8最近正好也用了Smalidea,就ZZ的原贴做一些补充。可调试APP如果Android的系统属性ro.debuggable等于1(用getprop ro.debuggable验证),则所有APP都可调试。如果ro.debuggable等于0,某APP的AndroidManifest.xml中有android:debuggable=”true”,该APP

阅读: 8

最近正好也用了Smalidea,就ZZ的原贴做一些补充。

  1. 可调试APP

如果Android的系统属性ro.debuggable等于1(用getprop ro.debuggable验证),则所有APP都可调试。如果ro.debuggable等于0,某APP的AndroidManifest.xml中有android:debuggable=”true”,该APP可调试。

对于模拟器,ro.debuggable等于1:

$ adb -s emulator-5554 shell "getprop ro.debuggable"
 1

真实手机上ro.debuggable一般等于0,其上绝大多数APP的AndroidManifest.xml中没有android:debuggable=”true”,为了在真实手机上调试这些APP,必须用些歪招,不在此文范围。

ZZ用了:

$ adb -s emulator-5554 shell "getprop | grep ro.debuggable"
 [ro.debuggable]: [1]

没必要,可以直接”getprop ro.debuggable”。

1. 下载

https://github.com/JesusFreke/smali/

https://github.com/JesusFreke/smali/wiki/smalidea

https://bitbucket.org/JesusFreke/smali/downloads

https://bitbucket.org/JesusFreke/smali/downloads/smalidea-0.03.zip

https://bitbucket.org/JesusFreke/smali/downloads/smali-2.2b4.jar

https://bitbucket.org/JesusFreke/smali/downloads/baksmali-2.2b4.jar

2. 安装

AndroidStudio->Configure->Plugins->Installpluginfromdisk->选中smalidea-0.03.zip->RestartAndroidStudio

3. 用baksmali反编译apk

ZZ用Apktool反编译,实际上Smalidea自带反编译工具

$ java -jarbaksmali-2.2b4.jar d -o outsome.apk

反编译结果出现在out子目录中

$ java -jarbaksmali-2.2b4.jar help d

baksmali有很多参数,下面这个参数你可能会感兴趣:

-a,--api
Thenumericapilevelofthefilebeingdisassembled (default: 15)

4. 在baksmali反编译基础上新建工程

创建目录:

X:\path\SOME_Smalidea

将baksmali得到的out子目录复制到上述目录,更名为src子目录:

X:\path\SOME_Smalidea\src
 
AndroidStudio->Importproject (EclipseADT, Gradle, etc.)->X:\path\SOME_Smalidea->Createprojectfromexistingsources
 
ProjectnameSOME_Smalidea
 Projectlocation X:\path\SOME_Smalidea

在AS左上角选择”Project Files”

SOME_Smalidea->src->右键菜单->Mark Directory As->Sources Root

5. 建立调试通道

对于可调试APP,有两种办法建立调试通道,一种是用DDMS,另一种是用ADB,其实前者也隐式使用ADB。

5.1 启动DDMS

X:\path\sdk\tools\monitor.bat

过去用ddms.bat启动DDMS,这个已经过时了,现在建议用monitor.bat启动DDMS。monitor.bat实际执行:

lib\monitor-x86\monitor.exe
 lib\monitor-x86_64\monitor.exe

选择哪种CPU架构,由如下命令控制:

java -jar X:\path\sdk\tools\lib\archquery.jar

最终受java的位数控制,如果用64-bits Java,将执行:

X:\path\sdk\tools\lib\monitor-x86_64\monitor.exe

最好用”where java”检查一下当前Java路径,调整环境变量,比如:

setpath=X:\path\Java\jre8\bin;%path%
 X:\path\sdk\tools\monitor.bat
 X:\path\sdk\tools\lib\monitor-x86_64\monitor.exe

假设启动DDMS失败,用Process Explorer检查是否存在多个monitor.exe,杀掉它们再试。此外可以用Tcpview检查8700/TCP被谁占用。

DDMS有GUI,在左上角区域可以看到所有可调试进程的PID及调试端口。从中选择待调试进程,会发现其多出一个调试端口,第一个端口(原有的)不固定,第二个端口(新增的)是固定的8700/TCP。这两个调试端口地位相当,都可以用于调试,只不过8700有利于固化Android Studio调试配置。8700始终跟着被选中的待调试进程,如果切换了待调试进程,8700将出现在新选中的进程行,上一个被选中的进程行不再出现8700。

关于DDMS、ADB、JDWP,有兴趣者参看:

Dalvik Debugger Support

dalvik/docs/debugger.html

Dalvik VM Debug Monitor

dalvik/docs/debugmon.html

system/core/adb/jdwp_service.c

《格蠢汇编》第20章《漫谈Android系统的调试模型》

5.2 adb forward tcp:hostport jdwp:pid

关掉DDMS,直接用ADB建立调试通道

$ adb -s emulator-5554 shell "ps | grep com.anything.some"
 USERPIDPPIDVSIZERSSWCHANPCNAME
 u0_a47 10140 795 187052 28200 ffffffffb7ede827 S com.anything.some

注意双引号的使用,这样可以确保执行Android系统中的grep,而不是PC上的grep,从而使得上述命令在Windows、Linux上都可用。

$ adb -s emulator-5554 forwardtcp:8700 jdwp:10140
 $ adb -s emulator-5554 forward --list
 emulator-5554 tcp:8700 jdwp:10140

关闭ADB建立的调试通道:

$ adb -s emulator-5554 forward --remove-all

上述命令的Windows实现可能有BUG,事后用Tcpview查看,adb仍在侦听8700/TCP,必须:

$ adbkill-server

我这里举例是以模拟器为目标,实际上可以是真实手机。

直接用ADB建立调试通道时,不一定使用8700/TCP。此处之所以仍然使用8700,是为了固化Android Studio调试配置。

5.3 启动APP之初就开始调试

前面假设APP已经启动,待调试代码仍可路过。如果待调试代码位于APP启动之初,需要额外操作。

假设目标是模拟器,检查AndroidManifest.xml

$ adb -s emulator-5554 shellamstart -D -W -n com.anything.some/.SomeActivity

在模拟器中会看到:

WaitingFor Debugger
ApplicationSOME (processcom.anything.some) is waitingfor thedebuggerto attach

然后启动DDMS或”adb forward tcp:hostport jdwp:pid”,建立调试通道。

假设目标是真实手机:

设置->开发者选项->USB调试

设置->开发者选项->选择调试应用->SOME

设置->开发者选项->等待调试器

去真实手机中正常启动SOME,也会停在”Waiting For Debugger”。

然后启动DDMS或”adb forward tcp:hostport jdwp:pid”,建立调试通道。

6. 在Android Studio中调试

Run->Edit Configurations->点击左上角+号->Remote

Name : DebugVia8700(这个名字可以任意)

Port : 8700(如果与DDMS配合,可以设成另一个端口,但每次都得改)

SOME_Smalidea->src->com/anything/some->b.smali

第72行附近代码:

--------------------------------------------------------------------------
if-nezv0, :cond_3c
 iget-object v0, p0, Lcom/anything/some/b;->a:Lcom/anything/some/SomeActivity;
 const v1, 0x7f060025
 --------------------------------------------------------------------------

在if-nez左侧空白处单击或按Ctrl-F8(参看Run菜单)设置断点

Run->DebugDebugVia8700

在Console面板中会看到:

Connectedto thetargetVM, address: 'localhost:8700', transport: 'socket'

去模拟器中正常操作SOME,触发断点,调用栈回溯:

com.anything.some.b.onClick(UnknownSource:-1)
android.view.View.performClick(View.java:4204)
 android.view.View$PerformClick.run(View.java:17355)
 android.os.Handler.handleCallback(Handler.java:725)
 android.os.Handler.dispatchMessage(Handler.java:92)
 android.os.Looper.loop(Looper.java:137)
 android.app.ActivityThread.main(ActivityThread.java:5041)
 java.lang.reflect.Method.invokeNative(Method.java:-1)
 java.lang.reflect.Method.invoke(Method.java:511)
 com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
 com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
 dalvik.system.NativeStart.main(NativeStart.java:-1)

可以单步跟踪,可以修改由this指针定位的成员变量。

对于JVM,我一直梦想着有这样一个Java字节码级别的调试器,可以看调用栈回溯、看单条Bytecode指令的中间状态(比如ifeq是否满足)、修改变量等等,一直没找到。想不到对于DVM,有Smalidea这样的东西,不错。

有些文章提到一个配置操作:

File->ProjectStructure->Project->ProjectSDK

对于在baksmali反编译基础上新建工程,此处显示。这些文章认为必须在此设置SDK版本,完全是胡说八道,根本不需要。

7. 排错

注意,”am start -D”仍然要求ro.debuggable=1或android:debuggable=”true”

假设在真实手机上调试一个不可调试APP,”am start -D”不会报错,但这个进程中不会出现JDWP线程,可用如下命令验证:

$ adb -s XXXshell "ps -t | grep -A 8 com.anything.some"
 $ adb -s XXXshell "ps -t | grep -B 6 JDWP"

对于这种情况,DDMS里看不到”com.anything.some”。如果用”adb forward tcp:8700 jdwp:pid”强行建立调试通道,只是看上去成功了,Tcpview看到adb侦听127.0.0.1:8700/TCP,在Android Studio中尝试调试时,报错:

ErrorrunningDebugVia8700: Unableto opendebuggerport (localhost:8700): java.net.SocketException "Connection reset"

简单点说,如果APP所在进程没有出现JDWP线程,不管你怎么折腾,都不要想着调试了。

如果您需要了解更多内容,可以

加入QQ群:570982169

直接询问:010-68438880

 
标签: Java Linux
反对 0举报 0 评论 0
 

免责声明:本文仅代表作者个人观点,与乐学笔记(本网)无关。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
    本网站有部分内容均转载自其它媒体,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责,若因作品内容、知识产权、版权和其他问题,请及时提供相关证明等材料并与我们留言联系,本网站将在规定时间内给予删除等相关处理.

  • SDK热更之如何在SDK代码中自动插桩及如何生成补
    写在前面本文是SDKHotfix相关的SDK热更系列文章中的一篇,以下为项目及系列文章相关链接:SDKHotfix整体介绍:http://blog.bihe0832.com/sdk_hotfix_project.htmlSDKHotfix对应github地址:https://github.com/bihe0832/SDKHoxFix这篇文章主要介绍一下SDK热更
  • ASimpleCache
    ASimpleCache 是一个为android制定的 轻量级的 开源缓存框架。轻量到只有一个java文件(由十几个类精简而来)。1、它可以缓存什么东西?普通的字符串、JsonObject、JsonArray、Bitmap、Drawable、序列化的java对象,和 byte数据。2、它有什么特色?特色主要是
    02-05 Java开源
  • 原生App与javascript交互之JSBridge接口原理、
    前期调研调研对象:支付宝,微信,云之家调研文档:Android中JS与Java的极简交互库 SimpleJavaJsBridge设计需求阅读类型的业务功能页面需要由前端H5实现,需要做到服务端可控;页面界面更改减少重新发布新版本的频率;功能页面部分原型需求无法实现,需要原生
  • RxJava系列番外篇:一个RxJava解决复杂业务逻辑
    之前写过一系列RxJava1的文章,也承诺过会尽快有RxJava2的介绍。无奈实际项目中还未真正的使用RxJava2,不敢妄动笔墨。所以这次还是给大家分享一个使用RxJava1解决问题的案例,希望对大家在使用RxJava的时候有一点点启发。对RxJava还不了解的同学可以先去看看
  • 框架Robust原理解析(下)
    框架Robust原理解析(下)
    一、回顾框架原理本篇继续来看热修复框架Robust原理,在之前的一篇文章中已经详细讲解了:Robust框架原理,因为这个框架不是开源的,所以通过官方给出的原理介绍,咋们自己模拟了案例和框架逻辑的简单实践。最后在通过反编译美团app进行验证咋们的逻辑实现是
  • 年度盘点(四) | 2016 年十大 Java / Android 开发者必读好文
    年度盘点(四) | 2016 年十大 Java / Android
    2016 年已经过去,感谢大家支持开发者头条。 年度盘点第四篇: 2016 年十大 Java / Android 开发者必读好文 。 长按识别文章摘要下方二维码,即可进入文章评论页。0. 推荐几个自己写的 Java 后端相关的范例项目这里推荐几个自己写的范例项目,主要采用 SSM(S
  • 8个华丽而实用的Java图表类库
    8个华丽而实用的Java图表类库
    学习Java的同学注意了!!! 学习过程中遇到什么问题或者想获取学习资源的话,欢迎加入Java学习交流群,群号码: 589809992 我们一起学Java! 前段时间我们为大家分享过一些最常用的Java图表应用和Android图表应用,无论是在PC平台上还是移动平台上,图表和报
  • 第151期:一个RxJava解决复杂业务逻辑的案例
    第151期:一个RxJava解决复杂业务逻辑的案例
    第151期:一个RxJava解决复杂业务逻辑的案例深度讨论 基本特效:饿了么丝滑无缝过度搜索栏的实现 diycode 帖子优先,就给上个头条吧。Android开发 一个RxJava解决复杂业务逻辑的案例 本文给大家分享一个使用RxJava解决问题的案例,希望对大家在使用RxJava的时
  • Eclipse 集成ijkplayer demo
    Eclipse 集成ijkplayer demo
    接着上一篇在Mac上编译ijkplayer的.so,现在将这些文件夹拷贝到windows上。(在mac和winds上集成到eclipse上是一样的,只是我这mac上没有安装eclipse)。现在开始说集成到Eclipse的步骤:1 更改目录结构 以 ijkplayer-armv7a 文件夹为例,删除选中的这四个文件
    12-23 EclipseJava
  • [Java] Retrofit2.0 如何进行GBK编码
    对Retrofit + OkHttp还不熟悉的人可以点传送门,先看下这两个东西的使用。Retrofit:https://github.com/square/retrofitOkHttp:https://github.com/square/okhttp分析接口文档要求Post请求,字段使用GBK编码我们先按照Retrofit的规范和接口文档来写接口: @PO
    12-23 RetrofitJava
点击排行