1. 样本软件版本号为2.7.6,有ShadowSafety加固,需要先dump dex,过程略(使用AdClose一键操作即可)
2. 先打开样本软件,发现侧边栏有个"点击登录"文字,把apk拖入jadx,搜索该字符串,右键全局搜索,来到唯一调用处
<string name="click_close">点击关闭</string>
<string name="click_login">点击登录</string>
<string name="close">关闭</string>
@Override // defpackage.C5863.InterfaceC5867
/* JADX INFO: renamed from: ݿ, reason: contains not printable characters */
public void mo7171() {
if (!C5863.m16532().m16546()) {
this.tv_account.setEnabled(true);
this.tv_account.setText(R.string.click_login);
this.iv_account_vip.setVisibility(8);
this.tv_vip_time.setVisibility(4);
this.iv_icon.setImageResource(R.drawable.icon_tt);
return;
}
StringBuilder sb = new StringBuilder(C5863.m16532().m16538());
if (C5056.m14246()) {
try {
sb.replace(3, 7, C5958.m16773("Hcjldg==\n", "N+LPXMp3PhY=\n"));
} catch (Exception unused) {
System.exit(0);
}
}
this.tv_account.setText(sb.toString());
if (!C5863.m16532().m16547()) {
this.iv_icon.setImageResource(R.drawable.icon_tt);
this.iv_account_vip.setVisibility(8);
this.tv_vip_time.setVisibility(4);
return;
}
this.iv_account_vip.setVisibility(0);
this.tv_vip_time.setVisibility(0);
this.iv_icon.setImageResource(R.drawable.icon_tt_vip);
if (C5863.m16532().m16544()) {
this.tv_vip_time.setText(R.string.forever_vip);
} else {
this.tv_vip_time.setText(getString(R.string.vip_surplus_time, DateUtil.getSurplusDate(getContext(), C5863.m16532().m16541() - System.currentTimeMillis())));
}
}
3.双击m16546来到C5863类,从getAccount之类的方法名可以看出这是个账号信息管理类,观察m16543和m16549方法,再结合f10990字段的SPUtil这个类,可以推测出前者在读取SharedPreferences保存的账号信息,后者在往SharedPreferences写入账号信息,所以我们可以在m16543方法执行完后主动调用m16548方法,写入一个伪造的LoginBean对象
package defpackage;
import android.content.Context;
import android.content.Intent;
import android.text.TextUtils;
import com.android.libs.util.SPUtil;
import com.android.libs.util.T;
import com.android.libs.util.ThreadPool;
import com.jy.x.separation.manager.R;
import com.jy.x.separation.manager.bean.LoginBean;
import com.jy.x.separation.manager.ui.buy.view.BuyActivity;
import com.jy.x.separation.manager.ui.login.view.LoginActivity;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/* JADX INFO: renamed from: ʼˉיˆ */
/* JADX INFO: loaded from: classes2.dex */
public class C5863 {
/* JADX INFO: renamed from: ݿ */
public static C5863 f10989;
/* JADX INFO: renamed from: ݵ */
public SPUtil f10990;
/* JADX INFO: renamed from: ݶ */
public String f10991;
/* JADX INFO: renamed from: ݷ */
public String f10992;
/* JADX INFO: renamed from: ݸ */
public long f10993;
/* JADX INFO: renamed from: ݹ */
public int f10994;
/* JADX INFO: renamed from: ݺ */
public boolean f10995;
/* JADX INFO: renamed from: ݻ */
public boolean f10996;
/* JADX INFO: renamed from: ݼ */
public long f10997;
/* JADX INFO: renamed from: ݽ */
public C11420 f10998;
/* JADX INFO: renamed from: ݾ */
public List<InterfaceC5867> f10999;
/* JADX INFO: renamed from: ʼˉיˆ$ݵ */
public class C5864 extends AbstractC11989<C11272> {
public C5864() {
}
@Override // defpackage.AbstractC11989, io.reactivex.Observer
public void onError(Throwable th) {
}
@Override // defpackage.AbstractC11989
/* JADX INFO: renamed from: ݶ */
public void mo7044(C11272 c11272) {
}
}
/* JADX INFO: renamed from: ʼˉיˆ$ݶ */
public class RunnableC5865 implements Runnable {
public RunnableC5865() {
}
@Override // java.lang.Runnable
public void run() {
try {
Thread.sleep(1000L);
C5863.this.f10997 = 0L;
C5863.this.m16559();
Thread.sleep(5000L);
if (C5863.this.m16547()) {
return;
}
C5863.this.f10997 = 0L;
C5863.this.m16559();
Thread.sleep(5000L);
if (C5863.this.m16547()) {
return;
}
C5863.this.f10997 = 0L;
C5863.this.m16559();
} catch (Throwable unused) {
}
}
}
/* JADX INFO: renamed from: ʼˉיˆ$ݷ */
public class C5866 extends AbstractC11989<LoginBean> {
public C5866() {
}
@Override // defpackage.AbstractC11989, io.reactivex.Observer
public void onError(Throwable th) {
super.onError(th);
}
@Override // defpackage.AbstractC11989
/* JADX INFO: renamed from: ݶ */
public void mo7044(LoginBean loginBean) {
if (loginBean.isSuccess()) {
C5863.this.m16549(loginBean, true);
return;
}
C5863.this.m16550(C5958.m16773("AwxwVM0spwiS3o7ZG2nbNM1Z\n", "d2MbMaPLPrM=\n") + loginBean.getMsg());
T.show(loginBean.getMsg());
}
}
/* JADX INFO: renamed from: ʼˉיˆ$ݸ */
public interface InterfaceC5867 {
/* JADX INFO: renamed from: ݿ */
void mo7171();
}
/* JADX INFO: renamed from: ݼ */
public static C5863 m16532() {
if (f10989 == null) {
f10989 = new C5863();
}
return f10989;
}
/* JADX INFO: renamed from: ݶ */
public void m16533(InterfaceC5867 interfaceC5867) {
if (this.f10999 == null) {
m16543();
}
this.f10999.add(interfaceC5867);
}
/* JADX INFO: renamed from: ݷ */
public void m16534() {
if (System.currentTimeMillis() - this.f10997 < 1800000) {
return;
}
m16559();
}
/* JADX INFO: renamed from: ݸ */
public final void m16535() {
if ((m16542() + (((long) m16540()) * 86400000)) - System.currentTimeMillis() < 0) {
m16556(false);
}
}
/* JADX INFO: renamed from: ݹ */
public boolean m16536() {
String strM16538 = m16532().m16538();
return TextUtils.isEmpty(strM16538) || strM16538.equals(this.f10991);
}
/* JADX INFO: renamed from: ݺ */
public boolean m16537(Context context) {
if (!m16546()) {
T.show(R.string.login_first);
context.startActivity(new Intent(context, (Class<?>) LoginActivity.class));
return true;
}
if (m16547()) {
return false;
}
T.show(R.string.no_vip_tip);
context.startActivity(new Intent(context, (Class<?>) BuyActivity.class));
return true;
}
/* JADX INFO: renamed from: ݻ */
public String m16538() {
return this.f10991;
}
/* JADX INFO: renamed from: ݽ */
public String m16539() {
return this.f10992;
}
/* JADX INFO: renamed from: ݾ */
public int m16540() {
return this.f10994;
}
/* JADX INFO: renamed from: ݿ */
public long m16541() {
return this.f10993 + (((long) this.f10994) * 86400000);
}
/* JADX INFO: renamed from: ހ */
public long m16542() {
return this.f10993;
}
/* JADX INFO: renamed from: ށ */
public void m16543() {
this.f10999 = new ArrayList();
this.f10990 = C10230.m27210();
this.f10998 = new C11420();
this.f10992 = this.f10990.getString(C5958.m16773("wjgIUUJH3h/SJQ==\n", "t0ttIx0zsXQ=\n"));
this.f10991 = this.f10990.getString(C5958.m16773("+m1fnfA885nga1Sb\n", "jx46769dkPo=\n"));
this.f10995 = this.f10990.getBoolean(C5958.m16773("hHbn7aqwOSA=\n", "8QWCn/XGUFA=\n"));
this.f10996 = this.f10990.getBoolean(C5958.m16773("JZQXF1Bv+qw1\n", "UOdyZQ8IlcI=\n"));
this.f10993 = this.f10990.getLong(C5958.m16773("PVMLtrCR3w8XUxqlnZPpCyFNCw==\n", "SCBuxO/ntn8=\n"));
this.f10994 = this.f10990.getInt(C5958.m16773("xE2eKZKmcT7uX5cyu7VHOthTng==\n", "sT77W83QGE4=\n"));
m16535();
}
/* JADX INFO: renamed from: ނ */
public boolean m16544() {
return m16547() && m16541() - System.currentTimeMillis() > 315360000000L;
}
/* JADX INFO: renamed from: ރ */
public boolean m16545() {
return this.f10996;
}
/* JADX INFO: renamed from: ބ */
public boolean m16546() {
return (TextUtils.isEmpty(this.f10992) || this.f10992.equals(C5958.m16773("2Qw=\n", "9D0Kx5SeEio=\n"))) ? false : true;
}
/* JADX INFO: renamed from: ޅ */
public boolean m16547() {
return m16546() && this.f10995;
}
/* JADX INFO: renamed from: ކ */
public void m16548(LoginBean loginBean) {
m16549(loginBean, false);
}
/* JADX INFO: renamed from: އ */
public void m16549(LoginBean loginBean, boolean z) {
m16553(loginBean.getAccount());
m16555(loginBean.getToken());
if (loginBean.getStatus() == 0) {
m16556(true);
} else {
if (m16547()) {
T.show(R.string.tip_vip_expired, 1);
}
m16556(false);
}
m16554(loginBean.getGone() != 0);
m16557(loginBean.getAliveTime());
m16558(loginBean.getTime());
m16535();
m16551();
}
/* JADX INFO: renamed from: ވ */
public void m16550(String str) {
this.f10998.mo30295(this.f10991, str, new C5864());
m16553("");
m16555("");
m16556(false);
m16557(1);
m16558(1L);
m16551();
}
/* JADX INFO: renamed from: މ */
public void m16551() {
Iterator<InterfaceC5867> it = this.f10999.iterator();
while (it.hasNext()) {
it.next().mo7171();
}
}
/* JADX INFO: renamed from: ފ */
public void m16552(InterfaceC5867 interfaceC5867) {
this.f10999.remove(interfaceC5867);
}
/* JADX INFO: renamed from: ދ */
public void m16553(String str) {
this.f10991 = str;
this.f10990.put(C5958.m16773("7bKwoXWqSwj3tLun\n", "mMHV0yrLKGs=\n"), str);
}
/* JADX INFO: renamed from: ތ */
public void m16554(boolean z) {
this.f10996 = z;
this.f10990.put(C5958.m16773("vCodICLDoIqs\n", "yVl4Un2kz+Q=\n"), z);
}
/* JADX INFO: renamed from: ލ */
public void m16555(String str) {
this.f10992 = str;
this.f10990.put(C5958.m16773("ZNY14mSQXRJ0yw==\n", "EaVQkDvkMnk=\n"), str);
}
/* JADX INFO: renamed from: ގ */
public void m16556(boolean z) {
this.f10995 = z;
this.f10990.put(C5958.m16773("Tty5dcmhFY0=\n", "O6/cB5bXfP0=\n"), z);
}
/* JADX INFO: renamed from: ޏ */
public void m16557(int i) {
this.f10994 = i;
this.f10990.put(C5958.m16773("w/aaar2czivp5JNxlI/4L9/omg==\n", "toX/GOLqp1s=\n"), i);
}
/* JADX INFO: renamed from: ސ */
public void m16558(long j) {
this.f10993 = j;
this.f10990.put(C5958.m16773("rnH1ZUWT5pCEceR2aJHQlLJv9Q==\n", "2wKQFxrlj+A=\n"), j);
}
/* JADX INFO: renamed from: ޑ */
public void m16559() {
if (m16546()) {
this.f10997 = System.currentTimeMillis();
this.f10998.mo30297(this.f10992, new C5866());
}
}
/* JADX INFO: renamed from: ޒ */
public void m16560() {
ThreadPool.getInstance().execute(new RunnableC5865());
}
}
package com.android.libs.util;
import android.content.SharedPreferences;
import android.text.TextUtils;
import android.util.Base64;
import com.tencent.mmkv.MMKV;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
/* JADX INFO: loaded from: classes6.dex */
public class SPUtil {
/* JADX INFO: renamed from: ݹ, reason: contains not printable characters */
public static final int f1266 = 1;
/* JADX INFO: renamed from: ݺ, reason: contains not printable characters */
public static final int f1267 = 2;
/* JADX INFO: renamed from: ݻ, reason: contains not printable characters */
public static final String f1268 = "app";
/* JADX INFO: renamed from: ݵ, reason: contains not printable characters */
public SharedPreferences f1269;
/* JADX INFO: renamed from: ݶ, reason: contains not printable characters */
public SharedPreferences f1270;
/* JADX INFO: renamed from: ݷ, reason: contains not printable characters */
public SharedPreferences.Editor f1271;
/* JADX INFO: renamed from: ݸ, reason: contains not printable characters */
public SharedPreferences.Editor f1272;
public SPUtil() {
this("app");
}
public void clear() {
this.f1271.clear();
m1846();
this.f1272.clear();
}
public Map<String, ?> getAll() {
HashMap map = new HashMap();
Map<String, ?> all = this.f1270.getAll();
for (String str : all.keySet()) {
map.put(str, all.get(str));
}
return map;
}
public boolean getBoolean(String str) {
return getBoolean(str, false);
}
public float getFloat(String str) {
return getFloat(str, 0.0f);
}
public int getInt(String str) {
return getInt(str, 0);
}
public long getLong(String str) {
return getLong(str, 0L);
}
public Object getObject(String str) {
String string = getString(str, "");
if (string.isEmpty()) {
return null;
}
return IOUtil.object4bytes(Base64.decode(string, 0));
}
public SharedPreferences getSharedPreferences() {
return this.f1270;
}
public String getString(String str) {
return getString(str, "");
}
public void put(String str, String str2) {
this.f1271.putString(str, str2);
m1846();
}
public void remove(String str) {
this.f1271.remove(str);
m1846();
this.f1272.remove(str);
}
/* JADX INFO: renamed from: ݵ, reason: contains not printable characters */
public final void m1846() {
this.f1271.commit();
}
public SPUtil(String str) {
this(str, 1);
}
public boolean getBoolean(String str, boolean z) {
if (this.f1270.contains(str)) {
return this.f1270.getBoolean(str, z);
}
boolean z2 = this.f1269.getBoolean(str, z);
if (z != z2) {
put(str, z2);
}
return z2;
}
public float getFloat(String str, float f) {
if (this.f1270.contains(str)) {
return this.f1270.getFloat(str, f);
}
float f2 = this.f1269.getFloat(str, f);
if (f != f2) {
put(str, f2);
}
return f2;
}
public int getInt(String str, int i) {
if (this.f1270.contains(str)) {
return this.f1270.getInt(str, i);
}
int i2 = this.f1269.getInt(str, i);
if (i != i2) {
put(str, i2);
}
return i2;
}
public long getLong(String str, long j) {
if (this.f1270.contains(str)) {
return this.f1270.getLong(str, j);
}
long j2 = this.f1269.getLong(str, j);
if (j != j2) {
put(str, j2);
}
return j2;
}
public String getString(String str, String str2) {
if (this.f1270.contains(str)) {
return this.f1270.getString(str, str2);
}
String string = this.f1269.getString(str, str2);
if (!TextUtils.isEmpty(string) && !str2.equals(string)) {
put(str, string);
}
return string;
}
public SPUtil(String str, int i) {
str = TextUtils.isEmpty(str) ? "app" : str;
MMKV mmkvMmkvWithID = MMKV.mmkvWithID(str, i);
this.f1269 = mmkvMmkvWithID;
this.f1272 = mmkvMmkvWithID.edit();
AESSharedPreferences aESSharedPreferences = new AESSharedPreferences(str);
this.f1270 = aESSharedPreferences;
this.f1271 = aESSharedPreferences.edit();
}
public void put(String str, Serializable serializable) {
this.f1271.putString(str, Base64.encodeToString(IOUtil.object2bytes(serializable), 0));
m1846();
}
public void put(String str, long j) {
this.f1271.putLong(str, j);
m1846();
}
public void put(String str, float f) {
this.f1271.putFloat(str, f);
m1846();
}
public void put(String str, int i) {
this.f1271.putInt(str, i);
m1846();
}
public void put(String str, boolean z) {
this.f1271.putBoolean(str, z);
m1846();
}
}
4.打开LoginBean类,我们可以手动构造一个LoginBean实例
package com.jy.x.separation.manager.bean;
import defpackage.C11272;
import java.io.Serializable;
/* JADX INFO: loaded from: classes3.dex */
public class LoginBean extends C11272 implements Serializable {
private String account;
private int aliveTime;
private int gone;
private String id;
private int status;
private long time;
private String token;
public String getAccount() {
return this.account;
}
public int getAliveTime() {
return this.aliveTime;
}
public int getGone() {
return this.gone;
}
public String getId() {
return this.id;
}
public int getStatus() {
return this.status;
}
public long getTime() {
return this.time;
}
public String getToken() {
return this.token;
}
}
5.逻辑理清了,那就开始动手hook,这里使用libxposed api 101,以下是代码实现
fun XposedModule.helloWorld(param: PackageReadyParam) {
val classLoader = param.classLoader
// 对于加固应用,在 Application onCreate 执行完后才能拿到真实 ClassLoader
onApplicationCreated {
// new 一个 LoginBean 对象,并填充必要字段
val loginBean = classLoader["com.jy.x.separation.manager.bean.LoginBean"].newInstance {
setField("account", "100")
setField("time", 4102416000000L)
setField("token", "100")
}
// 先执行原方法,再主动调用 އ 写入 SharedPreferences
hook(classLoader["ʼˉיˆ", "ށ"]).intercept { chain ->
chain.proceed()
classLoader["ʼˉיˆ", "އ", "com.jy.x.separation.manager.bean.LoginBean", Boolean::class.java].invoke(chain.thisObject, loginBean, true)
}
}
}
// 一些简易封装的工具函数,剩下的就不写了,本质都是 Java 原生反射库,可以自行使用 Java 原生反射库实现
inline fun XposedModule.onApplicationCreated(crossinline block: XposedModule.() -> Unit) {
hook(Application::class.java["onCreate"]).intercept { chain ->
chain.proceed()
block()
}
}
fun Class<*>.findField(fieldName: String): Field {
var clazz: Class<*>? = this
while (clazz != null) {
try {
return clazz.getDeclaredField(fieldName).apply { isAccessible = true }
} catch (e: NoSuchFieldException) {
clazz = clazz.superclass
}
}
throw NoSuchFieldException("Field $fieldName not found in $this or its hierarchy")
}
inline fun Class<*>.newInstance(vararg initargs: Any?, block: Any.() -> Unit): Any? = constructors[0].newInstance(*initargs).apply(block)
fun Any.setField(fieldName: String, value: Any?) = javaClass.findField(fieldName).set(this, value)
6.打包安装,勾选作用域,打开样本软件提示“token过期”,继续分析,发现m16559方法会在登陆状态为true时进行网络验证,C5866是个网络回调类,这里就直接拦截该方法
/* JADX INFO: renamed from: ޑ */
public void m16559() {
if (m16546()) {
this.f10997 = System.currentTimeMillis();
this.f10998.mo30297(this.f10992, new C5866());
}
}
hook(classLoader["ʼˉיˆ", "ޑ"]).intercept {} // 拦截方法执行
7.最后测试Vip功能正常使用