ChrisXisaer反编译技术探索!第一章-第一节 开始!

        未经作者同意请勿转载此文章!

  关于编译原理和如何编译计算机软件的相关书籍和资料非常的多。但如果你想了解反编译方面的知识或者逆向源代码的知识,那可能真正好的参考资料寥寥无几,大部分能看到的都是各位大师或者CRACKER们的作品和反编译成果。具体过程和技术要点往往被掩盖。所以有时候你可能觉得我就差那么一点就懂了。就如同当初的我。

    因此我想和大家一起揭开反编译中的一些奥秘。在不断的探索和学习中让我们揭开这道神秘的面纱。提到反编译我们应该先了解一下计算机软件的诞生过程。因为只有当我们了解了它是怎么来的,才能在我们回溯的过程中对一些编译器的工作方式和反编译工具的处理过程有一些比较清晰的认识,只有这样我们才能更有效的对我们要反编译的对象施加正确的方法以解决在这个过程中出现的各种问题。

   首先我们先来讨论一下软件的诞生,当程序开发者准备开发一款软件,他首先要面对的是如何选择平台,在远古时代,我们程序员的选择性很少,因为当时除了UNIX之外可能都是一些嵌入式的特定操作系统平台,而且反编译工具也寥寥无几,但当LINUX诞生之后,尤其是WINDOWS的到来使得计算机应用的爆炸式普及,恶意软件及病毒的肆虐,导致反编译技术也得到了迅猛的发展及壮大。目前我们探索的平台不仅在PC上还有很多移动设备,但究其根本还是3大系统在当家:WINDOWS,LINUX,以及MAC OS 系统。虽然市面上看起来各种系统多如牛毛,但基本都是这些系统的衍生品,而这三个系统也是从UNIX系统衍生而来,无论他们的文件系统,CPU工作时间分配方式,还是对多用户的支持模式。我们先以linux 为例:

 由于篇幅的限制以及对我们主题的考虑我接下来的分析将不会很深入, 在LINUX上我们看到的编译软件是GUN系列,在编译一份代码的过程中要经历四个过程:

 一、预编译 

1.将所有的#define删除,并展开所有的宏定义; 

2.处理所有的预编译指令,例如:#if,#elif,#else,#endif; 

3.处理#include预编译指令,将被包含的文件插入到预编译指令的位置; 

4.添加行号信息文件名标识,便于调试; 

5.删除所有的注释:

6.保留所有的#pragma编译指令,因为在编写程序的时候,我们经常要用到#pragma指令来设定编译器的状态或者是

指示编译器完成一些特定的动作。 

生成.i文件。

包括去注释 ,宏替换 ,头文件展开,条件编译

二、编译:C语言—汇编

1.扫描,语法分析,语义分析,源代码优化,目标代码生成,目标代码优化;

2.生成汇编代码;

3.汇总符号; 

4.生成.s文件

三、汇编:汇编—二进制 

1.根据汇编指令和特定平台,把汇编指令翻译成二进制形式;

2.合并各个section,合并符号表; 

3.生成.o文件

四、链接

1.合并各个.obj文件的section,合并符号表,进行符号解析; 

2.符号地址重定位; 

3.生成可执行文件

  上面这段是来自LINUX编译过程的相关文章中的一部分目的是让大家了解可执行程序的诞生。庆幸的是MAC OS 也用的GCC.如果是windows编译器可能会换成VisualStudio,但基本过程是一样的这里就不在赘述,唯一的区别就是,最后可执行程序在两个平台上一个以权限划分,一个以扩展名为依据。当然这里的可执行程序用词不太恰当,正确的说法应该叫做:可执行文件。正如文章开头所说的他们的文件系统工作方式一样。在我们接下来要研究的主要对象就是可执行文件的逆向过程。

 我们先来看一下什么是可执行文件:

- 可执行文件指的是可以由操作系统进行加载执行的文件;

- 可执行文件的文件格式常见有:
exe 和 dll(Windows 系列)、elf(Linux 系列)和 Mach-O(Mac系列);

- 可执行文件的 “格式”,和 “后缀” 二者没有直接关系,
事实上 Linux 下如 elf 类型是没有后缀名的;

- 可执行文件的 “执行” 二字,从直接执运行和间接调用两方面理解;

- 通用对象文件格(COFF,Common Object File Format)是这些 Unix-Like 系统可执行文件(如可执行的 elf、PE)的共同祖先,如今已被继承取代。

 

这是来自*的一段描述。至于他在各个系统中的叫法并不重要,重要的是最后一句他们都是通用对象文件格式,有共同的祖先。既然这样我们就很有必要研究一下这个可执行文件结构,读懂可执行文件结构我们就等于学会了如何反编译软件的一半。接下来我们一起来看一下这个文件结构(文件格式)标准:

ChrisXisaer反编译技术探索!第一章-第一节 开始!

 

   这张图非常的直观,每一个字段都代表一个文件中的一个区域,如果要讲清楚这个结构可能需要一份100页的论文,这里我们摘录出几个选段来介绍:

