本文博客地址:https://blog.csdn.net/QQ1084283172/article/details/80994434

在进行Android应用程序的逆向分析时,经常需要对Android应用程序的按钮事件、Activity界面等类的代码进行定位分析,传统的代码定位方法就是进行按钮或者Activity界面等显示的 字符串信息 进行全局的搜索,然后找他们的id或者类进行代码的定位,比较繁琐,这里介绍一个基于Xposed Hook实现的Android apk快速定位,灰色按钮克星工具DroidSword,当然了亦可以使用我前面的博客中提到的《Xposed框架Hook Android应用的所有类方法打印Log日志》和《查找和定位Android应用的按钮点击事件的代码位置基于Xposed Hook实现》进行Android应用程序的需要分析的代码的定位。

DroidSword工具的功能介绍:

1.快速定位Activity,以及点击View的信息

2.点击悬浮窗口获取Fragment

3.灰色按钮克星

4.文字修改神器

DroidSword工具的github地址:https://github.com/githubwing/DroidSword

DroidSword工具作者的学习博客:http://androidwing.net

DroidSword工具是基于Xposed Hook实现的,但是作者githubwing是使用Kotlin语言实现的,对于Kotlin语言不熟悉,但是对于DroidSword工具的实现思路还是能看明白,下面简要的分析一下。

1.类IHooker是作者编写的xposed hook的接口类,代码如下:

2.类net.androidwing.droidsword.Init是DroidSword工具xposed hook的入口类:

3.类ViewClickedHooker主要用于实现Hook类android.view.View的方法onTouchEvent,获取到View类的名称和View类的id以及View的事件监听类对象的类名称;Hook类android.view.View的方法dispatchTouchEvent,获取到的View类的名称、View类的id、View的事件监听类对象的类名称并在设备的界面上显示出来。

源码文件路径:/frameworks/base/core/java/android/view/View.java

