http://yunpan.cn/Qntt6v3L24e86
www.hackfans.com.cn bbs.hackfans.com.cn 饭客网络安全培训基地 中国最大的网络安全培训 只做网络安全 信息安全方面的培训 宗旨:坚持  宣传  信誉  实力  回报 专业培训网络信息安全人才  成就中国网络安全边防军团 ----------------------------------------------------------------------------- Gh0st系列教程一:序 学习前提,开发环境及其常见问题,windows理论基础,免杀理论基础
     大家好 我是大家的讲师Sid 从今天开始为大家讲解源码免杀方面的知识  源码免杀涉及到的东西很多 不可能在一套教程里全部讲完所需大家有一定的基础知识,如MAD的C++,落叶的汇编,紫英的打造个人GH0ST,洪流的免杀35课,大家掌握了以上知识学习起来会轻松很多
下面是我给大家准备的课程列表:
Gh0st系列教程一:序
              学习前提,开发环境及其常见问题,windows理论基础,免杀理论基础
Gh0st系列教程二:简单分析Gh0st RAT的运行流程
              简单介绍控制端,服务端流程,网络通信基础
Gh0st系列教程三:EXE基本流程
              API知识
Gh0st系列教程四:DLL基本流程
              动态链接库基础,线程,API知识
Gh0st系列教程五:控制端简单分析
              触发机制
Gh0st系列教程六:服务端功能添加
              “占坑”,开服务器3389,显示硬盘大小,内存大小(作业:添加安装时间)
Gh0st系列教程七:控制端功能添加
              解决重复上线,增加皮肤,更新3322域名,筛选主机(作业:一个BUG的解决)
Gh0st系列教程八:免杀基础之定位
              源码预处理,定位技巧
Gh0st系列教程九:免杀之基础修改方法
              杀软分析,基本免杀思路以及实现方法
Gh0st系列教程十:免杀之突破杀软主动
              智能判断杀软(进程),替换服务(WIN文件保护知识),(作业:通过注册表判断杀软)
Gh0st系列教程十一:个性修改
              自定义释放路径
Gh0st系列教程十二:免杀之实战演示(应该会有好几部分)
              卡巴,瑞星,金山,江民,NOD32,360杀毒,等等等等
Gh0st系列教程十三:Gh0st系列教程小节
一共大概15-20课之间 涉及到源码免杀的方方面面 如果你可以耐心的跟我学完这套源码免杀课程 相信你的免杀和C++功底都会上升一节
详细的我就不讲了 因为汇编 C++ 免杀教程饭客都有 大家如果仔细看完他们的教程基础的都会明白那么下面我就挑比较重要的地方讲解一下
学习前提:基本免杀和编程功底
       开发环境:VC6.0  (下载最新SDK补丁)
       常见问题:    调试版本与发布版本(区别 各自的优缺点)
                            句柄()
                            指针()
                            缓冲区buffer
结构体
       Windows基础:    API及其反汇编中的分析
                                   Svchost服务
       免杀理论基础:     E结构
                                   句柄与基地址
       学习目标与建议:我希望大家看完我这一套教程之后能够对编程与免杀有新的认识,并逐步培养自己的自学能力。
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WindowsNT\CurrentVersion\SvcHost]
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\BITS\Parameters]
饭客网络:http://www.hackfans.com.cn/
枚举
组
ALT+M
黑客防线:在攻与防的对立中寻求统一
网站地址:WwW.HacKeR.Com.CN:一直遥遥领先
网站宗旨:一直寻求攻于防的理念,组建一个最有特色的团队。
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
                          
                          黑客防线免杀培训班
                       http://www.hacker.com.cn
                        37.免杀之pe结构深入学习1
