zoukankan      html  css  js  c++  java
  • 学写压缩壳心得系列之三 模拟加载,步步为营

    在熟悉了PE结构之后,我们还有知道系统从磁盘加载静态文件映射到内存,作了哪一些的改变。
         PE结构,就好像一张指南,告之系统自己的各个属性,哪些地方保存着哪些数据,随后又加载到哪里去。加壳的PE文件始终是也是一个文件,同原始的PE文件比较,只不过是两种数据结构相同,却数据内容不同罢了。
        下面我们模拟一次系统loader的过程,探讨一下PE文件是如何从磁盘的静态数据加载的内存中去的。
        首先,loader会判断目标文件是否问正常的PE文件
    IMAGE_DOS_HEADER结构的MZ标志
    IMAGE_NT_HEADER结构的PE/0/0标志
    如果出错,就会弹出一个错误提示。\


     
    如果是正确的PE格式那么loader会读取IMAGE_OPTION_HEADER中ImageBase作为加载基址,随后读取IMAGE_OPTION_HEADER中的SizeofImage的值,来获得PE载入空间的大小。然后根据所开空间的大小和IMAGE_FILE_HEADER的NumberOfSections中读取节头部的数量,按照各IMAGE_SECTION_HEADER保存的信息将文件中各节的实体数据映射到内存之中。





     
    我们看到,测试文件一共有三个区段,例如:
    .text会被预计加载到ImageBase+10000h处的地方,在磁盘中的位置是0x400h处所占的内存映射空间是1000h,真实的大小是0x1c2h。我们来对照看一看:



     
    可以看到,在内存RVA0x1000h处和offset0x400h处,数据是一样的。




     
    在完成映射之后,读取IMAGE_DATA_DIRECTORY数组的第2项,即导入表的RVA,然后获取FirstThunk所指向的数据,修改成指向导入函数的实际地址。我们来看看未载入内存时FirstThunk所指向的值

     
    再来看看未载入内存时OriginalFirstThunk的值\




     
    我们发现,两个值是一样的,那么我们再来看看已经载入到内存时候FirstThunk所指向的数据
     


     
    OD已经注释了,这里的数据全部都替换成了导入函数实际的地址了。
     
    处理完导入表之后,读取IMAGE_DATA_DIRECTORY数组的第6项IMAGE_DIRECTORY_ENTRY_BASERELOC项,看是否存在重定位的数据。我们知道,如果是DLL文件,IMAGE_OPTION_HEADER中ImageBase不一定是正常的加载地址,这时候,需要重新定位。例如
    我们看到重定位表中:

     
    VirtualAddress 是0x1000h,第一个重定位数据是0x300Eh,高位的30中的3表示类型,低位0X0Eh表示偏移,所以对于内存映射偏移地址0x100Eh,转到内存中去看:


     
    我们可以看到,ImageBase+偏移等于0x0010100Eh,这正好是一个指针,取得机器码是28420010,如果这时候,载入的ImageBase不等于0x100000,那么就会用实际地址-预设地址算出一个偏移,再加上机器码。至此,loader就基本将磁盘上的PE文件整体映射到内存中了,然后读取到IMAGE_OPTION_HEADER中的AddressOfEntryPoint,加上ImageBase得到文件的入口点。
     
    可以参考linxer版主之前写过一篇关于模拟PE加载的代码:
    一段仿真PE加载器行为的程序
     
     
    那么,通过上面的介绍,我们要知道,为了模拟好系统loader,压缩壳的loader要做的步骤:
    1.保存原始PE文件MAGE_OPTION_HEADER中的ImageBase和AddressOfEntryPoint以及表头其他相关重要的结构
    2.解压完前后各个数据段的定位地址,方便准确找到各个结构
    3.原始PE文件的导入表信息,重定位信息和导出表信息,方便还原后修改和填充
    4.解压代码以及外壳代码
     
    综上,模拟了一遍loader的流程,我们知道,加壳文件也是正常的PE文件,与正常文件最不同的一点,就是在变回正常文件之前,模拟了一次系统loaer对PE文件的处理,将加壳文件转换成了正常文件。我们可以近似地将壳的shell处理被压缩的文件是一次模拟的系统loader。我们在写壳的shell的时候,就要用到上述的流程,在内存中模拟完loader解压之后,写回到磁盘中,整个的解压过程就完成了:)写得有点冗长,感谢您耐心的看完:)但水平有限,还请大家多多指正。

  • 相关阅读:
    黑马程序员——JAVA基础之System,Runtime,Date,Calendar,Math
    黑马程序员——JAVA基础之JDK1.5新特性高级for循环和可变参数
    黑马程序员——JAVA基础之Collections和Arrays,数组集合的转换
    黑马程序员——JAVA基础之Map集合
    黑马程序员——仅当源级别为 1.5 时已参数化的类型才可用的解决办法
    黑马程序员——JAVA基础之泛型和通配符
    黑马程序员——JAVA基础之Vector集合
    黑马程序员——JAVA基础之set集合
    黑马程序员——JAVA基础之List集合
    Bringing up interface eth0: Error: No suitable device found: no device found for connection 'System eth0'.
  • 原文地址:https://www.cnblogs.com/tk091/p/2456165.html
Copyright © 2011-2022 走看看