用户名:  密码:   
您当前的位置:首页 > 程序设计 >  汇编与密码学 > 

系统篇1_12

上次修改时间: 2017-12-01 10:00:22      来源:网络总结      作者:钢铁长陈
上一页      路径:DSD\Learn\assembly与反assembly\解密系列\      下一页

第1讲 序言
1. 可执行文件格式是操作系统本身执行机制的反映
2. EXE和DLL文件之间的区别完全是语义上的,,唯一的区别是一个字段标识出这个文件是EXE还是DLL,他们使用相同的PE格式
3. 64位windows只是对PE格式做了一些简单的修饰,新格式叫PE32+,没有新结构,只是将32位子字段扩展成64位
 PE格式定义的主要地方位于头文件winnt.h, 安装VC6后在VC98\include下,
 在.h搜索Image ,这里定义了PE结构
4. PE文件中的数据结构一般都有32位和64位之分,一般在名称上会表现出来,如image_nt_Headers32或image_nt_Header64
 两张图,见fishc.com日志,PE文件框架结构
 Dos stub,块表,通过块到找到块,结尾是COFF行号,符号表,调试信息表
 图2,详细图
5. PE的基本概念,PE使用是一个平面地址空间,所有代码和数据被合并在一起,组成一个很大的结构
 文件内容被分割为不同的区块,块中包含代码或数据,各个区块按页边界来对齐,区块没有大小限制,是一个连续的结构
 每个块有自己在内存中的一套属性,块是否含 代码,可写
6. PE不是作为单一内存映射文件,windows加载器,遍历PE文件并决定把那一部映射,文件较高的偏移映射到较高的内存地址
 磁盘上的数据结构布局还是不变
 磁盘的数据结构中寻找一些内容,装入到内存映射文件中找到相同的信息
 但数据间的相对位置可能改变,区别于原始的偏移位置
 图,如何映射到内存中
7. 基地址,ImageBase,内存中整个PE文件头的地址,被win加载器加载后,一个模块,模块的句柄hModule
 模块句柄相当的基地址,获得了这个模块的名柄,文件放内存最开始的
 GetModuleHandle(LPCTSTR lpModuleName)函数获取 ,参数是要获取模块的名称,返回值为模块的句柄
8. 文件偏移地址
 放磁盘时,各区块相对头的地址,偏移地址都是从0开始
9. 相对虚拟地址RVA
 PE放内存后比例一样,放内存后的各段地址是虚拟地址
 相对虚拟地址,每个虚拟地址相对基地址的偏移
 基地址+RVA=VA

第2讲 
1. MS-DOS头部
 每个PE文件是以一个DOS程序开始的,一旦程序在DOS下执行,DOS才能识别这是有效的
 PE文件的第一个字节起始于一个传统的DOS头部,称为image_dos_header
 就是一个结构
2. 空间——日志——搜PE,变形PE头添加节形式感染
 PE详解image_dos_header
 image_dos_header struct {
  ...
  e_magic dos可执行文件标记,MZ  4d 5a
  。。。
  e_lfanew 指向PE头的指针 最后是这个,偏移为+3ch
 }
 dos头和PE头之间为对齐,有些用0填充的
3. 用UE打开一个exe文件
 最开始是4d 5a MZ dos的可执行标记
 到3ch处去看,00 01 00 00  PE 偏移为0100h
4. PE文件头 ,挨着dos stub,image_nt_header结构
 在内存中加基地址,加载到内存后虽然基地址不一样了,但相对偏移不变
 
 空间——日志——搜PE,image_nt_header结构定义即各个属性的作用
 image_nt_header struct{
  Signature,字段被设为0000450h 是否有效PE主要看这里
  image_file_header 这是一个结构,结构中的结构
   {
    //运行平台 014c,可执行文件目标CPU的信息
    //文件区块数目 0008 表有8个区块
    文件创建日期和时间 值是以秒计算的,以1970年1月1日开始算,
    指向符号表
    文件属性
   }
  image_optional_header32{
   
  }
 }
