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

最近这段时间比较郁闷,就不分享和学习比较复杂的Android逆向技巧和工具了,每天进步一点就好。这里介绍一下,作者deskid编写的开启Android应用调试选项的工具XDebug,该工具也是基于Xposed框架实现的,也就是在Android应用的启动之前,设置Android应用的调试选项标志为开启,这样Android应用启动的时候,就可以调试模式进行启动。

作者的github地址:https://github.com/deskid/XDebug

XDebug工具就是在Android应用启动之前,开启Android应用的调试选项,这样在DDMS中就可以看到原来不显示的Android进程都显示出来了,Android应用也可以使用 adb shell am -D 命令进行调试启动了。当我们点击Android系统的Home界面上Android应用的图标,然后该Android应用就会被Launcher所启动,在Android应用的Activity界面显示之前,会经过一系列的复杂流程处理,这些流程的过程可以参考老罗的博文进行学习,这里只谈论涉及到XDebug工具部分,先看下XDebug工具的编写Xposed代码:

package com.github.debugxposed;

import android.os.Process;

import de.robv.android.xposed.IXposedHookLoadPackage;
import de.robv.android.xposed.IXposedHookZygoteInit;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.callbacks.XC_LoadPackage; /**
* Created by deskidz on 12/5/16.
*/ public class XDebugable implements IXposedHookLoadPackage, IXposedHookZygoteInit { private static final int DEBUG_ENABLE_DEBUGGER = 0x1; private XC_MethodHook debugAppsHook = new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param)
throws Throwable { XposedBridge.log("-- beforeHookedMethod :" + param.args[1]); int id = 5;
int flags = (Integer) param.args[id];
// 修改类android.os.Process的start函数的第6个传入参数
if ((flags & DEBUG_ENABLE_DEBUGGER) == 0) {
// 增加开启Android调试选项的标志
flags |= DEBUG_ENABLE_DEBUGGER;
}
param.args[id] = flags; if (BuildConfig.DEBUG) {
XposedBridge.log("-- app debugable flags to 1 :" + param.args[1]);
}
}
}; @Override
public void handleLoadPackage(final XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable { } // 实现的接口IXposedHookZygoteInit的函数
@Override
public void initZygote(final IXposedHookZygoteInit.StartupParam startupParam) throws Throwable { // /frameworks/base/core/java/android/os/Process.java
// Hook类android.os.Process的start函数
XposedBridge.hookAllMethods(Process.class, "start", debugAppsHook);
}
}

作者deskid选择在Android应用启动调用类android.os.Processstart函数之前,修改该函数的第6个传入参数,增加开启Android应用的调试选项的调试选项标记。类android.os.Process的start函数是在Android应用启动时调用类com.android.server.am.ActivityManagerService的函数startProcessLocked被调用的。

源码路径:

http://androidxref.com/5.1.0_r1/xref/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java#2893

在类android.os.Process中start函数的实现代码如下:

    /**
* Start a new process.
*
* <p>If processes are enabled, a new process is created and the
* static main() function of a <var>processClass</var> is executed there.
* The process will continue running after this function returns.
*
* <p>If processes are not enabled, a new thread in the caller's
* process is created and main() of <var>processClass</var> called there.
*
* <p>The niceName parameter, if not an empty string, is a custom name to
* give to the process instead of using processClass. This allows you to
* make easily identifyable processes even if you are using the same base
* <var>processClass</var> to start them.
*
* @param processClass The class to use as the process's main entry
* point.
* @param niceName A more readable name to use for the process.
* @param uid The user-id under which the process will run.
* @param gid The group-id under which the process will run.
* @param gids Additional group-ids associated with the process.
* @param debugFlags Additional flags.
* @param targetSdkVersion The target SDK version for the app.
* @param seInfo null-ok SE Android information for the new process.
* @param zygoteArgs Additional arguments to supply to the zygote process.
*
* @return An object that describes the result of the attempt to start the process.
* @throws RuntimeException on fatal start failure
*
* {@hide}
*/
public static final ProcessStartResult start(final String processClass,
final String niceName,
int uid, int gid, int[] gids,
int debugFlags, int mountExternal,
int targetSdkVersion,
String seInfo,
String[] zygoteArgs) {
try {
return startViaZygote(processClass, niceName, uid, gid, gids,
debugFlags, mountExternal, targetSdkVersion, seInfo, zygoteArgs);
} catch (ZygoteStartFailedEx ex) {
Log.e(LOG_TAG,
"Starting VM process through Zygote failed");
throw new RuntimeException(
"Starting VM process through Zygote failed", ex);
}
}

