2019-11-11
逆向工具
CE 教程
https://www.52pojie.cn/thread-915447-1-1.html
安卓逆向
Hook神器Cydia Substrate
Hook 神器 Xposed & HelloWord
XposedBridge.jar下载: https://jcenter.bintray.com/de/robv/android/xposed/api/ Xposed Installer Android 5.0以上: https://forum.xda-developers.com/showthread.php?t=3034811
1. 修改 build.gradle(app)
1.1 引入xposed api
下载 XposedBridge.jar 放入libs
android studio build.gradle 默认已经配置了,导入目录
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
...
}
1.2 编译支持api
dependencies {
//implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:26.1.0'
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
testImplementation 'junit:junit:4.12'
compileOnly 'de.robv.android.xposed:api:82'
compileOnly 'de.robv.android.xposed:api:82:sources'
compileOnly files('libs/api-82.jar')
}2. AndroidManifest.xml 配置模块元描述
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.yang.xphook">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme" >
<meta-data
android:name="xposedmodule"
android:value="true" />
<meta-data
android:name="xposeddescription"
android:value="xp module description" />
<meta-data
android:name="xposedminversion"
android:value="82" />
</application>
</manifest>
3. 代码
3.1 被Hook代码
//package org.yang.xphook.activity
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button but = findViewById(R.id.button);
but.setOnClickListener((v)->{
toastMessage("hi this original message");
});
}
public void toastMessage(String message){
Toast.makeText(this, message , Toast.LENGTH_SHORT).show();
}
}3.2 Hook代码
//package org.yang.xphook.xphook
public class MainInit implements IXposedHookLoadPackage {
@Override
public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
if (loadPackageParam.packageName.equals("org.yang.xphook")) {//app package name
XposedBridge.log("org.yang.xphook app has loaded");
Class clazz = loadPackageParam.classLoader.loadClass(
"org.yang.xphook.activity.MainActivity");//class name
//recordClassMethods(clazz);
XposedHelpers.findAndHookMethod(clazz, "toastMessage",String.class, new XC_MethodHook() {//method name
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
XposedBridge.log("toastMessage has Hooked!");
param.args[0] = "hahahhahahahaha 劫持参数..."; //modify param
super.beforeHookedMethod(param);
}
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
}
});
}
}
}4. xposed_init
在./java同级创建 assets文件夹, 再在assets下创建 xposed_init,指定xposed入口 内容:
org.yang.xphook.xphook.MainInit
5. 注意
请确保禁用Instant Run(File → Settings → Build, Execution, Deployment → Instant Run), 否则您的类不会直接包含在APK中, 而是通过Xposed无法处理的存根应用程序加载;
android studio 调试要禁用, 否则 xp框架日志 java.lang.ClassNotFoundException异常
6. 问题
Cannot load module问题
注释掉implementation fileTree(d....
https://blog.csdn.net/OneT1me/article/details/93968206
免重启
xposed_init 在调试的时候指向 HookLoader; 发布的时候指向 HookLogic
https://blog.csdn.net/u011956004/article/details/78612502
XpHook.rar
参考: https://www.h3399.cn/201811/634336.html 参考: https://www.52pojie.cn/thread-688466-1-1.html 参考: https://www.52pojie.cn/thread-873013-1-1.html
反编译APK
APK反编译基本目录分析
-
assets文件夹: 原始资源文件夹, 对应着Android工程的assets文件夹, 一般用于存放原始的图片, txt, css等资源文件;
-
lib: 存放应用需要的引用第三方SDK的so库; 比如一些底层实现的图片处理, 音视频处理, 数据加密的库等; 而该文件夹下有时会多一个层级, 这是根据不同CPU 型号而划分的, 如 ARM, ARM-v7a, x86等;
-
META-INF: 保存apk签名信息, 保证apk的完整性和安全性;
-
res: 资源文件夹, 其中的资源文件包括了布局(layout), 常量值(values), 颜色值(colors), 尺寸值(dimens), 字符串(strings), 自定义样式(styles)等;
-
AndroidManifest.xml文件: 全局配置文件, 里面包含了版本信息, activity, broadcasts等基本配置; 不过这里的是二进制的xml文件, 无法直接查看, 需要反编译后才能查看;
-
classes.dex文件: 这是安卓代码的核心部分,, dex是在Dalvik虚拟机上可以执行的文件; 这里有classes.dex和classes2.dex两个文件, 说明工程的方法数较多, 进行了dex拆分; ps:如果apk的方法数超过了65535, 会生成多个dex文件, 反编译的话需要对这多个dex文件均进行转换Jar包处理;
-
resources.arsc文件: 记录资源文件和资源id的映射关系;
需要工具
dex2jar-2.0.zip
jd-gui-windows-1.4.0.zip
进入 d2j-dex2jar.bat 文件所在目录, 命令
例 d2j-dex2jar.bat ../wx/classes.dex ../wx/classes2.dex
d2j-dex2jar.bat ../wx/classes.dex ../wx/classes2.dex ../wx/classes3.dex ../wx/classes4.dex ../wx/classes5.dex ../wx/classes6.dex ../wx/classes7.dex ../wx/classes8.dex ../wx/classes9.dex ../wx/classes10.dex ../wx/classes11.dex ../wx/classes12.dex
https://www.jianshu.com/p/9e0d1c3e342e https://blog.csdn.net/doomvsjing/article/details/54627529
android根目录下default.prop中属性修改 default.prop是生成到out下root目录下 1.如果能否直接打包的话, 可直接修改并打包 2.或者修改配置文件后, 再编译bootimage
default.prop是在根目录下, root根目录是包含在ramdisk.img下的 ramdisk.img和kernel.img是一起被打包到boot.img的
vysor EncoderFeeder.class
Smali
Smali是用于Dalvik(Android虚拟机)的反汇编程序实现, 汇编工具(将Smali代码汇编为dex文件)为smali.jar, 与之对应的baksmali.jar则是反汇编程序 Smali支持注解, 调试信息, 行数信息等基本Java的基本特性, 可以说是很接近Java编译在JVM上的中间语言了, 一般用来做Android程序的逆向工程
工具神器
https://down.52pojie.cn/Tools/Android_Tools/
mprop 无需重打包修改‘debuggable’属性
//推文件
adb push [FILE_PATH] /data/local/tmp/
//进入终端
adb shell
//全权限
su
//进入目录
cd /data/local/tmp/libs/armeabi-v7a/
//运行权限
chmod 755 mprop
//运行
./mprop
//设置值
setprop ro.debuggable 1
//重启
mprop -r
DDMS & Android Profiler
DDMS 的全称是Dalvik Debug Monitor Service, 是 Android 开发环境中的Dalvik虚拟机调试监控服务; 它为我们提供例如: 为测试设备截屏, 针对特定的进程查看正在运行的线程以及堆信息, Logcat, 广播状态信息, 模拟电话呼叫, 接收SMS, 虚拟地理坐标等等;
在 Android Studio 打开; Tools → Android → Android Device Monitor
或者SDK工具monitor.bat
监视应用调用栈
点击 start meohod profiling
再点击 stop meohod profiling
导出当前布局
Dump view UI hierarchy for Automator
或者使用ADB adb shell screencap -p /sdcard/app.png截屏幕图, adb shell uiautomator dump /sdcard/app.uix布局文件, 导到手机
这个文件可以在SDK工具 tools/uiautomatorviewer.bat 打开分析器,打开这两个文件
adb pull /sdcard/app.uix F:/app.uix pull pc; pc必须存在这个文件
adb shell screencap -p /sdcard/app.png
adb shell uiautomator dump /sdcard/app.uix
adb pull /sdcard/app.png F:/app.png //
adb pull /sdcard/app.uix F:/app.uix无需重打包 修改‘debuggable’属性 调试应用
Xposed里面有个插件BUildProp Enhancer, 安装后可以修改所有应用的‘debuggable’属性 或者使用 mprop工具
https://www.52pojie.cn/thread-794312-1-1.html
第一, 在使用以往的突破口方法(字符串搜索大法, UI界面元素分析等)方法无果的时候, 记住一个最新的方法就是获取当前应用执行片段的所有方法堆栈信息来获取突破口方法更加便捷;
第二, 因为需要使用DDMS获取当前应用执行片段的方法堆栈信息, 但是需要这个应用处于调试状态, 为了不进行反编译和回编译操作繁琐, 可以利用mprop工具直接修改系统的调试状态值;
第三, 任何一个应用如果利用页面H5进行展示功能, 那么他肯定有一个和本地交互的JS对应方法, 一般最直接的方法是找到这个页面的WebView, 然后hook他的addJavascriptInterface方法获取本地JS交互的对象, 或者是hook每次都会加载url的几个回调方法比如WebViewClient接口, 或者是WebViewChromeClient等;
第四, 支付宝可能为了安全起见或者是性能更或者是动态更新的原因来把很多页面做成H5了, 不得不佩服他把H5页面做的和本地页面几乎无差别还是很厉害的, 至少我一开始因为是本地页面; 所以以后分析支付宝的其他页面如果发现当前的activity是H5Activity的话, 那么就是H5页面进行加载的;
Jeb 工具反编译
../back_archive/software/jeb-2.2.7.201608151620_crack_jdk8_121.rar
https://www.52pojie.cn/thread-547547-1-1.html https://down.52pojie.cn/Tools/Android_Tools/
jadx 工具反编译
https://github.com/skylot/jadx [Android 转帖] Android 反编译利器, jadx 的高级技巧
(思路) 寻找Hook点
直接遍历所有方法 打印
// 自定义的回调函数接口
public class Module implements IXposedHookLoadPackage {
static String strClassName = "";
@Override
public void handleLoadPackage(final LoadPackageParam lpparam) throws Throwable {
// 被Hook操作的目标Android应用的包名, 进行Hook操作的过滤
String strPackageName = "com.guji.loveparty";
if (lpparam.packageName.equals(strPackageName)) {
XposedBridge.log("Loaded App:" + lpparam.packageName);
// 不在Android应用默认的classes.dex文件中的类方法的Hook操作, 例如:
// 1.MultiDex情况下的, 多dex文件中的类方法的Hook操作, 例如:classes1.dex中的类方法
// 2.主dex加载的jar(包含dex)情况下的, 类方法的的Hook操作
// Hook类方法ClassLoader#loadClass(String)
findAndHookMethod(ClassLoader.class, "loadClass", String.class, new XC_MethodHook() {
// 在类方法loadClass执行之后执行的代码
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
// 参数的检查
if (param.hasThrowable()) {
return;
}
// 获取指定名称的类加载之后的Class<?>
Class<?> clazz = (Class<?>) param.getResult();
// 获取加载的指定类的名称
String strClazz = clazz.getName();
XposedBridge.log("LoadClass: "+strClazz);
// 所有的类都是通过loadClass方法加载的
// 过滤掉Android系统的类以及一些常见的java类库
if (!strClazz.contains("xposed")) {
// 或者只Hook加密算法类, 网络数据传输类, 按钮事件类等协议分析的重要类
// 同步处理一下
synchronized (this.getClass()) {
// 获取被Hook的目标类的名称
strClassName = strClazz;
//XposedBridge.log("HookedClass: "+strClazz);
// 获取到指定名称类声明的所有方法的信息
Method[] m = clazz.getDeclaredMethods();
// 打印获取到的所有的类方法的信息
for (int i = 0; i < m.length; i++) {
//XposedBridge.log("HOOKED CLASS-METHOD: "+strClazz+"-"+m[i].toString());
if (!Modifier.isAbstract(m[i].getModifiers()) // 过滤掉指定名称类中声明的抽象方法
&& !Modifier.isNative(m[i].getModifiers()) // 过滤掉指定名称类中声明的Native方法
&& !Modifier.isInterface(m[i].getModifiers()) // 过滤掉指定名称类中声明的接口方法
) {
// Hook处理类方法findViewById
// public final View findViewById(int id)
if ((m[i].getName()).contains("findViewById")) {
// 对指定名称类中声明的非抽象方法进行java Hook处理
XposedBridge.hookMethod(m[i], new XC_MethodHook() {
// 被java Hook的类方法执行完毕之后, 打印log日志
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
// 打印被java Hook的类方法的名称和参数类型等信息
XposedBridge.log("HOOKED METHOD: "+strClassName+"-"+param.method.toString()+"findViewById: "+param.args[0].toString());
// View view = (View)param.getResult();
// XposedBridge.log("View-id: "+view.getId()+ "findViewById: "+param.args[0].toString());
}
});
}
// public void setText(CharSequence text)
if ((m[i].getName()).contains("setText")) {
// 对指定名称类中声明的非抽象方法进行java Hook处理
XposedBridge.hookMethod(m[i], new XC_MethodHook() {
// 被java Hook的类方法执行完毕之后, 打印log日志
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
// 打印被java Hook的类方法的名称和参数类型等信息
XposedBridge.log("HOOKED METHOD: "+strClassName+"-"+param.method.toString()+ "setText: "+param.args[0].toString());
// View view = (View)param.thisObject;
// XposedBridge.log("View-id: "+view.getId()+ "setText: "+param.args[0].toString());
}
});
}
// Hook处理类方法setOnClickListener
// public void setOnClickListener(OnClickListener l)
if ((m[i].getName()).contains("setOnClickListener")) {
// 对指定名称类中声明的非抽象方法进行java Hook处理
XposedBridge.hookMethod(m[i], new XC_MethodHook() {
// 被java Hook的类方法执行完毕之后, 打印log日志
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
// 打印被java Hook的类方法的名称和参数类型等信息
XposedBridge.log("HOOKED METHOD: "+strClassName+"-"+param.method.toString()+ "setOnClickListener: "+param.args[0].toString());
// View view = (View)param.thisObject;
// XposedBridge.log("View-id: "+view.getId()+ "setOnClickListener: "+param.args[0].toString());
}
});
}
// Hook处理类方法onClick
// public void onClick(View v)
if ((m[i].getName()).contains("onClick")) {
// 对指定名称类中声明的非抽象方法进行java Hook处理
XposedBridge.hookMethod(m[i], new XC_MethodHook() {
// 被java Hook的类方法执行完毕之后, 打印log日志
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
// 打印被java Hook的类方法的名称和参数类型等信息
XposedBridge.log("HOOKED METHOD: "+strClassName+"-"+param.method.toString()+"onClick: "+param.args[0].toString());
// View view = (View)param.thisObject;
// XposedBridge.log("View-id: "+view.getId()+ "onClick: "+param.args[0].toString());
}
});
}
}
}
}
}
}
});
}
}
// 获取指定名称的类声明的类成员变量, 类方法, 内部类的信息
public void dumpClass(Class<?> actions) {
XposedBridge.log("Dump class " + actions.getName());
XposedBridge.log("Methods");
// 获取到指定名称类声明的所有方法的信息
Method[] m = actions.getDeclaredMethods();
// 打印获取到的所有的类方法的信息
for (int i = 0; i < m.length; i++) {
XposedBridge.log(m[i].toString());
}
XposedBridge.log("Fields");
// 获取到指定名称类声明的所有变量的信息
Field[] f = actions.getDeclaredFields();
// 打印获取到的所有变量的信息
for (int j = 0; j < f.length; j++) {
XposedBridge.log(f[j].toString());
}
XposedBridge.log("Classes");
// 获取到指定名称类中声明的所有内部类的信息
Class<?>[] c = actions.getDeclaredClasses();
// 打印获取到的所有内部类的信息
for (int k = 0; k < c.length; k++) {
XposedBridge.log(c[k].toString());
}
}
}
/**
* Look up a method and place a hook on it. The last argument must be the callback for the hook.
* @see #findMethodExact(Class, String, Object...)
*/
/* 目标java方法的Hook
public static XC_MethodHook.Unhook findAndHookMethod(Class<?> clazz, String methodName, Object... parameterTypesAndCallback) {
if (parameterTypesAndCallback.length == 0 || !(parameterTypesAndCallback[parameterTypesAndCallback.length-1] instanceof XC_MethodHook))
throw new IllegalArgumentException("no callback defined");
XC_MethodHook callback = (XC_MethodHook) parameterTypesAndCallback[parameterTypesAndCallback.length-1];
Method m = findMethodExact(clazz, methodName, getParameterClasses(clazz.getClassLoader(), parameterTypesAndCallback));
return XposedBridge.hookMethod(m, callback);
}*/
/** @see #findAndHookMethod(Class, String, Object...) */
/* 目标java方法的Hook
public static XC_MethodHook.Unhook findAndHookMethod(String className, ClassLoader classLoader, String methodName, Object... parameterTypesAndCallback) {
return findAndHookMethod(findClass(className, classLoader), methodName, parameterTypesAndCallback);
}*/
/**
* Loads the class with the specified name. Invoking this method is
* equivalent to calling {@code loadClass(className, false)}.
* <p>
* <strong>Note:</strong> In the Android reference implementation, the
* second parameter of {@link #loadClass(String, boolean)} is ignored
* anyway.
* </p>
*
* @return the {@code Class} object.
* @param className
* the name of the class to look for.
* @throws ClassNotFoundException
* if the class can not be found.
*/
//public Class<?> loadClass(String className) throws ClassNotFoundException {
// return loadClass(className, false);
// }参考: https://blog.csdn.net/qq1084283172/article/details/80956455
安卓逆向 通过UI定位代码
https://www.jianshu.com/p/ea45509e2e24
DDMS 工具
DDMS 的全称是Dalvik Debug Monitor Service,是 Android 开发环境中的Dalvik虚拟机调试监控服务。
它为我们提供例如:为测试设备截屏,针对特定的进程查看正在运行的线程以及堆信息、Logcat、广播状态信息、模拟电话呼叫、接收SMS、虚拟地理坐标等等。
adb dump activity 实现类名
使用命令adb shell dumpsys activity | grep Focuse查看当前activit
当你想要查看当前手机屏幕正在显示的页面是哪个进程的那个activity时, 你可以输入 adb shell dumpsys activity top -C 10
adb shell dumpsys activity---------------查看ActvityManagerService 所有信息 adb shell dumpsys activity activities----------查看Activity组件信息 adb shell dumpsys activity services-----------查看Service组件信息 adb shell dumpsys activity providers----------产看ContentProvider组件信息 adb shell dumpsys activity broadcasts--------查看BraodcastReceiver信息 adb shell dumpsys activity intents--------------查看Intent信息 adb shell dumpsys activity processes---------查看进程信息
通过日志来定位代码
…