如题
VNCTF
BabyMaze
pyc加花。基本思路跟exe文件去花指令差不多,一般是各种跳来跳去的指令之间夹一些没用的指令,扰乱反编译器分析。直接dis看字节码,然后去修十六进制文件。
这个题可以很明显看出来,0处的指令就是跳转到4,而4处的指令是跳转到2,2处的指令是跳转到6,6处的指令就是正常的创建迷宫的指令了,所以把前三句patch掉。
在十六进制编辑器里把这三句删掉,然后改字节码长度co_code,减去6(因为上面三条指令是6个字节)。
pyc文件格式
- 开始4字节magic int,标识pyc版本信息
- 4字节int,表示时间戳
- 序列化了的PyCodeObject
- 此后是opcode,0x73开头,之后4字节表示opcode所占字节
- 此后,1字节表示存储类型,之后4字节表示该类型所占空间。
如果实在不知道co_code在哪里,可以用
hex(len(code.co_code))
看一下指令长度,然后在十六进制编辑器前几行里找这个值。
但是这个题很奇怪,为什么时间戳的地方都是0……
然后uncompyle6,看源码走迷宫就好了。
时空飞行
官方wp都有脚本,我就不抄过来了(逃
说一下中间那一步为什么要深搜:
因为那个方程是有很多组解的,直接逆向写脚本的话只能得到1组解,而z3也只能得到少数几组解,只有深搜能保证得到所有解。
此后对所有解中进行下一步逆向验证,符合条件的就正确,也就是在所有解里爆破了。
DASCTF
easyre
脚本不贴了,都是抄IDA代码,懒得改那一坨很丑的代码了
简单说一下我遇到的问题:
1.我刚开始手动脱壳的,虽然跑不了,但是IDA可以反编译出来。后来去网上搜了搜,大部分都是脱壳机……我下了好几个脱壳机,都说没有ASPack,很迷。有没有带师有什么很nb的脱壳机,请务必告诉我
2.加密是用的一个魔改的RC4,代码逻辑是什么不管,直接复制IDA代码,简单改一下然后跑。按道理来讲这种RC4不应该管他的逻辑,直接输入然后动调取值来异或,但是我手动脱的壳可能有些问题,(看别人说要用一个工具修复导入表,但是我摆弄了半天那个程序,没搞懂怎么玩的),跑不了所以没法动调。OD调试也8太会,输入之后直接退出了,麻。
3.刚开始跑出来是乱码,因为我最开始改的python,都用的range函数,改成C为了方便都用了while循环,结果我把计数器自增的代码写到最前面了,我是什么憨批。
3.改完之后跑是能跑出来了,但是中间有几个字符是乱码。虽然已经半夜两点多,但是不知道原因我是真!的!难!受!啊!!!网上找了份WP,两个代码一起调,发现是数据类型的锅。RC4里s盒正常人都用的unsigned char类型,我写脚本也顺手写成无符号字符型了,但是由于这个题是魔改,对s盒运算的时候有一些奇怪的运算,要用int才能保证运算结果的正确性,unsigned char会溢出而损失部分运算结果……我!#%^@$@^*#
HayyimCTF
ezrev
异或值不知道,后面有解base64,爆破一下
1 | enc=[0x73, 0x5A, 0x5C, 0x78, 0x76, 0x55, 0x48, 0x25, 0x76, 0x55, 0x7A, 0x7A, 0x70, 0x7F, 0x66, 0x68, 0x4A, 0x20, 0x48,0x64, 0x71, 0x7E, 0x2B, 0x7E, 0x70, 0x7F, 0x62, 0x64, 0x77,0x45, 0x7E, 0x67, 0x48, 0x23, 0x2B, 0x7D, 0x71, 0x20, 0x5C,0x22, 0x48, 0x7B, 0x54, 0x2B] |
hgame
upx0
没壳,被骗了
crc16,打表搜就行。
1 | crc=[] |
upx1
还能改magic,这波属实长见识了(什
解密都一样,就8说了,之后专门写一篇关于壳的(挖坑++
Answer’s Windows
好大的文件……关键字符串background-image: url(:/new/prefix1/C:/Users/Answer/Desktop/right.png);
定位到核心逻辑。往上翻可以翻到一个像密文的东东:;'>B<76\\=82@-8.@=T\"@-7ZU:8*F=X2J<G>@=W^@-8.@9D2T:49U@1aa
1 | if ( v21 != 56 |
看判断是v11,往上看,v11来源于v20,v20又经过sub_140001F90(v10, v20);
,进去这个函数康,康到base64加密的特征,码表是qword_140E82000
。康码表的交叉引用,有两个函数引用,sub_140001000
和sub_140001A50
。
看这两个函数的时候IDA有时候栈指针有问题……
按alt+k,自己算一下栈指针调一调就好了。
后者的核心逻辑如下:
1 | if ( !IsDebuggerPresent() ) |
分析半天,感觉逻辑好复杂,没分析明白……直接上手动调。
(额……无意间回来看到这里,突然发现他码表不就是ASCII码从33打到97吗……我当时到底是哪里没看明白……)
if里有反调,下断到这一句,手动改ZF标志位跳过反调,然后调完for循环去康qword_140E82000
,拿到码表:
1 | !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`a |
注意码表写到字符串里要转义一下。
直接去translate的话会报错:码表长度是65,与正常码表不一致……
这是因为最后的a是相当于原码表里的等号,是在最后padding用的,不属于码表范围。
把码表里最后的a删掉,密文里最后padding的a改成等号,写脚本解base:
1 | import base64 |
creakme3
这是PCC架构的文件,和以往的arm,x86有所不同,由PowerPC编译,所以IDA不能分析,linux不能运行
此题有提示,使用Ghidra分析便可得知主体逻辑
不过我用IDA还是能分析出来……
主逻辑:
1 | int __cdecl main(int argc, const char **argv, const char **envp) |
在我的wsl上跑不起来……数组a里是一堆数据,两个一组,第一个1字节,第二个2字节。
看结果是直接输出偶数处的字符,而且前面的欢迎语也说了会直接给flag,应该就是那个随机数满足一定条件就会给……
看for里的逻辑,是要奇数处的数字满足2j处大于等于2j-1,所以后面的2字节数字应该是排序。对2字节数字排序然后按顺序输出前面的1字节数据,那么写个脚本排序输出。不会写用含两个元素的元组排序呜呜呜
1 | enc=[0x30, 0x4E7D, 0x30, 0x67BD, 0x30, 0x7A48, 0x30, 0x82A2, 0x30, 0x933E, 0x31, 0x9C18, 0x32, 0x5AFF, 0x32, 0x6CD7, 0x32, 0xA6CA, 0x32, 0xBD79, 0x32, 0xCEBD, 0x33, 0x324A, 0x33, 0x3292, 0x33, 0x3905, 0x33, 0x4291, 0x33, 0x5ADE, 0x33 |
康题解说是猴子排序。搜了一下感觉这种排序好神必……不知道是谁想出来的哈哈哈哈
关于本文
本文作者 云之君, 许可由 CC BY-NC 4.0.