逆向方法论
年初 SECCON CTF 22 final 上第二天出了一道 KoH 题:给定 binary 要求写出源码,判定标准为编译后与目标 binary 的 diff,越小则分数越高。每一小时更换一门语言,从 c,c++ 到 d, go, web assembly 等等。我读完题目就放弃了因为我知道我的逆向水平就是依托答辩,而队友也不负众望基本一整天都在爆杀全场。我在崇拜之余不由得思考起一个问题,逆向应该怎么学?
这是一个困扰已久的问题,我在本科时期曾想过在 CTF 赛事中参与逆向题,但基本不得要领。我也直球问过别人:逆向该怎么学?
本科某同届逆向大哥(与某学长):多刷题就完事了
L3H Sec 某逆向大哥:多看就完事了
我能理解他们想表达什么,但这些回答显然对我毫无帮助((
what I want
我仔细考虑了一下逆向能做的事,比如写外挂等,我发现我并不是很喜欢逆向。那我想要的是什么呢?明确目标以后我承认有点标题党了,毕竟对于更喜欢漏洞利用、漏洞分析的我来说,我的“逆向”目标其实相当可笑:如何能在反编译工具中看懂程序?这里的程序基本没有复杂逻辑,也不需要选手的逆向技巧,而且程序一般也是带符号的。
比如,一个 c++ binary 放进 IDA 里我可能完全看不懂程序逻辑,各种奇奇怪怪的东西让人眼花缭乱,一个栈溢出我都可能发现不了。
do shit now
那么我应该怎么做呢?我试图总结出一套不值一提的逆向方法论,一个我需要去 check 的 list,这样在接触到一门新语言时对着 list 一条一条看,这样至少可以避免遗漏关键点,也能让我有一种“哎呀我把这个 list 上的东西都弄完那这个 blabla 语言的逆向我就会了”的感觉。最主要的是,在方法论的运用过程中这个 list 会被不断扩充、完善,进而更好地学习下一门语言的逆向。
学习的核心思路是:逆逆向,即正向。这种学习方法我还没想到过,在网上闲逛时受这篇文章启发才恍然大悟,决定造一个让自己学习体验更佳的方法论。学习逆向的过程中,不是像以前一样在 IDA 中苦苦尝试从 binary 到 source code 建立映射,而却是去从 source code 到 binary 建立映射。
对于每一门语言,把握以下这些关键点,尝试去自己写源码、编译,放进 IDA 里看。
- main 函数前发生了什么?
- main 函数
- 各种数据类型怎么存的?
- int, float, string, array
- global, local
- 类型转换?
- 更多数据类型?
- vec
- set
- 控制流?
- 库函数怎么调用的?
- 打印函数?输入函数?
- .plt? .got?
- …
- 自己写的函数怎么调用的?
- 分支,循环?
- 库函数怎么调用的?
- …
- 各种数据类型怎么存的?
- 该语言的其他特性
- …
或者可以说,对于新造的一门语言,你要去为它写一个 doc,你会去把握哪些关键点。原来学习逆向的最佳方式,反而是正向?