Geek 2025(reverse方向)
1.ez_pyyy
拿到一个pyc文件,直接丢给网页反编译
完整反编译出来的代码为:
1 | cipher = [ |
该代码对输入进行了五步处理:
- 转化为hex字符串
- 异或17
- 高低半字节交换
- 逆序
- 循环左移32位
逆操作顺序:
- 把密文拼回hex字符串并转成bytes
- 循环右移32位
- 逆序
- 再次进行高低半字节交换(可自反操作)
- 异或17
- 最后转回UTF-8
EXP:
1 | cipher = [ |
2.QYQSの奇妙冒险
直接ida打开审代码
主函数:
1 | strcpy(v6, "QYQS"); |
首先检测输入长度为21,然后对每个字节做两次XOR:
Str[j] ^= j; Str[j] ^= v6[j % 4];
已知v6 = “QYQS”和密文
直接解密就行
EXP:
1 |
|
3.ezRust
Rust语言编写的文件,ida打开审计代码
Shift+F12找到了疑似Base85和Base64码表的字符串

跟进继续找,感觉下面这串乱码看起来很像密文,而且也符合Base85的加密规律

提取密文用cyberchef解密

SYC{Ohjhhh_y0u_g3t_Ezzzzz3_Ru3t!@}
4.only_flower
ida打开,题目都叫flower了,那还说啥了,去花就完了

去完花就能看到清晰的加密逻辑:
1 | __main(); |
跟进encrypt函数:
1 | unsigned int __cdecl encrypt(int a1, int a2, unsigned int a3) |
加密步骤:
-
KEY[i % key_len] ^ a1[i]- 用密钥异或明文字节 -
rol8(result, KEY[i % key_len] & 7)- 将结果循环左移 (0-7) 位 -
i + result- 再加上索引值
逆向操作:
- 减去索引
- 循环右移
- 密钥异或
EXP:
1 | def ror8(value, shift): |
5.encode
elf文件,代码很简洁,但是藏了加密逻辑

main函数里有个异或0x5A

compare函数里藏了个base64,上面的unk_100003EF1双击进去是密文,跟进也能发现base64是没换表的

但是在码表上面看到了疑似密钥的字符串,跟进调用密钥的函数
X追踪调用后发现,还有一个enc函数被藏在scanf函数里

这个加密是一个对密钥进行魔改处理的tea算法

密文密钥和加密逻辑都到手了,接下来就是写解密代码
先用cyberchef解了base64和xor,然后转换一下数据端序组合成4字节为一组

EXP:
1 |
|
6.ezSMC
ida打开审计代码,联系题目很容易发现.miao段代码是被SMC加密处理过的

*两种解法:1.动调过掉SMC自解密;2.写ida python代码解密
这里演示第二种解法:
要写代码解密,就得先知道是怎么加密的
跟进miao_encrypt –> miao_xor函数,发现是对这段代码进行了一个异或3的处理

然后回去确认.miao段代码的起始地址(0x4A2000)和结束地址(0x4A2200)
接下来就是写ida python代码解密:
1 | start_address = 0x4A2000 |
然后回到.miao段重新按P反编译定义一下,就能看到加密逻辑了
这一块是一个没换表的基础base64

但是下面还有个enc0de函数,里面是一个换表base58


再回去审一下主函数:
1 | _main(argc, argv, envp); |
跟进分析上面的init和encode函数,代码实现了经典的RC4算法初始化和加解密,但这个RC4的密钥是单字节17,即0x11(v8 = 17; init(v7, &v8, 1i64);)
整段主函数的加密流程为:
- 输入转hex字符串
- 再转成bytes –> data
- 单字节0x11初始化RC4
- 对data进行RC4加密
- 把RC4输出转回hex字符串
- smc自解密(把后续要用到的base64算法解密出来)
- base64编码
- base58编码
接下来就是逆向加密顺序写解密代码了
先用cyberchef把换表base58和base64解了

EXP:
1 | import sys |
7.Gensh1n
ida打开文件,一开始看到的是一个哈希计算函数,但发现后面的判定有问题
1 | for (j = 0; j <= 7; ++j) |
这段判断的意思是,如果存在任意一个位置满足v7[j] == global_nodes[16 * j]的条件就判定成功
介于这个奇怪的判定,我觉得这应该不是真正的加密逻辑,我先试了动调,然后发现这个文件动调一次就开一次原神的网页(;`O´)o
还是回去Shift+F12吧,在字符串列表里找到了另一个判定语句,以及一个疑似密钥的字符串

跟踪发现调用这个密钥(arr)的函数是前面的那个init初始化函数:
1 | int __fastcall init_node(__int64 a1) |
结合前面分析,只要输入的8个字符里有任意一个与 "geek2025" 对应位置相同,就算判定成功
而跟进另一个判定语句进入的是一个cleanup函数:
1 | unsigned __int64 cleanup() |
这里才是真正的加密逻辑,要求输入为28字节,然后调用sub_44656函数,最后与result进行比对,还另外匹配了calculate_crc32(dest,28) 与 calculate_crc32(result,28)(双重保险),都相等才算判定成功
跟进sub_44656函数,发现就是一个标准的RC4:
1 | unsigned __int64 __fastcall sub_44656(__int64 a1, int a2, __int64 a3, int a4) |
密钥就是之前的geek2025,密文是result,可以解密了
EXP:
1 | def rc4_decrypt(data: bytes, key: bytes) -> bytes: |
8.QYQSの奇妙冒险2
ida打开文件,发现主函数跟上一题长得差不多,不信邪解了一次,果然是错的
然后开始动调
经过测试,在主函数最后一句return 0;上下个断点,然后直接让代码跑完
这时候再回头去定位跳转到验证成功的代码位置,发现居然有三个不同的判定



但在我的动调过程中,我没发现它有运行进入过第三层判定的代码,所以仔细检索一下第三层判定代码,发现其中unk_7FF603C0F000对应的数据即为真正的flag
(事后推测应该是藏有一个SMC之类的自解密算法)

SYC{M@y_bE_y0u_F1nd?}
9.stack_bomb
拿到文件,发现主函数没法反编译,看汇编中间应该是加了段混淆

但是在混淆前面还有一串调用函数,一个一个跟进查看函数作用
整理得:
1 | push offset loc_411307 //a2 + a1; |
然后继续往下分析,为了静态分析代码,先把混淆nop掉
主函数:
1 | v16[0] = 1; |
这段主函数看密文像一个tea,跟进sub_411014函数:
1 | v71 = *a1; |
代码中出现了一大堆STACK[…]的内容,在动调的辅助下慢慢看每个STACK对应的操作分别是什么,然后把他们整理下来
1 | uint32_t part1 = *(uint32_t*)ptr = STACK[0x26C]; |
再把这些整理成可读的代码:
1 | sum += delta; |
很显然一个标准tea算法的模样就出来了
最后就是提取主函数里的密文写解密代码了
EXP:
1 |
|
10.ez_vm
ida打开,联系题目就知道是vm虚拟机的题目
主函数里可以看到两个函数名明显有问题的函数

先找找有没有可疑的字符串,比如密文或者opcode
在sub_5c6d7e的位置找到了疑似密文的字符串

在sub_1a2b3c函数下面看到了一次vm,其中的string_process_program就是这一轮vm的opcode

同理在sub_9e8f7a函数里找到了第二轮vm的opcode——xor_compare_program

由两个opcode定义的不同名称猜测这个题应该是有两轮不同的加密逻辑,其中一轮是异或
然后再跟进去分析vm的具体实现,发现也存在两段不同的vm实现逻辑


介于vm本身的麻烦性和代码的复杂性,我选择边调试边理清代码的运行顺序和加密逻辑,通过几次调试对比opcode
最后整理出两段opcode对应的汇编及反汇编代码(参考了ai的分析):

贴上两段整理好的汇编:
1 | 0x01, 0x01, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, MOV |
1 | 0x01, 0x01, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, MOV |
第二段异或的值也可以动调出来

所以总之就是进行了一个加3和一个异或0x5A的操作,用cyberchef就能解了

SYC{W31c0m3_t0_r3@1_r3verse!}
11.GeekBinder
文件包里有个docker,先看so文件
代码很少,打开就能看见疑似密文的内容
1 | if ( !a1 || !a2 ) |
再检索一下代码还能找到一处异或处理:
1 | __int64 __fastcall attr_xor_cipher(__int64 a1, size_t a2, _QWORD *a3, size_t *a4) |
跟进一下sub_1119:
1 | unsigned __int64 __fastcall sub_1119(__int64 a1, unsigned __int64 a2, __int64 a3) |
其中引用的key是geek2025,然后就可以直接写解密代码了
EXP:
1 | enc = [ |
12.obfuscat3
主函数是很简洁明了的代码,但是关键加密函数(obf_encode)里加了混淆(但是这个带混淆的代码直接给ai它也能分析OvO)

函数里又调用了init_encode和exchange_encode
具体审核分析代码看起来是有个魔改后又拆分加了混淆的RC4,进行了自定义的S盒流密码变体,其中init_encode函数实现了KSA的功能,exchange_encode函数实现了swap的功能,而obf_encode应该是实现了PRGA的功能,RC4算法的魔改点是把最后char ^ S[(S[i] + S[j]) % 256]中的异或运算改成了 + ,所以解密的时候只要改成 - 就行了
ai的分析是:用了很多复杂的布尔式/按位算术把标准的 j = j + S[i] + key[i%len] 和 i++/idx = S[(S[i] + S[j]) & 0xFF] 等简单操作包裹、隐藏起来
然后就可以写解密代码了
EXP:
1 | cipher = [ |
13.reReverse
代码很简单,但看不出什么东西,后面看汇编看到有没反编译出来的内容,明显有判断对错的字符串

然后把这一大段汇编丢给gpt分析,分析出是一个xxtea
在如下汇编的位置能看到四个重复出现的字符串,就是xxtea的密钥

在大段汇编的最开始也出现了经典的delta数值

而密文也能在这段很长的汇编中间找到


而这几个密文具体的加密比对顺序在密钥的位置能看见(也可以调试起来看)

然后取一段分析加密式子
1 | .text:00000000004009A1 mov r12d, r10d |
最后贴上解密代码
EXP:
1 | #!/usr/bin/env python3 |
14.国产の光
鸿蒙逆向,用魔改jadx反编译abc文件,在Index里找到密文和两个疑似密钥的内容


然后ida打开so文件,看见了一个AES和一个base58,AES的密钥和iv就是前面在jadx里找到的那两个

跟进base58发现码表被换了

然后cyberchef解密就行

SYC{HarmonyOS_1s_right?right!}
15.Lastone
ida打开审计代码,在主函数就能看见密文的赋值

然后跟进对buffer进行处理的sub_5A1032函数,审计代码

在sub_5A11DB函数里是vm虚拟机的switch循环函数,相应的unk_5AC040就是opcode

对照分析了一下opcode:
1 | 0x10, 0x00, 0x12, 0x00, 0x00, 0x00, r0 = 0x12 |
这里算出来的8组r0, r1, r2, r3的值是用于下面funcs中最后一个参数算式中的,即(v8 + v6 * v7) ^ (40503 * v9)
但是这一部分也可以直接动调跑出来:
1 | 1. (0x9F + 0x11 * 0x07) ^ (0x9E37 * 0xD5) |
这八个算式算出来的值就是异或的参数,但是我这里直接去试着异或解不出来
于是选择动态调试,直接把密文patch进去然后运行,但是这样运行得到的结果中存在乱码

前四位根据经验直接替换成SYC{,后面的几位乱码经过几次手动爆破和动调验证之后得出了真正的值(不知道是不是非预期解)
SYC{1@St_0nE_THanKs_I_lOvE_y0U!}
16.ez_android
安卓题,先安装到雷电模拟器运行看看,发现有三个输入框,应该是有三段flag

然后jadx打开看看,在源码里找到了三个function函数,在资源文件里找到了三段密文

先看第一段,是一个标准的DES/ECB/NoPadding算法,密钥为12345678,但是对密文又进行了一次转16进制的操作

直接cyberchef解密就行

看第二段,主逻辑在native层

解压之后反编译so文件,虽然在Java这个函数下面没看到关键,但是在旁边的函数列表可以看到一个decrypt_xor函数

交叉引用回去也能看到它的调用情况

分析一下调用的参数,发现异或的是一整段内容(看命名应该是一个so文件),异或的值为0xAA

然后拿去cyberchef解密一下,解出来是一个elf文件

反编译查看这个elf文件,是一个标准的RC4,密钥为mysecret
再拿去cyberchef解密就能得到第二段flag
最后看第三段,也是在native层

ida打开分析代码,是个des算法
把des加密中的1改成0就变成解密了

然后动调把密文patch进去,直接就能调出第三段flag

SYC{Th1s_1s_Th3_R3@1ly_F1ag!}