5.  IMAGE_FILE_RELOCS_STRIPPED 0X0001
 IMAGE_FILE_EXECUTABLE_IMAGE 0X0002
 多种属性同时用可以或起来
 
第3讲 image_optional_header32详解
1. PE文件在磁盘和内存的各块相对位置不变,顺序不变,每个块间有些空白,一般用0填充,主要是为了对齐
 磁盘200H(512)个字节为一页对齐, 内存是1000H(4096)字节即4K为一页对齐。64位U是8K对齐
 为兼容,有的32位也会编译成8K对齐
2. dos头,实际上是一个结构,有两个地方要记住,开始的MZ开头,最后是指向真正的PE头的偏移
 每个PE文件的块在磁盘的偏移都是从0开始
3. PE头,PE的ascii开头
 PE头里也是一个结构,结构中有3个字段,另两个是字段都是结构。
4. image_file_header结构
5. image_optional_header32结构,里面有些的可选的字段
 大部分字段都不重要,病毒有时就是在这些地方作标记,不重复无效的感染
 网站,日志里找文章
 AddressOfEntryPoint字段,指定文件被执行的入口地址,如果附加了一段代码就把入口改到代码处,执行完病毒后再跳回去。 ImageBase字段,理想的装入字段
  可通过link.exe 指定/base:address来定义优先装入地址,不指定exe装入地址默认为00400000h
 SectionAlignment字段和FileAlignment 内存和文件中的区块对齐大小设置
  CPU查数据可一页一页番,不用一个一个字节查
6. 用UE打开一个exe文件,查看MZ,PE00
 从PE开始偏移,从0开始3C偏移处 
 Subsystem字段,指定子系统,指明程序的类型
7. image_data_directory 数据目录表
 自NT发布以来一直都是16个元素,是个数组
 每个元素是个结构,结构只有两个元素,都是4个字节,一个是数据的RVA,一个是数据块的长度
 导出表,
 导入表,需要那个函数,先放入到导入表
 资源,
 异常,安全,具体不详
 重定位表
 调试信息
 版权信息
 ...

第4讲 区块表或节表
1. PE文件到内存的映射,CPU从内存读取数据,要先把文件从硬盘放到内存中就叫映射
2. 执行一个PE文件时,windows并不是一开始就把整个文件读入内存的,如有的游戏有几十G是不可能都读到,
 采用的是内存映射文件类似的机制的。
3. windows装载器在装载时仅对立好虚拟地址和PE文件之间的映射关系
 仅在真正执行到某个内存面的指令这个页面才会被读到内存。这种机制使文件装入速度和文件大小沿江有关系
4. 系统装载不完全等同于内存映射文件,是有先择的,有些数据装入前被预处理,如重定位等,数据间相对位置可能发生微妙的变化
 装载器装载时前三部分不作处理,后面会变
 一般会处理,内存页的属性,节的偏移地址,节的尺寸,不进行映射的节
 详见日志——区块表和节表
 内存页的属性:
 节的偏移地址:页对齐,节是相同属性数据的组合,相同一个节所对应的内存页页属性相同
  硬盘会把页压的相当小,避免浪费
 节的尺寸:对齐不同,导致节的尺寸不同
 不进行映射的节:如.reloc节,对一些函数进行重定位。dll没有固定的地址,需要时拷贝过来,给它一个地址,重定位地址
  相同dll的同一个函数的在不同程序的地址空间地址不同
5. 第N个节表对应第N个区块,所有节的属性都定义在节表中
 节表由一系列的image_section_header结构排列而成,每个结构
 挨着PE头的,节表结构的叫数在PE头的image_nt,headers结构中
 
第5讲 区块表与区块
1. 区块表,用PEInfo(鱼自己编的)查看火狐的区块表。再用UE打开在16进制找,每个文件在磁盘的偏移地址都从0开始
2. image_nt_headers,Signature标志,
 +04h 
