软件的加密与解密
软件的加密与解密技术是矛与盾的关系,它们是在互相斗争中发展进步的。
两者在技术上的较量归根到底是一种利益的冲突。软件开发者为了维护自身的商业利益,不断寻找各种有效的技术来保护软件的版权,推迟软件被解密的时间;而解密者则受盗版所带来的高额利润的驱使或纯粹出于个人兴趣,不断开发新的解密工具,针对新出现的保护方式进行跟踪分析,以找到相应的解密方法。
没有无法解密的保护。对软件的保护仅靠技术是不够的,最终要靠人们的知识产权意识和法制观念的进步及生活水平的提高。如果一种保护技术的强度能达到让解密者在软件的生命周期内都无法将其完全破解的程度,这种保护技术就是成功的。软件保护方式的设计应在一开始就作为软件开发的一部分来考虑,列入开发计划和开发成本,并在保护强度、成本、易用性之间进行折中考虑,选择一个平衡点。
作为一个合格的程序员,要上至需求分析、设计抽象、设计模式,下至系统核心,熟悉整个系统的底层结构。
软件逆向工程
逆向工程(Reverse Engineering)是指根据已有的产物和结果,通过分析来推导出具体的实现方法。
对软件来说,==“可执行程序->反编译-> ...
ELF简介
可执行与可链接格式(Executable and Linkable Format,ELF),是Linux操作系统上的默认二进制格式
ELF用于可执行文件、对象文件、共享库及核心转储。64位ELF二进制格式与32位是相似的,主要区别在于某些头部字段和其他数据结构的大小和顺序。
类型
实例
可重定位的对象文件(Relocatable file)
.o;.a;.ko
可执行的对象文件(Executable file)
vi、gdb、及我们用链接器生成的可执行文件、bash shell 程序
可被共享的对象文件(Shared object file)
.so
核心转储文件(Core Dump File)
当进程意外终止时,系统可以将该进程的地址空间的内容及终止时的一些其他信息转储到核心转储文件 core dump
64位ELF二进制文件的格式和内容:
ELF二进制文件实际上包含4种类型的组件:
ELF 头部(executable header,也称为可执行文件头)、
一系列(可选)程序 头、
多个节、
节对应的各个(可选)节头。 ...
ELF节头
ELF二进制文件中的代码和数据在逻辑上被分为连续的非重叠块,称为节(section)。节没有任何预设的结构体,相反,每个节的结构体取决于内容。实际上,节甚至可能没有任何特定的结构体。通常,节只不过是代码或者数据的非结构化blob。每个节由节头描述,节头指定了节的属性,并允许你找到节中字节的位置。二进制文件中所有节的节头都包含在节头表中。
对节进行划分为链接器的使用提供了方便,当然节也可以被其他工具解析(如静态二进制分析工具),这意味着在设置进程和虚拟内存来执行二进制文件的时候,实际上并不需要每个节所包含的数据,有些节所包含的数据在执行的时候是根本不需要的,如符号信息或者重定位信息。
由于节只为链接器提供视图,因此节头表是ELF格式的可选部分,不需要链接的ELF二进制文件不需要有节头表。如果没有节头表,则ELF头部中的e_shoff字段将设置为零。
为了在进程中加载并执行二进制文件,需要对二进制文件中的代码和数据进行不同的组织,为此ELF二进制文件指定了另一种逻辑组织, 称为段(segment),它们在执行的时候使用,与节相对,节在链接的时候使用。
节的内容的逻辑组织只在 ...
ELF头部
每个ELF二进制文件都是从ELF头部开始的,该头部是一系列结构化的字节,这些字节可以告诉你这是一个什么样的ELF二进制文件,以及在文件的什么地方查找其他内容。要找出ELF头部的格式,可以在/usr/include/elf.h或者ELF规范中查找其类型定义(以及其他与ELF相关的类型和常量的定义)。
64位ELF文件头部:
ELF头部在此以C结构体Elf64_Ehdr的形式表示。如果你在/usr/include/elf.h中查找该结构体的定义,你可能会注意到给出的结构体定义包含诸如Elf64_Half和Elf64_word的类型。这些类型只用于uint16_t和uint32_t等整数类型的预定义(typedef)。
e_ident数组
ELF头部(和ELF二进制文件)以被称为e_ident的16字节数组开始。e_ident数组始终以4字节的“幻数”开头,以此标识该文件为ELF二进制文件。幻数由十六进制数字0x7f组成,后跟字母E、L及F的ASCII字符代码。
紧跟在幻数后面,有更多字节提供了有关ELF二进制文件类型规范的详细信息。在elf.h中,这些字节的索引(e_id ...
PE加载过程 FileBuffer-ImageBuffer
一、FileBuffer到ImageBuffer常见的误区
1.文件执行的总过程
我们知道一个硬盘上的文件读入到内存中(FileBuffer),是原封不动的将硬盘上的文件数据复制一份放到内存中
接着如果文件要运行,需要先将FileBuffer中的文件数据"拉伸",重载到每一个可执行文件的4GB虚拟内存中!此时称文件印象或者内存印象,即ImageBuffer
但是ImageBuffer就是文件运行时真正在内存中状态吗?或者说文件在ImageBuffer中就是表示文件被执行了吗?不!!!!!!
在ImageBuffer中的文件数据由于按照一定的规则被"拉伸",只是已经无线接近于可被windows执行的文件格式了!但是此时还不代表文件已经被执行了,因为此时文件也只是处在4GB的虚拟内存中,如果文件被执行操作系统还需要做一些事情,将文件真正的装入内存中,等待CPU的分配执行
所以不要理解为ImageBuffer中的状态就是文件正在被执行,后面操作系统还要做很多事情才能让Ima ...
PE简介
可移植可执行(Portable Executable,PE)格式。由于PE是Windows操作系统上使用的主要二进制格式,因此熟悉PE格式对在Windows操作系统上分析常见的二进制恶意软件非常有用。
PE是通用对象文件格式(Common Object File Format,COFF)的修改版本,在被ELF取代之前,COFF还在UNIX操作系统上使用。PE有时也被称为PE/COFF。让人困惑的是,PE的64位版本被称为PE32+。PE32+和原始PE格式相比只有很小的差异。
图3-1中显示的数据结构在WinNT.h中定义,该文件包含在Windows的软件开发工具包(Software Development Kit,SDK)中。
1.MS-DOS头和MS-DOS存根
MS-DOS是Microsoft在1981年发行的一款操作系统,Microsoft为了实现向后兼容,将其包含在二进制格式中。
引入PE格式时,有一段过渡期,即用户同时使用老旧的MS-DOS二进制文件和较新的PE二进制文件。为了避免在过渡期人们对此产生混淆,每个PE二进制文件都会以MS-DOS头开始,因此 ...
ELF节
对于各个节,readelf都会显示相关的基本信息,包括节头表里的索引、节的名称和类型。此外,你还可以查看节的虚拟地址、文件偏移及大小。对包含诸如符号表和重定向表的节,还有一列显示每个条目的大小。最后,readelf还显示每个节的相关标志、链接节的索引(如果存在)、其他信息(特定于节类型)及对齐要求。
.init和.fini节
.init节(清单2-5中的索引11)包含可执行代码,==用于执行初始化工作,并且在二进制文件执行其他代码之前运行。==可执行代码会有SHF_EXECINSTR标志,使用readelf查看Flg列,可发现该值为X❷。将控制权转移到二进制文件的main入口点之前,系统会先执行.init节的代码,如果熟悉面向对象编程,你可以将.init节看作构造函数。
.fini节(索引15)类似于.init节,不同之处在于其在主程序运行完后执行,本质上起到一种析构函数的作用。
.text节
.text节包含程序的主要代码,所以它是二进制文件分析或者逆向工作的重点。
.text节的类型为SHT_PROGBITS❸,因为其包含用户定义的代码。同时要注意节的标志,这些标志位 ...
PE的基本概念
PE(Portable Execute)文件是Windows下可执行文件的总称,常见的有DLL,EXE,OCX,SYS等,事实上,一个文件是否是PE文件与其扩展名无关,PE文件可以是任何扩展名。
PE文件并不是作为单一内存映射文件被装入内存,Windows加载器(又称PE加载器)遍历PE文件并决定文件的哪一部分被映射,这种映射方式是将文件较高的偏移位置映射到较高的内存地址中。PE文件的结构在磁盘和内存中是基本一样的,但在装入内存中时又不是完全复制。Windows加载器会决定加载哪些部分,哪些部分不需要加载。而且由于磁盘对齐与内存对齐的不一致,加载到内存的PE文件与磁盘上的PE文件各个部分的分布都会有差异。
PE文件至少包含两个段,即数据段和代码段。Windows NT 的应用程序有9个预定义的段,分别为 .text 、.bss 、.rdata 、.data 、.pdata 和.debug 段,这些段并不是都是必须的,当然,也可以根据需要定义更多的段(比如一些加壳程序)。
在应用程序中最常出现的段有以下6种:
.执行代码段,通常 .text (Microsoft)或 ...
ollvm原理
Obfuscator-LLVM
Ollvm大致可分为 bcf(虚假块), fla(控制流展开/扁平化), sub(指令膨胀), Split(基本块分割)
bcf:
克隆一个真实块,并随机替换其中的一些指令,然后用一个永远为真的条件建立一个分支。克隆后的块是不会被执行的。
Fla:
将所有的真实块使用一个switch case结构包裹起来,每个真实块执行完毕后都会重新赋值switch var,对于有分支的块会使用select指令,并跳转到switch起始代码块(分发器)上,根据switch var来执行下一个真实块。
Sub:
指令膨胀,将一条运算指令,替换为多条等价的运算指令。
Split:
利用随机数产生分割点,将一个基本块分割为两个,并使用绝对跳转连接起来。
关于ollvm具体的实现,可参考源码。
指令替换 -mllvm -sub
虚假控制流 -mllvm -bcf
控制流展平 -mllvm -fla
函数(Funtions)注解
还原思路
网上有很多还原ollvm的脚本,但是只能还原特征很明显的ollvm,或者说只是debug版的ollvm。在debug版中o ...
ELF程序头
程序头表提供了二进制文件的段视图,与节头表提供的节视图相反。早前讨论过的ELF二进制文件的节视图仅适用于静态链接。相比之下,下面我们将要讨论的是段视图。在将ELF二进制文件加载到进程并执行的时候,定位相关代码和数据并确定加载到虚拟内存中的内容时,操作系统和动态链接器就会用到段视图。
ELF段包含零个或多个节,实际上就是把多个节捆绑成单个块。段提供的可执行视图,只有ELF二进制文件会用到它们,而非二进制文件(如可重定位对象)则用不到它们。
程序头表使用Elf64_Phdr结构体类型的程序头对段视图进行编码,每个程序头均包含清单2-11所示的字段。
p_type字段
p_type字段标识了段的类型,该字段的重要类型包括PT_LOAD、PT_DYNAMIC及PT_INTERP。
PT_LOAD类型的段会在创建进程时加载到内存中,程序头的剩余部分描述了可加载块的大小和将其加载到的地址。
通常至少有两个PT_LOAD类型的段,一个包含不可写数据节,另一个包含可写数据节。
PT_INTERP类型的段包含了.interp节,该节提供了加载二进制文件的解释器的名称。 ...