刷到nssctf学到的新东西,记录一下经验。

题目前面的附件分析和代码定位都挺简单。

这里这个程序使用了程序代码优化,所以进来之后没有main函数,但是进来就是start函数,也很容易找到主函数(这里的main是我自己把ida的伪代码改名字的结果)

主函数里面的东西也很容易分析出逻辑,为了防止伪代码没有完整翻译汇编代码,我们进入到汇编代码里面再去看一眼。

大致看一眼就可以看到(也算是为了降低难度的提示,没有藏很深),可以看到有个“yes”字符串,通过判断r12与r13寄存器的值来判断是否进入到这一段代码,但是可以看到没有对r12有任何的操作,猜测这里还是藏代码了(前车经验)。

进入到这一段代码处,可以看到把flag的大概格式给出了,我们通过提示构造一个测试字符串到相关的位置,这里我构造的是flag{aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa3861},通过动调运行到
sub_404BF5(),我们会发现,每次动调步过这个函数之后,这个程序就马上退出了,这里应该是利用了程序的一些机制问题,这时候我还不知道,也实在没有思路去处理这个问题了。于是去搜索之后我知道了相关的知识点。
https://military-axe.github.io/blog/2023-06-11-2023-ciscn-ezbytes-write-up/
我是通过这个人的文章学习的
这个程序藏代码的方法是利用c++的异常处理机制,将相关代码藏在dwarf字节码里面,然后利用异常处理机制去执行这段隐藏的代码,因为本质上利用的是程序的异常处理机制,所以运行过这一部分的时候是会直接程序报错退出的。
程序的dwarf字节码的格式叫做.ez_frame,可以利用指令readelf -Wwf filename来读取异常处理相关的代码。

然后pc对应的值就是ida中相关函数的入口地址,通过在ida中查找相关的函数入口地址我们可以快速定位到某一些可能的用异常处理代码隐藏的正确代码。


然后丢给ai或者查找dwarf相关的代码语法,然后分析出主要的逻辑写一个代码然后组合在一起就是我们争取的flag了。
r12=(2616514329260088143^1237891274917891239)-1892739
r13=(8502251781212277489^1209847170981118947)-8971237
r14=(2451795628338718684^1098791727398412397)-1512312
r15=(8722213363631027234^1890878197237214971)-9123704print(b'flag{'+r12.to_bytes(8,'little')+r13.to_bytes(8,'little')+r14.to_bytes(8,'little')+r15.to_bytes(8,'little')+b'3861}')
#flag{e609efb5-e70e-4e94-ac69-ac31d96c3861}