R呦喂 发表于 2020-10-25 17:27:40

CTF中逆向的一些经验(转载)

0x00 判断文件类型我们拿到的题目一般是一个二进制可执行文件,而其中的大部分不是Windows平台下的PE文件就是Linux平台下的ELF文件。不管题目中所给文件带有什么扩展名,我们都应该亲自去检查文件头,使用任意文本编辑工具打开这个二进制文件,如果在开头看到MZ字样,那基本上可以确定这是一个Win系统下的可执行文件,相应的如果看到ELF字样即可基本断定这是一个运行于Linux系统下的可执行文件,扩展名为exe而实质上是一个ELF文件,这种情况在以往的CTF比赛中也是出现过的。
0x01 查壳与脱壳由于近年来CTF比赛中带壳的逆向题出现频率稍有增加,在静态分析之前,进行查壳是非常有必要的,常用的工具有PEID等,进行查壳后,如果是简单且常见的壳如UPX等,那么直接可以使用工具完成脱壳,如果一时半会找不到可用的工具,也可以尝试手工脱壳,例如ASPack就能够采用ESP定律来脱除。如果是侧重考察脱壳的题,一般程序本身就比较简单了,可以这样说,这类题如果能成功脱壳,基本上也算是做出来了。当然,脱壳并不能解决所有问题,之前有CTF比赛中甚至出现了VMP的题目,对于这种情况,还是建议使用调试器去动态调试,毕竟在逆向工程中太依赖IDA的F5功能也是不行的,还是应该锻炼自己的汇编指令阅读能力。如果是VMP比较新的版本,可能还需要使用Sharp OD等插件来隐藏调试行为。
0x02 静态分析一般是直接将二进制文件拖入IDA进行分析,在这个过程中,可以关注一下是否有符号库路径的提示出现,如果有这种情况,说明程序在编译阶段并没有清除相应的符号信息,我们或许能够从符号库路径的命名中得知一些关于本题的重要信息,大多数时候,静态分析完成后,我们会直接来到程序start处,直接F5,向下找即可来到main函数,直接查看反编译出来的C伪码,然而有时候IDA会出现识别不了函数的情况,比如说分析到某一段代码,视图就从C伪码变为汇编指令视图了,这时候可以尝试手工地在这段汇编指令中识别出函数,并且使用IDA的创建函数功能,这样一来就能够继续查看C伪码,提高我们的做题效率
如何从一段汇编代码中把函数找出来?首先得找到函数头部,很多函数的头部看起来会如下所示:push    ebpmov   ebp, esp先将调用者的堆栈的基址(ebp)入栈,以保存之前任务的信息。然后将调用者的栈顶指针(esp)的值赋给ebp,作为新的基址(即被调用者的栈底)。然后我们继续寻找函数尾部pop ebpret需要注意的是,如果函数不只有一条路径返回值,我们还得确保函数尾部下方的跳转全都朝下,上方的跳转全部朝上
要是在IDA中遇到Sp analysis failed怎么办?这种情况,有时候是由于某些指令的干扰导致IDA分析出来的栈平衡被破坏所致,会导致IDA生成C伪码失败我们需要手动地调整栈平衡,在IDA中依次点击Options-General,勾选Stack pointer函数刚开始的指令看起来如下图所示:函数结束前的指令如下图:可以看到每一条指令的前面增加了一个数字,这个数字即指示栈顶指针(SP),在调用带参数的Call后,push和pop或者进行抬栈、清栈后栈顶指针才会改变,上图的mov esp,ebp后SP值显然不合理,应该使用Alt+K快捷键进行调整,调整后如下图所示:这时再使用F5,IDA已经能够生产正确的C伪码了
0x03一些常见题型1. 方程组(HCTF2017逆向第一题)对输入做了异或

本题中三个方程的关键代码


爆破解法:def solve(idx1,idx2,idx3,idx4):
    for x in range(0,255):
      if(((x ^ idx1 )& idx2 )>> idx3) | (((x ^ idx1) << idx3 )& idx2) == idx4:
            print(chr(x^0x76), end='')
key1 =
for ele in key1:
    solve(0xAD,0xAA,0x1,ele)
key2 =
for ele in key2:
    solve(0xbe,0xcc,0x2,ele)
key3=
for ele in key3:
solve(0xef,0xf0,0x4,ele)Z3约束器解法:from z3 import *
def z3_solve(idx1,idx2,idx3,idx4):
    solver = Solver()
    x = BitVec('x', 32)
    solver.add((((x ^ idx1 )& idx2 )>> idx3) | (((x ^ idx1) << idx3 )& idx2) == idx4)
    if solver.check() == sat:
      print(chr(solver.model().as_long() ^ 0x76), end='')
key1 =
for ele in key1:
    z3_solve(0xAD,0xAA,0x1,ele)
key2 =
for ele in key2:
    z3_solve(0xbe,0xcc,0x2,ele)
key3=
for ele in key3:
z3_solve(0xef,0xf0,0x4,ele)Z3是一款由微软开发的约束求解器,其代码目前托管在https://github.com/Z3Prover/z3如果题目的方程比较简单,使用爆破当然简单粗暴,方便快捷;但当题目涉及到多元方程或者方程组时,使用Z3求解是比较高效率的,强烈推荐。
Tags: C伪码、IDA、peid、SP值、UPX、VMP、Z3约束器、代码、关键代码、判断文件类型、工具、效率、查壳、栈平衡、栈顶指针、汇编、汇编指令、爆破解法、符号信息、脱壳、视图、调试行为、静态分析
稿件转自:安全脉搏   作者:China H.L.B

roger 发表于 2020-10-27 10:01:09

帖子格式堪忧!

quit1234567 发表于 2021-5-26 17:11:17

非常好的帖子,学习了

xiaoweiwb 发表于 2021-10-28 06:39:20

谢谢分享谢谢分享

Arsenal 发表于 2021-11-5 10:08:38

太强了,赞赞赞!!!!!

xiaoweiwb 发表于 2021-12-23 08:14:26

谢谢分享谢谢分享
页: [1]
查看完整版本: CTF中逆向的一些经验(转载)