1.看到很多会员对pe结构的了解都不是很深入。其实很多人说做免杀可以不用去学汇编不用去学pe结构等知识,那纯粹是在扯淡。学什么,我们必须从原理开始,这样我们才能成为这方面的 NO.1 。好今天就让我带领大家来深入的学习下pe结构知识吧。补足你之前的空缺。
因为pe结构这方面课程比较多,我就分几个课时来讲吧。
PE文件结构
DOS 头部结构定义
//word 与 UNSHORT 等效
[Copy to clipboard] [ - ]
CODE:
typedef struct _IMAGE_DOS_HEADER {          // DOS .EXE 头结构定义开始                 文件中的位置(偏移量)
    WORD   e_magic;                         // 魔术数字    ASCII字符MZ                            0x00000000-0x00000001
    WORD   e_cblp;                          // 文件最后页的字节数                      0x00000002-0x00000003
    WORD   e_cp;                            // 文件页数                                0x00000004-0x00000005
    WORD   e_crlc;                          // 重定位元素个数                          0x00000006-0x00000007
    WORD   e_cparhdr;                       // 以段落为单位的头部大小                  0x00000008-0x00000009
    WORD   e_minalloc;                      // 所需的最小附加段                        0x0000000A-0x0000000B
    WORD   e_maxalloc;                      // 所需的最大附加段                        0x0000000C-0x0000000D
    WORD   e_ss;                            // 初始的堆栈段(SS)相对偏移量值            0x0000000E-0x0000000F
    WORD   e_sp;                            // 初始的堆栈指针(SP)值                    0x00000010-0x00000011
    WORD   e_csum;                          // 校验和                                  0x00000012-0x00000013
    WORD   e_ip;                            // 初始的指令指针(IP)值                    0x00000014-0x00000015
    WORD   e_cs;                            // 初始的代码段(CS)相对偏移量值            0x00000016-0x00000017
    WORD   e_lfarlc;                        // 重定位表在文件中的偏移地址              0x00000018-0x00000019
    WORD   e_ovno;                          // 覆盖号                                  0x0000001A-0x0000001B
    WORD   e_res[4];                       // 保留字(一般都是为确保对齐而预留)         0x0000001C-0x00000023
    WORD   e_oemid;                         // OEM 标识符(相对于 e_oeminfo)            0x00000024-0x00000025
    WORD   e_oeminfo;                       // OEM 信息,即 e_oemid 的细节             0x00000026-0x00000027
    WORD   e_res2[10];                      // 保留字(一般都是为确保对齐而预留)        0x00000028-0x0000003B
    LONG   e_lfanew;                        // 新 exe 头在文件中的偏移地址             0x0000003C-0x0000003F
  } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;  