类android.os.Process中start函数最终调用的类android.os.Process的startViaZygote函数,代码如下;如果Android应用开启了调试模式选项的标志,那么在创建Android应用的进程时,会增加"--enable-debugger"选项,这样Android应用就可以以调试模式进行启动了。

    /**
* Starts a new process via the zygote mechanism.
*
* @param processClass Class name whose static main() to run
* @param niceName 'nice' process name to appear in ps
* @param uid a POSIX uid that the new process should setuid() to
* @param gid a POSIX gid that the new process shuold setgid() to
* @param gids null-ok; a list of supplementary group IDs that the
* new process should setgroup() to.
* @param debugFlags Additional flags.
* @param targetSdkVersion The target SDK version for the app.
* @param seInfo null-ok SE Android information for the new process.
* @param extraArgs Additional arguments to supply to the zygote process.
* @return An object that describes the result of the attempt to start the process.
* @throws ZygoteStartFailedEx if process start failed for any reason
*/
private static ProcessStartResult startViaZygote(final String processClass,
final String niceName,
final int uid, final int gid,
final int[] gids,
int debugFlags, int mountExternal,
int targetSdkVersion,
String seInfo,
String[] extraArgs)
throws ZygoteStartFailedEx {
synchronized(Process.class) {
ArrayList<String> argsForZygote = new ArrayList<String>(); // --runtime-init, --setuid=, --setgid=,
// and --setgroups= must go first
argsForZygote.add("--runtime-init");
argsForZygote.add("--setuid=" + uid);
argsForZygote.add("--setgid=" + gid);
if ((debugFlags & Zygote.DEBUG_ENABLE_JNI_LOGGING) != 0) {
argsForZygote.add("--enable-jni-logging");
}
if ((debugFlags & Zygote.DEBUG_ENABLE_SAFEMODE) != 0) {
argsForZygote.add("--enable-safemode");
}
if ((debugFlags & Zygote.DEBUG_ENABLE_DEBUGGER) != 0) {
argsForZygote.add("--enable-debugger");
}
if ((debugFlags & Zygote.DEBUG_ENABLE_CHECKJNI) != 0) {
argsForZygote.add("--enable-checkjni");
}
if ((debugFlags & Zygote.DEBUG_ENABLE_ASSERT) != 0) {
argsForZygote.add("--enable-assert");
}
if (mountExternal == Zygote.MOUNT_EXTERNAL_MULTIUSER) {
argsForZygote.add("--mount-external-multiuser");
} else if (mountExternal == Zygote.MOUNT_EXTERNAL_MULTIUSER_ALL) {
argsForZygote.add("--mount-external-multiuser-all");
}
argsForZygote.add("--target-sdk-version=" + targetSdkVersion); //TODO optionally enable debuger
//argsForZygote.add("--enable-debugger"); // --setgroups is a comma-separated list
if (gids != null && gids.length > 0) {
StringBuilder sb = new StringBuilder();
sb.append("--setgroups="); int sz = gids.length;
for (int i = 0; i < sz; i++) {
if (i != 0) {
sb.append(',');
}
sb.append(gids[i]);
} argsForZygote.add(sb.toString());
} if (niceName != null) {
argsForZygote.add("--nice-name=" + niceName);
} if (seInfo != null) {
argsForZygote.add("--seinfo=" + seInfo);
} argsForZygote.add(processClass); if (extraArgs != null) {
for (String arg : extraArgs) {
argsForZygote.add(arg);
}
} return zygoteSendArgsAndGetResult(argsForZygote);
}
}

到这里,XDebug工具的原理已经很清楚了,基于作者的思路,也可以Hook类android.os.Process的startViaZygote函数,在该函数执行之前修改其第6个参数,增加Android开启调试选项的标志,谢谢原作者的思路。

为什么XDebug工具的作者deskid在选择实现Hook类android.os.Process的start函数时,实现的是Xposed框架的de.robv.android.xposed.IXposedHookZygoteInit接口而不是de.robv.android.xposed.IXposedHookLoadPackage接口呢?

如果是选择实现de.robv.android.xposed.IXposedHookLoadPackage接口则Hook类android.os.Process的start函数已经晚了,因为该函数已经执行过了,IXposedHookLoadPackage接口是Hook的Android应用启动时的ActivityThread.handleBindApplication函数,而类android.os.Process的start函数在handleBindApplication函数执行之前,因此这里选择实现IXposedHookZygoteInit接口,并且实现IXposedHookZygoteInit接口的修改对所有启动的App都有影响,下面是Xposed框架的api的说明。

Xposed框架的Api说明文档:https://api.xposed.info/reference/packages.html

有关Xposed源码的学习,后面再研究~

