适用于IDA Pro的CGEN框架

阅读量    119385 |

分享到: QQ空间 新浪微博 微信 QQ facebook twitter

http://p9.qhimg.com/t01f4732bc9349356c3.jpg

        当我想要去分析某些媒体嵌入式处理器(Media-embedded processor)的代码时,我便发现了这个问题。在通常情况下,我会在IDA Pro(一款专业的交互式反汇编器)里面进行我所有的解析和研究工作,但是有少数几类处理器是IDA并不支持的,而我在上面所提到的处理器正是这其中一种。但值得庆幸的是,有一种专门针对这类复杂架构的objdump工具可供我们使用。在经过了一番摸索之后,我认为,将反汇编程序移植到IDA上能够更加节省我的时间,因为手动处理和标注objdump的输出数据简直是太麻烦了。

处理过程

事实证明,互联网上并没有太多关于编写IDA处理器模块的内容和资料。SDK的说明文档也十分的简洁,文档并没有进行过多的描述(它只是让你去阅读示例代码和头文件),即以下这两个文档:一份是在线指导教程,这份文档在网上已经找不到了;另一份是Chris Eagle所著的《The IDA Pro Book》。打开这本书,然后翻到专门讲解编写处理器模块的章节,你会发现这一章其实根本没有什么内容(它提示你:该部分内容缺少相关文档),因为很多人都曾尝试过编写处理器模块,但他们都没能成功。

Chris Eagle在《The IDA Book》第二版中写到:

编写处理器模块之所以如此的困难,其中的一个原因就在于,processor_t结构体包含有56个数据域,而这些数据域都必须要进行初始化,其中的26个数据域是函数指针。除此之外,还有一个数据域是一个指向数组的指针,而在这个数组中还保存有大量的结构体指针,这些结构体指针会指向不同类型的结构体(asm_t),在这些不同类型的结构体中,每一个结构体又会包含有59个需要进行初始化操作的数据域。天啊,这简直是太复杂了!

但是,我并不是一个容易放弃的人,所以我选择继续阅读下去,并逐渐熟悉了创建一个处理器模块所需要进行的操作和步骤。在这篇文章中,我并不打算对具体的操作步骤进行详细的描述,因为Chris已经在他的书中写得非常详细了,所以我在此只会进行一个简单的概括。

IDA处理器模块

IDA的处理器模块有四大组件。“分析器”能够解析机器代码的原始位数据,并且生成一条指令的相关信息。“模拟器”能够利用“分析器”所生成的信息来帮助IDA对数据进行更加深入地分析。比如说,如果一条指令需要引用某个数据,你的模块就可以让IDA根据给定的内存地址来寻找这个数据。如果指令需要执行一次函数调用,你的模块就可以让IDA去创建一个功能函数。与它的名称相反,“模拟器”实际上并不会“模拟”出一个指令集。“输出器”所做的工作是:对“分析器”所生成的数据进行解析,然后将其输出给用户。最后,即是架构信息,在其他的资料中,架构信息其实并不算是一个组件,但我认为它可以算是其中的一大组件。架构信息并不是一段代码,而是一种静态结构,IDA可以从中获取例如寄存器名称和指令助记符等重要信息。

CGEN框架

适用于媒体嵌入式处理器(Mep)的binutils(objdump)是由CGEN框架生成的。CGEN框架的目标就是将编写CPU工具(编译程序,反编译程序,以及模拟器等等)的任务抽象为编写CPU定义。它可以通过Scheme语言来对CPU(包括硬件组件,指令集,以及操作数等等)进行描述。CGEN能够识别这些定义,并且为CPU工具输出其所需要的C/C++代码。起初,我并不想使用CGEN,我原本打算直接把binutils代码直接加入至一个IDA模块(à la Hexagon)之中。理论上,你的模块并不需要遵守上述所列出的规则。你可以让分析器记录原始位数据,然后模拟器可以不进行任何操作,输出器可以直接利用binutils来生成完整的解析结果并将结果输出给用户。然而,如果这样做,你就没有让IDA充分发挥其强大的功能。当然了,你也没有充分利用CGEN的CPU定义所提供给我们的有效信息。这种定义(理论上)是十分健壮的,它可以为处理器生成RTL代码,所以我们理所应当向IDA提供尽可能多的信息。

CGEN生成器

生成器(CGEN的说明文档称它们为“应用程序”)同样是使用Scheme语言编写的。在此之前,我一行功能代码都没有写过,所以即使是一个相对较小的代码库,我也花费了一整天的时间去理解其中的代码。CGEN有其自身的对象系统,他们将其命名为COS。CPU描述中的每一个定义都是一个对象,每一个生成器都会赋予这些对象一个能够将其自身打印输出的方法。比如说:模拟器可以给操作数对象提供一种“生成代码并赋值”的方法。然后它会调用一个函数来生成一条指令的相应语义,并将其转换为C语言代码的形式。就像一个真正的软件工程师一样,我从模拟器,反编译程序,以及架构描述中剥离出了生成器的相关函数,并使用我自己所编写的代码来将这些函数组合在了一起,并以此来制作IDA模块所需要用到的组件。

结果

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

上图中,所有蓝色部分均为程序自动分析的结果。

从最基础的层面上来说,生成模块能够打印输出objdump中所有你需要的数据信息。分析器能够找到操作数(如果存在的话)的正确类型。模拟器会尝试寻找所有连续的内存地址。如果我们需要的话,输出器还能够正确打印并输出所有的指令,以及类型/大小/名称均无错误的操作数。

目前而言,它还有一件最主要的事情还没做,即跟踪堆栈指针。除此之外,它没有对函数的跳转和调用进行验证(这一过程需要用到CF_CALL标识)。它也没有对指令的运行状态进行检测和验证(这一过程需要用到CF_STOP标识),但这一步骤可以手动进行,所以在此我不进行过多的论述。

当你成功地生成了IDA模块的各个组件之后,你仍然需要手动编写processor_t结构体,notify()函数(可选),以及专门的打印函数(CPU定义中有相关的内容)。然后,你就可以将CGEN的headers从binutils中拷贝出来,并使用IDA SDK对其进行编译。比如说,让我们来看一看Mep模块,你可以重复使用其中大部分的代码(你只需要更换其中的某些字符串和常量即可)。

下载

        点击下面第一个链接获取CGEN框架的源代码,点击下面第二个链接获取Toshiba MeP模块的源代码。如果我还有时间,我会继续给大家提供更多有关CGEN以及IDA模块的信息。

https://github.com/yifanlu/cgen

https://github.com/yifanlu/toshiba-mep-idp

分享到: QQ空间 新浪微博 微信 QQ facebook twitter
|推荐阅读
|发表评论
|评论列表
加载更多