这就是我们的DOS stub
上述域中真正在 windows 下有用的只有 e_lfanew
接下来就是DOS STUB(DOS实模式残余程序,或一段完整的DOS程序),对Windows NT 及 windows 3.1 以上的版本,没有多大的作用。
DOS STUB一般没什么用,只是如果一旦程序运行在dos下
2.2、PE Header 实际就是一个 IMAGE_NT_HEADERS 结构。定义如下:
typedef struct _IMAGE_NT_HEADERS {
    DWORD Signature;
    IMAGE_FILE_HEADER FileHeader;
    IMAGE_OPTIONAL_HEADER OptionalHeader;
} IMAGE_NT_HEADERS, *PIMAGE_NT_HEADERS,PeHeader;
PE 头部结构
[Copy to clipboard] [ - ]
CODE:
typedef struct _IMAGE_NT_HEADERS {          //PE 头结构定义开始
  DWORD Signature;                          //签名(文件类型标志),文件中的偏移量由 DOS 头中的域 e_lfanew 来指定
  IMAGE_FILE_HEADER FileHeader;             //PE 文件头结构(占用20个字节)
  IMAGE_OPTIONAL_HEADER32 OptionalHeader;   //可选头结构(占用224个字节)
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS3  
1.Signature:一DWORD 类型,值为50h, 45h, 00h, 00h(PE\0\0)。如果IMAGE_NT_HEADERS的Signature域值等于" E\0\0",那么就是有效的PE文件。Microsoft定义了常量IMAGE_NT_SIGNATURE供我们使用,定义如下:
#define IMAGE_DOS_SIGNATURE                 0x5A4D      // MZ
#define IMAGE_OS2_SIGNATURE                 0x454E      // NE
#define IMAGE_OS2_SIGNATURE_LE              0x454C      // LE
#define IMAGE_VXD_SIGNATURE                 0x454C      // LE
#define IMAGE_NT_SIGNATURE                  0x00004550  // PE00
2.FileHeader:该结构域包含了关于PE文件物理分布的信息,比如节数目、文件执行机器等。
3.OptionalHeader:该结构域包含了关于PE文件逻辑分布的信息,虽然域名有"可选"字样,但实际上本结构总是存在的。
三、File Header(文件头)
File Header(IMAGE_FILE_HEADER)包含在PE Header(IMAGE_NT_HEADERS)里面,其结构定义:
typedef struct _IMAGE_FILE_HEADER {
    WORD Machine;
    WORD NumberOfSections;
    DWORD TimeDateStamp;
    DWORD PointerToSymbolTable;
    DWORD NumberOfSymbols;
    WORD SizeOfOptionalHeader;
    WORD Characteristics;
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
IMAGE_FILE_HEADER 结构成员含义:
1.Machine:该文件运行所要求的CPU。对于Intel平台,该值是IMAGE_FILE_MACHINE_I386 (14Ch)。我们尝试了LUEVELSMEYER的pe.txt声明的14Dh和14Eh,但Windows不能正确执行。
一些CPU识别码的定义:
Intel I386    0x14C
Intel i860    0x14D
MIPS R300    0x162
MIPS R400    0x166
DEC Alpha AXP   0x184
Power PC    0x1F0(little endian)
Motorola 68000   0x268
PA RISC    0x290(Precision Architecture)
#define IMAGE_FILE_MACHINE_UNKNOWN           0
#define IMAGE_FILE_MACHINE_I386              0x014c  // Intel 386.
#define IMAGE_FILE_MACHINE_R3000             0x0162  // MIPS little-endian, 0x160 big-endian
#define IMAGE_FILE_MACHINE_R4000             0x0166  // MIPS little-endian
#define IMAGE_FILE_MACHINE_R10000            0x0168  // MIPS little-endian
#define IMAGE_FILE_MACHINE_WCEMIPSV2         0x0169  // MIPS little-endian WCE v2
#define IMAGE_FILE_MACHINE_ALPHA             0x0184  // Alpha_AXP
#define IMAGE_FILE_MACHINE_POWERPC           0x01F0  // IBM PowerPC Little-Endian
#define IMAGE_FILE_MACHINE_SH3               0x01a2  // SH3 little-endian
#define IMAGE_FILE_MACHINE_SH3E              0x01a4  // SH3E little-endian
#define IMAGE_FILE_MACHINE_SH4               0x01a6  // SH4 little-endian
#define IMAGE_FILE_MACHINE_ARM               0x01c0  // ARM Little-Endian
#define IMAGE_FILE_MACHINE_THUMB             0x01c2
#define IMAGE_FILE_MACHINE_IA64              0x0200  // Intel 64
#define IMAGE_FILE_MACHINE_MIPS16            0x0266  // MIPS
#define IMAGE_FILE_MACHINE_MIPSFPU           0x0366  // MIPS
#define IMAGE_FILE_MACHINE_MIPSFPU16         0x0466  // MIPS
#define IMAGE_FILE_MACHINE_ALPHA64           0x0284  // ALPHA64
#define IMAGE_FILE_MACHINE_AXP64             IMAGE_FILE_MACHINE_ALPHA64
2.NumberOfSections:文件的节数目。如果我们要在文件中增加或删除一个节,就需要修改这个值。
3.TimeDateStamp:文件创建日期和时间。其格式是自从1969年12 月31 日4:00 P.M. 之后的总秒数。据我计算,0xFFFFFFFFh是136.19251950152207001522070015221 年。
4.PointerToSymbolTable:COFF 符号表格的偏移位置。此域只对COFF 除错信息有用。
5.NumberOfSymbols:COFF 符号表格中的符号个数。
6.SizeOfOptionalHeade:指示紧随本结构之后的 Optional Header(IMAGE_OPTIONAL_HEADER)结构大小,必须为有效值。
7.Chracteristics:关于本文件信息的标记。一些比较重要的性质如下:
0x0001 文件中没有重定位(relocation)
0x0002 文件是一个可执行程序exe(也就是?不是OBJ 或LIB)
0x2000 文件是dll,不是exe。
一般情况下,如果要遍历节表就得使用 NumberOfSections,其它的几个域作用不大。
四、Optional Header
4.1、RVA 及其相关概念:
RAV 代表相对虚拟地址。RVA是虚拟空间中到参考点的一段距离。RVA就是类似文件偏移量的东西。当然它是相对虚拟空间里的一个地址,而不是文件头部。举例说明,如果PE文件装入虚拟地址(VA)空间的400000h处,且进程从虚址401000h开始执行,我们可以说进程执行起始地址在RVA 1000h。每个RVA都是相对于模块的起始VA的。?址(VA)0x401000h - 基址(BA)0x400000h = RVA 0x1464h。基址(Base Address)用来描述被映射到内存中的exe或者dll的起始位置。 400000H
为什么PE文件格式要用到RVA呢? 这是为了减少PE装载器的负担。因为每个模块都有可能被重载到任何虚拟地址空间,如果让PE装载器修正每个重定位项,这肯定是个梦魇。相反,如果所有重定位项都使用RVA,那么PE装载器就不必操心那些东西了: 它只要将整个模块重定位到新的起始VA。这就象相对路径和绝对路径的概念: RVA类似相对路径,VA就象绝对路径。
在PE文件中大多数地址多是RVAs 而 RVAs只有当PE文件被PE装载器装入内存后才有意义。如果直接将文件映射到内存而不是通过PE装载器载入,则不能直接使用那些RVAs。必须先将那些RVAs转换成文件偏移量。
4.2、Optional Header 结构是 IMAGE_NT_HEADERS 中的最后成员。包含了PE文件的逻辑分布信息。该结构共有31个域,一些是很关键,另一些不太常用。其结构定义:
typedef struct _IMAGE_OPTIONAL_HEADER {
    WORD    Magic;
    BYTE    MajorLinkerVersion;
    BYTE    MinorLinkerVersion;
    DWORD   SizeOfCode;
    DWORD   SizeOfInitializedData;
    DWORD   SizeOfUninitializedData;
    DWORD   AddressOfEntryPoint;
    DWORD   BaseOfCode;
    DWORD   BaseOfData;
    DWORD   ImageBase;
    DWORD   SectionAlignment;
    DWORD   FileAlignment;
    WORD    MajorOperatingSystemVersion;
    WORD    MinorOperatingSystemVersion;
    WORD    MajorImageVersion;
    WORD    MinorImageVersion;
    WORD    MajorSubsystemVersion;
    WORD    MinorSubsystemVersion;
    DWORD   Win32VersionValue;
    DWORD   SizeOfImage;
    DWORD   SizeOfHeaders;
    DWORD   CheckSum;
    WORD    Subsystem;
    WORD    DllCharacteristics;
    DWORD   SizeOfStackReserve;
    DWORD   SizeOfStackCommit;
    DWORD   SizeOfHeapReserve;
    DWORD   SizeOfHeapCommit;
    DWORD   LoaderFlags;     DWORD   NumberOfRvaAndSizes;
    IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER, *PIMAGE_OPTIONAL_HEADER;
IMAGE_OPTIONAL_HEADER 结构成员含义:
1.Magic:用来定义 image 的状态
0x0107(IMAGE_ROM_OPTIONAL_HDR_MAGIC):一个 ROM image
0x010B(IMAGE_NT_OPTIONAL_HDR_MAGIC): 一个正常的(一般的)EXE image。大部份PE 文件都含此值。
2.MajorLinkerVersion、MinorLinkerVersion:产生此PE文件的链接器的版本。以十进制而非十六进制表示。例如2.23 版。
3.SizeOfCode:所有code section 的总和大小。大部分程序只有一个 code section,所以此域通常就是 .text section 的大小。
4.SizeOfInitializedData:所有包含初始化内容的 sections(但不包括 code section)的总和大小。似乎不包括 initialized data sections 在内。
5.SizeOfUninitializedData:所有需要PE装载器将内存地址空间赋予它但是却不占用硬盘空间的所有 sections 的大小总和。这些 sections 在程序启动时并不需要特别内容,所以导致 Uninitialized Data 这种叫法。为初始化的内容通常放在 .bss section 中。
6.AddressOfEntryPoint:这是PE文件开始执行的位置。这是一个RVA,通常会落在 .text section.此域适用于 exe 或 dll。OEP
7.BaseOfCode:一个RVA,表示程序中的 code section 从何开始。code section 通常在 data section 之前,在PE 表头之后。微软链接器所产生的exes 中,此值通常为0x1000。Borland 的TLINK32则通常指定此值为0x10000。因为预设情况下TLINK时以64k为对齐粒度的,而MS用的是4k。
8.BaseOfData:一个RVA,表示程序中的 data section 从何开始。data section 一般位于code section 和 PE 表头之后。
9.ImageBase:PE文件的优先装载地址(Base Address)。比如,如果该值是400000h,PE装载器将尝试把文件装到虚拟地址空间的400000h处。字眼"优先"表示若该地址区域已被其他模块占用,那PE装载器会选用其他空闲地址。
10.SectionAlignment:内存中节对齐的粒度。例如,如果该值是4096 (1000h),那么每节的起始地址必须是4096的倍数。若第一节从401000h开始且大小是10个字节,则下一节必定从402000h开始,即使401000h和402000h之间还有很多空间没被使用。
11.FileAlignment:文件中节对齐的粒度。例如,如果该值是(200h),,那么每节的起始地址必须是512的倍数。若第一节从文件偏移量200h开始且大小是10个字节,则下一节必定位于偏移量400h,即使偏移量512和1024之间还有很多空间没被使用或定义。预设值就是0x200h。
12.MajorOperatingSystemVersion/MinorOperatingSystemVersion:使用此可执行程序的操作系统的最小版本。WIN32程序的这两个域通常指定为1.0。
13.MajorSubsystemVersion/MinorSubsystemVersion:WIN32子系统版本。若PE文件是专门为WIN32设计的,该子系统版本必定是4.0否则对话框不会有3维立体感。
14.MajorImageVersion/MinorImageVersion:使用者自定义的域,允许你拥有不同版本的exe或dll。可以利用链接器的 /VERSION 选项设定其值。例如:LINK /VERSION:2.0 myobj.obj。
15.Reserved1:似乎总是0。
16.SizeOfImage:内存中整个PE映像体的尺寸。它是所有头和节经过节对齐处理后的大小。也就是从image base 开始,直到最后一个 section为止。最后一个section 的尾端必需是SectionAlignment 的倍数。
  
17.SizeOfHeaders:所有头 + 节表的大小,也就等于文件尺寸减去文件中所有节的尺寸。可以以此值作为PE文件第一节的文件偏移量。
18.CheckSum:此程序的一个CRC 校验和。PE中此域通常被忽略并被设为0。然而,所有的driver DLLs、所有在开机时载入的DLLs、以及server DLLs 都必须有一个合法的 CheckSum。其演算法可以在IMAGEHLP.DLL中获得。IMAGEHLP.DLL 的代码可以在WIN32 SDK中找到。
19.Subsystem:用来识别PE文件属于哪个子系统。对于大多数Win32程序,只有两类值: Windows GUI 和 Windows CUI (控制台)。WINNT.h中定义如下:
#define IMAGE_SUBSYSTEM_UNKNOWN          0  Unknown subsystem.
#define IMAGE_SUBSYSTEM_NATIVE           1  不需要子系?(例如驱动程序)
#define IMAGE_SUBSYSTEM_WINDOWS_GUI      2  在Windows GUI 子系统中运行
#define IMAGE_SUBSYSTEM_WINDOWS_CUI      3  在Windows 字符模式子系统中运行(也就是console 应用程序)
#define IMAGE_SUBSYSTEM_OS2_CUI          5  在OS/2 字符模式子系统中运行(也就是OS/2 1.x 应用程序)
#define IMAGE_SUBSYSTEM_POSIX_CUI        7  在Posix 字符模式子系统中运行
#define IMAGE_SUBSYSTEM_NATIVE_WINDOWS   8  一个Win9x驱动
#define IMAGE_SUBSYSTEM_WINDOWS_CE_GUI   9  在Win CE 子系统中运行
20.DllCharacteristics:一组标志位,用来指出dll的初始化函数(例如 DllMain)在什么环境下被调用。这个值总是0,但是操作系统会在四种情况发生式调用dll的初始化函数。此值的四个值的意义如下:
0x0001:当DLL被载入一个进程的地址空间时
0x0002:当一个线程结束时
0x0004:但一个线程开始时
0x0008:当DLL退出时
0x2000:一个WDM驱动
21.SizeOfStackReserve:线程初始堆栈的保留大小。然而并不是所有的这些内存都被系统指定。此值预设为0x100000(1MB)。如果你的程序中调用CreateThread 并指定其堆栈大小为0,获得的线程就有一个与此值相同大小的堆栈。
22.SizeOfStackCommit:一开始就被指定给执行线程初始堆栈的内存数量。微软的链接器预设此值为0x1000(一个page),Borland 的TLINK32把它设为0x2000(两个page)。
23.SizeOfHeapReserve:保留给最初的进程堆(process heap)的虚拟内存数量。这个堆的句柄可以利用GetProcessHeap 获得。并不是所有的这些内存都被指定。
24.SizeOfHeapCommit:一开始就被指定给进程堆(process heap)的内存数量。此值预设为0x1000个字节(位元组)。
25.LoaderFlags:Debug用。可能作用:
a.在开始这个进程之前引发一个中断?
b.在进程被载入之后引发一个除错器执行?
26.NumberOfRvaAndSizes:在DataDirectory(下一个域)数组的成员结构个数。目前的工具总是把此值设为16。
27.DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]:一个IMAGE_DATA_DIRECTORY 结构数组。每个结构给出一个重要数据结构的RVA。数组的第一个元素代表 Exported Function Table(如果有的话)的地址和大小,第二个元素代表Imported Function Table 的地址和大小,依此类推。下面是其顺序的完整列表:
// Directory Entries
#define IMAGE_DIRECTORY_ENTRY_EXPORT   0  // Export Directory
#define IMAGE_DIRECTORY_ENTRY_IMPORT   1  // Import Directory
#define IMAGE_DIRECTORY_ENTRY_RESOURCE   2  // Resource Directory
#define IMAGE_DIRECTORY_ENTRY_EXCEPTION  3  // Exception Directory
#define IMAGE_DIRECTORY_ENTRY_SECURITY   4  // Security Directory
#define IMAGE_DIRECTORY_ENTRY_BASERELOC  5  // Base Relocation Table
#define IMAGE_DIRECTORY_ENTRY_DEBUG   6  // Debug Directory
#define IMAGE_DIRECTORY_ENTRY_COPYRIGHT  7  // Description String
#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR  8  // Machine Value (MIPS GP)
#define IMAGE_DIRECTORY_ENTRY_TLS    9  // TLS Directory
#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG  10 // Load Configuration Directory
#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT  11 // Bound Import Directory in headers
#define IMAGE_DIRECTORY_ENTRY_IAT    12 // Import Address Table
96/112   8  Export Table Export Table address and size.
104/120  8  Import Table Import Table address and size
112/128  8  Resource Table Resource Table address and size.
120/136  8  Exception Table Exception Table address and size.
128/144  8  Certificate Table Attribute Certificate Table address and size.
136/152  8  Base Relocation Table Base Relocation Table address and size.
144/160  8  Debug Debug data starting address and size.
152/168  8  Architecture Architecture-specific data address and size.
160/176  8  Global Ptr Relative virtual address of the value to be stored in the global pointer register. Size member of this structure must be set to 0.
168/184  8  TLS Table Thread Local Storage (TLS) Table address and size.
176/192  8  Load Config Table Load Configuration Table address and size.
184/200  8  Bound Import Bound Import Table address and size.
192/208  8  IAT Import Address Table address and size.
200/216  8  Delay Import Descriptor Address and size of the Delay Import Descriptor.
208/224  8  COM+ Runtime Header COM+ Runtime Header address and size
216/232  8  Reserved
                    38.免杀之pe结构深入学习(2)
                      黑客防线免杀培训班
                     Http://www.hacker.com.cn
       上节课,我们已经学习了DOS MZ header 和 PE header结构,Windows操作系统是大
部分都是用c写的,所以Windows的一些内核数据结构非常多。    那么我们今天呢。来学习
下节表结构和输入表结构。因为大家很多基础比较差,所以如果一节课讲的比较多的话,怕
大家吸收不了,到头来还是什么也做不了。所以我们分开来讲解吧。
       节表结构。节表结构位于PE Header结构之后。节表结构后面就是各个节。我们最
主要是要了解,什么是节表?什么是节?以及他们之间的关系。但是我不知道大家是否熟悉
我们的pe文件是如何映射到内存的。这里我给大家找两个图片。大家可以看下。如图1
接下来我们来看下节表结构。
typedef struct _IMAGE_SECTION_HEADER {
  BYTE   Name[IMAGE_SIZEOF_SHORT_NAME]; // 节表名称,如".text"
  union {
  DWORD PhysicalAddress;   // 物理地址
  DWORD VirtualSize;   // 真实长度
  } Misc;
  DWORD VirtualAddress;   // RVA
  DWORD SizeOfRawData;   // 物理长度
  DWORD PointerToRawData; // 节基于文件的偏移量
  DWORD PointerToRelocations; // 重定位的偏移
  DWORD PointerToLinenumbers; // 行号表的偏移
  WORD   NumberOfRelocations; // 重定位项数目
  WORD   NumberOfLinenumbers; // 行号表的数目
  DWORD Characteristics;   // 节属性
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
ASCII
Udicode
PE\0\0 0x00004550
intel CPU采用的是Little-endian
50 45 00 00
D0 00 00 00
Big - endian
                    
pe装载器的装载过程:
1. 读取 IMAGE_FILE_HEADER 的 NumberOfSections域,知道文件的节数目。
2. 定位节表。
3. 遍历整个结构数组检查各成员值。
4. 对于每个结构,读取PointerToRawData域值并定位到该文件偏移量。然后再读取SizeOfRawData
域值来决定映射内存的字节数。将VirtualAddress域值加上ImageBase域值等于节起始的虚拟地址。
然后就准备把节映射进内存,并根据Characteristics域值设置属性。遍历整个数组,直至所有节都已处理完毕。
导入表(也常是大家所说的输入表)
    导入函数就是被程序调用但执行代码不再程序中的函数。这些函数位于一个或者多个DLL
中。
   pe装载器是如何得到输入表的地址呢?我们并不是通过各个节名就可以得到各个结构的偏移,因为节是通过各个属性来定义  ?
什么意思?就是比如我们的数据拥有可读可写等属性,则归纳为一节。一个节中的数据仅仅是属性相同,并不代表他们的用途
相同, 比如导入表和导出表等有可能和只读常量放在一个节中,因为他们用途是不相同。所以节名只是一个简单的定义。标识而已
让我们更加清楚,一般连接器连接的时候. MS编译器编译的程序一般是一.text开头的。而borland公司的编译器编译的程序代码段
的是以.code开头的。          
它是 Optional_Header的DataDirectory成员的结构。
typedef struct _IMAGE_DATA_DIRECTORY {
    DWORD VirtualAddress;
    DWORD Size;
} IMAGE_DATA_DIRECTORY,*PIMAGE_DATA_DIRECTORY;
CALL 函数地址1
函数地址1   jmp dword ptr [内存地址]
      
导入表的结构是什么呢?
typedef struct _IMAGE_IMPORT_DESCRIPTOR {
    _ANONYMOUS_UNION union {
        //DWORD Characteristics;
        DWORD OriginalFirstThunk;//指向IMAGE_THUNK_DATA的一个指针
    } DUMMYUNIONNAME;
    DWORD TimeDateStamp;
    DWORD ForwarderChain;
    DWORD Name; //动态链接库的Name
    DWORD FirstThunk; //指向IMAGE_THUNK_DATA的一个指针
} IMAGE_IMPORT_DESCRIPTOR,*PIMAGE_IMPORT_DESCRIPTOR;
这里有两种导入方法,一种是以序号导入,一种是以字符串类型的函数名来导入的。
我们的每一个IMAGE_THUNK_DATA都是定义一个导入函数的信息。
他的结构定义
typedef struct _IMAGE_THUNK_DATA32 {
    union {
        DWORD ForwarderString;  //指向 IMAGE_IMPORT_BY_NAME  结构
        DWORD Function;
        DWORD Ordinal;
        DWORD AddressOfData;
    } u1;
} IMAGE_THUNK_DATA32,*PIMAGE_THUNK_DATA32;
typedef struct _IMAGE_IMPORT_BY_NAME {
    WORD Hint; //函数的序号
    BYTE Name[1];         //函数名
} IMAGE_IMPORT_BY_NAME,*PIMAGE_IMPORT_BY_NAME;
CALL 内存地址1
jmp DWORD ptr [内存地址]
                    
PE相关名词解释如下:
1.入口点(Entry Point)
程序在执行时的第一行代码的地址就是这个值。
2.文件偏移地址(File Offset)
PE文件在磁盘上储存时,各数据的地址称文件偏移地址(File Offset)。
用十六进制工具(例如Hex Workshop、WinHex等)打开文件显示的地址就是文件偏移地址。
3.虚拟地址(Virtual Address,VA)
由于Windows程序是运行在386保护模式下,在保护模式下,
程序访问存储器所使用的逻辑地址称为虚拟地址(Virual Address,VA)。
与实地址模式下的分段地址类似,虚拟地址也可写成"段:偏移量"的形式,这里的段是指段选择器。
4.基地址(ImageBase)
文件执行时将被映像到指定内存地址中,这个初始内存地址称为基址(ImageBase)。
在Windows NT中,缺省的值是10000h;对于DLLs,缺省值为400000h。在Windows 9x中,
10000h不能用来装入32位的执行文件,因为该地址处于所有进程共享的线性地址区域,
因此Microsoft将Win32可执行文件的缺省基地址改变为400000h。
5.相对虚拟地址
相对虚拟地址(Relative Virual Address,RVA)表示此段代码在内存中相对于基地址的偏移
。即:相对虚拟地址(RVA)=虚拟地址(VA)-基址(ImageBase)。
5C200000   RVA
00 00 20 5C
0000205C -输入表区段起始地址 00002000 = 5c  相对于输入表区段起始地址的偏移
相对于输入表区段起始地址的偏移 + 输入表区段文件偏移的起始地址 =文件的偏移地址
       5c                     +    600   =65c
                      
                      CALL 内存地址1   MessageBox
    内存地址1         jmp dword [内存地址]
   // FirstThunk  这个成员不能修改,操作系统需要修改这个地址...............
                    黑客防线
              [第39课]免杀之PE结构深入学习(3)
              HTTP://WWW.HACKER.COM.CN
typedef struct _IMAGE_EXPORT_DIRECTORY {
    DWORD   Characteristics; //标志的结合
    DWORD   TimeDateStamp; //文件的创建时间
    WORD    MajorVersion;//米什么用处,总是设置为0
    WORD    MinorVersion;//米什么用,总是设置为0
    DWORD   Name; //模块名称的RVA
    DWORD   Base;//被本模块引出的函数的起始序数 1
    
    DWORD   NumberOfFunctions; //模块引出的函数的总数/符号的总数
    DWORD   NumberOfNames; //模块中一个指向所有函数名的RVA数组,本成员旧时指向的所有函数名RVA数组
    DWORD   AddressOfFunctions;     // RVA from base of image
    DWORD   AddressOfNames;         // RVA from base of image
    DWORD   AddressOfNameOrdinals;  // RVA from base of image
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;
http://yunpan.cn/QbxmxJzfP5QSH |