一般View组件情况下,Hook类android.view.View的类方法onTouchEvent函数,View组件通过获取实例对象View中的成员变量mListenerInfo->mOnClickListener所属的类名称,得到响应View按钮单击事件的监听响应类OnClickListener的信息。

    /*** Implement this method to handle touch screen motion events.* <p>* If this method is used to detect click actions, it is recommended that* the actions be performed by implementing and calling* {@link #performClick()}. This will ensure consistent system behavior,* including:* <ul>* <li>obeying click sound preferences* <li>dispatching OnClickListener calls* <li>handling {@link AccessibilityNodeInfo#ACTION_CLICK ACTION_CLICK} when* accessibility features are enabled* </ul>** @param event The motion event.* @return True if the event was handled, false otherwise.*/public boolean onTouchEvent(MotionEvent event) {final int viewFlags = mViewFlags;if ((viewFlags & ENABLED_MASK) == DISABLED) {if (event.getAction() == MotionEvent.ACTION_UP && (mPrivateFlags & PFLAG_PRESSED) != 0) {setPressed(false);}// A disabled view that is clickable still consumes the touch// events, it just doesn't respond to them.return (((viewFlags & CLICKABLE) == CLICKABLE ||(viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE));}if (mTouchDelegate != null) {if (mTouchDelegate.onTouchEvent(event)) {return true;}}if (((viewFlags & CLICKABLE) == CLICKABLE ||(viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)) {switch (event.getAction()) {case MotionEvent.ACTION_UP:boolean prepressed = (mPrivateFlags & PFLAG_PREPRESSED) != 0;if ((mPrivateFlags & PFLAG_PRESSED) != 0 || prepressed) {// take focus if we don't have it already and we should in// touch mode.boolean focusTaken = false;if (isFocusable() && isFocusableInTouchMode() && !isFocused()) {focusTaken = requestFocus();}if (prepressed) {// The button is being released before we actually// showed it as pressed.  Make it show the pressed// state now (before scheduling the click) to ensure// the user sees it.setPressed(true);}if (!mHasPerformedLongPress) {// This is a tap, so remove the longpress checkremoveLongPressCallback();// Only perform take click actions if we were in the pressed stateif (!focusTaken) {// Use a Runnable and post this rather than calling// performClick directly. This lets other visual state// of the view update before click actions start.if (mPerformClick == null) {mPerformClick = new PerformClick();}if (!post(mPerformClick)) {performClick();}}}if (mUnsetPressedState == null) {mUnsetPressedState = new UnsetPressedState();}if (prepressed) {postDelayed(mUnsetPressedState,ViewConfiguration.getPressedStateDuration());} else if (!post(mUnsetPressedState)) {// If the post failed, unpress right nowmUnsetPressedState.run();}removeTapCallback();}break;case MotionEvent.ACTION_DOWN:mHasPerformedLongPress = false;if (performButtonActionOnTouchDown(event)) {break;}// Walk up the hierarchy to determine if we're inside a scrolling container.boolean isInScrollingContainer = isInScrollingContainer();// For views inside a scrolling container, delay the pressed feedback for// a short period in case this is a scroll.if (isInScrollingContainer) {mPrivateFlags |= PFLAG_PREPRESSED;if (mPendingCheckForTap == null) {mPendingCheckForTap = new CheckForTap();}postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout());} else {// Not inside a scrolling container, so show the feedback right awaysetPressed(true);checkForLongClick(0);}break;case MotionEvent.ACTION_CANCEL:setPressed(false);removeTapCallback();removeLongPressCallback();break;case MotionEvent.ACTION_MOVE:final int x = (int) event.getX();final int y = (int) event.getY();// Be lenient about moving outside of buttonsif (!pointInView(x, y, mTouchSlop)) {// Outside buttonremoveTapCallback();if ((mPrivateFlags & PFLAG_PRESSED) != 0) {// Remove any future long press/tap checksremoveLongPressCallback();setPressed(false);}}break;}return true;}return false;}

对于AdapterView类型的View组件,通过Hook类android.view.View的方法dispatchTouchEvent,AdapterView组件获取实例对象View中的成员变量mOnItemClickListener的类(事件响应类)的类名称,得到监听和响应用户单击事件的处理类OnItemClickListener的信息。

/*** Pass the touch screen motion event down to the target view, or this* view if it is the target.** @param event The motion event to be dispatched.* @return True if the event was handled by the view, false otherwise.*/public boolean dispatchTouchEvent(MotionEvent event) {if (mInputEventConsistencyVerifier != null) {mInputEventConsistencyVerifier.onTouchEvent(event, 0);}if (onFilterTouchEventForSecurity(event)) {//noinspection SimplifiableIfStatementListenerInfo li = mListenerInfo;if (li != null && li.mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED&& li.mOnTouchListener.onTouch(this, event)) {return true;}if (onTouchEvent(event)) {return true;}}if (mInputEventConsistencyVerifier != null) {mInputEventConsistencyVerifier.onUnhandledEvent(event, 0);}return false;}

4.类ActivityHooker主要用于实现Hook类android.app.Activity的方法onResume,获取类方法onResume所属类Activity的实例对象的类名称并显示出来。

    /*** Called after {@link #onRestoreInstanceState}, {@link #onRestart}, or* {@link #onPause}, for your activity to start interacting with the user.* This is a good place to begin animations, open exclusive-access devices* (such as the camera), etc.** <p>Keep in mind that onResume is not the best indicator that your activity* is visible to the user; a system window such as the keyguard may be in* front.  Use {@link #onWindowFocusChanged} to know for certain that your* activity is visible to the user (for example, to resume a game).** <p><em>Derived classes must call through to the super class's* implementation of this method.  If they do not, an exception will be* thrown.</em></p>* * @see #onRestoreInstanceState* @see #onRestart* @see #onPostResume* @see #onPause*/protected void onResume() {if (DEBUG_LIFECYCLE) Slog.v(TAG, "onResume " + this);getApplication().dispatchActivityResumed(this);mCalled = true;}

5.类FragmentHooker用于实现Hook类"android.support.v4.app.Fragment"的方法onResume和方法setUserVisibleHint,获取类Fragment的类名称并进行显示。

源码文件路径:/frameworks/support/v4/java/android/support/v4/app/Fragment.java

    /*** Called when the fragment is visible to the user and actively running.* This is generally* tied to {@link Activity#onResume() Activity.onResume} of the containing* Activity's lifecycle.*/public void onResume() {mCalled = true;}

    /*** Set a hint to the system about whether this fragment's UI is currently visible* to the user. This hint defaults to true and is persistent across fragment instance* state save and restore.** <p>An app may set this to false to indicate that the fragment's UI is* scrolled out of visibility or is otherwise not directly visible to the user.* This may be used by the system to prioritize operations such as fragment lifecycle updates* or loader ordering behavior.</p>** @param isVisibleToUser true if this fragment's UI is currently visible to the user (default),*                        false if it is not.*/public void setUserVisibleHint(boolean isVisibleToUser) {if (!mUserVisibleHint && isVisibleToUser && mState < STARTED) {mFragmentManager.performPendingDeferredStart(this);}mUserVisibleHint = isVisibleToUser;mDeferStart = !isVisibleToUser;}

有作者gtict112将DroidSword工具的功能用java代码进行了实现并添加了新的功能构建成工程xposedhook,xposedhook工程的github地址:https://github.com/gtict112/xposedhook,后面有时间我再看下将这部分代码集成到我自己的Xposed模块中。

DroidSword工具的类ViewClickedHooker的代码:

package net.androidwing.droidsword.hookerimport android.app.AlertDialog
import android.app.AndroidAppHelper
import android.app.Dialog
import android.content.DialogInterface
import android.view.MotionEvent
import android.view.View
import android.widget.*
import de.robv.android.xposed.XC_MethodHook
import de.robv.android.xposed.XposedHelpers
import de.robv.android.xposed.callbacks.XC_LoadPackage
import net.androidwing.droidsword.func.TextViewChanger
import net.androidwing.droidsword.func.ViewEnabler
import net.androidwing.droidsword.utils.LogUtils/*** Created  on 28/10/2017.*/
class ViewClickedHooker : IHooker {override fun hook(lp: XC_LoadPackage.LoadPackageParam) {// Hook类android.view.View的方法onTouchEvent// public boolean onTouchEvent(MotionEvent event)XposedHelpers.findAndHookMethod(View::class.java,"onTouchEvent",MotionEvent::class.java, object : XC_MethodHook() {override fun afterHookedMethod(param: MethodHookParam?) {super.afterHookedMethod(param)// 获取类方法onTouchEvent所在的实例对象Viewval view = param?.thisObject as View// 获取类方法onTouchEvent的传入参数MotionEvent实例对象val event = param.args!![0] as MotionEvent// 对用户点击屏幕的事件进行判断if (event.action == MotionEvent.ACTION_UP) {// 获取实例对象View中的成员变量mListenerInfo->mOnClickListener所属的类名称val listener = XposedHelpers.getObjectField(XposedHelpers.getObjectField(view, "mListenerInfo"),"mOnClickListener").javaClass.name// 显示获取到的View类的名称、View类的id、View的事件监听类对象的类名称ActivityHooker.setActionInfoToMenu("","${view.javaClass.name} ${view.id} \nListener: $listener")antiDisable(view)}}})// Hook类android.view.View的方法dispatchTouchEvent// public boolean dispatchTouchEvent(MotionEvent event)XposedHelpers.findAndHookMethod(View::class.java,"dispatchTouchEvent",MotionEvent::class.java, object : XC_MethodHook() {override fun afterHookedMethod(param: MethodHookParam?) {super.afterHookedMethod(param)// 获取类方法dispatchTouchEvent所在类View的实例val view = param?.thisObject as View// 获取类方法onTouchEvent的传入参数MotionEvent实例对象val event = param.args!![0] as MotionEvent// 进行用户点击屏幕的事件类型的判断if (event.action == MotionEvent.ACTION_DOWN) {// 进行View类型的判断(AdapterView)if (view is AdapterView<*>) {// 获取实例对象View中的成员变量mOnItemClickListener的类(事件响应类)的类名称val listener = XposedHelpers.getObjectField(view,"mOnItemClickListener").javaClass.name// 显示获取到的View类的名称、View类的id、View的事件监听类对象的类名称ActivityHooker.setActionInfoToMenu("","${view.javaClass.name} ${view.id} \nListener: $listener")}}}})// 文字修改功能的实现XposedHelpers.findAndHookMethod(View::class.java,"onTouchEvent",MotionEvent::class.java, object : XC_MethodHook() {override fun afterHookedMethod(param: MethodHookParam?) {super.afterHookedMethod(param)val targetView = param?.thisObject as Viewif (true) {// ??showChangeTextDialog(targetView, param)}}})}private fun antiDisable(view: View) {//TODO 默认开启待添加配置文件if (false) {ViewEnabler.antiDisable(view)}}/*** 文本修改神器功能*/private fun showChangeTextDialog(targetView: View,param: XC_MethodHook.MethodHookParam) {//TODO 默认开启待添加配置文件val event = param.args!![0] as MotionEventif (false) {TextViewChanger.showChangeDialog(targetView, event)}}

DroidSword工具的类ActivityHooker的代码:

package net.androidwing.droidsword.hookerimport android.app.Activity
import android.app.AndroidAppHelper
import android.app.Fragment
import android.content.Context
import android.graphics.Color
import android.os.Build
import android.os.Bundle
import android.support.v7.widget.AppCompatImageHelper
import android.text.TextUtils
import android.view.LayoutInflater
import android.view.ViewGroup
import android.widget.FrameLayout
import android.widget.TextView
import android.widget.Toast
import de.robv.android.xposed.XC_MethodHook
import de.robv.android.xposed.XposedHelpers
import de.robv.android.xposed.callbacks.XC_LoadPackage
import net.androidwing.droidsword.utils.LogUtils
import java.util.ArrayList/*** Created  on 30/10/2017.*/
class ActivityHooker : IHooker {// /frameworks/base/core/java/android/app/Activity.javaoverride fun hook(lp: XC_LoadPackage.LoadPackageParam) {// Hook类android.app.Activity的方法onResume// protected void onResume()XposedHelpers.findAndHookMethod(Activity::class.java, "onResume", object : XC_MethodHook() {override fun afterHookedMethod(param: MethodHookParam?) {super.afterHookedMethod(param)// 获取类方法onResume所属类Activity的实例对象val activity = param?.thisObject as Activity// 显示类对象实例Activity的类名称addTextView(activity)// Hook类Fragment的类方法,获取类Fragment实例对象的类名称FragmentHooker().hookFragment(param)}})}// 显示类对象实例Activity的类名称private fun addTextView(activity: Activity) {// 获取类对象实例Activity的类名称val className = activity.javaClass.name.toString()// 构建TextView实例对象if (sTextView == null) {genTextView(activity)}if (sTextView?.parent != null) {val parent = sTextView?.parentif (parent is ViewGroup) {parent.removeView(sTextView)}}(activity.window.decorView as FrameLayout).addView(sTextView)// 显示类对象实例Activity的类名称setActionInfoToMenu(className, "")sTextView?.bringToFront()}// 创建TextView的实例对象private fun genTextView(activity: Activity) {sTextView = TextView(activity)with(sTextView!!) {textSize = 8fy = 48 * 2fsetBackgroundColor(Color.parseColor("#cc888888"))setTextColor(Color.WHITE)layoutParams = FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT,FrameLayout.LayoutParams.WRAP_CONTENT)}}companion object {var sTextView: TextView? = nullprivate var sActivityName = ""private var sViewName = ""fun setActionInfoToMenu(activityName: String, viewName: String) {sTextView?.text = getActionInfo(activityName, viewName)}public var sFragmentName = ""private fun getActionInfo(activityName: String, viewName: String): CharSequence? {if (activityName.isEmpty().not()) {sActivityName = activityName}if (viewName.isEmpty().not()) {sViewName = viewName}val pid = android.os.Process.myPid()return "Activity: $sActivityName \nPid: $pid \nClick: $sViewName \nFragment:$sFragmentName"}}

DroidSword工具的类FragmentHooker的代码:

package net.androidwing.droidsword.hookerimport de.robv.android.xposed.XC_MethodHook
import de.robv.android.xposed.XposedHelpers
import de.robv.android.xposed.callbacks.XC_LoadPackage
import net.androidwing.droidsword.utils.LogUtils/*** Created  on 30/10/2017.*/
class FragmentHooker : IHooker {override fun hook(lp: XC_LoadPackage.LoadPackageParam) {}// /frameworks/support/v4/java/android/support/v4/app/Fragment.javafun hookFragment(param: XC_MethodHook.MethodHookParam?) {// Hook类"android.support.v4.app.Fragment"的方法onResume// public void onResume()XposedHelpers.findAndHookMethod(param?.thisObject?.javaClass?.classLoader?.loadClass("android.support.v4.app.Fragment"),"onResume",object : XC_MethodHook() {override fun afterHookedMethod(param: MethodHookParam?) {super.afterHookedMethod(param)// 获取类Fragment的类名称ActivityHooker.sFragmentName = (param?.thisObject?.javaClass?.name!!)// 进行类Fragment的类名称显示的设置ActivityHooker.setActionInfoToMenu("","")}override fun beforeHookedMethod(param: MethodHookParam?) {super.beforeHookedMethod(param)}})// Hook类"android.support.v4.app.Fragment"的方法setUserVisibleHint// public void setUserVisibleHint(boolean isVisibleToUser)XposedHelpers.findAndHookMethod(param?.thisObject?.javaClass?.classLoader?.loadClass("android.support.v4.app.Fragment"),"setUserVisibleHint", Boolean::class.java,object : XC_MethodHook() {override fun afterHookedMethod(param: MethodHookParam?) {super.afterHookedMethod(param)if (param?.args!![0] == true) {LogUtils.e("fragment showing:")LogUtils.e("fragment ${param?.thisObject?.javaClass?.name}")// 获取类Fragment的类名称ActivityHooker.sFragmentName = (param?.thisObject?.javaClass?.name!!)// 进行类Fragment的类名称显示的设置ActivityHooker.setActionInfoToMenu("","")}}override fun beforeHookedMethod(param: MethodHookParam?) {super.beforeHookedMethod(param)}})}}

Android apk快速定位、灰色按钮克星--DroidSword相关推荐

  1. 超级灰色按钮克星1.4.1309.12

    软件简介:传统的超级灰色按钮克星只能激活传统Windows平台下的按钮.本软件不仅可以激活传统Windows平台下的软件,也可以激活DOTNET平台下的软件. 新版本支持最新Win8 x86/x64操 ...

  2. Android 如何快速定位当前页面是哪个Activity or Fragment

    在日常需求开发中,经常碰到不太熟悉的模块,如何快速定位相应页面对应的Activity/Fragment ? (1)查看当前Activity  :adb shell "dumpsys wind ...

  3. Android签名打包很慢,Android APK快速签名—优化打包时间

    一.Android签名机制 Android签名机制可划分为ROM签名机制与第三方APK签名机制,在这里只讨论APK签名机制. Android系统在安装APK的时候,首先会检验APK的签名,如果发现签名 ...

  4. android listview快速定位,【转】android中ListView的定位:使用setSelectionFromTop实现ListView的position的保持...

    如果一个ListView太长,有时我们希望ListView在从其他界面返回的时候能够恢复上次查看的位置,这就涉及到ListView的定位问题: 解决的办法如下: 这里使用了setSelectionFr ...

  5. 如何快速定位Android APP中的关键函数?

    需求来源 在逆向分析中,肯定是越快地定位到目标函数越好,那么有没有这样的一种工具可以快速地辅助分析人员定位到目标函数呢? 最早的一个想法是这样的: - 通过某种机制让APP输出函数调用时候的日志记录. ...

  6. 位置在此计算机上运行程序灰色,Win10电脑中定位服务按钮灰色无法开启的2种解决方法...

    在win10系统中自带有定位功能,这是系统收集数据的一个途径,很多应用会用到定位功能,比如地图应用就会用到我们的定位,所以我们就需要手动来开启定位服务,不过有win10系统用户反映说操作中心的定位按钮 ...

  7. 快速定位解决Android内存泄漏

    此文章来源于APP架构师这个公众号 今天的主题是Android开发中的内存泄漏,之所以说这个是因为前几天做了项目中的内存泄漏排查与解决,在这里总结一下,被提供一种快速定位解决Android内存泄漏的方 ...

  8. android的快速开发框架集合

    android的快速开发框架集合 出自:http://blog.csdn.net/shulianghan/article/details/18046021 1.Afinal  (快速开发框架) 简介: ...

  9. android apk 减小apk的大小

    因为推广的需要,公司需要把APK的大小再"减小"一下,4M以内! 当达到4M以内之后,公司建议说,能否再压压?2M如何? 瘦身前 因为平时就考虑到大小的限制,所以很多工作已经做过了 ...

  10. 利用Android Studio快速搭建App

    大家好,我是烤鸭: 给大家分享一个简单的用Android Studio快速搭建app 工具: Android Studio 64位 专业版 插件: Datepicker Timepicker okht ...

最新文章

  1. 使用libjpeg进行图片压缩(哈夫曼算法,无损压缩)
  2. 2020-WEB开发路线图,和即将到来的 2021-WEB技术清单
  3. 第二阶段_第五小节_C#基础3
  4. was6 linux 卸载,重新安装was61
  5. Shiro的subject实质上是当前执行用户的特定视图。
  6. 获取字符串中不重复的第一个字符
  7. 伪随机序列MATLAB实现
  8. Pyinstller打包的exe文件反编译
  9. 智能健康管理系统开发提供精准健康管理
  10. 常用编程语言的介绍及特点
  11. 1044 : 不及格率
  12. android适配器
  13. 一款 Material Design 风格的妹子福利 App.
  14. z-buffer算法
  15. pythonapi是什么意思_API是什么意思?API文档又是什么意思?
  16. 学术期刊划分(SCI、EI、SSCI、IEEE、CSSCI等)
  17. 多因子选股Alpha策略
  18. MSPA提取生态源地过程
  19. 乳腺癌2002~2018城市和乡村个年龄段患病率曲线图绘制 ---pyechart
  20. keil5 报错no target connected

热门文章

  1. 两张图让你快速读懂JVM字节码指令
  2. 华硕服务器主板型号命名规则,华硕ROG系列主板命名规则详解_华硕 Maximus V Formula_主板评测-中关村在线...
  3. c语言答辩ppt案例,c语言ppt例子课题了答辩ppt成品中南民族大学.ppt
  4. mike21换成计算机名称,mike21
  5. 文库/豆丁网等免账号,积分下载器
  6. 收藏 | 应急响应的基本流程
  7. 前端项目-尚品会-来自b站尚硅谷视频
  8. 计算机科学基础慕课答案,大学计算机基础mooc习题整理(含答案)
  9. 安拆网:脚手架钢管规格及施工要求
  10. YOLO算法之车型识别