如何xposed hook 带"壳"的app
前段时间做了个游戏内购xposed 插件,但是当前的游戏部分都加壳了,并且最新的游戏支付sdk也进行加密了,这样就尴尬了
于是到网上搜索了下:看到"非虫"大大在看雪上发的部分代码如何hook 360加固的应用:原帖貌似被删了,在网上找了部分代码
链接地址:http://www.jianshu.com/p/0d74461ea199
大概原理:拿到壳的ClassLoader 然后再根据壳的ClassLoader 拿到对应的Class 然后在hook
if (loadPackageParam.packageName.equals("com.package.name")) { XposedHelpers.findAndHookMethod("com.qihoo.util.StubAppxxxxxxxx", loadPackageParam.classLoader, "getNewAppInstance", Context.class, new XC_MethodHook() { @Override protected void afterHookedMethod(MethodHookParam param) throws Throwable { super.afterHookedMethod(param); Context context = (Context) param.args[0]; ClassLoader classLoader =context.getClassLoader(); XposedHelpers.findAndHookMethod("com.amap.api.location.AMapLocation", classLoader, "getLongitude", new XC_MethodHook(){ @Override protected void afterHookedMethod(MethodHookParam param) throws Throwable { super.afterHookedMethod(param); param.setResult(123.123123); } }); XposedHelpers.findAndHookMethod("com.amap.api.location.AMapLocation", classLoader, "getLatitude", new XC_MethodHook(){ @Override protected void afterHookedMethod(MethodHookParam param) throws Throwable { super.afterHookedMethod(param); param.setResult(33.333333); } }); } }); }
根据这个原理 查看xposed源码 XposedHelpers.findAndHookMethod方法
public static Unhook findAndHookMethod(String className, ClassLoader classLoader, String methodName, Object... parameterTypesAndCallback) {
return findAndHookMethod(findClass(className, classLoader), methodName, parameterTypesAndCallback);
}
在查看:其中findclass方法
public static Class<?> findClass(String className, ClassLoader classLoader) {
if(classLoader == null) {
classLoader = XposedBridge.BOOTCLASSLOADER;
}
try {
return ClassUtils.getClass(classLoader, className, false);
} catch (ClassNotFoundException var3) {
throw new XposedHelpers.ClassNotFoundError(var3);
}
}
也就是通过ClassLoader 加载Class 然后在进行hook,想到一个办法就是
在类加载的时候进行hook
对于加固的应用 xposed 拿到的Classloader 不一定能加载到Class
于是根据android 源码 加载Class用到的一个是BootClassLoader(系统启动的时候创建的),另一个是PathClassLoader(应用启动时创建的),所以只用看PathClassLoader的源码
public class PathClassLoader extends BaseDexClassLoader
接着看BaseDexClassLoader
public class BaseDexClassLoader extends ClassLoader {
private final DexPathList pathList;
/**
* Constructs an instance.
*
* @param dexPath the list of jar/apk files containing classes and
* resources, delimited by {@code File.pathSeparator}, which
* defaults to {@code ":"} on Android
* @param optimizedDirectory directory where optimized dex files
* should be written; may be {@code null}
* @param libraryPath the list of directories containing native
* libraries, delimited by {@code File.pathSeparator}; may be
* {@code null}
* @param parent the parent class loader
*/
public BaseDexClassLoader(String dexPath, File optimizedDirectory,
String libraryPath, ClassLoader parent) {
super(parent);
this.pathList = new DexPathList(this, dexPath, libraryPath, optimizedDirectory);
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
List<Throwable> suppressedExceptions = new ArrayList<Throwable>();
Class c = pathList.findClass(name, suppressedExceptions);
if (c == null) {
ClassNotFoundException cnfe = new ClassNotFoundException("Didn't find class \"" + name + "\" on path: " + pathList);
for (Throwable t : suppressedExceptions) {
cnfe.addSuppressed(t);
}
throw cnfe;
}
return c;
}
//......
}
于是一路分析下去:
得到:BaseDexClassLoader.findClass(String name)
----->DexPathList.findClass(String name, List<Throwable> suppressed)
----->DexFile.loadClassBinaryName(String name, ClassLoader loader, List<Throwable> suppressed)
---->DexFile.defineClass(String name, ClassLoader loader, Object cookie,List<Throwable> suppressed)
---->defineClassNative(name, loader, cookie);
defineClassNative(name, loader, cookie);方法为native方法 xposed 无法hook
最后如果给想在类加载完成时进行hook那么就要在DexFile.defineClass(String name, ClassLoader loader, Object cookie,List<Throwable> suppressed)这个方法上做文章:
使用xposed hook dalvik.system.DexFile.defineClass方法在然后在hook 后方法里进行过滤拿到想要的Class
public void hookDefineClass() { try { /*get DexFile Class*/ Class clazz = loadPackageParam.classLoader.loadClass("dalvik.system.DexFile"); Method[] methods = clazz.getDeclaredMethods(); for (int i = 0; i < methods.length; i++) { String name = methods[i].getName(); if (name.equalsIgnoreCase("defineClass")) { hookhelper.hookMethod(methods[i], new MethodHookCallBack() { @Override public void beforeHookedMethod(HookParam param) throws IOException, ClassNotFoundException { } @Override public void afterHookedMethod(HookParam param) throws IOException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException, JSONException { //ClassName String ClassName = (String) param.args[0];; if(ClassName.equalsIgnoreCase("xxxx")){ //here do something //get Class Class clazz = (Class) param.getResult(); // do something you want XposedHelpers.findAndHookMethod(Class<?> clazz, String methodName, Object... parameterTypesAndCallback) } } }); } } } catch (ClassNotFoundException e) { e.printStackTrace(); } }
一个例子(由于使用自己封装的xposed方法):
UnicomPay.java(联通支付sdk)
package com.xiaobai.viptools.xposedpay; import com.xiaobai.viptools.impl.PayOrderHook; import com.xiaobai.viptools.xposed.HookParam; import com.xiaobai.viptools.xposed.MethodHookCallBack; import java.io.IOException; import java.lang.reflect.Method; import de.robv.android.xposed.XposedBridge; import de.robv.android.xposed.callbacks.XC_LoadPackage; /** * * Created by xiaobai on 2017/2/3. */ public class UnicomPay implements PayOrderHook { private XC_LoadPackage.LoadPackageParam lpparam; public UnicomPay(XC_LoadPackage.LoadPackageParam loadPackageParam) { this.lpparam = loadPackageParam; } @Override public void Hookpay(Class clazz) throws ClassNotFoundException { Method[] methods=clazz.getMethods(); for (int i = 0; i <methods.length; i++) { String name=methods[i].getName(); if (name.equalsIgnoreCase("pay")){ Method paymethod=methods[i]; HookPayMethond(paymethod); } } } private void HookPayMethond(Method method){ hookhelper.hookMethod(method, new MethodHookCallBack() { @Override public void beforeHookedMethod(HookParam param) throws IOException { XposedBridge.log("paymethod arg size:"+param.args.length); Class clazz= param.args[param.args.length-1].getClass(); HookPayresult(clazz); } @Override public void afterHookedMethod(HookParam param) throws IOException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException { } }); } private void HookPayresult(Class clazz){ Method[] methods=clazz.getMethods(); for (int i = 0; i < methods.length; i++) { if (methods[i].getName().equalsIgnoreCase("PayResult")){ hookhelper.hookMethod(methods[i], new MethodHookCallBack() { @Override public void beforeHookedMethod(HookParam param) throws IOException { XposedBridge.log("arg[1]:code "+param.args[1]); param.args[1]=1; XposedBridge.log("payhook success"); } @Override public void afterHookedMethod(HookParam param) throws IOException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException { } }); } } } }
HookPayMethod.java
package com.xiaobai.viptools.XposedModule; import android.content.Context; import com.xiaobai.viptools.helper.JsonHelper; import com.xiaobai.viptools.impl.HookHelperInterface; import com.xiaobai.viptools.util.ContextHolder; import com.xiaobai.viptools.xposed.HookHelperFacktory; import com.xiaobai.viptools.xposed.HookParam; import com.xiaobai.viptools.xposed.MethodHookCallBack; import de.robv.android.xposed.callbacks.XC_LoadPackage; /** * Created by xiaobai on 2017/2/3. */ public class HookPayMethod { private XC_LoadPackage.LoadPackageParam loadPackageParam; private HookHelperInterface hookhelper = HookHelperFacktory.getHookHelper(); public HookPayMethod(XC_LoadPackage.LoadPackageParam loadPackageParam) { this.loadPackageParam = loadPackageParam; } /*针对加壳app hook defineclass 过滤app*/ public void hookDefineClass() { try { /*获取DexFile Class*/ Class clazz = loadPackageParam.classLoader.loadClass("dalvik.system.DexFile"); Method[] methods = clazz.getDeclaredMethods(); for (int i = 0; i < methods.length; i++) { String name = methods[i].getName(); if (name.equalsIgnoreCase("defineClass")) { hookhelper.hookMethod(methods[i], new MethodHookCallBack() { @Override public void beforeHookedMethod(HookParam param) throws IOException, ClassNotFoundException { } @Override public void afterHookedMethod(HookParam param) throws IOException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException, JSONException { selectPayMethod(param); } }); } } } catch (ClassNotFoundException e) { e.printStackTrace(); } } private void selectPayMethodDebug(HookParam param) throws ClassNotFoundException { String ClassName = (String) param.args[0]; // System.out.println(ClassName); if (unicompay && ClassName.equalsIgnoreCase("com.unicom.dcLoader.Utils")) { Class PayClass = (Class) param.getResult(); UnicomPay unicomPay = new UnicomPay(loadPackageParam); unicomPay.Hookpay(PayClass); } } }
对付简单的加固应该没问题:有任何问题联系:xiaobaiyey@outlook.com