热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

fcd——一款优秀的反编译利器

fcd中一个备受吹捧的功能就是它可以在输出类C代码之前,对代码进行简化处理。这对于逆向工程师而言,绝对是一个福音,因为当逆向工程师在对程序进行混淆处理时,它可以提供非常大的帮助。在2015年网络安全意

https://img.php1.cn/3cd4a/1eebe/cd5/99b88427bc9ce0dc.webp

fcd中一个备受吹捧的功能就是它可以在输出类C代码之前,对代码进行简化处理。这对于逆向工程师而言,绝对是一个福音,因为当逆向工程师在对程序进行混淆处理时,它可以提供非常大的帮助。在2015年网络安全意识周(CSAW)的CTF大赛上,Wyvern挑战赛中所发生的事情就是个很好的例子。

在资格赛和最后一轮的终极赛中,都曾出现过500分的高分,这也是CSAW CTF大赛历史上最高的个人挑战赛得分了。我们将在这篇文章中主要对资格赛第一轮-Wyvern挑战赛进行讲解。广大读者们可以查看2015年CSAW CTF挑战赛的赛事报道来获取更多具体的信息。

下载csaw-wyvern

启动程序之后,我们将会看到以下信息:

http://p6.qhimg.com/t01b5da19085df6c2f6.png

当然了,在wyvern中运行strings命令并不会给我们提供任何有帮助的输出信息。所以从战略角度出发,第二步就是使用一款反汇编工具(例如objdump)来对数据进行处理。但是,这样所得到的处理结果绝对会让你疯掉的。因为在你所得到输出代码之后,你还需要对每一个字符进行检测,而且还有可能发生溢出等问题:

$ objdump -M intel -d csaw-wyvern2
[snip]
00000000004014b0 <_Z15transform_inputSt6vectorIiSaIiEE>:
  4014b0:  55                         push   rbp
  4014b1:  48 89 e5                    mov    rbp,rsp
  4014b4:  53                         push   rbx
  4014b5:  48 83 ec 48           sub    rsp,0x48
[spurious branch code starts here]
  4014b9:  8b 04 25 68 03 61 00  mov    eax,DWORD PTR ds:0x610368
  4014c0:   8b 0c 25 58 05 61 00   mov    ecx,DWORD PTR ds:0x610558
  4014c7:   89 c2                       mov    edx,eax
  4014c9:   81 ea 01 00 00 00      sub    edx,0x1
  4014cf:    0f af c2                imul   eax,edx
  4014d2:  25 01 00 00 00        and    eax,0x1
  4014d7:  3d 00 00 00 00        cmp    eax,0x0
  4014dc:   40 0f 94 c6            sete   sil
  4014e0:  81 f9 0a 00 00 00      cmp    ecx,0xa
  4014e6:  41 0f 9c c0             setl   r8b
  4014ea:   44 08 c6              or     sil,r8b
  4014ed:  40 f6 c6 01            test   sil,0x1
  4014f1:   48 89 7d f0           mov    QWORD PTR [rbp-0x10],rdi
  4014f5:   0f 85 05 00 00 00      jne    401500 <_Z15transform_inputSt6vec
[snip]

在经过了分析和处理之后,我们得到了类似((x * (x – 1)) & 0x1) == 0 || y <10的分析结果。

如果你的计算机中安装有Hex-Rays(一款反汇编利器),那么你将会看到大量复杂的数据,你将很难从这一大堆数据中提取到你所需要的信息。因为其中的每一个数据块是由14个无用的垃圾指令所组成,而其中也并没有多少有用的指令。这就成功隐藏了大量的指令控制流信息。

在资格赛过程中,Ryan Stortz通过推特(@withzombies)表示,他在第一个阶段曾使用了动态分析,而结果是非常可观的。大多数的团队(不包括我的团队)会选择使用因特尔的Pin(一款由因特尔公司研发的动态二进制指令分析工具)来对代码进行分析处理,并找出能够让程序长时间运行的输入信息。但我并不清楚这些团队在第二阶段做过什么。由于fcd无法处理如此之大的程序,所以我不得不手动来对这些代码进行凡混淆处理,直到我能够发现这些代码的实际意义。这些过程听起来会显得单调和乏味,而且即使你没日没夜地对这些数据进行,也不一定能够得到你所期望的结果。