3. 算字节找各区块,与PEInfo进行对比
4. name,多数区块以点开头,但点不是必须的,NULL的二进制是0,一般命名都是在8个字节内
 有$的区块名,前面有$的相同名的区块载入时会合并,
 区块名要唯一,病毒感染PE文件时一般会开一个区块,还要测一个文件有没感染过
5. 包含代码的一般用.code,但用.data也可以,但最好用统一的命名规则。不能以区块名作为定位标准和依据
 还要要看目录表
6. Virtual Size,对表对应的区块的大小,区块数据没有对齐处理前的实际大小
 SizeOfRawData:区块在磁盘中所占的大小,已经被200h对齐了
 PointerToRawData,区块在磁盘中的偏移,从文件头开始  
 Characteristics:区块的属性,按位指出区块的属性,可能是多个属性or起来的
  重定位区块,共享区块,可被执行,
  
第6讲上下  区块描述,对齐值,及RVA详解
1. PE文件至少有两个块,一个代码块,一个数据块。 .rdata表只读区块,
2. 区块名称及意义
 .data,全局变量,静态变量一般放这
 .text, 放代码,是指令,有的命名为code区块
 .rsrc, 资源,模块的全部资源,图标,菜单,位图等,只读的
 .bss, 未初始化的数据,
 .tls, 线程局部存储器
 .reloc, 基址重定位
3. VC++中也可自己命名区块,用#pragma来声明
 区块一般是从obj文件开始,
4. 区块的对齐值
 磁盘尽量缩小对齐值,一般是200h, FileAlignment中为区块的长度
 区块间隙
5. x86的CPU是4KB,加载到内存对齐就是1000h,用UE加载也是,64位CPU上中8KB,即2000h
6. RVA与文件偏移的转换,相对虚拟地址Relative Virtual Address
 00400000h是虚拟出来的, 在那4GB里算,RVA就是相对于0040...得来的,不是物理地址
7. x86的区块从1000h开始,知道自己在虚拟空间的基址,再知道RAV
 UE,C+G 0x5000,可跳到5000处
8. 换算RVA和文件偏移两者
 每个区块的RVA记录在image_section_header中virtualAddress字段
9. 定义内存的位置在文件的位置

第7讲  
1. 区块中的数据仅是由于属性相同而放在一起,并不一定是一种用途,
 不同用途的数据可能被放入同一个区块中。
2. 数据目录表 Image_optional_deader32
3. 输入表,外部的数据,
 输入函数,也称导入函数,被程序调用,但代码又不在程序中,函数的代码位于相关的dll中,程序中只有函数名,dll名
4. 找出MessageBox在内存中的地址,用W32DasmV10.0打开程序
 可看到Import Module的两个模块,user32.dll,kernel32.dll
 只用了user32.dll中的MessageBoxA
 搜索这个函数,找到Call的地址
 找到最底部也没有,应是动态链入的,加入内存,
 42开头的是虚拟地址,
5. 用UE打开找到上步算出的物理地址,找到MessageBoxA.user32

第8讲 输入表的机制和定位,它的数据结构
1. 输入输出表是PE重要的概念
 输入表以iid数据组开始,每个PE链接进来的dll文件都分别对应一个iid数组结构,最后以全为0的iid结构
2. iid也是一个结构,第一个字段是联合类型
 Mage_import_descriptor struct{
 union
  Characteristics  DWORD ?
  OriginalFirstThunk  DWORD ?
 ends
 
 }
3. OriginalFirstThunk指向int的的结构
4. IDT什么时候存什么值
 image_import_by_name
 函数的序号,函数的名字
5. 动态的,输入地址表,静态的只知道函数名,不知道地址,引索的过程
 第一个数组不能改写INT,第二个要重载, 由PE装载器
 IAT,输入地址表,函数的真正的地址,加载器搜索,IAT是变量,最后就IAT有用
