NewStarCTF2023_Week3_WP
Reverse
花
去花
按c强制生成代码
第二处
第三处
在0x00401500处按P生成函数
主函数,RC4加密,key是WOWOWOWWOWOWOW
exp
1 | from Crypto.Cipher import ARC4 |
flag
flag{You!FlowerMaster!YouPassTheThirdPZGALAXYlevel!}
STL
C++逆向,大致能读懂相关函数
直接爆破,脚本跑得有点慢,大致20min能出结果
exp
1 | from Crypto.Util.number import long_to_bytes |
flag
flag{b53fc431-eb1f-89da-5bd5-2e1184728a5das}
EzDLL
主程序中分析
key是
看看dll中的encrypt,是魔改过的xtea,注意魔改的地方
然后写脚本解,结果发现已知解不出来
倒回去重新分析主程序发现在TLS中加入了反调试,并且修改了xtea的key
计算一下真正的key是[5,20,13,14]
刚刚臭不可闻的key瞬间就浪漫起来了
exp
1 |
|
flag
flag{Ca1l_y0u_3ven_1f_w3_@r3_f@r_Apart!}
pyexe
直接pyinstxtractor,得到的文件是加密过的。注意使用和源文件同版本python,不然会出现如下skipping pyz extraction的问题
在反编译python生成可执行文件exe时,引用的类库文件经常遇到使用Crypto模块AES算法加密,解包生成的并不是pyc文件,而是加密的pyc.encrypted文件,它无法查看编译。
第一步,获取Crypto的key,这是打包时由开发者指定的。解包完成后将在根目录形成名为 pyimod00_crypto_key.pyc 的文件,将它转为py文件即可查看key文件。
第二步,编写解密处理的脚本代码
我们先获取key = '00000000new1star'
然后用脚本fix
1 | import glob |
然后uncompyle6 反编译 fakekey.pyc得到源码
1 | # uncompyle6 version 3.9.0 |
首先从 settings import了一个key
看看\PYZ-00.pyz_extracted里面的settings.pyc
源代码不难理解,主要是changefun2,让GPT解释一下
main函数是一个rc4然后异或5
所以整体加密就是rc4加密后异或5,接着pop加密后的flag的第5和-3位,最后base64
我们只需爆破第5位和第-3位字符即可
exp
1 | import base64 |
flag
flag{no_ke1_no_fuN!}
Let’s Go
go逆向,直接用ida7.7
先看main_init,iv异或了0x32
接着看main_main
动调看看iv是什么
iv是和key一样,但是记得异或0x32
exp
1 | from Crypto.Cipher import AES |
flag
flag{It's_time_to_Go!!!Let's_Go}
ez_chal_1
主函数分析如下
再看看sub_401170,明显xtea,多了个异或
动调获取key
exp
1 |
|
flag
flag{Let's_Dr1nk_A_Cup_Of_Te4!!}
Andronative
调用了native层的encode,传入输入和deadbeef
解包之后查看librunfaraway.so
的encode函数
先看看最后的check,最后的结果经过test后与
6DTNDRc1uJyyyd/GrT+bW3NNIoXzPQyK722kicTTFTTySTzyRE+BWdXnW6zF7UY9iUZK27QN
比较
查看test,应该是base64
往前看,对v22赋完值(0~0xff)后,进行了_ROL2_移位
_ROL2_是ida内置函数,在ida/plugins/defs.h中可以查看到定义
再看看_ROL_函数
有两个参数:(value, int count)
第一个参数为左移的数,第二个参数为左移的位数。
如果第二个参数值为负数,则实际上为循环右移 -count位。
该函数的实现细节为:
先得到value的位数,然后count对位数取模。
如果count值大于0,则先右移-count取模的结果,然后在左移取模的结果,得到的两个数相或,即为循环左移的结果。
如果count值小于0,先左移在右移即可。
举例来说: value = 0110, count = 6
value为4位数, 6 % 4 = 2,
0110先右移4-2=2位,得到0001,然后在左移2位,得到1000,0001 | 1000结果为1001,即循环左移结果为1001。
知道ROL2的含义后只需将v22的数据用lazyida dump出来(其实就是0-255)
然后自己写个c模拟一下,可以得到所需的box表
1 |
|
之后的加密逻辑其实就是和传进来的key异或,然后执行ROL1移位
ROL1根据以上分析其实就等效于
1 | uint16_t __ROL1__(uint16_t value, int count) { |
据此可以写出exp
exp
1 | import base64 |
flag
flag{I_hate_le333ekk_asd213sadlgajaieo2sa_this_is_s0?}
除此之外还可以考虑动态调试来获取box
先配置一下ida调试所需要的android_server,先打开模拟器
然后在命令行中依次输入以下命令
1 | adb devices |
再新开一个命令行,执行adb forward tcp:23946 tcp:23946
转发端口
然后打开DDMS
(没有的的请自行安装android sdk)
以debug模式启动进程
1 | adb shell am start -D -n com.chick.runfaraway/com.chick.runfaraway.MainActivity #包名/包名.入口Activity |
提示Waiting for debugger
ida 打开选择Debugger->Attach->Remote ARM Linux/Android debugger
sebug option设置和端口设置
找到要attach的进程进行attach
返回DDMS,查看进程端口
恢复java层运行,注意8626是DDMS里查询到的端口号。
1 | jdb -connect com.sun.jdi.SocketAttach:hostname=127.0.0.1,port=8626 |
此时就可以开始动态调试了,具体调试过程就不写了
2hard2u
用 JEB 打开(JEB自带反混淆,用JADX打开无法去除BlackObfuscator混淆)
先看看 MainActivity 的 oncreat函数
可以看到 用密钥friedchick
对输入进行 encrypt
然后对结果进行encode,encode是调用了native层
然后观察一下 encrypt 函数,有KSA,RPGA,可以确定是RC4
接下来分析 native 层
解包分析 libit2hard2u.so
可以看到是一个 Tea
那么我们先解Tea
1 |
|
端序问题转换一下,提取出数据0x6,0x1,0xc3,0x88,0xc3,0xac,0xc2,0xbd,0xc2,0xb8,0xc2,0xae,0xc2,0xa2,0x13,0xc3,0xa2,0xc3,0xbc,0xc3,0xab,0x7,0x28,0xc3,0x8f,0x43,0xc2,0x87,0xc2,0x94,0xc3,0x9d,0x54,0x6c,0xc2,0x95,0xc3,0x85,0xc3,0xa1,0x53,0xc2,0x86,0x5d,0x78,0xc3,0xbc,0xc2
因为在java字符串传递到jni接口时,采用了GetStringUtfChars,这个函数会自动采用utf-8的解码格式。
我们需要将提取到的utf-8编码的数据转化为对应的Unicode编码
UTF-8编码,是Unicode的一种可变长度字符编码,是Unicode的一种实现方式,又称万国码;UTF8使用1~4字节为每个字符编码,相对于Unicode 固定的四字节长度,更节省存储空间。UTF-8字节长度与Unicode 码点对应关系如下:
一字节(0x00-0x7F)-> U+00~U+7F
二字节(0xC280-0xDFBF)-> U+80~U+7FF
三字节(0xE0A080-0xEFBFBF)-> U+800~U+FFFF
四字节(0xF0908080-0xF48FBFBF)-> U+10000~U+10FFFF
字符U+0000到U+007F(ASCII)被编码为字节0×00到0x7F(ASCIⅡ兼容)。这意味着只包含7位ASCIl字符的文件在ASCIⅡ和UTF-8两种编码方式下是一样的。
所有大于0x007F的字符被编码为一个有多个字节的串,每个字节都有标记位集,常用汉字基本上都被编码成三字节。
1 | data = [0x6,0x1,0xc3,0x88,0xc3,0xac,0xc2,0xbd,0xc2,0xb8,0xc2,0xae,0xc2,0xa2,0x13,0xc3,0xa2,0xc3,0xbc,0xc3,0xab,0x7,0x28,0xc3,0x8f,0x43,0xc2,0x87,0xc2,0x94,0xc3,0x9d,0x54,0x6c,0xc2,0x95,0xc3,0x85,0xc3,0xa1,0x53,0xc2,0x86,0x5d,0x78,0xc3,0xbc,0xc2] |
由于出题人代码写胡了,少了最后几位[168,56,93]
,正确的转换结果应该为[6, 1, 200, 236, 189, 184, 174, 162, 19, 226, 252, 235, 7, 40, 207, 67, 135, 148, 221, 84, 108, 149, 197, 225, 83, 134, 93, 120, 252, 168, 56, 93]
然后解一下RC4
exp
1 | from Crypto.Cipher import ARC4 |
flag
flag{G0ddamn700h@rd_f0ru_n0w!!!}