在进行了三个多月的努力之后,我们终于可以加快我们的进程了。虽然Fcd不是最好的反编译工具,但是它还是能够处理好这一较为奇葩的任务的。

以龙制龙

相较于其他的反编译工具而言,fcd的一个主要优点就是用户可以编写Python优化代码,并将其提供给LLVM来对程序代码进行简化处理。LLVM能够利用不变的输出结果来查找代码,而且还能够删除无效的数据,并简化剩余的代码。所以我们只需要向LLVM提供一小段命令,LLVM就能够将剩下繁重的工作完成。所以我们就不需要在去手动处理垃圾代码了,而且LLVM还能够将一些不可预测的代码转变为一些有意义的信息。

在我们的例子中,无论是在哪一个阶段,条件变量都是从数据段中进行加载的,但是这些数据从未被修改过。所以这也就意味着,这些变量值永远等于0。利用Python语言,我们可以将这些信息写入一个优化参数中,并将其提供给fcd来进行处理。

假设你正在进行挑战赛,你首先需要做的就是找出代码中一些有意思的函数。在对数据进行了手动检查或者动态分析之后,你应该就会发现我所指的有意思的函数就是sanitize_input (0x401cc0)和transform_input (0x4014b0),这两个函数能够对输入行数据进行转换和测试,但我们尚不清楚其具体的工作机制。

在本文的例子中,我们将会利用fcd完成以下两件事情:第一,保存可执行文件所对应的LLVM汇编文件(生成这类文件通常需要很长的时间);第二,我们需要使用经过优化处理的fcd参数(我们的自定义参数)来进行操作。由于生成一个编译文件将会消耗大量的时间,如果我们使用自定义参数,那么将会为我们节省大量的时间。

$ fcd -p -n -e 0x4014b0 -e 0x401cc0 wyvern > wyvern.ll

大家可以通过查阅手册来获取有关上述代码中选项的更多信息,其中几个重要选项如下:


  • -p(部分)-这个选项将会告诉fcd,我们只对少数的几个函数感兴趣;


  • -e(入口地址)-指定我们所感兴趣的函数的虚拟地址;


  • -n-这个选项表示我们需要一个LLVM汇编文件。


这一过程将需要一段时间(我的电脑需要20秒处理时间)。在这一点上,Wyvern就毫无可比性了,因为它将需要大约7分钟的处理时间。

接下来,我们需要编写一个Python脚本来传递经过优化的参数设置。

从上图给出的汇编代码中,我们可以看到混淆代码加载了两个值(值为0),我们需要对这两个值进行修改。请放心,LLVM的功能足够强大,它能够处理这些值为0的数据。

在我们的优化脚本中,需要使用到一个passName变量和一个runOnFunction(或者runOnmodule)全局函数。对于那些熟悉LLVM参数结构的人来说,这两个参数并没有什么稀奇的。在我们的实际操作中,我们只需要访问私有函数,所以我们的参数构造基本如下:

from llvm import *
 
passName = "Wyvern cleanup"
 
def runOnFunction(func):
       changed = False
       bb = func.GetFirstBasicBlock()
       while bb != None:
              changed |= _runOnBB(bb)
              bb = bb.GetNextBasicBlock()
       return changed
 
def _runOnBB(bb):
       changed = False
       inst = bb.GetFirstInstruction()
       while inst != None:
              changed |= _runOnInst(inst)             
              inst = inst.GetNextInstruction()
       return changed
 
def _runOnInst(inst):
       if inst.GetInstructionOpcode() != Opcode.Load:
              return False
      
       cAddress = inst.GetOperand(0).IsAConstantExpr()
       if cAddress == None or cAddress.GetConstOpcode() != Opcode.IntToPtr:
              return False
      
       constantInt = cAddress.GetOperand(0).IsAConstantInt()
       if constantInt == None:
              return False
      
       address = constantInt.ConstIntGetZExtValue()
       if address < 0x610318 or address > 0x6105ac: # x and y variables
              return False
      
       zero = inst.TypeOf().ConstInt(0, False)
       inst.ReplaceAllUsesWith(zero)
       return True

当LLVM的封装参数被执行时,runOnFunction函数将会运行。如果参数对函数进行了修改,那么该函数的返回值必须为True。该函数将会对代码中的基本数据块进行处理,并将其传递给_runOnBasicBlock。_runOnBasicBlock会对每一个数据区块的指令进行迭代处理,并将处理后的数据传递给_runOnInst。

