- 反编译 AndroidKiller 逆向 实践案例 MD
| 我的GitHub | 我的博客 | 我的微信 | 我的邮箱 |
|---|---|---|---|
| baiqiantao | baiqiantao | bqt20094 | baiqiantao@sina.com |
目录
反编译 AndroidKiller 逆向 实践案例 MD
PS:以下所有内容,包括测试用来逆向的APP均已脱敏
参考我的其他博客内容:
AndroidKiller 简介
Android Killer 是一款可以对APK进行反编译的工具,它能够对反编译后的Smali文件进行修改,并将修改后的文件进行打包。
AndroidKiller的基本功能:
- 可以修改清单文件,比如修改包名
- 可以修改(替换)任意资源文件,比如 string、drawable、color、layout 等,以及 assets、raw 等
- 可以对整个工程中的字符或文件进行搜索(支持匹配编码、匹配文件类型、匹配范围)
- 可以查看对应的 smali 、class 源码,以及反编译的 java 源码
可以对修改后的工程重新打包
插件升级
软件中的Apktool可能会因为版本太低导致 apk 的反编译失败,此时需要到 Apktool 官网去下载最新版本的Apktool。
下载完成后找到解压好的 AndroidKiller 目录下的bin\apktool\apktool目录将下载的最新版的 apktool 复制进去。
然后修改 AndroidKiller 根目录下的bin\apktool下的apktool.bat和apktool.ini文件,将里面对应的文件名改为你下载的最新的 apktool 文件名。
基本使用
使用 AndroidKiller 对 Apk 进行反编译只需要将 Apk 文件拖入软件即可。
反编译后我们可以对资源文件等进行简单的修改,修改后后点击左上角菜单栏中的Android -- 编译即可重新编译成APK。
另外我们也可以点击 smali 目录,查看反编译的 smali 源码,并可以在某一 smali 源码文件中右键 -- 查看 -- 查看源码通过 Java Decompiler 查看反编译的 java 源码。
实践案例
修改清单文件
经常会修改包名、应用图标、应用名称等基本信息,只需在这里找到相应的res并修改即可。
另外还可以查看其使用的Application,因为一般一些初始化操作、全局常量的设置等都是在Application里面。
<manifest package="包名" >
<application android:icon="图标" android:label="名称" android:name="使用的Application">
打印 debug 级别的日志
或者说是开启debug模式,一般有如下几种处理思路
方式一:直接代理 Log 类
按如下方式便可以 hook 住系统 Log 的方法调用,我们可以在 Log.d 等方法被调用 前/后 做自己的逻辑,比如对日志进行过滤、把日志保存到文件中。
public class XposedZygoteInit implements IXposedHookZygoteInit {
@Override
public void initZygote(StartupParam startupParam) throws Throwable {
//hook住某个方法。参数:类名,类加载器,方法名,参数列表,Hook成功后的回调
XposedHelpers.findAndHookMethod("android.util.Log", StartupParam.class.getClassLoader(), "d", String.class, String.class, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
//Log.i("bqt", "【代理系统的Log类,可以在这里把日志保存到文件中】" + param.args[0] + " ," + param.args[1]);
}
});
}
}
方式二:通过修改字段值修改判断条件
比如,反编译一款 APP 后发现其打印日志的部分逻辑如下:
public class LogTool{
public static boolean a = ;
public static String b = "通用的tag";
public static void a(String paramString) {
if (a) {
Log.d(b, paramString);
}
}
在 release 包中,这个值静态字段 a 肯定是 false,我们只需将其改为 true 即可打印 debug 下才会打印的日志。
hook 方式如下:
public class XposedInit implements IXposedHookLoadPackage {
@Override
public void handleLoadPackage(final XC_LoadPackage.LoadPackageParam lpparam) throws Exception {
if (lpparam.packageName.equals(应用的包名,进入if代表此应用启动了,可以开始hook了)) {
Field field = XposedHelpers.findClass("完整路径.LogTool", lpparam.classLoader).getField("a");
field.setAccessible(true);
field.setBoolean(null, true); //静态字段的 the object whose field should be modified is null
}
}
}
PS:hook 系统类不能通过 IXposedHookLoadPackage ,而需要通过 IXposedHookZygoteInit,因为此应用启动前,系统类已经被加载过了,已经错过了 hook 的时机了。
方式三:通过修改方法返回值修改判断条件
比如,反编译一款 APP 后发现其打印日志的部分逻辑如下:
public class LogTool {
public static void d(String paramString1, String paramString2) {
if (isLogAble(LogLevel.DEBUG)) {
//...
}
}
private static boolean isLogAble(LogLevel paramLogLevel) {
if (logcatLevel.value == LogLevel.OFF.value) {
return false;
}
if (logcatLevel.value == LogLevel.ALL.value) {
return true;
}
return logcatLevel.compare(paramLogLevel) >= 0;
}
}
类似上述案例,我们只需hook住isLogAble方法,并且将返回值直接返回true即可跳过日志级别判断。
hook 方式如下:
XposedHelpers.findAndHookMethod("类的完整路径", lpparam.classLoader, "isLogAble", "参数的完整路径", new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
Log.i("bqt", "【" + Arrays.toString(param.args) + "】");
param.setResult(true);
}
});
方式四:修改 BuildConfig.DEBUG 中的 DEBUG 常量值
这种方式和上面那种方式类似,不过适用场景更广泛。
APP编译时会自动为每一个module生成一个 BuildConfig 类,其中包含一些经常使用到的与环境相关的常量,例如:
public final class BuildConfig {
public static final boolean DEBUG = Boolean.parseBoolean("true"); //是否是调试模式
public static final String APPLICATION_ID = "com.bqt.test"; //包名
public static final String BUILD_TYPE = "debug";
public static final String FLAVOR = "";
public static final int VERSION_CODE = 1;
public static final String VERSION_NAME = "1.0";
}
很多时候,我们判断是否应打印日志就是根据 BuildConfig.DEBUG 来确定的,所以我们只需要修改这个值就可以了。
修改这个值的方式肯定不是通过Xposed框架,因为这些常量都是 final 类型的,动态框架肯定是无法修改的,一种可行的方式:
- 修改
.class文件,具体详见:Javassist 字节码 简介 案例 MD - 重新打成jar包,具体详见:字节码 反编译 APKTool 重新打jar包 MD
- 重新编译APK(借助AndroidKiller)
如何hook混淆后指定类中的指定方法
首先需要明白,混淆后的类名、方法名、成员变量名等都是固定的,反编译后你看到的名字是什么,运行时它的名字就是什么,不会再变的
然后你还需要知道,他的名字虽然是固定的,但是往往你没办法直接hook,因为很多混淆后的名字都是非法字符,你即没法输入(IDE不识别),也没法通过编译(编译器不识别),所以需要采用特殊的方式来hook。
以下是一种可供参考的案例:
//从指定类中混淆后的方法名中获取匹配的方法
String methodName = "";
Method[] methods = XposedHelpers.findClass("o.ayc", lpparam.classLoader).getDeclaredMethods();
for (Method method : methods) {
method.setAccessible(true);
//匹配返回值,这里只是简单字符串匹配,更精确的可以通过类型匹配
if (method.getReturnType().toString().contains("HttpURLConnection")) {
methodName = method.getName();
break;
}
}
通过上述方法,便可跳过IDE和编译器的名称规范的检查,在运行时便可匹配混淆后的类或方法(运行时并不会进行规范性检查)。
完整案例
基本步骤
1、安装 XposedInstaller.apk,安装后启动此应用,安装 framework ,重启手机
2、AS工程中添加依赖
compileOnly 'de.robv.android.xposed:api:82:sources'//xposed依赖,注意这个版本号和framework版本号并不是一致的
implementation files('libs/javassist.jar')//非必须
3、application下添加三个meta-data
<meta-data
android:name="xposedmodule"
android:value="true"/>
<meta-data
android:name="xposeddescription"
android:value="这是对你使用xposed能完成功能的简要描述"/>
<meta-data
android:name="xposedminversion"
android:value="89"/>
4、编写Hook逻辑
5、配置完整的Hook类类名
新建assets文件夹,文件夹下新建xposed_init文件(文件名固定),在文件中填写hook逻辑所在类的fully qualified class name:
com.bqt.test.temp.XposedInit
com.bqt.test.temp.XposedZygoteInit
6、有任何代码变动,都需重装APP后重启手机才能生效
XposedInit
public class XposedInit implements IXposedHookLoadPackage {
@Override
public void handleLoadPackage(final XC_LoadPackage.LoadPackageParam lpparam) throws Exception {
if (lpparam.packageName.equals("应用1的包名,进入if代表此应用启动了,可以开始hook了")) {
//开启日志打印
XposedHelpers.findAndHookMethod("类的完整路径", lpparam.classLoader, "isLogAble", "参数的完整路径", new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
Log.i("bqt", "日志级别【" + Arrays.toString(param.args) + "】");
param.setResult(true);
}
});
//从指定类中混淆后的方法名中获取匹配的方法
String methodName = "";
Method[] methods = XposedHelpers.findClass("o.ayc", lpparam.classLoader).getDeclaredMethods();
for (Method method : methods) {
method.setAccessible(true);
//匹配返回值,这里只是简单字符串匹配,更精确的可以通过类型匹配
if (method.getReturnType().toString().contains("HttpURLConnection")) {
methodName = method.getName();
break;
}
}
//hook住某个方法。参数:类名,类加载器,方法名,参数列表,Hook成功后的回调
XposedHelpers.findAndHookMethod("o.ayc", lpparam.classLoader, methodName, String.class, new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
Log.i("bqt", "1-【" + param.method.getName() + "】" + param.args[0]);
}
});
//只能hook具体的方法,不能hook接口的方法或抽象的方法。比如只能hook住某个Runnable的实现类的run方法,而不能hook住所有Runnable的run方法
XposedHelpers.findAndHookMethod("o.ayf", lpparam.classLoader, "run", new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
Log.i("bqt", "2-【" + param.thisObject.getClass().toString() + "】");
}
});
} else if (lpparam.packageName.equals("应用2的包名")) {
//开启日志打印
Field field = XposedHelpers.findClass("完整路径.LogTool", lpparam.classLoader).getField("a");
field.setAccessible(true);
field.setBoolean(null, true); //静态字段的 the object whose field should be modified is null
//注意,基本类型变量的class文件不能使用其相应包装类型来标识,例如 boolean.class 不能使用 Boolean.class 来代替
XposedHelpers.findAndHookMethod("包名.a", lpparam.classLoader, "a", long.class, String.class, boolean.class, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
Log.i("bqt", "3-【" + Arrays.toString(param.args) + "】");
}
});
}
}
}
XposedZygoteInit
public class XposedZygoteInit implements IXposedHookZygoteInit {
@Override
public void initZygote(StartupParam startupParam) throws Throwable {
XposedHelpers.findAndHookMethod("android.util.Log", StartupParam.class.getClassLoader(), "d", String.class, String.class, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
//Log.i("bqt", "【代理系统的Log类,可以在这里把日志保存到文件中】" + param.args[0] + " ," + param.args[1]);
}
});
}
}
2019-09-30
- 反编译 AndroidKiller 逆向 实践案例 MD的更多相关文章
- 反编译 APKTool 逆向助手
最佳实践--Android逆向助手 1.点击"反编译apk,完成后res下的所有资源就都可以正常使用了,相当于apktool的功能------目前已失效,但是直接用rar解压是可以的!2.点 ...
- 字节码 反编译 APKTool 重新打jar包 MD
Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...
- 专注于C#.Net WPF软件开发-软件反编译-软件破解-逆向-靖芯科技-包括安卓APK反编译
靖芯科技提供.Net软件开发,软件修改定制二次开发,软件破解,反编译,逆向等各项优质服务: 包括安卓APK软件反编译. 包括但不限于C#,WPF,Surface,Winform,Asp.net.JAV ...
- android 反编译 逆向工具整理
需要准备的道具需要哪些软件会在后面逆向过程中详细介绍,这里先大致罗列一下 android一台root并安装了xposed框架的手机(主要是为了脱壳) 类似[海马玩]这种模拟器 android-kill ...
- 使用AndroidKiller进行APK反编译
安装环境 JDK 最好用JDK8,问就是坑太多了 Android Studio 官网安装即可,安装教程如下 https://www.runoob.com/android/android-studio- ...
- 推荐.Net、C# 逆向反编译四大工具利器
转自:https://blog.csdn.net/kongwei521/article/details/54927689 在项目开发过程中,估计也有人和我遇到过同样的经历:运行环境出现了重大Bug亟需 ...
- Android应用安全防护和逆向分析 ——apk反编译
概述 最近一直在学习Android应用安全相关和逆向分析的知识.现在移动app在安全方面是越来越重视了,特别是那些巨头企业涉及到钱的应用,那加密程度,简直是丧心病狂,密密麻麻.从这里可以看出,对于应用 ...
- Android逆向之旅---反编译利器Apktool和Jadx源码分析以及错误纠正
Android逆向之旅---反编译利器Apktool和Jadx源码分析以及错误纠正 http://blog.csdn.net/jiangwei0910410003/article/details/51 ...
- 【转载】关于 .Net 逆向的那些工具:反编译篇
在项目开发过程中,估计也有人和我遇到过同样的经历:生产环境出现了重大Bug亟需解决,而偏偏就在这时仓库中的代码却不是最新的.在这种情况下,我们不能直接在当前的代码中修改这个Bug然后发布,这会导致更严 ...
随机推荐
- 第二篇Scrum冲刺博客
第二篇Scrum冲刺博客 一.站立式会议 提供当天站立式会议照片一张 二.每个人的工作 成员 已完成工作 明天计划完成的工作 遇到的困难 林剑峰 初步学习小程序的编写.博客园的撰写 初步完成用户界面 ...
- 【MySQL】备份和恢复
语法 mysqldump -uslave -p -h127.0.0.1 --single-transaction --set-gtid-purged=OFF database1 table1 tabl ...
- Vue2.0 新手入门 — 从环境搭建到发布
什么是 Vue Vue 是一个前端框架,特点是数据绑定 比如你改变一个输入框 Input 标签的值,会自动同步更新到页面上其他绑定该输入框的组件的值 组件化 页面上小到一个按钮都可以是一个单独的文件. ...
- uwsgi no python application found错误的解决(python3+centos6)
近期在努力把自己的项目从python2转到python3上,因为生产环境无法抛弃centos7,所以只好在centos7上安装了python3.装好了python3,将python命令软连接改成pyt ...
- angular6 导出Excel文件
1.安装file-saver.@types/file-saver和xlsx npm install file-saver --save npm install @types/file-saver -- ...
- Flask拾遗总汇1
目录 1.flask的路由分发方式 2.请求响应相关 3.flask配置文件拾遗(config) 4.路由系统参数配置 4.1 可传入参数: 4.2 常用路由系统有以上五 5.反向生成URL: url ...
- D. Maxim and Array
https://www.cnblogs.com/qscqesze/p/5925893.html 原博客 http://codeforces.com/group/1EzrFFyOc0/contest/ ...
- python 数据库小测试
1.整理博客 2.详细解释下列mysql执行语句的每个参数与参数值的含义 mysql -hlocalhost -P3306 -uroot -proot # mysql (连接数据库) # hloc ...
- 201871010101-陈来弟《面向对象程序设计(java)》第二周学习总结
201871010101-陈来弟<面向对象程序设计(java)>第二周学习总结 项目 内容 这个作业属于哪个课程 <任课教师博客主页链接>https://www.cnblogs ...
- Spring Boot版本号说明
Spring Boot的版本选择一般是这样的,如下图: 那版本号后面的英文代表什么含义呢? 具体含义,如下文所示: SNAPSHOT:快照版,表示开发版本,随时可能修改: M1(Mn):M是miles ...