6. 工具 PEinfo.exe ,UE,loadPE,hello.exe
 用上面的工具验证结果,用UE看静态结果,用loadPE看动态的结果
7. loadPE找到进程右击dump full..,保存为exe,但打不开,要修复PE结构后才能打开
 用PEInfo打开,和UE查看
 虚拟地址和物理地址这时一样,找到Messagebox的地址

第9讲 导出表
1. 前上讲了输入表,这里讲导出表。动态链接库,内存只存一个动态链接库,
2. 动态库是被映射到其他应用程序的地址空间中执行的。它和应用程序可以看成是一体的,需要时复制,不需要时释放。
3. 输出表在动态链接库里,记录dll中的函数和地址,程序要dll的地址和函数的地址
5. dll有导出表
6. 导出表结构,主要是个表格,函数名,输出序数,,不提倡仅用序数索引函数方法。
 数据目录表的第一个成员指向导出表,IED结构,有些字段没有用到
 模块名真实名称,基数,导出函数的总数,以名称方式导出函数的总数,可以序号和名称导出
 指向输出函数名字的||RVA,
7. 函数名和地址的挂勾通过AddressOfNameOrdinals
8. 从序号查找函数的入口地址,定位PE文件头,从PE文件头中image_optional_header32中取出数据目录表,
 检测索引值是否大于导出表的NumberOfFunctions
9. 用函数名查找地址,要复杂些,循环找函数名,找到记下索引值
 一般情况下病毒程序就是通过函数查找入口地址,
10. 输出表结构实例分析,解剖Counter.dll,用PEinfo.exe,UltraEdit,W32DasmV10.0,该dll中只有两个函数
 先找各地址,再用WD载入dll
 地址是RVA,相对于本可执行文件的基址,用VC编译的dll起始地址都是10000000

第10讲 基址重定位详解
1. 基址重定位,重定位是程序理论上要占据这个地址,,但由于某种原因不能占,就要移到别的地方,就要基址重定位。
2. 可执行文件都有4G地址空间,但dll不是,dll没有自己的,寄生在程序的空间,
3. 程序中的那些语句进行基址重定位,凡涉及到直接寻址的指令都需要进行重定位处理
 机器码中有直接的就叫直接寻址
4. WD32的复制代码,在左点,按shift可复制
5. 间接寻址,
6. 重定位的算法为将直接寻址指令中的双字地址加上模块的实际装入地址与模块建议装入地址之差
7. 那些信息应保存在重定位表中
 建议装入的地址在PE文件阔大中已经定义,
 实际装入的地址在没有被装载时根据无从得知
 PE文件的重定位表保存的是
8. 基址重定位结构表
 image_base_relocation struc
 
 VirtualAddress是base relocaton Table的位置是一个RVA值
9. 举例:

第11讲  资源
1. 修改软件的图标,汉化,去广告,
 字符串表也是资源,工具栏,版本信息等
2. 360zip作实验对象,修改它 
3. 需要的工具,Resource Hacker, exeScope
4. 用RH打开文件
 修改菜单——编译脚本 ——保存,再复制到根目录下就可以了运行
5. 替换迅雷的图标,另存为
6. 资源结构,几乎所有PE文件中都有资源,资源的组织方式比导入导出表复杂多了
 资源类型,资源ID,资源代码页,资源
7. 每种类型的资源有多种,不同类型的资源放在不同目录里

第12讲 资源的目录结构
1. 数据目录表中的。。。第三项包含资源的RVA和大小
2. 每层有两个结构
 ID=1光标,ID=2位图,ID=4菜单
3. 以名称为名字
4. 资源目录入口结构
 从资源区块开始的偏移量
5. 一般是3层,有时更少些
6. 示例演示,工具PEinfo和UE
 有些是外星来的
用exeScope可看图标的二进制形式