原教程链接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()); } } );
}
}
|