ctfplus-逆向每周练习-easyApp、rand_py、BabyJar、ez_pyyy、Minesweeper

admin 2026-06-23 05:54:27 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 文档分析了5道CTF逆向题目解题过程:easyApp通过动态加载DEX与方程组求解;randpy破解伪随机数种子;BabyJar逆向Base64与位交换加密;ezpyyy处理多层编码转换;Minesweeper逆向游戏逻辑。核心方法包括静态分析、数学求解、编码转换与算法还原,提供完整Python/Java解密脚本。 综合评分: 85 文章分类: 逆向分析,CTF,WEB安全,移动安全,安全工具


cover_image

ctfplus-逆向每周练习-easyApp、rand_py、BabyJar、ez_pyyy、Minesweeper

原创

李北辰 李北辰

SPEEDCoding

2026年6月21日 15:54 山西

在小说阅读器读本章

去阅读

#

1.easyApp

是一个apk文件,拖入模拟器中运行需要输入flag进行判断,然后拖入jadx中静态分析MainActivity中的代码:

可以看到首先读取了dex.zip文件(在assets里面,导出后再用jadx加载即可),然后判断输入的flag是否长度是42,再截取前26位,进行base64编码,编码后需要等于:MHhHYW1le0RvX3kwdV9sMHYzX2FuZHIwMWQ=,把这个base64解码即可得到flag的前面部分:

然后再读取输入字符串从第26个字符到末尾转换为字节数组,以hexstring的形式传入刚才动态加载的dex.zip中的Secret.Check方法中,接下来把dex.zip直接拖入jadx,查看Secret.Check方法:

package com.example.easyapp; import java.math.BigInteger; /* loaded from: dex.bin */public class Secret { public static boolean check(String str) { BigInteger bigInteger = new BigInteger(str.substring(0, 16), 16); BigInteger bigInteger2 = new BigInteger(str.substring(8, 24), 16); BigInteger bigInteger3 = new BigInteger(str.substring(16, 32), 16); return bigInteger2.add(bigInteger.multiply(new BigInteger(”3”))) .subtract(new BigInteger(”27454419028250566601”)) .equals(BigInteger.ZERO) &&  bigInteger3.multiply(new BigInteger(”2”)) .subtract(bigInteger2.multiply(new BigInteger(”5”))) .add(new BigInteger(”20616666104378640363”)) .equals(BigInteger.ZERO) &&  bigInteger.add(bigInteger3.multiply(new BigInteger(”4”))) .subtract(new BigInteger(”1dce62be9f0fa2f6c”, 16)) .equals(BigInteger.ZERO); }}

前面截取了26到42的字符串,一共16个字符串,转换成hexstring正好32个字节,这里第一个16字节数为0-16字节,第二个16字节数为8-24字节,第三个16字节数为16-32字节,然后需要满足下面的方程:

(big2+(big1*3))-27454419028250566601 = 0big3*2 - big2*5 + 20616666104378640363 = 0big1 + big3*4 - 0x1dce62be9f0fa2f6c = 0

使用python的sympy库求解并输出,脚本如下:

import sympy as spimport base64 big1, big2, big3 = sp.symbols('big1 big2 big3')eq1 = sp.Eq(big2 + 3*big1, 27454419028250566601)eq2 = sp.Eq(big3 * 2 - big2 * 5, -20616666104378640363)eq3 = sp.Eq(big1 + big3*4, 0x1dce62be9f0fa2f6c)solution = sp.solve((eq1, eq2, eq3), (big1, big2, big3))print(solution[big1])print(solution[big2])print(solution[big3]) big1 = solution[big1]big2 = solution[big2]big3 = solution[big3]str1_hex = hex(big1)str2_hex = hex(big2)str3_hex = hex(big3)print(str1_hex)print(str2_hex)print(str3_hex)str1 = base64.b16decode(str1_hex[2:].encode(), casefold=True)print(str1)str2 = base64.b16decode(str2_hex[2:].encode(), casefold=True)print(str2)str3 = base64.b16decode(str3_hex[2:].encode(), casefold=True)print(str3)

输出:

跟前面的flag进行拼接即可(注意这里需要去掉交叉字符串):0xGame{Do_y0u_l0v3_andr01d_4nd_dex_loader}

2.rand_py

这是一个pyinstaller打包的exe程序,首先使用pyinstxtrator.py提取出pyc文件:

