00x1 校验
apk签名


看app包名


.line 194
invoke-virtual {p1}, Landroid/content/pm/PackageManager$NameNotFoundException;->printStackTrace()V
const-string p1, ""
return-object p1
.end method
.method protected onCreate(Landroid/os/Bundle;)V
.registers 13
.line 38
invoke-super {p0, p1}, Landroidx/appcompat/app/AppCompatActivity;->onCreate(Landroid/os/Bundle;)V
const p1, 0x7f0b001c
.line 39
invoke-virtual {p0, p1}, Lcom/zj/wuaipojie/ui/ChallengeFifth;->setContentView(I)V
const p1, 0x7f08006d
.line 40
invoke-virtual {p0, p1}, Lcom/zj/wuaipojie/ui/ChallengeFifth;->findViewById(I)Landroid/view/View;
move-result-object p1
check-cast p1, Landroid/widget/Button;
const v0, 0x7f08006c
.line 41
invoke-virtual {p0, v0}, Lcom/zj/wuaipojie/ui/ChallengeFifth;->findViewById(I)Landroid/view/View;
move-result-object v0
move-object v2, v0
check-cast v2, Landroid/widget/TextView;
const v0, 0x7f08006a
.line 42
invoke-virtual {p0, v0}, Lcom/zj/wuaipojie/ui/ChallengeFifth;->findViewById(I)Landroid/view/View;
move-result-object v0
move-object v4, v0
check-cast v4, Landroid/widget/TextView;
const v0, 0x7f080066
.line 43
invoke-virtual {p0, v0}, Lcom/zj/wuaipojie/ui/ChallengeFifth;->findViewById(I)Landroid/view/View;
move-result-object v0
java
.method protected onCreate(Landroid/os/Bundle;)V
.registers 13
.line 38
invoke-super {p0, p1}, Landroidx/appcompat/app/AppCompatActivity;->onCreate(Landroid/os/Bundle;)V
const p1, 0x7f0b001c
.line 39
invoke-virtual {p0, p1}, Lcom/zj/wuaipojie/ui/ChallengeFifth;->setContentView(I)V
const p1, 0x7f08006d
.line 40
invoke-virtual {p0, p1}, Lcom/zj/wuaipojie/ui/ChallengeFifth;->findViewById(I)Landroid/view/View;
move-result-object p1
check-cast p1, Landroid/widget/Button;
const v0, 0x7f08006c
.line 41
invoke-virtual {p0, v0}, Lcom/zj/wuaipojie/ui/ChallengeFifth;->findViewById(I)Landroid/view/View;
move-result-object v0
move-object v2, v0
check-cast v2, Landroid/widget/TextView;
const v0, 0x7f08006a
.line 42
也就是说他的xml本身就是不同的用处,你不是一个xml有不同的东西。
java
protected void onCreate(Bundle bundle) {
//oncreate 消息响应函数,是用来"表示一个窗口正在生成"。
//标准动作,恢复保存,框架启动
super.onCreate(bundle);
//显示视图
//2131427356 xml视图
//加载视图内容
setContentView(2131427356);
//findViewById 是 Android 开发中用于在布局文件中查找并获取视图组件的核心方法
//查找核心组件
//寻找上面的东西
//xml类型bt
Button button = (Button) findViewById(2131230829);
TextView textView = (TextView) findViewById(2131230828);
TextView textView2 = (TextView) findViewById(2131230826);
TextView textView3 = (TextView) findViewById(2131230822);
TextView textView4 = (TextView) findViewById(2131230824);
TextView textView5 = (TextView) findViewById(2131230827);
TextView textView6 = (TextView) findViewById(2131230825);
//long转换
//字符串xml
long parseLong = Long.parseLong(getString(2131755054));
//获取hase
getHash();
//视图监听
button.setOnClickListener(new ExternalSyntheticLambda0(textView, this, textView2, textView3, textView6, textView4, parseLong, textView5));
}
java
private final void getHash() {
//ServiceCreator创建代理
//create创建
//获取Hash,enqueue((Callback) new 1(this)执行网络请求
((AppService) ServiceCreator.INSTANCE.create(AppService.class)).getAppHash().enqueue((Callback) new 1(this));
}