舔舐伤口

至少目前为止,我认为fcd强大的功能和出色的性能已经成功地引起了大量相关从业人员的关注。但是,由于别名分析的问题,它并没有提供分析处理后的输出结果。不幸的是,从九十年代初期开始,安全专家普遍认为别名分析是不太可能进行判定的,所以fcd也不太可能去解决这个问题。

据我了解,目前只有一个团队在对fcd进行开发工作,但是在其诞生不到一年的时间内,该项目就能够取得如此之大的成就和进步,这不得不让人对它的未来抱有很大的希望。而且,它几乎将Wyvern打得体无完肤了,这也是一个非常令人兴奋的里程碑时刻。

所以,我决定暂时不去参加比赛,我想进行更多的训练,也许当我觉得自己的水平有了一定的进步时,再去参加比赛也不迟。所以,我们需要时刻擦亮自己的眼睛!

由于篇幅有限,具体信息请查看原文。


推荐阅读
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • 原文地址:https:www.cnblogs.combaoyipSpringBoot_YML.html1.在springboot中,有两种配置文件,一种 ... [详细]
  • Java在运行已编译完成的类时,是通过java虚拟机来装载和执行的,java虚拟机通过操作系统命令JAVA_HOMEbinjava–option来启 ... [详细]
  • 先看官方文档TheJavaTutorialshavebeenwrittenforJDK8.Examplesandpracticesdescribedinthispagedontta ... [详细]
  • Spring源码解密之默认标签的解析方式分析
    本文分析了Spring源码解密中默认标签的解析方式。通过对命名空间的判断,区分默认命名空间和自定义命名空间,并采用不同的解析方式。其中,bean标签的解析最为复杂和重要。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • IhaveconfiguredanactionforaremotenotificationwhenitarrivestomyiOsapp.Iwanttwodiff ... [详细]
  • Linux重启网络命令实例及关机和重启示例教程
    本文介绍了Linux系统中重启网络命令的实例,以及使用不同方式关机和重启系统的示例教程。包括使用图形界面和控制台访问系统的方法,以及使用shutdown命令进行系统关机和重启的句法和用法。 ... [详细]
  • 本文讨论了在Windows 8上安装gvim中插件时出现的错误加载问题。作者将EasyMotion插件放在了正确的位置,但加载时却出现了错误。作者提供了下载链接和之前放置插件的位置,并列出了出现的错误信息。 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • 本文讨论了使用差分约束系统求解House Man跳跃问题的思路与方法。给定一组不同高度,要求从最低点跳跃到最高点,每次跳跃的距离不超过D,并且不能改变给定的顺序。通过建立差分约束系统,将问题转化为图的建立和查询距离的问题。文章详细介绍了建立约束条件的方法,并使用SPFA算法判环并输出结果。同时还讨论了建边方向和跳跃顺序的关系。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • C++字符字符串处理及字符集编码方案
    本文介绍了C++中字符字符串处理的问题,并详细解释了字符集编码方案,包括UNICODE、Windows apps采用的UTF-16编码、ASCII、SBCS和DBCS编码方案。同时说明了ANSI C标准和Windows中的字符/字符串数据类型实现。文章还提到了在编译时需要定义UNICODE宏以支持unicode编码,否则将使用windows code page编译。最后,给出了相关的头文件和数据类型定义。 ... [详细]
  • 李逍遥寻找仙药的迷阵之旅
    本文讲述了少年李逍遥为了救治婶婶的病情,前往仙灵岛寻找仙药的故事。他需要穿越一个由M×N个方格组成的迷阵,有些方格内有怪物,有些方格是安全的。李逍遥需要避开有怪物的方格,并经过最少的方格,找到仙药。在寻找的过程中,他还会遇到神秘人物。本文提供了一个迷阵样例及李逍遥找到仙药的路线。 ... [详细]
  • 模板引擎StringTemplate的使用方法和特点
    本文介绍了模板引擎StringTemplate的使用方法和特点,包括强制Model和View的分离、Lazy-Evaluation、Recursive enable等。同时,还介绍了StringTemplate语法中的属性和普通字符的使用方法,并提供了向模板填充属性的示例代码。 ... [详细]
author-avatar
ik人生如梦场
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有