- 反编译 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然后发布,这会导致更严 ...
随机推荐
- Oracle分析函数FIRST_VALUE、LAST_VALUE
FIRST_VALUE.LAST_VALUE分析函数可以按照特定分组和排序取出组内首尾值,语法 FIRST_VALUE { (expr) [ {RESPECT | IGNORE} NULLS ] | ...
- (原)堆叠hourglass网络
转载请注明出处: https://www.cnblogs.com/darkknightzh/p/11486185.html 论文: https://arxiv.org/abs/1603.06937 官 ...
- openCV CV2用法(转)
文章转自:https://www.kancloud.cn/aollo/aolloopencv/262768 一.读入图像 使用函数cv2.imread(filepath,flags)读入一副图片 fi ...
- Wpf DataGrid动态添加列,行数据(一)
由于最近有这方面的需求,而且刚接触wpf不久,在网上找了很多方法,都不是使用MVVM模式的,因为DataGrid的列不能绑定 这就难受了,我想了个折中的方法,这个是使用了MVVMLight的消息机制, ...
- Python面试题(2)
1.一行代码实现1-100的和 ? 1 2 3 print(sum(range(1,101))) #range中的参数是1<=i<101 #sum是计算参数的和 2.在函数内部改变全局变量 ...
- 小程序开发第一天josn和wxml
视频中只有app.josn路径还有wxm文本.js中没有调用page.原视频中是可以出来文本内容的. 但是把js调用page以后是可以呈现的 所以疑问点就是为什么以前可以? 1.微信开发工具改了,强制 ...
- 简要说明盒子模型和flex布局
盒子模型:可以看做是一个盒子,包括外边距.边框.内边距.实际内容. flex布局:弹性布局,灵活性好. 当给元素设置display:flex时,它就是flex容器,它的所有子元素自动成为容器成员,称为 ...
- bzoj2287【POJ Challenge】消失之物 缺一01背包
bzoj2287[POJ Challenge]消失之物 缺一01背包 链接 bzoj 思路 分治solve(l,r,arr)表示缺少物品\([l,r]\)的dp数组arr. 然后solve(l,mid ...
- 【LG2567】[SCOI2010]幸运数字
[LG2567][SCOI2010]幸运数字 题面 洛谷 题目大意: 问你区间\([L,R](1\leq L\leq R\leq 10^{10})\)中有几个数是仅由\(6,8\)组成的数的倍数. 题 ...
- C实现Linux中copy功能
/* mycp.c */ #include<stdio.h> #include<stdlib.h> #include<unistd.h> #include<f ...