python pyinstxtractor.py D:\桌面\rand_py\rand_py.exe

然后找到提取出来的pyc文件:rand_py.pyc,再使用pycdc.exe转换为python代码:

pycdc.exe rand_py.pyc > rand_py.py

成功提取出python代码:

 # Source Generated with Decompyle++# File: rand_py.pyc (Python 3.10) import randomenc_flag = [ 5554865, 8824328, 9324119, 2254831, 5757818, 2986985, 1878515, 9324119, 6857238, 5690625, 9073978, 3189766, 4267438, 9923116, 5042226, 4263793, 7510142, 3443924, 4569572, 5690625, 9923116, 4263793, 7510142, 3443924, 9923116, 5554865, 2464675, 6002055, 1327718, 4569572, 7510142, 5073474]user_input = input('Check your flag:')for i in range(len(user_input)): random.seed(ord(user_input[i])) num = random.randint(1000000, 9999999) if num != enc_flag[i]: print('WRONG!!!!!!') exit(1)print('YEAH,you are right!!!')

这里通过random.seed设置伪随机数种子,然后enc_flag列表里面的每个数字都是根据flag对应下标位置字符串生成的伪随机数,直接写python脚本爆破即可:

import randomenc_flag = [ 5554865, 8824328, 9324119, 2254831, 5757818, 2986985, 1878515, 9324119, 6857238, 5690625, 9073978, 3189766, 4267438, 9923116, 5042226, 4263793, 7510142, 3443924, 4569572, 5690625, 9923116, 4263793, 7510142, 3443924, 9923116, 5554865, 2464675, 6002055, 1327718, 4569572, 7510142, 5073474]flag = ''for i in range(len(enc_flag)): for seed in range(0x20, 0x7f): random.seed(seed) num = random.randint(1000000, 9999999) if num == enc_flag[i]: flag += chr(seed) breakprint(flag)

输出得到flag:

PDSCTF{Simple_random_and_Python}

3.BabyJar

题目是一个jar包文件,使用jd-gui进行反编译查看java源码:

先看BabyJar.class,首先实例化了一个Encrypt类e,然后定义了一个enc字符串,应该是base编码,然后获取到用户输入的flag,再对输入的flag调用e.encrypt方法得到返回值,返回值再跟enc字符串做比较。

package com.BabyJar.demo; import java.util.Scanner; public class BabyJar { public static void main(String[] args) { Encrypt e = new Encrypt(); Scanner input = new Scanner(System.in); String enc = ”QsY1V5cX9jJyF2JSAgdikwfCEneTAgICUpNnd1Iyk8IXUkJ3QhcyZ8J3YpY=”; System.out.println(”Please input your flag:”); String flag = input.nextLine(); String Encrypted_flag = e.encrypt(flag); if (Encrypted_flag.equals(enc)) { System.out.println(”Congratulations!!”); } else { System.out.println(”Try Again!!”); }  }}

然后看Encrypt类,先把输入的字符串转换为字节数组,然后每个字节先跟key异或得到temp,然后temp的高4位和低4位互相交换,得到加密后的字节数组,再进行base64编码得到刚才的enc字符串。

package com.BabyJar.demo; import java.util.Base64; public class Encrypt { int key = 20;
&nbsp;public&nbsp;String&nbsp;encrypt(String text)&nbsp;{&nbsp;byte[] originalBytes = text.getBytes();&nbsp;byte[] encryptedBytes =&nbsp;new&nbsp;byte[originalBytes.length];&nbsp;for&nbsp;(int&nbsp;i&nbsp;=&nbsp;0; i < originalBytes.length; i++) {&nbsp;byte&nbsp;c&nbsp;=&nbsp;originalBytes[i];&nbsp;byte&nbsp;temp&nbsp;=&nbsp;(byte)(c ^&nbsp;this.key);&nbsp;encryptedBytes[i] = (byte)((temp &&nbsp;0xF0) >>&nbsp;4&nbsp;| (temp &&nbsp;0xF) <<&nbsp;4);&nbsp;}&nbsp;&nbsp;return&nbsp;Base64.getEncoder().encodeToString(encryptedBytes);&nbsp;}}

只需要把enc字符串使用base64解码,然后再对每个字节重新交换高四位和低四位,然后跟20异或,即可解密,python解密脚本如下:

