【2026春节】解题领红包之三 {Android 初级题}
题外话
我也是看正己老师安卓逆向课程才入的门,正己老师出的题我肯定要好好品鉴一下,唉~中级题我一个也做不出来
软件界面分析
通过观察界面和我对使用我发现每当我点击重新开始时九宫格内的数据都会进行重新排序,我进行了合理的假设,猜测这个九宫格是一个一维数组存储的序号数据,通过打乱一维数组进行打乱图片数据。接下来我们的目标就是找到在哪里进行数据初始化的我们把初始化的数据改为排序好的顺序就可以直接胜利了。
查找点击重新开始按钮后的回调
在 jadx 中搜索确实可以看到两个重新开始文本的引用(不知道这是什么混淆看不出来一点是按钮的操作),虽然有两个调用但是它两个是相对的,而且在这个判断之前还有 z8 数据的使用,我直接进行了 hook k.c 方法,发现 z8 一直都是 false 值,也就是会走进 else 分支,那么我们继续往下分析
AbstractC2253k.m3505c(c2176b, c0108c, m1970d, z8, c2403u, 8, 0);
if (z8) {
AbstractC2250h.m3485c("重新开始", new C2304i(c2443g2, 0), AbstractC0984d.m1894c(c0167j), false, false, c2403u, 390, 24);
c2403u.m3672Y(1157296644);
boolean m3684f4 = c2403u.m3684f(interfaceC2358V7);
Object m3652D4 = c2403u.m3652D();
} else {
AbstractC2250h.m3485c("重新开始", new C2304i(c2443g2, 1), null, false, false, c2403u, 6, 28);
c2403u.m3672Y(1157296644);
boolean m3684f5 = c2403u.m3684f(interfaceC2358V7);
Object m3652D5 = c2403u.m3652D();
}
AbstractC2250h.m3485c 发现没有返回值,但是它的反编译无法转成 Java 不知道为什么,是觉得是重要代码不让转换了吗?
这个方法有两个类的引用参数,其他都是基本数据类型,字符串除外。
c2403u 这个引用我们不确定是不是,可以使用算法助手 hook 全部方法查看参数和返回值,最后会排除它
锁定 C2304i 类
通过 hook C2304i 发现每次点击重新开始后都会调用,观察代码,会调用 this.f7589k.m3816d()
package p154u1;
import p029J1.InterfaceC0269a;
import p032K1.AbstractC0309l;
import p159w1.C2443g;
import p162x1.C2468j;
/* renamed from: u1.i */
/* loaded from: classes.dex */
public final class C2304i extends AbstractC0309l implements InterfaceC0269a {
/* renamed from: j */
public final /* synthetic */ int f7588j;
/* renamed from: k */
public final /* synthetic */ C2443g f7589k;
/* JADX WARN: 'super' call moved to the top of the method (can break code semantics) */
public /* synthetic */ C2304i(C2443g c2443g, int i3) {
super(0);
this.f7588j = i3;
this.f7589k = c2443g;
}
@Override // p029J1.InterfaceC0269a
/* renamed from: q */
public final Object mo185q() {
switch (this.f7588j) {
case 0:
this.f7589k.m3816d();
return C2468j.f8299a;
default:
this.f7589k.m3816d();
return C2468j.f8299a;
}
}
}
查看 this.f7589k.m3816d()
发现它调用了 C2177c.m3392a() 继续跟进查看
public final void m3816d() {
this.f8244e.m405v();
C0546A c0546a = this.f8245f;
if (c0546a != null) {
c0546a.mo1297a(null);
}
this.f8245f = null;
this.f8248i.m1599k(C2177c.m3392a());
this.f8246g = EnumC2438b.f8230i;
this.f8247h = false;
this.f8250k.m1599k(null);
}
查看 C2177c.m3392a()
查看它的返回值是 C2176b 类的实例,hook 一下会发现它的参数有一个数组。
并且 C2176b.m3391a 方法其实最后走的也是初始化方法,我们 hook 它的初始化方法就可以发现会调用 102 次,就是在打乱数组数据,到这里 C2176b 类就存储了我们要找到的一维数组
public static C2176b m3392a() {
C2176b c2176b = new C2176b(AbstractC2487k.m3865D(C2176b.f7184h), 8, false, 0, 0L, false, 0L);
long currentTimeMillis = System.currentTimeMillis();
int i3 = (int) currentTimeMillis;
int i4 = (int) (currentTimeMillis >> 32);
int i5 = ~i3;
?? abstractC0415e = new AbstractC0415e();
abstractC0415e.f879k = i3;
abstractC0415e.f880l = i4;
abstractC0415e.f881m = 0;
abstractC0415e.f882n = 0;
abstractC0415e.f883o = i5;
abstractC0415e.f884p = (i3 << 10) ^ (i4 >>> 4);
if ((i4 | i3 | i5) != 0) {
for (int i6 = 0; i6 < 64; i6++) {
abstractC0415e.mo1104b();
}
int i7 = -1;
int i8 = 0;
C2176b c2176b2 = c2176b;
while (i8 < 100) {
int i9 = c2176b2.f7186b;
int i10 = i9 / 3;
int i11 = i9 % 3;
ArrayList arrayList = new ArrayList();
if (i10 > 0) {
arrayList.add(Integer.valueOf(i9 - 3));
}
if (i10 < 2) {
arrayList.add(Integer.valueOf(i9 + 3));
}
if (i11 > 0) {
arrayList.add(Integer.valueOf(i9 - 1));
}
if (i11 < 2) {
arrayList.add(Integer.valueOf(i9 + 1));
}
ArrayList arrayList2 = new ArrayList();
Iterator it = arrayList.iterator();
while (it.hasNext()) {
Object next = it.next();
if (((Number) next).intValue() != i7) {
arrayList2.add(next);
}
}
C2176b m1769a0 = AbstractC0915a.m1769a0(c2176b2, ((Number) arrayList2.get(abstractC0415e.mo1107c(0, arrayList2.size()))).intValue());
if (m1769a0 != null) {
c2176b2 = m1769a0;
}
i8++;
i7 = i9;
}
return C2176b.m3391a(c2176b2, null, 0, false, 0, 0L, false, 0L, 3);
}
throw new IllegalArgumentException("Initial state must have at least one non-zero element.".toString());
}
查看 C2176b 类
package p148s1;
import java.util.List;
import p032K1.AbstractC0306i;
import p032K1.AbstractC0308k;
import p165y1.AbstractC2488l;
/* renamed from: s1.b */
/* loaded from: classes.dex */
public final class C2176b {
/* renamed from: h */
public static final List f7184h = AbstractC2488l.m3883i(0, 1, 2, 3, 4, 5, 6, 7, 8);
/* renamed from: a */
public final List f7185a;
/* renamed from: b */
public final int f7186b;
/* renamed from: c */
public final boolean f7187c;
/* renamed from: d */
public final int f7188d;
/* renamed from: e */
public final long f7189e;
/* renamed from: f */
public final boolean f7190f;
/* renamed from: g */
public final long f7191g;
public C2176b(List list, int i3, boolean z2, int i4, long j3, boolean z3, long j4) {
this.f7185a = list;
this.f7186b = i3;
this.f7187c = z2;
this.f7188d = i4;
this.f7189e = j3;
this.f7190f = z3;
this.f7191g = j4;
}
/* renamed from: a */
public static C2176b m3391a(C2176b c2176b, List list, int i3, boolean z2, int i4, long j3, boolean z3, long j4, int i5) {
List list2;
int i6;
boolean z4;
int i7;
long j5;
boolean z5;
long j6;
if ((i5 & 1) != 0) {
list2 = c2176b.f7185a;
} else {
list2 = list;
}
if ((i5 & 2) != 0) {
i6 = c2176b.f7186b;
} else {
i6 = i3;
}
if ((i5 & 4) != 0) {
z4 = c2176b.f7187c;
} else {
z4 = z2;
}
if ((i5 & 8) != 0) {
i7 = c2176b.f7188d;
} else {
i7 = i4;
}
if ((i5 & 16) != 0) {
j5 = c2176b.f7189e;
} else {
j5 = j3;
}
if ((i5 & 32) != 0) {
z5 = c2176b.f7190f;
} else {
z5 = z3;
}
if ((i5 & 64) != 0) {
j6 = c2176b.f7191g;
} else {
j6 = j4;
}
AbstractC0308k.m749e(list2, "tiles");
return new C2176b(list2, i6, z4, i7, j5, z5, j6);
}
public final boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof C2176b)) {
return false;
}
C2176b c2176b = (C2176b) obj;
if (AbstractC0308k.m745a(this.f7185a, c2176b.f7185a) && this.f7186b == c2176b.f7186b && this.f7187c == c2176b.f7187c && this.f7188d == c2176b.f7188d && this.f7189e == c2176b.f7189e && this.f7190f == c2176b.f7190f && this.f7191g == c2176b.f7191g) {
return true;
}
return false;
}
/* JADX WARN: Multi-variable type inference failed */
public final int hashCode() {
int m721e = AbstractC0306i.m721e(this.f7186b, this.f7185a.hashCode() * 31, 31);
int i3 = 1;
boolean z2 = this.f7187c;
int i4 = z2;
if (z2 != 0) {
i4 = 1;
}
int m723g = AbstractC0306i.m723g(this.f7189e, AbstractC0306i.m721e(this.f7188d, (m721e + i4) * 31, 31), 31);
boolean z3 = this.f7190f;
if (!z3) {
i3 = z3 ? 1 : 0;
}
return Long.hashCode(this.f7191g) + ((m723g + i3) * 31);
}
public final String toString() {
return "PuzzleState(tiles=" + this.f7185a + ", emptyIndex=" + this.f7186b + ", isCompleted=" + this.f7187c + ", moveCount=" + this.f7188d + ", elapsedMs=" + this.f7189e + ", isRunning=" + this.f7190f + ", startTimeMs=" + this.f7191g + ')';
}
}
修改 C2177c.m3392a() 方法返回值实现快速胜利
Java.perform(function () {
console.log("frida -U -f com.zj.wuaipojie2026 -l hook_script.js")
console.log("开始挂接 s1.c 和 s1.b 脚本");
// 挂接 s1.b 的构造函数
let C2176b = Java.use("s1.b");
console.log("获取s1.b的所有构造函数:");
let constructors = C2176b.class.getConstructors();
for (let i = 0; i < constructors.length; i++) {
console.log(`[+] 构造函数${i}: ${constructors[i]}`);
}
C2176b["$init"].overload('java.util.List', 'int', 'boolean', 'int', 'long', 'boolean', 'long').implementation = function (list, i3, z2, i4, j3, z3, j4) {
// console.log(`[+] C2176b.$init 被调用:`);
// console.log(` 列表: ${list.toString()} (大小: ${list ? list.size() : '空'})`);
// console.log(` 参数i3: ${i3}`);
// console.log(` 参数z2: ${z2}`);
// console.log(` 参数i4: ${i4}`);
// console.log(` 参数j3: ${j3}`);
// console.log(` 参数z3: ${z3}`);
// console.log(` 参数j4: ${j4}`);
// 调用原始构造函数
this["$init"](list, i3, z2, i4, j3, z3, j4);
// return this;
};
// 挂接 s1.c.a() 方法
let C2177c = Java.use("s1.c");
C2177c["a"].implementation = function () {
console.log("[+] C2177c.a() 方法被调用,返回自定义 C2176b 实例");
try {
// 创建包含0-8的ArrayList数组
let ArrayList = Java.use("java.util.ArrayList");
let list = ArrayList.$new();
// 向列表中添加0-8的整数
for (let i = 0; i <= 8; i++) {
list.add(Java.use("java.lang.Integer").valueOf(i));
}
console.log(`[+] 创建了包含 ${list.size()} 个元素的 ArrayList: ${list.toString()}`);
// 创建新的C2176b实例
// 注意:这里使用构造函数直接创建,而不是先创建实例再调用$init
let bInstance = C2176b.$new(
list, // 列表参数:包含0-8的ArrayList
8, // 整数参数i3:8
false, // 布尔参数z2:false
0, // 整数参数i4:0
0, // 长整型参数j3:0L
false, // 布尔参数z3:false
0 // 长整型参数j4:0L
);
console.log("[+] 成功创建 C2176b 实例");
return bInstance;
} catch (error) {
console.log(`[!] 创建 C2176b 时出错: ${error}`);
console.log("错误堆栈:", error.stack);
// 如果出错,调用原始方法
console.log("回退到原始方法调用");
return this["a"]();
}
};
console.log("所有挂接已成功安装");
});
【2026春节】解题领红包之四 {Windows 初级题}
观察应用程序的图标这是一个被 pyinstaller 打包的python应用
我们使用 pyinstxtractor 可以进行解包
python pyinstxtractor.py crackme_easy.exe
解包后我们查看目录中文件,其中有python版本的库文件(python314.dll),struct和crackme_easy 文件有都已经被抹去了,我们可以使用 010编辑器查看,第二个是其他库文件的文件头没有被抹去前16个字节数据信息
$ ls
PYZ.pyz
PYZ.pyz_extracted/
VCRUNTIME140.dll*
_bz2.pyd*
_decimal.pyd*
_hashlib.pyd*
_lzma.pyd*
_socket.pyd*
_ssl.pyd*
_zstd.pyd*
api-ms-win-core-console-l1-1-0.dll*
api-ms-win-core-datetime-l1-1-0.dll*
api-ms-win-core-debug-l1-1-0.dll*
api-ms-win-core-errorhandling-l1-1-0.dll*
api-ms-win-core-fibers-l1-1-0.dll*
api-ms-win-core-file-l1-1-0.dll*
api-ms-win-core-file-l1-2-0.dll*
api-ms-win-core-file-l2-1-0.dll*
api-ms-win-core-handle-l1-1-0.dll*
api-ms-win-core-heap-l1-1-0.dll*
api-ms-win-core-interlocked-l1-1-0.dll*
api-ms-win-core-libraryloader-l1-1-0.dll*
api-ms-win-core-localization-l1-2-0.dll*
api-ms-win-core-memory-l1-1-0.dll*
api-ms-win-core-namedpipe-l1-1-0.dll*
api-ms-win-core-processenvironment-l1-1-0.dll*
api-ms-win-core-processthreads-l1-1-0.dll*
api-ms-win-core-processthreads-l1-1-1.dll*
api-ms-win-core-profile-l1-1-0.dll*
api-ms-win-core-rtlsupport-l1-1-0.dll*
api-ms-win-core-string-l1-1-0.dll*
api-ms-win-core-synch-l1-1-0.dll*
api-ms-win-core-synch-l1-2-0.dll*
api-ms-win-core-sysinfo-l1-1-0.dll*
api-ms-win-core-timezone-l1-1-0.dll*
api-ms-win-core-util-l1-1-0.dll*
api-ms-win-crt-conio-l1-1-0.dll*
api-ms-win-crt-convert-l1-1-0.dll*
api-ms-win-crt-environment-l1-1-0.dll*
api-ms-win-crt-filesystem-l1-1-0.dll*
api-ms-win-crt-heap-l1-1-0.dll*
api-ms-win-crt-locale-l1-1-0.dll*
api-ms-win-crt-math-l1-1-0.dll*
api-ms-win-crt-process-l1-1-0.dll*
api-ms-win-crt-runtime-l1-1-0.dll*
api-ms-win-crt-stdio-l1-1-0.dll*
api-ms-win-crt-string-l1-1-0.dll*
api-ms-win-crt-time-l1-1-0.dll*
api-ms-win-crt-utility-l1-1-0.dll*
base_library.zip
crackme_easy.py
crackme_easy.pyc
libcrypto-3.dll*
libssl-3.dll*
'pyi-contents-directory _internal'
pyi_rth_inspect
pyiboot01_bootstrap
pyimod01_archive
pyimod02_importers
pyimod03_ctypes
pyimod04_pywin32
python314.dll*
select.pyd*
struct
ucrtbase.dll*
unicodedata.pyd*
二进制查看器
使用 脚本直接读取出Python字节码的反汇编
运行脚本需要使用 python3.14 版本的 python解释器
import marshal
import dis
import sys
if __name__ == '__main__':
pyc_path = "crackme_easy.pyc"
with open(pyc_path, 'rb') as f:
code_obj = marshal.load(f)
# 重定向标准输出到文件
with open('dis_output.txt', 'w') as f_out:
original_stdout = sys.stdout
sys.stdout = f_out
dis.dis(code_obj)
sys.stdout = original_stdout
让AI把Python字节码的反汇编转成源代码
import hashlib
import base64
import sys
def xor_decrypt(data, key):
"""
简单的异或解密函数
"""
result = bytearray()
for i, byte in enumerate(data):
result.append(byte ^ key ^ (i & 255))
return result.decode('utf-8', errors='ignore')
def get_encrypted_flag():
"""
获取加密的标志
"""
enc_data = 'e3w+fiRvfW18fnx4ZAZ6Pj43YwB9OWMXfXo8Dg4O'
return base64.b64decode(enc_data)
def generate_flag():
"""
生成正确的标志
"""
encrypted = get_encrypted_flag()
key = 78
result = bytearray()
for i, byte in enumerate(encrypted):
result.append(byte ^ key)
return result.decode('utf-8')
def calculate_checksum(s):
"""
计算字符串的校验和
"""
total = 0
for i, c in enumerate(s):
total += ord(c) * (i + 1)
return total
def hash_string(s):
"""
计算字符串的SHA256哈希
"""
return hashlib.sha256(s.encode()).hexdigest()
def verify_flag(user_input):
"""
验证用户输入的标志是否正确
"""
correct_flag = generate_flag()
if len(user_input) != len(correct_flag):
return False
for i in range(len(correct_flag)):
if user_input[i] != correct_flag[i]:
return False
return True
def fake_check_1(user_input):
"""
第一个假的检查函数,用于迷惑用户
"""
fake_hash = 'a1b2c3d4e5f67890abcdef1234567890abcdef1234567890abcdef1234567890'
return hash_string(user_input) == fake_hash
def fake_check_2(user_input):
"""
第二个假的检查函数,用于迷惑用户
"""
fake_hash = '1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef'
return hash_string(user_input) == fake_hash
def main():
print('==================================================')
print(' CrackMe Challenge - Python Edition')
print('==================================================')
print('Keywords: 52pojie, 2026, Happy New Year')
print('Hint: Decompile me if you can!')
print('--------------------------------------------------')
user_input = input('\n[?] Enter the password: ').strip()
if fake_check_1(user_input):
print('\n[!] Nice try, but not quite right...')
input('\nPress Enter to exit...')
return
if fake_check_2(user_input):
print("\n[!] You're getting closer...")
input('\nPress Enter to exit...')
return
if verify_flag(user_input):
checksum = calculate_checksum(user_input)
expected_checksum = calculate_checksum(generate_flag())
if checksum == expected_checksum:
print('\n==================================================')
print(' *** SUCCESS! ***')
print('==================================================')
print('[+] Congratulations! You cracked it!')
print('[+] Correct flag: ' + user_input)
else:
print('\n[!] Checksum failed!')
else:
print('\n[X] Access Denied!')
print('[X] Wrong password. Keep trying!')
input('\nPress Enter to exit...')
if __name__ == '__main__':
try:
main()
except KeyboardInterrupt:
print('\n\n[!] Interrupted by user')
sys.exit(0)
编写出获取 flag 的脚本
import base64
def decode_flag():
# 加密的flag
enc_data = 'e3w+fiRvfW18fnx4ZAZ6Pj43YwB9OWMXfXo8Dg4O'
# 解码base64
encrypted = base64.b64decode(enc_data)
# 解密(异或操作,key=78)
key = 78
result = bytearray()
for i, byte in enumerate(encrypted):
result.append(byte ^ key)
return result.decode('utf-8')
if __name__ == '__main__':
flag = decode_flag()
print(f"真正的 flag: {flag}")
【2026春节】解题领红包之六 {番外篇 初级题}
观察压缩包内的文件
通过观察发现文件 lua51.dll 和 love.dll 这是一个lua和love框架来写的程序
然后解压 CatchTheCat.exe 就可以发现 main.lua 文件 看大小那这个估计就是这个程序的主文件了,把文件丢给AI或者自己分析可以发下一下函数(我不会lua就给AI进行分析了)
local function getWinMessage()
local content = nil
if love.filesystem.getInfo("assets/flag.dat") then
content = love.filesystem.read("assets/flag.dat")
end
if not content or currentDifficulty ~= "hard" then
return "You WIN!"
end
local key = "52pojie"
local keyLen = #key
local result = {}
local bit = require("bit")
for i = 1, #content do
local b = string.byte(content, i)
local k = string.byte(key, ((i - 1) % keyLen) + 1)
table.insert(result, string.char(bit.bxor(b, k)))
end
return table.concat(result)
end
然后编写解密脚本
def decrypt_flag():
key = b"52pojie"
with open("flag.dat", "rb") as f:
data = f.read()
result = bytearray()
for i, b in enumerate(data):
k = key[i % len(key)]
result.append(b ^ k)
print(result.decode())
if __name__ == "__main__":
decrypt_flag()
结语
做完这几个题怎么说呢,感觉自身实力很弱,借助AI也做不出来中级题,初级题也是全靠AI帮我解答我不会的问题,如果离开AI我认为我一道题都做不出来,AI带来了很方便的学习成本与一个指导老师,但是AI发展越来越牛现在真的有点恐惧AI的能力了,像我这样平平无奇的人未来该何去何从。
感谢观看文章!!!