段表"Section Header table"(在图的最顶层的那个段)在整个目标文件中的偏移,而段表是一个元素为"Elf64_Shdr"结构体类型的数组,它的元素的数量正好是图中间那些字段的数量,也就是它的每个元素存储了中间一些字段如".text",".symtab"等字段的信息,这些信息包括字段名,大小等等属性。所以概括的来说,通过读取ELF头,可以得到段表,然后通过读取段表中各个字段元素,就可以得出各个字段的信息了。那么读到这里,ELF结构轮廓已然清晰,接下来就是分析ELF文件各个字段的具体用途,以及某些字段是具体如何关联才使得链接器能够完全理解这个文件。

1 .text字段:用于保存程序中的代码片段

2 .data字段:用于保存已经初始化的全局变量和局部变量

3 .bss字段:用于保存未初始化的全局变量和局部变量

4 .rodata:顾名思义,保存只读的变量

5 .comment:保存编译器版本信息

6 .symtab:符号表,各个目标文件链接的接口

7 .strtab:字符串表,保存符号的名字,因为各个字符串大小不一,所以统一把所有字符串放到这个段里,后续其他段通过某个符号在字符串标中的偏移可以取到符号。

8 .rela.text:因为程序声明使用了未在程序内部定义的函数或者变量,所以需要等到链接时(定义在别的目标文件或者库里)对这个符号的地址进行重新定位,不然会引用到错误的地址。

9 .shstrtab:和strtab类似,不过保存是段名,也就是说里面保存的字符串是所有段的名字

10 Section Header Table:段表,保存了所有段的信息,本身通过Elf头找到,可以解析出所有段的位置。

接下来是一个Windows系统下可执行文件(PE)的文件格式:

ChrisXisaer反编译技术探索!第一章-第一节 开始!

 

 

 

如同 ELF 存在的 ELF 头,PE 格式文件也有 PE 头(PE header),而且加以区分 PE 格式还在文件的最上面加上了 MS-DOS 头部(DOS MZ header)… PE文件的第一个字节起始于MS-DOS头部,被称作IMAGE_DOS_HEADER。

紧随 DOS 头的,是 PE 头。PE Header 是 PE 相关结构 NT 映像头(IMAGE_NT_HEADERS)的简称,其中包含许多PE装载器用到的重要字段

包括:

程序入口点(OEP,Original Entry Point)
文件偏移地址(File Offset)
虚拟地址(VA,Visual Address)
基地址(ImageBase,这个单词记住)
相对虚拟地址(RVA,Relative Virual Address)
文件偏移地址是指数据在PE文件中的地址,是文件在磁盘上存放时相对于文件开头的偏移。文件偏移地址从 PE 文件的第一个字节开始计数,起始值为 0。用十六进制工具(如 WINHEX)打开文件所显示的地址就是文件偏移地址。对于一个确定的文件,基地址可能变化这是由编译器决定的,而偏移是固定的。
  通过上面的图片和介绍我们可以看到可执行文件结构在各个平台上除了文件头的区别外基本保持一致,这也很大程度上简化了我们逆向阅读代码的过程。所以我建议大家还是深入的研究一下。至少理解.text段、rdata段、data段等代表的意义以及相互之间的关系。

  虽然上面有讲解各个段的作用我这里还是有必要在多说一些:

(1).text段保存的二进制格式代码,在通过编译软件(翻译软件)之前是以两种方式存放的,首先在需要编译软件处理的内容都是以汇编语言格式存在,这也是我们在通过反编译还原二进制代码的时候得到的中间语言。这种可执行文件一般是通过C,C++,Delph等。第二需要解释型的语言所构建的可执行文件,其存在形式通常是一种依赖于相关解释器的中间语言,比如C#的中间语言MSIL,以及JAVA的中间语言JAVAIL,即以字节码的形式存在。无论我们通过反编译软件拿到的这两种代码格式哪一种。其每一行的意义就是一个文件在磁盘中的:文件内相对地址+指令格式 的形式存在。每一行所占用的空间大小是一个字节。也是磁盘和内存的基本存储单位。

(2).data 用于已经初始化的全局变量和局部变量,这里的已经初始化的意思不单单是赋值的意思还有已经初始化类的对象存放的地址(对于C++等面向对象的语言)。以及函数指针的存放地址。

ChrisXisaer反编译技术探索!第一章-第一节 开始!

(3)对于.rodata/rdata,.bss段的补充说明同第二小节中一样。时刻注意这些将对你未来的反编译之路有很大的帮助。

本节我们就先讲解这些内容,接下来我将跟大家一起探索由编译型语言所构建的中间语言--汇编语言。当然这也是一本书都可能讲不完的知识。我所阐述的观点可能只限于在反编译过程中需要用到的汇编知识,可能和我们大家平常所学习的汇编语言不太一样。但是其根源理论是一样的。另外文章中所设计某些知识可能来自与其他的作者或参考文献,我这里就不一一道谢了。但是所用之内容均是*转载之基础。不涉及任何版权问题,以及不承担任何法律上的责任。

 

上一篇:安装中文bootmgr启动菜单到硬盘EFI分区


下一篇:从ADK的WinPE自己手动构建自己的PE