import&nbsp;base64&nbsp;enc = ”QsY1V5cX9jJyF2JSAgdikwfCEneTAgICUpNnd1Iyk8IXUkJ3QhcyZ8J3YpY=”enc_bytes = base64.b64decode(enc)enc_byte_array =&nbsp;bytearray(enc_bytes)key =&nbsp;20flag =&nbsp;b''for&nbsp;i&nbsp;in&nbsp;range(len(enc_byte_array)):&nbsp;temp = ((enc_byte_array[i] &&nbsp;0xf0) >>&nbsp;4) | ((enc_byte_array[i] &&nbsp;0x0f) <<&nbsp;4)&nbsp;temp = temp ^ key&nbsp;flag +=&nbsp;bytes([temp])print(flag)

运行后成功得到输出:

b'0xGame{73e214d2-d85c-4441-bc17-8e10c0e7b8c2}'

4.ez_pyyy

题目给的是一个pyc文件,直接pycdc转换为py源码:

pycdc.exe&nbsp;____python_______.pyc > result.py

得到的python源码为:

&nbsp;# Source Generated with Decompyle++# File: ____python_______.pyc (Python 3.8)&nbsp;cipher = [&nbsp;48,&nbsp;55,&nbsp;57,&nbsp;50,&nbsp;53,&nbsp;55,&nbsp;53,&nbsp;50,&nbsp;52,&nbsp;50,&nbsp;48,&nbsp;55,&nbsp;101,&nbsp;52,&nbsp;53,&nbsp;50,&nbsp;52,&nbsp;50,&nbsp;52,&nbsp;50,&nbsp;48,&nbsp;55,&nbsp;53,&nbsp;55,&nbsp;55,&nbsp;55,&nbsp;50,&nbsp;54,&nbsp;53,&nbsp;55,&nbsp;54,&nbsp;55,&nbsp;55,&nbsp;55,&nbsp;53,&nbsp;54,&nbsp;98,&nbsp;55,&nbsp;97,&nbsp;54,&nbsp;50,&nbsp;53,&nbsp;56,&nbsp;52,&nbsp;50,&nbsp;52,&nbsp;99,&nbsp;54,&nbsp;50,&nbsp;50,&nbsp;52,&nbsp;50,&nbsp;50,&nbsp;54]&nbsp;def&nbsp;str_to_hex_bytes(s =&nbsp;None):&nbsp;return&nbsp;s.encode('utf-8')&nbsp;&nbsp;def&nbsp;enc(data =&nbsp;None, key =&nbsp;None):&nbsp;return&nbsp;None((lambda&nbsp;.0&nbsp;=&nbsp;None: [ b ^ key&nbsp;for&nbsp;b&nbsp;in&nbsp;.0&nbsp;])(data))&nbsp;&nbsp;def&nbsp;en3(b =&nbsp;None):&nbsp;return&nbsp;b <<&nbsp;4&nbsp;&&nbsp;240&nbsp;| b >>&nbsp;4&nbsp;&&nbsp;15&nbsp;&nbsp;def&nbsp;en33(data =&nbsp;None, n =&nbsp;None):&nbsp;'''整体 bitstream 循环左移 n 位'''&nbsp;bit_len =&nbsp;len(data) *&nbsp;8&nbsp;n = n % bit_len&nbsp;val =&nbsp;int.from_bytes(data,&nbsp;'big')&nbsp;val = (val << n | val >> bit_len - n) & (1&nbsp;<< bit_len) -&nbsp;1&nbsp;return&nbsp;val.to_bytes(len(data),&nbsp;'big')&nbsp;if&nbsp;__name__ ==&nbsp;'__main__':&nbsp;flag =&nbsp;''&nbsp;data = str_to_hex_bytes(flag)&nbsp;data = enc(data,&nbsp;17)&nbsp;data =&nbsp;bytes((lambda&nbsp;.0: [ en3(b)&nbsp;for&nbsp;b&nbsp;in&nbsp;.0&nbsp;])(data))&nbsp;data = data[::-1]&nbsp;data = en33(data,&nbsp;32)&nbsp;if&nbsp;data.hex() == cipher:&nbsp;print('Correct! ')&nbsp;else:&nbsp;print('Wrong!!!!!!!!')

这段代码先把flag以utf8编码成字节数组,然后再调用enc函数进行第一次加密,针对每个字节跟key进行异或,得到的结果再每个字节调用en3函数,对每个字节低4位和高4位互换位置,然后再倒序排序字节数组,再调用en33函数最后加密得到cipher,参考题目的python源码写解密脚本:

