资 讯

网站建设、app开发、微信开发、网络营销知识汇聚

We provide professional and all-round information services to enterprises from all levels and angles

软件开发保护和分析技术原理
admin 2018-08-15

 上海软件系统开发CPU最重要的功能就是进行逻辑运算,比如加、减、乘、除这些常用的运算。为了让CPU能够真正为我们所用,我们必定要 有控制CPU进行运算的能力。在计算机中, 因为CPU只能进行纯数字的运算,所以CPU是数字指令模式的,也就是说,我们使用CPU的过程是: 向CPU输入一段数字和处理这些数字的方式,CPU经过运算后返回- -堆数字结果。另外,计算机处理我们所输入的数字的方式,我们也是以数字的形式告诉CPU的,如今大部分CPU只接受二进制(只需要用0和1表示)数字,任何其他形式的数字最终都会转换为二进制输入到CPU中。我们将输入CPU的这些数据(包括需要被处理的数字和处理方式)称为指令或代码,将CPU的运算结果称为指令结果。为了实现不同的目的,需要让CPU处理不同数目和类别的指令, 这类指令称为指令集。你可能听说过x86、x87、 mmx、sse、 MIPS等,它们都是不
  同的指令集。一块CPU可能具备处理多种指令集的能力,比如我们目前常用的Intel通用处理器般都具备处理x86、x87、 mmx指令集的能力。

  依次单击"File" - + "Open PE File"菜单项,打开一一个PE程序文件(例如c: lwindows lsystem32lnotepad.exe ),然后单击"BasicHADERS tree view in hexeditor"按钮,打开如图0.4所示的界面。通过该界面显示的内容和相关文档,我们可以详细地观察PE文件头的各个成员在文件中的对应数据和位置。相信通过这样的直观观察,读者一定能够很快对PE文件格式有所了解。

实际上,在PE文件头中,DOS Header (详见Windows S DK winnt.h头文件中的IMAGE_ DOS_ HEADER )部分对于32位与64位PE程序来说,只有其中的Magic Number和e_ lfanew ( File address of newexe header )成员是重要的,其他成员都只有16位程序才会使用。在这个头中, Magic Number固定为4D和5A(MZ),所以,判断一个PE文件最简单的方法就是观察文件是否由字符"MZ" 开始,如果不是,则该文件一定不是可以直接运行的PE文件。
  紧接着DOS头的是FileHeader(详 见winnt.h 中的IMAGE_ FILE_ HEADER)。在这个头中,Machine (如图0.4所示的Signature )、  NumberOfSections.  SizeOfOptionalHeader、Characteristics成员都是必需的,Machine成员固定为“50 4500 00"字节序列。因此,在判断DOS头后,进一步验证PE文件是否正确的方法就是验证这里的字节序列。NumberOfSections指明 了该PE文件头所拥有的区段数目,对于一个能够正确运行的PE程序文件来说,区段映射必须正确。
  SizeOfOptionalHeader指明,了紧接着FileHeader的Optional Header的大小,操作系统会验证这里的值来判断PE文件的特征,所以也是必需且要正确设定的。Characteristics指定 了PE文件所具备的信息,如是否是DLL模块等,这对于操作系统是否能够正确识别PE程序文件是必要的。
  在Optional Header中(尽管这个头的名字的意思是”可选头”,

但是这个文件头在32位及以上的PE文件中是必需的) ,这个文件头根据PE文件( 32位/64位)的不同有不同的结构,分别在winnt.h中定义为  IMAGE_ OPTIONAL HEADER32  和IMAGE_ OPTIONAL HEADER64。两者的大体结构是一样的,只是在各成员中的大小不一样。在Optional Header中,很多成员(如Magic、  AddressOfEntryPoint.  lmageBase、  SectionAlignment.FileAlignment. DlICharacteristics、  NumberOfRvaAndSizes)都是必需的,其中MajorSubsystemVersion、MinorSubsystemVersion成员 指定了该PE程序文件运行所需要的最小子系统版本。从Visual Studio 2012开始,编译器默认将这个版本设定为6.0,因此Windows 2003及以下系统默认无法运行Visual Studio 2 012编译器编译的PE程序文件。
  在Optional Header中,还有 一个DataDirectory数组成员 ,这个成员指定了PE程序运行时的另外一一些信息,如图0.5所示。这个目录表指定了该PE程序运行时的必要信息,如导入表等。

 实际上,只有ntll.dI模块是完全在内核中载入的,其他模块的载入(包括kernel32 dIl的载入)都是在新进程本身的空间中初始化的。我们可以通过下面的方法了解这个过程。
  LdrlnitializeThunk函数是新进程创建后进程空间中运行的第一条指令入口,我们可以使调试器在这个入口点中断,从而分析之后的整个初始化过程。普通调试器并不具备中断到L drIntializeThunk函数的功能,使用OllyDbg的插件StrongOD并打开"Break On Ldr"功能就可以中断到L drinitialize' Thunk函数入口。  其中,参数InheritDisposition指明了映射类型。当该参数指定为SEC_ IMAGE时,该函数将校验映射区块的文件格式。当内存映射完成,系统就开始向模块列表添加模块信息,然后转入PE的相关加载。为了观察Windows是如何加载PE程序的,我们可以观察RtllmageDirectoryEntryToData函数。我们要庆幸, PE程序中大多数需要初始化的数据都由PE头中的DataDirectory目录指定,而Windows正好利用RtlmageDirectoryEntryToData函数定位数据目录并导出了该函数。该函数定义如下。