java
.method protected onCreate(Landroid/os/Bundle;)V
.registers 15
.line 44
invoke-super {p0, p1}, Landroidx/appcompat/app/AppCompatActivity;->onCreate(Landroid/os/Bundle;)V
const p1, 0x7f0b001c
.line 45
invoke-virtual {p0, p1}, Lcom/zj/wuaipojie/ui/ChallengeFifth;->setContentView(I)V
const p1, 0x7f080076
.line 46
invoke-virtual {p0, p1}, Lcom/zj/wuaipojie/ui/ChallengeFifth;->findViewById(I)Landroid/view/View;
move-result-object p1
check-cast p1, Landroid/widget/Button;
const v0, 0x7f080062
.line 47
invoke-virtual {p0, v0}, Lcom/zj/wuaipojie/ui/ChallengeFifth;->findViewById(I)Landroid/view/View;
move-result-object v0
check-cast v0, Landroid/widget/Button;
const v1, 0x7f080075
.line 48
invoke-virtual {p0, v1}, Lcom/zj/wuaipojie/ui/ChallengeFifth;->findViewById(I)Landroid/view/View;
move-result-object v1
move-object v3, v1
check-cast v3, Landroid/widget/TextView;
const v1, 0x7f080073
.line 49
invoke-virtual {p0, v1}, Lcom/zj/wuaipojie/ui/ChallengeFifth;->findViewById(I)Landroid/view/View;
move-result-object v1
move-object v5, v1
check-cast v5, Landroid/widget/TextView;
const v1, 0x7f08006e
.line 50
invoke-virtual {p0, v1}, Lcom/zj/wuaipojie/ui/ChallengeFifth;->findViewById(I)Landroid/view/View;
move-result-object v1
move-object v6, v1
check-cast v6, Landroid/widget/TextView;
const v1, 0x7f080070
.line 51
invoke-virtual {p0, v1}, Lcom/zj/wuaipojie/ui/ChallengeFifth;->findViewById(I)Landroid/view/View;
move-result-object v1
move-object v8, v1
check-cast v8, Landroid/widget/TextView;
const v1, 0x7f080074
.line 52
invoke-virtual {p0, v1}, Lcom/zj/wuaipojie/ui/ChallengeFifth;->findViewById(I)Landroid/view/View;
move-result-object v1
move-object v11, v1
check-cast v11, Landroid/widget/TextView;
const v1, 0x7f080072
.line 53
invoke-virtual {p0, v1}, Lcom/zj/wuaipojie/ui/ChallengeFifth;->findViewById(I)Landroid/view/View;
move-result-object v1
move-object v7, v1
check-cast v7, Landroid/widget/TextView;
const v1, 0x7f080071
.line 54
invoke-virtual {p0, v1}, Lcom/zj/wuaipojie/ui/ChallengeFifth;->findViewById(I)Landroid/view/View;
move-result-object v1
move-object v12, v1
check-cast v12, Landroid/widget/TextView;
const v1, 0x7f10002f
.line 55
invoke-virtual {p0, v1}, Lcom/zj/wuaipojie/ui/ChallengeFifth;->getString(I)Ljava/lang/String;
move-result-object v1
invoke-static {v1}, Ljava/lang/Long;->parseLong(Ljava/lang/String;)J
move-result-wide v9
.line 56
move-object v1, p0
check-cast v1, Landroid/content/Context;
invoke-direct {p0, v1}, Lcom/zj/wuaipojie/ui/ChallengeFifth;->checkSign(Landroid/content/Context;)Z
move-result v2
if-nez v2, :cond_79
const/4 v2, 0x0
.line 57
invoke-static {v2}, Ljava/lang/System;->exit(I)V
.line 59
:cond_79
invoke-virtual {p0}, Lcom/zj/wuaipojie/ui/ChallengeFifth;->check_root()Z
move-result v2
if-eqz v2, :cond_8b
const-string v2, "root"
.line 60
check-cast v2, Ljava/lang/CharSequence;
const/4 v4, 0x1
invoke-static {v1, v2, v4}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;
move-result-object v1
invoke-virtual {v1}, Landroid/widget/Toast;->show()V
.line 62
:cond_8b
sget-object v1, Lcom/zj/wuaipojie/ui/ChallengeFifth$$ExternalSyntheticLambda1;->INSTANCE:Lcom/zj/wuaipojie/ui/ChallengeFifth$$ExternalSyntheticLambda1;
invoke-virtual {v0, v1}, Landroid/widget/Button;->setOnClickListener(Landroid/view/View$OnClickListener;)V
.line 67
invoke-direct {p0}, Lcom/zj/wuaipojie/ui/ChallengeFifth;->getHash()V
.line 68
invoke-direct {p0}, Lcom/zj/wuaipojie/ui/ChallengeFifth;->getappsign()Ljava/lang/String;
.line 69
new-instance v0, Lcom/zj/wuaipojie/ui/ChallengeFifth$$ExternalSyntheticLambda0;
move-object v2, v0
move-object v4, p0
invoke-direct/range {v2 .. v12}, Lcom/zj/wuaipojie/ui/ChallengeFifth$$ExternalSyntheticLambda0;-><init>(Landroid/widget/TextView;Lcom/zj/wuaipojie/ui/ChallengeFifth;Landroid/widget/TextView;Landroid/widget/TextView;Landroid/widget/TextView;Landroid/widget/TextView;JLandroid/widget/TextView;Landroid/widget/TextView;)V
invoke-virtual {p1, v0}, Landroid/widget/Button;->setOnClickListener(Landroid/view/View$OnClickListener;)V
return-void
.end method
java
protected void onCreate(Bundle bundle) {
//启动框架,生成窗口
super.onCreate(bundle);
//加载渲染
setContentView(2131427356);
//寻找组件xml
Button button = (Button) findViewById(2131230838);
Button button2 = (Button) findViewById(2131230818);
TextView textView = (TextView) findViewById(2131230837);
TextView textView2 = (TextView) findViewById(2131230835);
TextView textView3 = (TextView) findViewById(2131230830);
TextView textView4 = (TextView) findViewById(2131230832);
TextView textView5 = (TextView) findViewById(2131230836);
TextView textView6 = (TextView) findViewById(2131230834);
TextView textView7 = (TextView) findViewById(2131230833);
//寻找字符串xml,long转换
long parseLong = Long.parseLong(getString(2131755055));
//获取上下文(字典管理,环境管理,资源地址),类似session
Context context = (Context) this;
//没有签名验证函数
if (!checkSign(context)) {
//这里,退出
System.exit(0);
}
//检查包含,root,以及兼容
if (check_root()) {
//输出
Toast.makeText(context, "root", 1).show();
}
//事件监听
button2.setOnClickListener(ExternalSyntheticLambda1.INSTANCE);
//获取哈希
getHash();
getappsign();
button.setOnClickListener(new ExternalSyntheticLambda0(textView, this, textView2, textView3, textView6, textView4, parseLong, textView5, textView7));
}
关键
可以改一下
java
private final boolean checkSign(Context context) {
try {
//遍历
//getPackageInfo 是一个在多个平台中用于获取应用包(Package)信息的函数
//获取应用签名(一般只有一个)
for (Signature signature : context.getPackageManager().getPackageInfo(context.getPackageName(), 64).signatures) {
//获取对象
MessageDigest instance = MessageDigest.getInstance("SHA");
//更新转化
instance.update(signature.toByteArray());
//instance.digest() 是 Java 中 MessageDigest 对象的方法,用于完成哈希计算并返回最终的摘要字节数组(byte[])
//转化字符串
String encodeToString = Base64Utils.INSTANCE.encodeToString(instance.digest());
Log.e("zj2595", "sign:" + encodeToString);
//可以调试伪造,调试法,对比
if (!Intrinsics.areEqual(this.SIGNATURE, encodeToString)) {
return false;
}
}
} catch (Exception e) {
e.printStackTrace();
}
return true;
}
java
private final String SIGNATURE = "h99Ici0iopj8tC6NkfqyJgs73ss=";
java
invoke-virtual {调用者, 参数...}, 方法的所属类;->方法名(参数类型)返回值类型
格式
所以把v0改成1,就是一种很诡异的绕过,因为签名输出越过导致异常报错,而异常报错又会返回t
或者替换硬编码
还有改跳转逻辑
java
method public final checkSignature(Landroid/content/Context;Ljava/lang/String;)Z
.registers 6
//修改这里
const/4 v0, 0x0
//Signature signature : context.getPackageManager().getPackageInfo(context.getPackageName(), 64).signatures
.line 285
:try_start_1//开始符号,try开始
//invoke-virtual调用虚方法,(可以被子类重写的方法,也就是普通的非静态、非私有、非构造方法)
//p1 拥有这个方法的对象
//context.getPackageManager()
//invoke-virtual {p1}, Landroid/content/Context对象调用方法所在的类
//getPackageManager//方法名()参数列表(传参)//Landroid/content/pm/PackageManager;//返回类型
invoke-virtual {p1}, Landroid/content/Context;->getPackageManager()Landroid/content/pm/PackageManager;
//在方法调用后获取并存储返回的对象引用。
//上面产生的结果存储
//存储v1
move-result-object v1
.line 286
//调用
invoke-virtual {p1}, Landroid/content/Context;->getPackageName()Ljava/lang/String;
//存储
move-result-object p1
//赋值64
const/16 v2, 0x40
//context.getPackageManager(),context.getPackageName(),64
//getPackageInfo
//v1调用者,p1, v2传参
//context.getPackageManager().getPackageInfo(context.getPackageName(), 64).signatures
invoke-virtual {v1, p1, v2}, Landroid/content/pm/PackageManager;->getPackageInfo(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;
//存储
move-result-object p1
.line 287
// iget-object指令类型
//p1目标寄存器(存储的地方),p1源寄存器从字段上面读取
//一个p1存储特定结果,一个p1存储所有结果
//同一个,覆盖获取
//context.getPackageName()
iget-object p1, p1, Landroid/content/pm/PackageInfo;->signatures:[Landroid/content/pm/Signature;
//赋值
const-string v1, "SHA-256"
// MessageDigest instance = MessageDigest.getInstance("SHA");
//MessageDigest.getInstance
.line 288
invoke-static {v1}, Ljava/security/MessageDigest;->getInstance(Ljava/lang/String;)Ljava/security/MessageDigest;
//存储
move-result-object v1
.line 289
// instance.update(signature.toByteArray());
//aget-object p1, p1, v0 是 Smali 语法指令,表示从对象数组 p1 的索引 v0 处获取一个对象引用,并存回 p1。
//for (Signature signature : //context.getPackageManager().getPackageInfo(context.getPackageName(), 64).signatures)
//p1=p1[p0]
//因为for循环
aget-object p1, p1, v0
//
invoke-virtual {p1}, Landroid/content/pm/Signature;->toByteArray()[B
//存储
move-result-object p1
//instance.update(signature.toByteArray());
invoke-virtual {v1, p1}, Ljava/security/MessageDigest;->update([B)V
.line 290
//instance.digest()
invoke-virtual {v1}, Ljava/security/MessageDigest;->digest()[B
//存储
move-result-object p1
//赋值
const-string v1, "zj595"
.line 291
//sget-object 是 Smali(Android Dalvik 字节码)中用于从静态字段读取对象引用并存入寄存器的指令
//Base64Utils.INSTANCE.encodeToString(instance.digest());
sget-object v2, Lcom/zj/wuaipojie/util/Base64Utils;->INSTANCE:Lcom/zj/wuaipojie/util/Base64Utils;
//Base64Utils.INSTANCE.instance.digest()
///Base64Utils.INSTANCE.encodeToString(instance.digest());
//
invoke-virtual {v2, p1}, Lcom/zj/wuaipojie/util/Base64Utils;->encodeToString([B)Ljava/lang/String;
//存储
move-result-object v2
//调用静态方法传入寄存器
//String encodeToString = Base64Utils.INSTANCE.encodeToString(instance.digest());
// Log.e("zj2595", "sign:" + encodeToString);
invoke-static {v1, v2}, Landroid/util/Log;->e(Ljava/lang/String;Ljava/lang/String;)I
.line 292
// if (!Intrinsics.areEqual(this.SIGNATURE, encodeToString)) {
// return false;
//}
//
sget-object v1, Lcom/zj/wuaipojie/util/Base64Utils;->INSTANCE:Lcom/zj/wuaipojie/util/Base64Utils;
//静态方法调用,p2是参数,v1调用者
//decode解码
//p2被解码
invoke-virtual {v1, p2}, Lcom/zj/wuaipojie/util/Base64Utils;->decode(Ljava/lang/String;)[B
//存储
move-result-object p2
.line 293
//对比
//V数组
//Z返回值
invoke-static {p1, p2}, Ljava/util/Arrays;->equals([B[B)Z
//存储结果
move-result p1
//try
:try_end_39
.catch Ljava/lang/Exception; {:try_start_1 .. :try_end_39} :catch_3a
//返回对比结果
return p1
//出错
:catch_3a
//返回 v0
return v0
.end method
java
· Smali 版:p2 解码,两个 byte[] 比。
· Java 版:p1 编码,两个 String 比。
java
public final boolean check_root() {
//有一个不满足才可以
if (!(checkRootMethod1() || checkRootMethod2())) {
if (!checkRootMethod3()) {
return false;
}
}
return true;
}
java
public final boolean checkRootMethod1() {
//在 Android(Java/Kotlin)中:android.os.Build.TAGS 是一个运行时字符串(如 "release-keys" 或 "test-keys"),表示系统镜像的签名类型,由系统编译时设定,非可编程构建标签。
String str = Build.TAGS;
//不是空,并且检查包含,忽略大小写,没有默认参数
//$default编译自带
//所以掩码只是一个机制,默认的时候有用。
return str != null && StringsKt.contains$default(str, "test-keys", false, 2, null);
}
java
public final boolean checkRootMethod2() {
/*
// Can't load method instructions: Load method exception: android.s.ۦۤ۟ۨ cannot be cast to android.s.yv in method: com.zj.wuaipojie.ui.ChallengeFifth.checkRootMethod2():boolean, dex:
*/
//nsupportedOperationException是一个运行时异常,通常在尝试对不支持操作的集合或数据结构执行某些操作时抛出。
//检查兼容
throw new UnsupportedOperationException("Method not decompiled: com.zj.wuaipojie.ui.ChallengeFifth.checkRootMethod2():boolean");
}
java
public final boolean checkRootMethod3() {
boolean z = false;
Process process = null;
try {
//代码执行
//检查环境是不是root
process = Runtime.getRuntime().exec(new String[]{"/system/xbin/which", "su"});
//一行一行读取数据流
if (new BufferedReader(new InputStreamReader(process.getInputStream())).readLine() != null) {
z = true;
}
} catch (Throwable unused) {
if (process != null) {
process.destroy();
}
//返回
return z;
}
}

pm代理
原包签名信息

io重定向
校验代码
java
public static final void m455onCreate$lambda1(TextView textView, ChallengeFifth challengeFifth, TextView textView2, TextView textView3, TextView textView4, TextView textView5, long j, TextView textView6, TextView textView7, View view) {
//获取挑战五
ChallengeFifth challengeFifth2 = challengeFifth;
String str = "通过";
textView.setText(challengeFifth.checkSign(challengeFifth2) ? str : "不通过");
textView2.setText(challengeFifth.checkPMProxy() ? str : "不通过");
textView3.setText(challengeFifth.checkApplication() ? str : "不通过");
textView4.setText(challengeFifth.useNewAPICheck() ? str : "不通过");
textView5.setText(challengeFifth.check_crc(j) ? str : "不通过");
textView6.setText(challengeFifth.check_Hash(challengeFifth2) ? str : "不通过");
if (!SecurityUtil.getSecret(challengeFifth2)) {
str = "不通过";
}
textView7.setText(str);
}
普通签名校验
java
//签名校验
private final boolean checkSign(Context context) {
Signature[] signatureArr;
try {
//遍历签名,获取包信息下面的签名
for (Signature signature : context.getPackageManager().getPackageInfo(context.getPackageName(), 64).signatures) {
//获取类
MessageDigest messageDigest = MessageDigest.getInstance("SHA");
//更新,添加字节签名
messageDigest.update(signature.toByteArray());
//字符串化
//MessageDigest.digest() 是 Java 中 java.security.MessageDigest 类的方法,用于完成哈希计算并返回固定长度的字节数组
String encodeToString = Base64Utils.INSTANCE.encodeToString(messageDigest.digest());
Log.e("zj2595", "sign:" + encodeToString);
//对比
if (!Intrinsics.areEqual(this.SIGNATURE, encodeToString)) {
return false;
}
}
return true;
} catch (Exception e) {
e.printStackTrace();
return true;
}
}
// 系统源码 android.app.ApplicationPackageManager
IPackageManager mPM; // 这个是真正的系统服务接口
```
它存在于系统框架层,不在你的 APK 反编译代码里,所以搜索当前代码找不到。
java
private final boolean checkPMProxy() {
String str;
try {
//获取实例
//getPackageManager() 是 Android Context 中的方法,用于获取 PackageManager 实例,以访问设备上已安装应用的元数据(如版本、权限、图标等)
PackageManager packageManager = getPackageManager();
//反射获取字段
//反射机制中用于获取类指定字段的方法,能访问包括私有字段在内的所有字段,但不包含继承的字段。
Field declaredField = packageManager.getClass().getDeclaredField("mPM");
//setAccessible 是 Java 反射中 AccessibleObject 类提供的方法,主要用于批量或单独设置访问权限标志,开启后能绕过语言的访问控制检查
//暴力获取私有字段开关
declaredField.setAccessible(true);
//packageManager 通常指 Android 开发中的核心管理类
//获取类名
str = declaredField.get(packageManager).getClass().getName();
} catch (Exception e) {
e.printStackTrace();
str = "";
}
//返回比较(替换法?)
return Intrinsics.areEqual("android.content.pm.IPackageManager$Stub$Proxy", str);
}
java
private final boolean checkApplication() {
//获取上下文类简短名称,比较
return Intrinsics.areEqual("MainApplication", getApplication().getClass().getSimpleName());
}
java
private final boolean useNewAPICheck() {
String str;
Signature[] signatureArr;
try {
if (Build.VERSION.SDK_INT >= 28) {
signatureArr = getPackageManager().getPackageInfo(getPackageName(), 134217728).signingInfo.getApkContentsSigners();
} else {
signatureArr = getPackageManager().getPackageInfo(getPackageName(), 64).signatures;
}
str = MD5Utils.INSTANCE.MD5(Base64Utils.INSTANCE.encodeToString(signatureArr[0].toByteArray()));
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
str = "";
}
//这里拼接str
Log.e("zj2595", "newsign:" + str);
//这里比较,硬编码,直接改
return Intrinsics.areEqual("074f64af5821ae6aa1ac1779ad5687ad", str);
}
public final boolean check_crc(long j) {
try {
ZipEntry entry = new ZipFile(getPackageCodePath()).getEntry("classes.dex");
Log.e("zj2595", "dexCrc:" + entry.getCrc());
return entry.getCrc() == j;
} catch (Exception e) {
e.printStackTrace();
return true;
}
}
java
public static /* synthetic */ void $r8$lambda$9qXr8aOuCuEvSBHyRMO0tTgIToY(TextView textView, ChallengeFifth challengeFifth, TextView textView2, TextView textView3, TextView textView4, TextView textView5, long j, TextView textView6, TextView textView7, View view) {
m455onCreate$lambda1(textView, challengeFifth, textView2, textView3, textView4, textView5, j, textView6, textView7, view);
}

java
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.activity_challenge_fifth);
Button button = (Button) findViewById(R.id.check_sign_btn);
Button button2 = (Button) findViewById(R.id.btn_smali);
final TextView textView = (TextView) findViewById(R.id.check_sign);
final TextView textView2 = (TextView) findViewById(R.id.check_pm);
final TextView textView3 = (TextView) findViewById(R.id.check_application);
final TextView textView4 = (TextView) findViewById(R.id.check_crc);
final TextView textView5 = (TextView) findViewById(R.id.check_sha1);
final TextView textView6 = (TextView) findViewById(R.id.check_new_sign);
final TextView textView7 = (TextView) findViewById(R.id.check_native_sign);
//这里
//每一次修改编译打包后会变化
// public static final int crc = 0x7f10002f;硬编码的j
final long parseLong = Long.parseLong(getString(R.string.crc));
ChallengeFifth challengeFifth = this;
if (!checkSign(challengeFifth)) {
System.exit(0);
}
if (check_root()) {
Toast.makeText(challengeFifth, "root", 1).show();
}
button2.setOnClickListener(ChallengeFifth$$ExternalSyntheticLambda1.INSTANCE);
getHash();
getappsign();
button.setOnClickListener(new View.OnClickListener() { // from class: com.zj.wuaipojie.ui.ChallengeFifth$$ExternalSyntheticLambda0
@Override // android.view.View.OnClickListener
public final void onClick(View view) {
//这玩意儿被混淆了,也不知道为什么他没有被混淆。
//以后遇到这样我该怎么回溯?
ChallengeFifth.$r8$lambda$9qXr8aOuCuEvSBHyRMO0tTgIToY(textView, this, textView2, textView3, textView6, textView4, parseLong, textView5, textView7, view);
}
});
}
java
public final boolean check_crc(long j) {
try {
//获取压缩包classes.dex
ZipEntry entry = new ZipFile(getPackageCodePath()).getEntry("classes.dex");
Log.e("zj2595", "dexCrc:" + entry.getCrc());
//getCrc() 返回该压缩条目的 CRC-32 校验和(long 类型),用于校验解压后数据完整性
//根据
//改返回
//entry.getCrc()会变动
return entry.getCrc() == j;
} catch (Exception e) {
e.printStackTrace();
return true;
}
}
java
public final boolean check_Hash(Context context) {
String apkPath = getApkPath(this);
FileInputStream fileInputStream = null;
try {
try {
MessageDigest messageDigest = MessageDigest.getInstance("SHA-1");
byte[] bArr = new byte[1024];
Ref.IntRef intRef = new Ref.IntRef();
FileInputStream fileInputStream2 = new FileInputStream(new File(apkPath));
while (true) {
try {
int read = fileInputStream2.read(bArr);
intRef.element = read;
if (read <= 0) {
break;
}
messageDigest.update(bArr, 0, intRef.element);
} catch (Exception e) {
e = e;
fileInputStream = fileInputStream2;
e.printStackTrace();
if (fileInputStream != null) {
try {
fileInputStream.close();
} catch (IOException e2) {
e2.printStackTrace();
}
}
return false;
} catch (Throwable th) {
th = th;
fileInputStream = fileInputStream2;
if (fileInputStream != null) {
try {
fileInputStream.close();
} catch (IOException e3) {
e3.printStackTrace();
}
}
throw th;
}
}
String bigInteger = new BigInteger(1, messageDigest.digest()).toString(16);
Log.e("zj2595", "hash:" + bigInteger);
boolean areEqual = Intrinsics.areEqual(bigInteger, this.ApkHash);
try {
fileInputStream2.close();
} catch (IOException e4) {
e4.printStackTrace();
}
return areEqual;
} catch (Throwable th2) {
th = th2;
}
} catch (Exception e5) {
e = e5;
}
}
java
public static native boolean getSecret(Context context)
hook
java
sget-object p10, Lcom/zj/wuaipojie/util/ContextUtils;->INSTANCE:Lcom/zj/wuaipojie/util/ContextUtils;
invoke-virtual {p10}, Lcom/zj/wuaipojie/util/ContextUtils;->getContext()Landroid/content/Context;
move-result-object p10
invoke-static {p10}, Lcom/zj/wuaipojie/util/SecurityUtil;->hook(Landroid/content/Context;)V
java对应
java
// 1. 拿到 ContextUtils 这个单例工具的实例
ContextUtils utils = ContextUtils.INSTANCE;
// 2. 调用它的 getContext() 方法,获取 Application 级别的上下文
Context appContext = utils.getContext();
// 3. 把上下文传进去,执行核心的攻击逻辑
SecurityUtil.hook(appContext);

从定向肯定是校验之前就已经转走了。

java
.line 75
invoke-virtual {p1, p6, p7}, Lcom/zj/wuaipojie/ui/ChallengeFifth;->check_crc(J)Z
move-result p0
if-eqz p0, :cond_47
move-object p0, v1
goto :goto_48
:cond_47
move-object p0, v2
:goto_48
check-cast p0, Ljava/lang/CharSequence;
invoke-virtual {p5, p0}, Landroid/widget/TextView;->setText(Ljava/lang/CharSequence;)V
.line 76
invoke-virtual {p1, p10}, Lcom/zj/wuaipojie/ui/ChallengeFifth;->check_Hash(Landroid/content/Context;)Z
move-result p0
if-eqz p0, :cond_55
move-object p0, v1
goto :goto_56
:cond_55
move-object p0, v2
:goto_56
check-cast p0, Ljava/lang/CharSequence;
invoke-virtual {p8, p0}, Landroid/widget/TextView;->setText(Ljava/lang/CharSequence;)V
.line 77
invoke-static {p10}, Lcom/zj/wuaipojie/util/SecurityUtil;->getSecret(Landroid/content/Context;)Z
move-result p0
if-eqz p0, :cond_62
goto :goto_63
:cond_62
move-object v1, v2
:goto_63
check-cast v1, Ljava/lang/CharSequence;
invoke-virtual {p9, v1}, Landroid/widget/TextView;->setText(Ljava/lang/CharSequence;)V
return-void
.end method
.method private final useNewAPICheck()Z
.registers 4
.line 156
:try_start_0
sget v0, Landroid/os/Build$VERSION;->SDK_INT:I
const/16 v1, 0x1c
if-lt v0, v1, :cond_1b
.line 157
invoke-virtual {p0}, Lcom/zj/wuaipojie/ui/ChallengeFifth;->getPackageManager()Landroid/content/pm/PackageManager;
move-result-object v0
.line 158
invoke-virtual {p0}, Lcom/zj/wuaipojie/ui/ChallengeFifth;->getPackageName()Ljava/lang/String;
move-result-object v1
const/high16 v2, 0x8000000
.line 157
invoke-virtual {v0, v1, v2}, Landroid/content/pm/PackageManager;->getPackageInfo(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;
move-result-object v0
.line 161
iget-object v0, v0, Landroid/content/pm/PackageInfo;->signingInfo:Landroid/content/pm/SigningInfo;
invoke-virtual {v0}, Landroid/content/pm/SigningInfo;->getApkContentsSigners()[Landroid/content/pm/Signature;
move-result-object v0
goto :goto_2b
.line 163
:cond_1b
invoke-virtual {p0}, Lcom/zj/wuaipojie/ui/ChallengeFifth;->getPackageManager()Landroid/content/pm/PackageManager;
move-result-object v0
.line 164
invoke-virtual {p0}, Lcom/zj/wuaipojie/ui/ChallengeFifth;->getPackageName()Ljava/lang/String;
move-result-object v1
const/16 v2, 0x40
.line 163
invoke-virtual {v0, v1, v2}, Landroid/content/pm/PackageManager;->getPackageInfo(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;
move-result-object v0
.line 167
iget-object v0, v0, Landroid/content/pm/PackageInfo;->signatures:[Landroid/content/pm/Signature;
.line 169
:goto_2b
sget-object v1, Lcom/zj/wuaipojie/util/Base64Utils;->INSTANCE:Lcom/zj/wuaipojie/util/Base64Utils;
const/4 v2, 0x0
aget-object v0, v0, v2
invoke-virtual {v0}, Landroid/content/pm/Signature;->toByteArray()[B
move-result-object v0
invoke-virtual {v1, v0}, Lcom/zj/wuaipojie/util/Base64Utils;->encodeToString([B)Ljava/lang/String;
move-result-object v0
.line 170
sget-object v1, Lcom/zj/wuaipojie/util/MD5Utils;->INSTANCE:Lcom/zj/wuaipojie/util/MD5Utils;
invoke-virtual {v1, v0}, Lcom/zj/wuaipojie/util/MD5Utils;->MD5(Ljava/lang/String;)Ljava/lang/String;
move-result-object v0
:try_end_3e
.catch Landroid/content/pm/PackageManager$NameNotFoundException; {:try_start_0 .. :try_end_3e} :catch_3f
goto :goto_45
:catch_3f
move-exception v0
.line 172
invoke-virtual {v0}, Landroid/content/pm/PackageManager$NameNotFoundException;->printStackTrace()V
const-string v0, ""
.line 174
:goto_45
也就是说在即将校验的方法之前加上这个代码,重定向



哈希没有过

我大概懂了,就是他读取的逻辑先读取你没有修改的源apk,修改的就找过了。
对APP进行路径拦截,重定向


或者这个

有些签名是根据文件值来进行签名,你改签名这些(文件里的东西)会变动,不改就不会变动。
隐藏root
一是修改逻辑返回
二是算法助手(没成功)

模拟器检测等等
////
java
public static final void m478onCreate$lambda0(SmaliLearn smaliLearn, TextView textView, TextView textView2, TextView textView3, View view) {
//直接改isVip返回
int isVip = smaliLearn.isVip();
if (isVip == 0) {
textView.setText("非会员");
} else if (isVip == 1) {
textView.setText("会员");
} else if (isVip == 4) {
textView.setText("大会员");
} else if (isVip == 16) {
textView.setText("超级会员");
} else if (isVip == 99) {
textView.setText("至尊会员");
}
long time = new Date().getTime();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
if (smaliLearn.vipEndTime() < time) {
textView2.setText("已过期");
} else {
textView2.setText(simpleDateFormat.format(Long.valueOf(smaliLearn.vipEndTime())));
}
//
int i = smaliLearn.vip_coin;
if (i != 0) {
textView3.setText(String.valueOf(i));
}
}
}
java
public final int getVip_coin() {
return this.vip_coin;
}
private final int vip_coin;
//赋值?
java
public final int isVip() {
return 0;
}
java
public final long vipEndTime() {
//改
return 1671889481513L;
}
java
method private static final onCreate$lambda-0(Lcom/zj/wuaipojie/ui/SmaliLearn;Landroid/widget/TextView;Landroid/widget/TextView;Landroid/widget/TextView;Landroid/view/View;)V
.registers 9
.line 21
invoke-virtual {p0}, Lcom/zj/wuaipojie/ui/SmaliLearn;->isVip()I
//返回0
move-result p4
//判断
//if-eqz 是 Smali(Android Dalvik/ART 字节码的汇编语言)中的条件跳转指令
//跳转
if-eqz p4, :cond_35//非会员
const/4 v0, 0x1
if-eq p4, v0, :cond_2d
const/4 v0, 0x4
if-eq p4, v0, :cond_25
const/16 v0, 0x10
if-eq p4, v0, :cond_1d
const/16 v0, 0x63
if-eq p4, v0, :cond_15
goto :goto_3c
:cond_15
const-string p4, "至尊会员"
.line 26
check-cast p4, Ljava/lang/CharSequence;
invoke-virtual {p1, p4}, Landroid/widget/TextView;->setText(Ljava/lang/CharSequence;)V
goto :goto_3c
:cond_1d
const-string p4, "超级会员"
.line 25
check-cast p4, Ljava/lang/CharSequence;
invoke-virtual {p1, p4}, Landroid/widget/TextView;->setText(Ljava/lang/CharSequence;)V
goto :goto_3c
:cond_25
const-string p4, "大会员"
.line 24
check-cast p4, Ljava/lang/CharSequence;
invoke-virtual {p1, p4}, Landroid/widget/TextView;->setText(Ljava/lang/CharSequence;)V
goto :goto_3c
:cond_2d
const-string p4, "会员"
.line 23
check-cast p4, Ljava/lang/CharSequence;
invoke-virtual {p1, p4}, Landroid/widget/TextView;->setText(Ljava/lang/CharSequence;)V
goto :goto_3c
:cond_35
const-string p4, "非会员"
.line 22
check-cast p4, Ljava/lang/CharSequence;
invoke-virtual {p1, p4}, Landroid/widget/TextView;->setText(Ljava/lang/CharSequence;)V
.line 28
:goto_3c
new-instance p1, Ljava/util/Date;
invoke-direct {p1}, Ljava/util/Date;-><init>()V
invoke-virtual {p1}, Ljava/util/Date;->getTime()J
move-result-wide v0
.line 29
new-instance p1, Ljava/text/SimpleDateFormat;
const-string p4, "yyyy-MM-dd"
invoke-direct {p1, p4}, Ljava/text/SimpleDateFormat;-><init>(Ljava/lang/String;)V
.line 30
invoke-virtual {p0}, Lcom/zj/wuaipojie/ui/SmaliLearn;->vipEndTime()J
move-result-wide v2
cmp-long p4, v2, v0
if-gez p4, :cond_5c
const-string p1, "已过期"
.line 31
check-cast p1, Ljava/lang/CharSequence;
invoke-virtual {p2, p1}, Landroid/widget/TextView;->setText(Ljava/lang/CharSequence;)V
goto :goto_6d
.line 33
:cond_5c
invoke-virtual {p0}, Lcom/zj/wuaipojie/ui/SmaliLearn;->vipEndTime()J
move-result-wide v0
invoke-static {v0, v1}, Ljava/lang/Long;->valueOf(J)Ljava/lang/Long;
move-result-object p4
invoke-virtual {p1, p4}, Ljava/text/SimpleDateFormat;->format(Ljava/lang/Object;)Ljava/lang/String;
move-result-object p1
check-cast p1, Ljava/lang/CharSequence;
invoke-virtual {p2, p1}, Landroid/widget/TextView;->setText(Ljava/lang/CharSequence;)V
.line 35
:goto_6d
iget p0, p0, Lcom/zj/wuaipojie/ui/SmaliLearn;->vip_coin:I
if-eqz p0, :cond_7a
.line 36
invoke-static {p0}, Ljava/lang/String;->valueOf(I)Ljava/lang/String;
move-result-object p0
check-cast p0, Ljava/lang/CharSequence;
invoke-virtual {p3, p0}, Landroid/widget/TextView;->setText(Ljava/lang/CharSequence;)V
:cond_7a
return-void
.end method
java
.method public final isVip()I
//表示当前方法总共使用 2 个寄存器
.registers 2
const/4 v0, 0x0
//限制进制
//返回0
return v0
.end method
改钻石黑屏了

这个方法没有用

成功
黑屏原因
第2个P0相当于这个类的实例地址
如果前面先给他复值了,他就会把这个东西当成地址引用从而报错
java
const/16 p0, 0x63
//第二个p0=this
//this.SmaliLearn.vip_coin
iget p0, p0, Lcom/zj/wuaipojie/ui/SmaliLearn;->vip_coin:I
java
.line 35
:goto_6d
iget p0, p0, Lcom/zj/wuaipojie/ui/SmaliLearn;->vip_coin:I
const/16 p0, 0x63
if-eqz p0, :cond_7c

java
.method public final getVip_coin()I
.registers 2
const/16 p1, 0x0
.line 12
//iget读取字段
//读取vip_coin赋值
//p0是实例
//v0存储
iget v0, p0, Lcom/zj/wuaipojie/ui/SmaliLearn;->vip_coin:I
//返回p1
return p1
.end method
java
.line 31
//检查是否可以强制转化
check-cast p1, Ljava/lang/CharSequence;
//
invoke-virtual {p2, p1}, Landroid/widget/TextView;->setText(Ljava/lang/CharSequence;)V
goto :goto_6d
java
.line 35
:goto_6d
//存储判断是否大于0
iget p0, p0, Lcom/zj/wuaipojie/ui/SmaliLearn;->vip_coin:I
//会卡死
if-nez p0, :cond_7a
.line 35
:goto_6d
iget p0, p0, Lcom/zj/wuaipojie/ui/SmaliLearn;->vip_coin:I
if-eqz p0, :cond_7a
java
:cond_7a
return-void
.end method
java
int i = smaliLearn.vip_coin;
if (i != 0) {
textView3.setText(String.valueOf(i));
}
java
.line 31
//检查类型,强制转化
check-cast p1, Ljava/lang/CharSequence;
//设置显示
invoke-virtual {p2, p1}, Landroid/widget/TextView;->setText(Ljava/lang/CharSequence;)V
goto :goto_6d
.line 35
:goto_6d
//赋值
iget p0, p0, Lcom/zj/wuaipojie/ui/SmaliLearn;->vip_coin:I
//如果是0
if-eqz p0, :cond_7a
.line 36
//静态方法获取,p0转化字符串
//const/16 p0, 0x63
invoke-static {p0}, Ljava/lang/String;->valueOf(I)Ljava/lang/String;
//删除然后写一个新的?
//赋值
move-result-object p0
//检查类型,强转
check-cast p0, Ljava/lang/CharSequence;
//设置显示
invoke-virtual {p3, p0}, Landroid/widget/TextView;->setText(Ljava/lang/CharSequence;)V
:cond_7a
//这里,直接完了
return-void
.end method


查找调用静态字段

是看看哪里对他进行赋值,因为他是去那个判断的。

反调试


java
.method protected attachBaseContext(Landroid/content/Context;)V
.registers 2
.line 11
invoke-super {p0, p1}, Landroid/app/Application;->attachBaseContext(Landroid/content/Context;)V
.line 13
//反调试
invoke-virtual {p0}, Lcom/zj/wuaipojie/MainApplication;->checkForDebugger()V
return-void
.end method
.method public final checkForDebugger()V
.registers 2
.line 18
invoke-static {}, Landroid/os/Debug;->isDebuggerConnected()Z
move-result v0
if-eqz v0, :cond_a
const/4 v0, 0x0
.line 20
invoke-static {v0}, Ljava/lang/System;->exit(I)V
:cond_a
return-void
.end method