本文博客地址: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. 不一样的软件们——GitHub 热点速览 v.21.10

    作者:HelloGitHub-小鱼干 创意,是程序员的一个身份代名词,一样的软件有不一样的玩法.比如,你可以像用 git 一样操作一个 SQL 数据库,dolt 就是这样的数据库.又比如,你可以只写文 ...

  2. HDU_5414 CRB and String 【字符串】

    一.题目 CRB and String 二.分析 对于这题,读懂题意非常重要. 题目的意思是在$s$的基础上,按题目中所描述的步骤,即在$s$中任意选择一个字符$c$,在这个字符后面添加一个不等于$c ...

  3. 2019 GDUT Rating Contest III : Problem A. Out of Sorts

    题面: 传送门 A. Out of Sorts Input file: standard input Output file: standard output Time limit: 1 second M ...

  4. Git常用命名

    文字整理: git config - - 可以配置git的参数,可以使用 git config --list查看已经配置的git参数. 其中有三个级别的保存位置, –system(本系统) –glob ...

  5. SEO优化基础知识

    一.标点符号的重要性 很多人忽略了标点符号对爬虫的重要性,爬虫并不是对所有标点符号都爬取,下面列举几个对关键字分隔有帮助的符号. 1.1.逗号( , ) ==> 千万千万要使用英文的逗号,而不是 ...

  6. sqlmap在https下的一种错误 - ssl连接失败

    在昨天与师傅的交流中师傅考了我一个问题,在用sqlmap跑的时候遇到ssl爆红该怎么办,因为在实战中并没有遇到过这种情况,所以今天补一下知识. 首先查询了ssl的概念,通俗来说,如果一个网站没有安装s ...

  7. python-3-3 字典

    一 元组(tuple) 1.元组也是一个list,他和list的区别是 元组里面的数据无法修改 元祖用()小括号表示,如果元祖里面只有一个元素的话,必须在这个元素的后面添加一个逗号,不然就不是元祖了 ...

  8. Kubernetes使用metric-server让HPA弹性伸缩运行

    监控架构概述 kubernetes监控指标大体可以分为两类:核心监控指标和自定义指标,核心监控指标是kubernetes内置稳定可靠监控指标,早期由heapster完成,现由metric-server ...

  9. [搜索]P1088 火星人

    火星人 题目描述 人类终于登上了火星的土地并且见到了神秘的火星人.人类和火星人都无法理解对方的语言,但是我们的科学家发明了一种用数字交流的方法.这种交流方法是这样的,首先,火星人把一个非常大的数字告诉 ...

  10. .NET Request对象介绍

    Request对象用于检索从浏览器向服务器所发送的请求信息.它提供对当前页请求的访问,包括标题,Cookie,客户端证书等等.它也与HTTP协议的请求消息对应 Request常用的属性 属性 具体内容 ...