import&nbsp;base64cipher = [&nbsp;48,&nbsp;55,&nbsp;57,&nbsp;50,&nbsp;53,&nbsp;55,&nbsp;53,&nbsp;50,&nbsp;52,&nbsp;50,&nbsp;48,&nbsp;55,&nbsp;101,&nbsp;52,&nbsp;53,&nbsp;50,&nbsp;52,&nbsp;50,&nbsp;52,&nbsp;50,&nbsp;48,&nbsp;55,&nbsp;53,&nbsp;55,&nbsp;55,&nbsp;55,&nbsp;50,&nbsp;54,&nbsp;53,&nbsp;55,&nbsp;54,&nbsp;55,&nbsp;55,&nbsp;55,&nbsp;53,&nbsp;54,&nbsp;98,&nbsp;55,&nbsp;97,&nbsp;54,&nbsp;50,&nbsp;53,&nbsp;56,&nbsp;52,&nbsp;50,&nbsp;52,&nbsp;99,&nbsp;54,&nbsp;50,&nbsp;50,&nbsp;52,&nbsp;50,&nbsp;50,&nbsp;54]def&nbsp;en3(b =&nbsp;None):&nbsp;#print(str(b))&nbsp;#print(b)&nbsp;return&nbsp;b <<&nbsp;4&nbsp;&&nbsp;240&nbsp;| b >>&nbsp;4&nbsp;&&nbsp;15def&nbsp;en33(data =&nbsp;None, n =&nbsp;None):&nbsp;'''整体 bitstream 循环左移 n 位'''&nbsp;print(hex(data))&nbsp;bit_len =&nbsp;len(cipher) *&nbsp;8&nbsp;n = n % bit_len&nbsp;val = data&nbsp;val = (val << n | val >> bit_len - n) & ((1&nbsp;<< bit_len) -&nbsp;1)&nbsp;print(hex(val))&nbsp;return&nbsp;val.to_bytes(len(cipher),&nbsp;'big')def&nbsp;enc(data =&nbsp;None, key =&nbsp;None):&nbsp;return[b ^ key&nbsp;for&nbsp;b&nbsp;in&nbsp;data]&nbsp;data =&nbsp;bytes(cipher)print(data.decode('utf-8'))data = data.decode('utf-8')str1 = data[:(len(data)) -&nbsp;8]str2 = data[(len(data)) -&nbsp;8:]print(str1)print(str2)new_data_str = str2 + str1print(new_data_str)new_data =&nbsp;bytearray.fromhex(new_data_str)print(new_data)new_data = new_data[::-1]temp = [en3(b)&nbsp;for&nbsp;b&nbsp;in&nbsp;new_data]print(temp)temp = enc(temp,&nbsp;17)print(bytes(temp))

运行后解密成功:

输出:079257524207e45242420757772657677756b7a6258424c6224226079257524207e45242420757772657677756b7a6258424c6224226c6224226079257524207e45242420757772657677756b7a6258424bytearray(b'\xc6”B&\x07\x92WRB\x07\xe4RBB\x07Ww&WgwV\xb7\xa6%\x84$')[66,&nbsp;72,&nbsp;82,&nbsp;106,&nbsp;123,&nbsp;101,&nbsp;119,&nbsp;118,&nbsp;117,&nbsp;98,&nbsp;119,&nbsp;117,&nbsp;112,&nbsp;36,&nbsp;36,&nbsp;37,&nbsp;78,&nbsp;112,&nbsp;36,&nbsp;37,&nbsp;117,&nbsp;41,&nbsp;112,&nbsp;98,&nbsp;36,&nbsp;34,&nbsp;108]b'SYC{jtfgdsfda554_a54d8as53}'

5.Minesweeper

题目文件给的是html和js文件,打开html后发现是一个扫雷游戏,应该是需要完成游戏获取flag,这里先查看js代码,发现被混淆了,找个在线网站去混淆(https://webfem.com/tools/js-decode/index.html):

然后在js文件里面搜flag的关键词,找到了flag的生成代码:

这里的打印flag是我加上去的,找个地方主动调用这个函数然后就可以在控制台打印出flag:


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:SPEEDCoding 李北辰 李北辰《ctfplus-逆向每周练习-easyApp、randpy、BabyJar、ezpyyy、Minesweeper》

评论:0   参与:  0