原教程链接https://www.52pojie.cn/thread-850885-1-1.html
原教程解锁程序下载链接https://github.com/luckyfuture0177/BlogData/blob/master/temporary/%E8%A7%A3%E9%94%81%E7%A8%8B%E5%BA%8F.zip
破解流程 将作业app放入JEB进行反编译
分析MainActivity解锁部分的代码,v0变量是一个字符串拼接,经过两次a.a方法的处理,最后取前六位。
跟进a.a方法
这是一个加密算法,将传入的参数进行一系列的处理,最后返回。我们可以直接hook这个方法,让它把返回值打印出来。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 package com.luckyfuture.xposedpractice1;import android.util.Log;import de.robv.android.xposed.IXposedHookLoadPackage;import de.robv.android.xposed.XC_MethodHook;import de.robv.android.xposed.callbacks.XC_LoadPackage;import static de.robv.android.xposed.XposedHelpers.findAndHookMethod;public class HookMain implements IXposedHookLoadPackage { public void handleLoadPackage (XC_LoadPackage.LoadPackageParam lpparam) throws Throwable { if (!lpparam.packageName.equals("com.ss.android.ugc.aweme" )) { return ; } Log.i("Hook_work" ,"进入解锁程序" ); findAndHookMethod( "com.hfdcxy.android.by.test.a" , lpparam.classLoader, "a" , String.class, new XC_MethodHook() { @Override protected void beforeHookedMethod (MethodHookParam param) throws Throwable { } protected void afterHookedMethod (MethodHookParam param) throws Throwable { Log.i("解锁密码" ,param.getResult().toString()); } } ); } }
安装到模拟器上实验
成功打印出返回值,因为a.a方法被调用了两次,所以只看最后一次的即可。前六位为解锁密码,输入即可进入下一关。
分析第二关的反编译代码
每次点击按钮coin值加1,然后将coin的值域0x270F(9999)比较。
我们可以hook p.a方法,Hook传入的参数,每次点击按钮coin值增加9999
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 findAndHookMethod( "com.hfdcxy.android.by.test.b" , lpparam.classLoader, "a" , SharedPreferences.class, TextView.class, int .class, new XC_MethodHook() { @Override protected void beforeHookedMethod (MethodHookParam param) throws Throwable { param.args[2 ] = 9999 ; Log.i("Tiger_test" ,"成功充值一万金币" ); } } );
Hook成功
其它思路 Hook substring系统函数 第一步生成解锁码时,调用了substring函数
1 String v0 = a.a(a.a(Settings.System.getString(MainActivity.this.getContentResolver(), "android_id")) + "hfdcxy1011").substring(0, 6);
能否Hook这个函数,打印解锁码
首先在Android studio中调用这个函数,查看它的源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public String substring (int beginIndex, int endIndex) { if (beginIndex < 0 ) { throw new StringIndexOutOfBoundsException(this , beginIndex); } if (endIndex > length()) { throw new StringIndexOutOfBoundsException(this , endIndex); } int subLen = endIndex - beginIndex; if (subLen < 0 ) { throw new StringIndexOutOfBoundsException(subLen); } return ((beginIndex == 0 ) && (endIndex == length())) ? this : fastSubstring(beginIndex, subLen); }
直接编写Hook代码
1 2 3 4 5 6 7 8 9 10 11 12 13 findAndHookMethod( "java.lang.String" , lpparam.classLoader, "substring" , int .class, int .class, new XC_MethodHook() { @Override protected void afterHookedMethod (MethodHookParam param) throws Throwable { Log.i("HookWork" ,"substring的返回值为" +param.getResult().toString()); } } );
Hook成功
Hook 类中静态变量 还有一个地方调用了解锁码
1 com.hfdcxy.android.by.a.a.a("解锁码" + v0);
这里可以Hook a.a方法的参数,直接将arg1打印出来,即为解锁码。也可以Hook a类中的静态变量使a.a=True,让程序自己打印出解锁码。
1 2 3 4 5 6 7 8 9 10 if (lpparam.packageName.equals("com.ss.android.ugc.aweme" )) { Log.i("HookWork" ,"找到包" ); Class Clazz = XposedHelpers.findClass("com.hfdcxy.android.by.a.a" , lpparam.classLoader); Log.i("HookWork" ,"找到类" ); Field a = Clazz.getDeclaredField("a" ); Log.i("HookWork" ,"找到字段" ); a.setAccessible(true ); XposedHelpers.setStaticObjectField(Clazz,"a" ,true ); Log.i("HookWork" ,"静态变量a的值已被修改" ); }
运行程序,成功修改了a的值,app自己打印出了解锁码
所有代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 package com.luckyfuture.xposedpractice1;import android.content.SharedPreferences;import android.util.Log;import android.widget.TextView;import java.lang.reflect.Field;import de.robv.android.xposed.IXposedHookLoadPackage;import de.robv.android.xposed.XC_MethodHook;import de.robv.android.xposed.XposedHelpers;import de.robv.android.xposed.callbacks.XC_LoadPackage;import static de.robv.android.xposed.XposedHelpers.findAndHookMethod;import static de.robv.android.xposed.XposedHelpers.findClass;import static de.robv.android.xposed.XposedHelpers.findField;import static de.robv.android.xposed.XposedHelpers.incrementMethodDepth;public class HookMain implements IXposedHookLoadPackage { public void handleLoadPackage (final XC_LoadPackage.LoadPackageParam lpparam) throws Throwable { if (lpparam.packageName.equals("com.ss.android.ugc.aweme" )) { Log.i("HookWork" ,"找到包" ); Class Clazz = XposedHelpers.findClass("com.hfdcxy.android.by.a.a" , lpparam.classLoader); Log.i("HookWork" ,"找到类" ); Field a = Clazz.getDeclaredField("a" ); Log.i("HookWork" ,"找到字段" ); a.setAccessible(true ); XposedHelpers.setStaticObjectField(Clazz,"a" ,true ); Log.i("HookWork" ,"静态变量a的值已被修改" ); } if (!lpparam.packageName.equals("com.ss.android.ugc.aweme" )) { return ; } Log.i("HookWork" ,"进入解锁程序" ); findAndHookMethod( "com.hfdcxy.android.by.test.a" , lpparam.classLoader, "a" , String.class, new XC_MethodHook() { @Override protected void beforeHookedMethod (MethodHookParam param) throws Throwable { } protected void afterHookedMethod (MethodHookParam param) throws Throwable { Log.i("HookWork" ,"a方法的返回值为" +param.getResult().toString()); } } ); findAndHookMethod( "com.hfdcxy.android.by.test.b" , lpparam.classLoader, "a" , SharedPreferences.class, TextView.class, int .class, new XC_MethodHook() { @Override protected void beforeHookedMethod (MethodHookParam param) throws Throwable { param.args[2 ] = 9999 ; Log.i("HookWork" ,"成功充值一万金币" ); } } ); findAndHookMethod( "java.lang.String" , lpparam.classLoader, "substring" , int .class, int .class, new XC_MethodHook() { @Override protected void afterHookedMethod (MethodHookParam param) throws Throwable { Log.i("HookWork" ,"substring的返回值为" +param.getResult().toString()); } } ); } }