CrackMe&F***Me
来自NSSCTF 4th 2025 的一道需要手动解包exe的题目
最开始是想用pyinstxtractor进行解包,尝试了几下一直报错。
看一眼pyinstxtractor.py源码。发现报错的原因是没有找到MAGIC。
这个MAGIC一般在文件末尾附近,pyinstxtractor 用它定位 TOC 表,从而获取文件入口。看一眼附件的MAGIC,发现MAGIC被修改为了 ‘swI\014\013\012\013\016’ 。
修改回 ‘MEI\014\013\012\013\016’ 然后用pyinstxtractor进行解包。
发现没有解包完全,最重要的内容解压失败了,估计是压缩的时候加密了。
pyinstaller 在打包时提供了加密压缩的功能,不过最新版本中好像取消掉了。查看一下pyinstaller的源码,就可以看到加解密方法,AES。
pyinstxtractor-ng好像有自动解密的功能,尝试解压也失败了,也是解压错误。
这里用pyinstaller源码下提供的一个archive_viewer.py 脚本,查看一下压缩文件的信息。可以发现里面确实有一个名为”CrackMe&F***Me”的脚本文件被压缩了。
再次尝试提取,依然解压错误。接下来就只能在解密后提取文件或者获得密钥
IDA分析,main函数进去后调用的就是主逻辑函数。
这里可以发现MAGIC的检验被修改了。等下动调的时候要把MAGIC改回 ‘swI\014\013\012\013\016’ 不然会闪退。
逻辑有很多,但是每一步都有字符串,于是从字符串入手。
搜索”archive” 会看到一个脚本解压失败的字符串。
引用过去,发现这里有个marshal,那么这里就是python字节码被转为code对象的地方,我们只需要在marshal函数下断点就能拿到python机器码。分析这个函数前面的逻辑,大概就是在遍历文件,判断类型是不是 ‘s’ 然后解压,获取这个脚本文件。解密代码就在getFile函数里面,不过也不需要逆解密代码了,直接获取python机器码即可。
下断点动调,发现程序竟然没有执行到断点位置?于是单步运行,看看在这个函数执行前的函数有什么猫腻。
发现运行到下面这个函数python机器码就被执行了。继续跟进去。
会发现里面调用CreateProcessW创建了一个子进程,子进程执行的程序正是CreackMe&&FxxMe.exe。
原来是子进程运行到了python机器码码执行的位置。接下来我们要调试子进程来获取机器码的内容。
这里用x64dbg的dbgchild插件来调试子进程。先计算一下内存地址,在mashal函数下断点。继续运行后弹出子进程的调试界面,并断在marshal函数处。第一次断在这里是bootstrap的机器码,第二次才是CrackMe&F***Me的字节码。看到机器码长度正好是,解压后CrackMe&F**Me的长度。
用Scylla导出内存数据,写脚本反序列化,再用dis模块反编译一下即可看到逻辑。注意使用的python版本应为3.8。
1 2 3 4 5 6 7 8 import disimport marshalwith open ('MEM_000001B5EC17E2B0_000003B9.mem' , 'rb' ) as f: data = f.read() print ("len: " ,len (data)) a = marshal.loads(data) dis.dis(a)
密文”d29b81e136efc517c2967b863f584baf4b82f710f8869f5a56185cb22a9a25fc”
密钥”NSSCTF”
加密函数看似是一个RC4,猜测没有魔改
如果不确定,可以直接丢给AI反写出python脚本。
解密
PyArmerMini
来自 Lilctf 2025 的预热赛题,pyarmermini逆向,一个贴近真实生产环境的题目
pip 安装一个同版本的pyarmor_mini,去安装的软件包下寻找pyarmor_mini.pyd分析。在sub_62401600函数中可以看到反序列化字节码的位置PyMarshal_ReadObjectFromString。之后调用PyImport_ExecCodeModuleObject执行python字节码。
动调看PyMarshal_ReadObjectFromString的参数发现就是提取了0x7e个字节后面的数据进行反序列化(即偏移0x7e是 code object 开始的位置)。提出字节码,手动反序列化后用dis反汇编。
1 2 3 4 5 6 import disimport marshaldata = b'PYARMIN\x01\x03\x0bP`o\x10\x0f\x0f~\x00\x00\x00\xde\x07\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00@\xd1\xb3s\xe1\x93\xdb\xd9\xe4-\xa9)\xea \xfai\xa6D\xf6\x19\xbb\x89\x83u1\xc3[\xaa~\xa9pu\x8e\xd87\x03\xb3s,ai\xfe\x01#O\xf0\xee\xc7\xb7S,?~\xfa\xbe\xa2\x97\xd0\xd5\xd9g\x04\xdcl\x96\xaf\xd2\xfa\xcc\x97\xe3\x01\xceYQ\xbf\xb9\xc3\x98\xd1\xb4\t\x0e\xb7Y\x83\xec\xa7\x04\xec\x95\x8cj\xfc\xe3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\t\x00\x00\x00\x00\x00\x00\x00\xf3\x00\x03\x00\x00\x97\x00\x02\x00d\x00g\x01d\x01\x19\x00\x00\x00\x00\x00\x00\x00\x00\x00d\x02\x19\x00\x00\x00\x00\x00\x00\x00\x00\x00d\x03\xa6\x01\x00\x00\xab\x01\x00\x00\x00\x00\x00\x00\x00\x00\\\x01\x00\x00Z\x00\x02\x00d\x00g\x01d\x01\x19\x00\x00\x00\x00\x00\x00\x00\x00\x00d\x02\x19\x00\x00\x00\x00\x00\x00\x00\x00\x00d\x04\xa6\x01\x00\x00\xab\x01\x00\x00\x00\x00\x00\x00\x00\x00\\\x01\x00\x00Z\x01\t\x00\x02\x00e\x02d\x05\xa6\x01\x00\x00\xab\x01\x00\x00\x00\x00\x00\x00\x00\x00Z\x03e\x04\xa0\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00e\x03d\x06d\x07d\x08\x85\x03\x19\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa0\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa6\x00\x00\x00\xab\x00\x00\x00\x00\x00\x00\x00\x00\x00d\t\xa6\x02\x00\x00\xab\x02\x00\x00\x00\x00\x00\x00\x00\x00d\nz\x06\x00\x00\x02\x00e\x04d\x0b\xa6\x01\x00\x00\xab\x01\x00\x00\x00\x00\x00\x00\x00\x00k\x02\x00\x00\x00\x00\x02\x00e\x00e\x03d\x0cd\x07\x85\x02\x19\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa0\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa6\x00\x00\x00\xab\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa6\x01\x00\x00\xab\x01\x00\x00\x00\x00\x00\x00\x00\x00\xa0\x07\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa6\x00\x00\x00\xab\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa0\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00d\r\xa6\x01\x00\x00\xab\x01\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00e\x01d\x0e\x84\x00\x02\x00e\te\ne\x03\xa6\x02\x00\x00\xab\x02\x00\x00\x00\x00\x00\x00\x00\x00\xa6\x02\x00\x00\xab\x02\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00e\x04d\x0f\xa6\x01\x00\x00\xab\x01\x00\x00\x00\x00\x00\x00\x00\x00k\x02\x00\x00\x00\x00g\x03Z\x0b\x02\x00e\x0ce\x0b\xa6\x01\x00\x00\xab\x01\x00\x00\x00\x00\x00\x00\x00\x00s\x16\x02\x00e\rd\x10\xa6\x01\x00\x00\xab\x01\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x02\x00e\x0ed\x11\xa6\x01\x00\x00\xab\x01\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00d\x01Z\x0fe\x03D\x00]$Z\x10d\x12\x02\x00e\ne\x10\xa6\x01\x00\x00\xab\x01\x00\x00\x00\x00\x00\x00\x00\x00z\n\x00\x00d\x13z\x0c\x00\x00Z\x10e\x0fe\x10z\x14\x00\x00Z\x0fe\x0fe\x10d\x11z\x01\x00\x00r\x02d\x14n\x01d\x15z\x10\x00\x00Z\x0f\x8c%\x02\x00e\x04d\x16\xa6\x01\x00\x00\xab\x01\x00\x00\x00\x00\x00\x00\x00\x00e\x0fk\x02\x00\x00\x00\x00r\r\x02\x00e\rd\x17\xa6\x01\x00\x00\xab\x01\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00d\x07S\x00\x02\x00e\rd\x10\xa6\x01\x00\x00\xab\x01\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00d\x07S\x00#\x00\x01\x00\x02\x00e\rd\x18\xa6\x01\x00\x00\xab\x01\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x02\x00e\x0ed\x11\xa6\x01\x00\x00\xab\x01\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00Y\x00d\x07S\x00x\x03Y\x00w\x01)\x19\xa9\x03s\x10\x00\x00\x00\xb7S,?~\xfa\xbe\xa2\x97\xd0\xd5\xd9g\x04\xdcls\x0f\x00\x00\x00\x96\xaf\xd2\xfa\xcc\x97\xe3\x01\xceYQ\xbf\xb9\xc3\x98s\x0f\x00\x00\x00\xd1\xb4\t\x0e\xb7Y\x83\xec\xa7\x04\xec\x95\x8cj\xfc\xe9\x00\x00\x00\x00\xe9\x02\x00\x00\x00\xf3!\x00\x00\x00^\xac\x9eI\x89\xd5\xeb\xfc\xa5\xd5\n$\xd1\xf3\xfb\xf1\x1d\xb8\x1a\x89@>\xd3\xfe]\xc0\x8f5\xf9\x97:\x01\x00\xf3!\x00\x00\x00\x89\x03\xfe\xeaf\x12\xb3\xb2\x05\xe4\xfa\xaa\x95e\xe9\xabK\xd1_UqS+\xe7\xaa\x81\x88x\x9b\xa5\xbd\xf5\x00\xfa\x13Tell me your flag: \xe9\x03\x00\x00\x00N\xe9\x04\x00\x00\x00\xda\x03big\xe9\xb2\xc4|\x17\xda\x0880309898i\xf0\xff\xff\xff\xda08475869b2b6434ba59b53079e1ea334aae9483bf87e890b7c\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\xf3\x0c\x00\x00\x00\x97\x00|\x00|\x01z\x0c\x00\x00S\x00)\x01N\xa9\x00)\x02\xda\x01x\xda\x01ys\x02\x00\x00\x00 \xfa\x11<frozen plain.py>\xfa\x08<lambda>r\x13\x00\x00\x00\x0b\x00\x00\x00s\n\x00\x00\x00\x80\x00\x98A\xa0\x01\x99E\x80\x00\xf3\x00\x00\x00\x00\xda\x0239\xda\x05Wrong\xe9\x01\x00\x00\x00\xe9\x91\x00\x00\x00\xe9[\x00\x00\x00\xe9\x07\x00\x00\x00\xe9\x08\x00\x00\x00\xda]490113086473394987304775875938824284212507397345393304550549845726940286289777973973840177024\xda\x05Right\xfa\x16Exception occurred QwQ)\x11\xda\x06sha256\xda\x06reduce\xda\x05input\xda\x04flag\xda\x03int\xda\nfrom_bytes\xda\x06encode\xda\thexdigest\xda\x08endswith\xda\x03map\xda\x03ord\xda\x07group_1\xda\x03all\xda\x05print\xda\x04exit\xda\x03acc\xda\x01ir\x0f\x00\x00\x00r\x14\x00\x00\x00r\x12\x00\x00\x00\xfa\x08<module>r0\x00\x00\x00\x01\x00\x00\x00s\xf4\x01\x00\x00\xf0\x03\x01\x01\x01\xd8\x00\x1a\xd0\x00\x1a\xd0\x00\x1a\xd0\x00\x1a\xd4\x00\x1a\xd0\x00\x1a\xd4\x00\x1a\xd0\x00\x1a\xd1\x00\x1a\xd4\x00\x1a\xd1\x00\x1a\xd0\x00\x1a\xd8\x00\x1c\xf0\x03\x00\x01\x1b\xd0\x00\x1a\xd0\x00\x1a\xd4\x00\x1a\xd8\x00\x1c\xd4\x00\x1c\xd0\x00\x1c\xd1\x00\x1c\xd4\x00\x1c\xd1\x00\x1c\xd0\x00\x1c\xf0\x04\x1b\x01\x0c\xd8\x0b\x10\x885\xd0\x11&\xd1\x0b\'\xd4\x0b\'\x80D\xf0\x06\x00\t\x0c\x8f\x0e\x8a\x0e\x90t\x98A\x98D\x98q\x98D\x94z\xd7\x17(\xd2\x17(\xd1\x17*\xd4\x17*\xa8E\xd1\x082\xd4\x082\xb0Y\xd1\x08>\xc0#\xc0#\xd8\x0c\x1b\xf1\x03\x01C\x01\x1d\xf4\x00\x01C\x01\x1d\xf2\x00\x01\t\x1d\xe0\x08\x0e\x88\x06\x88t\x90C\x90D\x90D\x8cz\xd7\x0f \xd2\x0f \xd1\x0f"\xd4\x0f"\xd1\x08#\xd4\x08#\xd7\x08-\xd2\x08-\xd1\x08/\xd4\x08/\xd7\x088\xd2\x088\xb8\x1f\xd1\x08I\xd4\x08I\xd8\x08\x0e\x88\x06\xd0\x0f!\xd0\x0f!\xa03\xa03\xa0s\xa8D\xa1>\xa4>\xd1\x082\xd4\x082\xb0c\xb0c\xb8/\xd16J\xd46J\xd2\x08J\xf0\t\x05\x0f\x06\x80G\xf0\x0e\x00\x0c\x0f\x883\x88w\x89<\x8c<\xf0\x00\x02\x05\x10\xd8\x08\r\x88\x05\x88g\x89\x0e\x8c\x0e\x88\x0e\xd8\x08\x0c\x88\x04\x88Q\x89\x07\x8c\x07\x88\x07\xe0\n\x0b\x80C\xd8\r\x11\xf0\x00\x03\x05$\xf0\x00\x03\x05$\x88\x01\xd8\r\x10\x903\x903\x90q\x916\x946\x89\\\x98T\xd1\x0c!\x88\x01\xd8\x08\x0b\x88q\x89\x08\x88\x03\xd8\x08\x0b\x90a\x98!\x91e\xd0\x11"\x90\x11\x90\x11\xa0\x11\xd1\x08#\x88\x03\x88\x03\xe0\x07\n\x80s\x88?\xd1\x07\x1b\xd4\x07\x1b\x98s\xd2\x07"\xd0\x07"\xd8\x08\r\x88\x05\x88g\x89\x0e\x8c\x0e\x88\x0e\x88\x0e\x88\x0e\xe0\x08\r\x88\x05\x88g\x89\x0e\x8c\x0e\x88\x0e\x88\x0e\x88\x0e\xf8\xf0\x04\x02\x01\x0c\xd8\x04\t\x80E\xd0\n"\xd1\x04#\xd4\x04#\xd0\x04#\xd8\x04\x08\x80D\x88\x11\x81G\x84G\x80G\x80G\x80G\x80G\xf8\xf8\xf8s\x12\x00\x00\x00\xb6D\x1dE"\x00\xc5\x15\x0bE"\x00\xc5"\x18E=\x03' a = marshal.loads(data[0x7e ::]) dis.dis(a)
然后恢复逻辑,编写解密脚本
实测用z3解只需要解最后的和校验即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 from z3 import *from functools import reducedef solve_for_length (length ): s = Solver() var = [BitVec(f'flag_{i} ' , 8 ) for i in range (length)] s.add(var[0 ] == ord ('L' )) s.add(var[1 ] == ord ('I' )) s.add(var[2 ] == ord ('L' )) s.add(var[3 ] == ord ('C' )) s.add(var[4 ] == ord ('T' )) s.add(var[5 ] == ord ('F' )) s.add(var[6 ] == ord ('{' )) s.add(var[length-1 ] == ord ('}' )) for char in var: s.add(And(char >= 32 , char <= 126 )) for char in var: i = (BitVecVal(145 , 8 ) - char) ^ BitVecVal(91 , 8 ) acc1 = acc | ZeroExt(acc.size() - i.size(), i) shift_amount = If((i & 1 ) == 1 , BitVecVal(7 , 1024 ), BitVecVal(8 , 1024 )) acc = acc1 << shift_amount s.add(acc == BitVecVal(490113086473394987304775875938824284212507397345393304550549845726940286289777973973840177024 , 1024 )) flag = [] while s.check() == sat: m = s.model() flag.append('' .join([chr (m[var[i]].as_long()) for i in range (length)])) block = [] for i in range (length): block.append(m[var[i]]!= var[i]) s.add(Or(block)) print (flag) if len (flag) > 0 else None for i in range (32 , 48 ): solve_for_length(i)