开启Android应用调试选项的工具XDebug的介绍的更多相关文章

  1. 开启Android Apk调试与备份选项的Xposed模块的编写

    本文博客地址:https://blog.csdn.net/QQ1084283172/article/details/80963610 在进行Android应用程序逆向分析的时候,经常需要进行Andro ...

  2. Android无线调试及手机设备与PC同屏工具——Chrome插件Vysor

    我们平时用手机调试时,经常是手不离机,以前可以下载个jar包能把手机屏映射到电脑桌面,但是运行比较卡,后来就放弃了,再之,手机接数据线有时也不太方便 ,pc与手机(连wifi)如处同一网段,就可以通过 ...

  3. Android开发调试日志工具类[支持保存到SD卡]

    直接上代码: package com.example.callstatus; import java.io.File; import java.io.FileWriter; import java.i ...

  4. Android 开发调试最优选项

    1 开发环境 VS2019 16.4.5 2 开发调试选项 Android 选项

  5. Android开发工具——Android Studio调试技巧

    .调试的两种方式 到目前,调试的相关基础我们已经介绍完了,但是不少同学对Android Studio中这两个按钮感到困惑:Debug和Attach process. 这里我们就简单介绍一下这两者的区别 ...

  6. 【Java/Android性能优3】Android性能调优工具TraceView使用介绍

    本文转自:http://blog.csdn.net/innost/article/details/9008691 在软件开发过程中,想必很多读者都遇到过系统性能问题.而解决系统性能问题的几个主要步骤是 ...

  7. Android 常用的性能分析工具详解:GPU呈现模式, TraceView, Systrace, HirearchyViewer(转)

    此篇将重点介绍几种常用的Android性能分析工具: 一.Logcat 日志 选取Tag=ActivityManager,可以粗略地知道界面Displaying的时间消耗.当我们打开一个Activit ...

  8. 【转】Android Eclipse调试技巧

    原文地址:https://www.cnblogs.com/tianchunming/p/5423942.html Android Eclipse调试技巧   在Android 应用程序开发中我们经常需 ...

  9. Android动态调试so库JNI_Onload函数-----基于IDA实现

    之前看过吾爱破解论坛一个关于Android'逆向动态调试的经验总结帖,那个帖子写的很好,对Android的脱壳和破解很有帮助,之前我们老师在上课的时候也讲过集中调试的方法,但是现在不太实用.对吾爱破解 ...

随机推荐

  1. Vue入门干货,以及遇到的坑

    一.安装环境及Vue脚手架搭建 参考文档:https://www.jianshu.com/p/1626b8643676 二.开发文档 官方文档:https://cn.vuejs.org/v2/guid ...

  2. 在windows上安装MySQL数据库注意点及Navicat Premium 15的破解

    在windows上安装MySQL数据库  跟随慕课网教程(http://www.imooc.com/wiki/mysqllesson/mysqlwindows.html)下载安装MySQL: 其中注意 ...

  3. Python--入门接口测试(1)

    1. 什么是接口测试?为什么要做接口测试? 接口测试是测试系统组件间接口的一种测试.接口测试主要用于检测外部系统与系统之间以及内部各个子系统之间的交互点.测试的重点是要检查数据的交换.传递和控制管理过 ...

  4. httpd解析PHP

    1.vim /usr/local/apache2.4/conf/httpd.conf 编辑httpd的主配置文件 搜索ServerName,把ServerName www.example.com:80 ...

  5. Memory Networks02 记忆网络经典论文

    目录 1 Recurrent Entity Network Introduction 模型构建 Input Encoder Dynamic Memory Output Model 总结 2 hiera ...

  6. LAMP环境搭建与配置

    下载mysql 解压 运行错误 下载插件 启动成功 安装Apache 解压 报错  安装插件 再次报错 修改文档 成功 安装插件 下载 安装php 安装完成 解析php 安装完成 虚拟主机(共享主机, ...

  7. 19. 一文搞懂 Go Modules 前世今生及入门使用

    Hi,大家好. 我是明哥,在自己学习 Golang 的这段时间里,我写了详细的学习笔记放在我的个人微信公众号 <Go编程时光>,对于 Go 语言,我也算是个初学者,因此写的东西应该会比较适 ...

  8. 力扣 - 208. 实现Trie(前缀树)

    目录 题目 思路 代码 复杂度分析 题目 208. 实现 Trie (前缀树) 思路 在我们生活中很多地方都用到了前缀树:自动补全,模糊匹配,九宫格打字预测等等... 虽然说用哈希表也可以实现:是否出 ...

  9. Elasticsearch集群升级指引

    目录 背景 第一部分 版本升级指引 第二部分 升级方法和具体步骤 总结 参考文献及资料 背景 Elasticsearch集群的版本升级是一项重要的集群维护工作.本篇文章参考官方文档,将详细介绍相关细节 ...

  10. Dynamics CRM安装教程四:DNS配置

    在为MS CRM 配置Claims-based认证之前,你需要在域控服务器的DNS中添加一些记录,来解析CRM的各个断点,添加內容如下(本次环境全部安装在一台机子中): AD FS 服务器(例: ad ...