void WINAPI RillmageDi rectoryEntryToData(HMODULE hmod, void* a2, DWOR D type,LPDWORD lpSize)
  其中,参数type定义了需要获取数据目录的索引,在系统完成映像内存映射后,我们就可以在该函数上下断点并进行观察。通过观察可以发现,在系统所有的数据目录加载过程中,对主模块来说导入表是最为重要的,对DLL模块来说重定位目录也是至关重要的,其他数据目录可以根据程序的不同进行选择。
  当系统加载各目录以后,就进入模块入口代码的调用过程,控制权就移交给被加载的程序代码了。作为软件或程序的设计者,我们自然希望自己设计的程序能够完全按照自己希望的那样运行,更关键的是, 我们希望 自己的劳动成果能够有正确的体现。例如,我们为某种目的而设计了一套相当强大的软件,并且为此付出了几年的心血,因此,我们希望从使用该软件的人或机构那里得到相应的回报,比如现金,我们希望别人在使用这套我们辛苦开发出来的程序时能够付费。
  但是,如果软件的开发者与用户之间没有明确的信任关系,我们该如何确保用户在使用我们的软件时付费呢?其中比较重要的手段就是,通过更改软件的设计,让软件具备一种验证能力( 授权),通过对软件的这部分功能进行操作,如输入验证码等方式,控制用户对软件的使用。
  这听起来相当"高科技”,但是根据我们对程序的理解和现实情

  软件开发公司此时的情况就是,原定的程序经过用户的修改,变得和我们的预期不一样了。修改00DE10A3处的指令后,无论用户输入什么字符串,程序都会知道00DE10C9处的代码,也就是显示“功能2!”这个字符串,这和我们设计这个程序的预期完全不一样。
  程序的设计者自然希望程序完全按照自己的设计运行,但是通过上面的例子可以看出,程序的修改在这种情况下是非常容易的。所以,我们有很强的意愿,希望能通过一定的手段防止程序的流程被修改,让程序完全按照我们的设计运行,这就是所有软件保护技术的核心和最终目的。
  实现这个目标是很困难的。因为根据CPU的一般设计,输入CPU的指令可以是CPU所支持的任意指令,也就是说, CPU自身不会也不太可能判断它所接受的指令是否是被篡改的指令。所以,要想防止我们为程序设计的指令被篡改,必须通过其他技术手段来实现。1.防止调试
  防止调试就是阻碍用户对我们所设计的程序进行调试,尽量使用户很难甚至不能调试程序。如果用户无法调试被保护的程序,那么篡改程序的执行流程就会变得非常困难。这种思路曾经在一段时间内指导了很多保护系统的设计者,因此在这方面也发展出了非常多的技术手段,之后我们将讨论其中的一部分。
  2.防止分析
  防止分析是指将程序中的代码或者数据通过各种技术手段(如变形、移位等)变换为更加复杂和不直观的等价代码。虽然在程序执行结果上是相同的,但是这样做将大大提高分析者对代码的阅读和理解难度。这种技术手段的最终思想都是:用计算机在速度和存储量上的优势使代码变得复杂,拖延分析者对程序代码的理解时间,迫使分析者无法正确理解程序代码的真正用意,也就无从改变程序的运行流程甚至破解程序。
  3.防止修改
  防止修改是指通过技术手段,防止被保护程序的代码和数据被修

反调试作为一种重要的软件保护手段,已经成为各种保护系统的必备技术,现今的各种游戏保护系统尤其注重反调试技术。反调试技术的应用能够将众多分析者拒之i ]外一很 多分析者对软件的分析和研究严重依赖现存的调试软件和文献,如果通过反调试技术使他们对程序的调试结果不能达到预期,他们大都会放弃。在这里我们就介绍其中几种基本的反调试技术。
  1.1.1  函数检测
  软件系统开发函数检则就是通过Windows自带的公开或未公开的函数直接检测程序是否处于调试状态。最简单的调试器检测函数是IsDebuggerPresent,  该函数的原型为  "BOOL  WINAPIIsDebuggerPresent(VOID)",当检测到程序处于调试状态时返回"TRUE”。IsDebuggerPresent函数的汇编代码如图1.1所示。数据检测是指程序通过测试一些与调试相关的关键位置的数据来判断是否处于调试状态。例如,在1.1.1节的函数检测中,我们了解到PEB的第3个字节表示进程是否处于调试状态,数据检测就是在程序中由程序自身直接定位到这些数据地址并测试其中的数值,这样就避免了调用函数(调用函数是非常引人注目的,也容易被Hook)。但是,使用这种数据检测方式需要处理很多平台之间的兼容性问题,如果选取的测试数据的位置会根据平台的变化而变化,那就很麻烦。这种方式也会带来好处,例如将检测代码放到虚拟机中就会很隐蔽。我们可以构建检测代码,如图1.4所示。

  • 上一篇:游戏软件系统开发几大要素你清楚吗
  • 下一篇:手机软件开发自动完成编辑框AutoComp leteTextView
  • © 2011-2018 www.keyrey.com 上海科睿网络科技有限公司 © 版权所有 沪ICP备12032097号-1
    友情链接 : 上海app开发 app开发公司 app制作 手机软件开发 手机软件开发公司 小程序开发 上海网站制作公司
    QQ在线咨询

    上海app开发QQ在线咨询 上海app开发QQ在线咨询
    电话咨询
    400-877-9280 app开发公司电话咨询
    即时在线咨询 手机软件开发即时在线咨询
    微信扫一扫
    添加app制作微信 上海网站制作公司微信
    科睿网络-互联网开发营销专家

    凡事有交代 件件有着落 事事有回应

    立即获取为您量身定制的开发营销方案

    咨询热线 400-877-9280