原教程链接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进行反编译

image-20210330153929559

分析MainActivity解锁部分的代码,v0变量是一个字符串拼接,经过两次a.a方法的处理,最后取前六位。

跟进a.a方法

image-20210330154802158

这是一个加密算法,将传入的参数进行一系列的处理,最后返回。我们可以直接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 {
//before什么都不做
}
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
Log.i("解锁密码",param.getResult().toString()); //打印a方法的返回值
}
}

);
}

}

安装到模拟器上实验

image-20210330162337195

成功打印出返回值,因为a.a方法被调用了两次,所以只看最后一次的即可。前六位为解锁密码,输入即可进入下一关。

分析第二关的反编译代码

image-20210330162946050

image-20210330163339765

每次点击按钮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","成功充值一万金币");
}
}
);

image-20210330164718049

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);
}

// Android-changed: Use native fastSubstring instead of String constructor.
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());
}
}
);

image-20210331093624742

Hook成功

Hook 类中静态变量

还有一个地方调用了解锁码

1
com.hfdcxy.android.by.a.a.a("解锁码" + v0);

image-20210331093703341

这里可以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自己打印出了解锁码

image-20210331090918798

所有代码

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 {
//before什么都不做
}
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
Log.i("HookWork","a方法的返回值为"+param.getResult().toString()); //打印a方法的返回值
}
}

);

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());
}
}
);

}

}