
下载、查壳、
jadx反编译,打开encoder类和MainActlvity 类


这道题的核心逻辑分为两个类:Encoder(加密算法类)和MainActlvity(主界面 + 反射改密钥类),下面逐行拆解。
一、Encoder 类(加密核心)
public class Encoder {
// 【迷惑项】初始默认密钥,private私有,外部无法直接访问
private int key = 123456789;
// 加密方法:输入明文字符串,输出密文字符串
public String encode(String str) {
StringBuilder sb = new StringBuilder();
// 遍历输入字符串的每一个字符
for (char c : str.toCharArray()) {
// 核心运算:字符 与 key 做异或运算,强转为char类型拼接
sb.append((char) (c ^ this.key));
}
return sb.toString();
}
}
逻辑说明
- 加密算法 :单字节异或对称加密。
- 加密:
密文字符 = 明文字符 ^ 密钥 - 解密:
明文字符 = 密文字符 ^ 密钥(异或是可逆运算,同一个密钥运算两次就还原明文)
- 加密:
- 数据类型 :Java 的
char是 16 位 Unicode 字符,因此异或后会得到中文类的宽字符,也就是我们看到的乱码密文。 - 坑点提示 :这里的
key = 123456789是写死的初始值,但程序运行时并不会用这个值,后面会通过反射动态修改。
二、MainActlvity 类(反射改密钥,核心考点)
public class MainActlvity {
public MainActlvity() {
try {
// 1. 获取Encoder类中名为"key"的私有字段
Field declaredField = Encoder.class.getDeclaredField("key");
// 2. 暴力反射:打破private访问权限限制
declaredField.setAccessible(true);
// 3. 动态修改:将encoder对象的key字段,设置为新值 987654321
declaredField.set(MainActivity.encoder, 987654321);
} catch (IllegalAccessException | NoSuchFieldException e) {
e.printStackTrace();
}
}
}
逐行逻辑
getDeclaredField("key")
反射获取Encoder类的key成员变量。因为key是private私有的,常规方式访问不到,必须用反射。setAccessible(true)
开启暴力访问,忽略 Java 的访问修饰符检查,才能修改 private 字段。set(..., 987654321)
把全局encoder实例的key值,从原来的123456789覆盖为987654321。
✅ 程序运行时,真实生效的加密密钥是 987654321,不是类里写的 123456789,这是这道题最核心的考点。
三、完整校验流程(结合题目逻辑)
- APP 启动时,创建
MainActlvity实例,构造方法执行,通过反射把Encoder的key改成987654321。 - 用户在输入框输入 flag,点击校验按钮。
- 调用
encoder.encode(输入内容),用修改后的密钥 987654321对输入做异或加密。 - 把加密后的结果,和代码里固定的密文字符串
棿棢棢棲棥棷棊棐棁棚棨棨棵棢棌做对比。 - 完全相等则提示验证成功,否则失败。

- 成员变量
public static Encoder encoder;:静态加密类引用,Encoder 是外部类,截图看不到实现。public static MainActivity mainActivity;:静态 Activity 引用;mainActivity = new MainActivity();这行写法不符合 Android 规范,Activity 不能直接 new,该行不会参与业务逻辑,属于冗余无效代码。
- onCreate 生命周期方法
setContentView(R.layout.activity_main):加载布局页面;findViewById获取输入框、按钮控件;- 给按钮绑定点击事件;点击时调用
lambda$onCreate$0$MainActivity方法。
lambda$onCreate$0$MainActivity:synthetic 合成方法,Java 编译 lambda / 匿名内部类时自动生成,不是开发者手写的原始方法名。
- 校验逻辑 lambda$onCreate000MainActivity
- 获取输入框文本,调用
encoder.encode()做加密,把加密结果打印控制台; - 关键条件:
用户输入 → encode加密 → 和写死的中文密文字符串比对- 如果加密结果等于
"梡椆梮棜椋椒粜棐棁梲棨槮梀"→ Toast 弹出YES - 否则弹出
NO
- 如果加密结果等于
Toast第三个参数 0,等价Toast.LENGTH_SHORT短时弹窗。
写解密脚本:
python
cipher="棿棢棢棲棥棷棊棐棁棚棨棨棵棢棌"
key=987654321
flag=""
for c in cipher:
flag+=chr((ord(c)^key)%128);
print(flag)
对128取模的原因是因为ASCII字符集只有128个字符,所以如果不取模,那么异或运算的结果可能超出ASCII范围,导致无法正确解密。取模128可以保证结果在0到127之间,也就是ASCII字符集的有效范围。
本题知识点:1、查壳
2、加后缀名
3、知道函数逻辑
4、知道对128求余