traditional
analysis
附件是一个无壳elf64和一个flag.enc文件,猜测是要对flag.enc文件进行解密。
main函数有一个call cs:off_564C6050EB00
,猜测是rust、nim之类的语言,通过搜索字符串发现有.rs
可以判断是rust的程序。
直接进入到sub_564C604BFA40
分析,发现这个函数汇编层面比较复杂,F5也不是很清晰。
在Linux上尝试运行elf文件:
发现触发了rust的panic,其中'We lost the flag!: Os { code: 2, kind: NotFound, message: "No such file or directory" }'
引起了我们的注意,应该是程序在读取文件时发现没有找到flag文件。
我们重新在ida搜索字符串,发现了flag.txt,由此可以推断:程序读取flag.txt,将其加密,然后将加密结果存入flag.enc。另外使用findcrypt发现程序里面有base64 table。
接下来就是动态调试,在sub_564C604BFA40
开头下好断点,在开始之前我还在程序同级目录下创建了flag.txt文件,写入了helloworld123321
。
此处在flag.txt文件不存在时会跳转到loc_555870DE126D
,也就是文件不存在的情况。
此处执行完call cs:off_555870E2FF90
后,会发现rsp+148h+flag_txt_data
存储了文件内容的指针,即helloworld123321
,说明该函数负责读取文件。
另外,call b64encode_564C604C19A0
执行完之后在rsp+148h+src
里发现了helloworld123321
base64编码后的字符串aGVsbG93b3JsZDEyMzMyMTAw
。
call cs:memcpy_ptr
是将This is the flag:
和aGVsbG93b3JsZDEyMzMyMTAw
进行拼接,
接下来还将 Just decode it :P
拼接到新字符串末尾,并将整体字符串进行逆序。
得到了字符串This is the flag: aGVsbG93b3JsZDEyMzMyMTAw Just decode it :P
,逆序后就是P: ti edoced tsuJ wATMyMzMyEDZsJ3b39GbsVGa :galf eht si sihT
。
接下来是一个循环,对字符串的每一个字符进行依次遍历,并根据各种情况对字符进行计算,将计算结果组成新的字符串。
大致的计算方法是:
1 | ' ' -> '/' |
循环结束后,就是本题思路最有意思的地方了,程序将上面循环计算得到的结果作为base64解码的输入,并将解码的结果写入flag.enc文件中。
script
1 | import base64 |
因为时间匆忙,这个脚本写的不是很好,最后需要自己手动补一个}
。
Figole
analysis
一个apk文件,直接在手机上安装可以看到就是一个输入并检测。
使用jadx打开。
通过manifest文件发现入口在com.example.shctf.DActivity
,手机点击check按钮之后会执行m210lambda$onCreate$0$comexampleshctfDActivity
,另外secret、key通过l1、l2两个方法计算得到。
我们先看l1方法,cn通过base64解码得到,com.example.shctfdex.UT
是很明显的java类,s是app的timesnewroman.ttf文件的路径,可以在jadx的资源文件/assets下发现。try代码块可以发现是利用java反射获取并调用com.example.shctfdex.UT
的gf
方法。
l2方法同理。
1 | public String l1(Context context) { |
我们把timesnewroman.ttf
用jadx导出,可以发现是一个dex文件。那么我们直接用jadx打开:
com.example.shctfdex.UT
的gf
方法调用了gd
方法,从数据库中读取数据,也就是apk里面的calibri.ttf
文件。
1 | public String gd() { |
读取数据库的方法如下:(脑子抽了把calibri.ttf
重命名成calibri.ttf.dex
,可以忽略)
通过以上方法分析l1、l2可以找到secret和key的值,接下来分析加密部分。
m210lambda$onCreate$0$comexampleshctfDActivity
里的result通过l3
计算得到,里面调用了com.example.shctfdex.DX
的ech
方法。另外,l3的最后一个参数需要cdec
方法计算得到,就是一个xor操作。
1 | public String ech(String message, String s) { |
可以看出就是AES加密,Mode为CBC,aes key和aes iv需要通过getK
计算得到。
在动手之前先整理下程序的流程:
- secret 通过 l1 计算得到
- key 通过 l2 计算得到
- 将 secret、key传递给
m210lambda$onCreate$0$comexampleshctfDActivity
- flag 就是我们的输入
- result 通过 l3 计算得到,将flag和
cdec(q)
以参数传递,这里的q就是key- cdec函数的参数是一个hexstring,将参数转换成整数数组,并将每一个元素进行异或加密
- l3 调用了 ech 方法,AES的Key和IV需要getK方法进行计算
- 将 y (也就是secret)与result进行比较
script
1 | import base64 |