精华内容
下载资源
问答
  • PAGE PAGE 1 Win10系统开机提示windows似乎未正确加载的具体解决方法 Win10系统开机提示windows似乎未正确加载该如何解决这个问题下面就给大家分享Win10系统开机提示windows似乎未正确加载的具体解决方法 解决方法 1...
  • 重启即可正常启动了,如下图所示 相关文章教程推荐:windows教程 以上就是win10电脑提示windows似乎未正确加载的详细内容,更多请关注ki4网其它相关文章!win7系统无法搜索新更新_网站服务器运行维护 win7系统无法...

    win10系统提示无法与主DNS服务器通信_网站服务器运行维护

    win10系统提示无法与主DNS服务器通信的解决方法是:1、首先,打开控制面板,进入【更改适配器设置】;2、然后,打开wlan属性界面,进入高级TCP/IP设置界面;3、最后,删除DNS服务器地址即可。

    ERJfYz.jpg

    在出现弹窗的界面选择查看高级修复选项,如下图所示

    bAnEF3.png

    进入高级选项,我们点击启动修复,如下图所示

    NnMBBz.png

    (推荐学习:java入门教程)

    修复完成,按F8进入启动选择界面,我们先选择最后一次正确配置,如下图所示

    Fzyqim.png

    进入最好,如果没进入,我们重启选择安全模式,如下图所示win10快速启用要不要开_网站服务器运行维护

    Windows 10的快速启动,只是在开机时关掉了一些自检过程,其实在使用中对开机速度没有太大的提升,没有必要打开。

    bABbua.png

    上面两个选择肯定一个可以进入系统界面,然后win+R调出运行,输入services.msc点击确定按钮,如下图所示

    IviERr.png

    进入服务列表,找到Windows update选项,如下图所示

    zyMbmq.png

    双击此服务,将启动类型改为自动,点击状态的启动按钮,点击应用按钮,重启即可正常启动了,如下图所示

    zUZnu2.png

    相关文章教程推荐:windows教程

    展开全文
  • windows PE文件结构及其加载机制

    万次阅读 多人点赞 2016-04-29 15:00:50
    1. 概述PE文件的全称是Portable Executable,意为可移植...它是1993年Windows NT系统引入的新可执行文件格式,到现在已经经过20多年了。虽然使用PE作为可执行文件格式的Windows操作系统已经更换了很多版本,其结构的变

    1. 概述

    PE文件的全称是Portable Executable,意为可移植的可执行的文件,常见的EXE、DLL、OCX、SYS、COM都是PE文件,PE文件是微软Windows操作系统上的程序文件(可能是间接被执行,如DLL)。它是1993年Windows NT系统引入的新可执行文件格式,到现在已经经过20多年了。虽然使用PE作为可执行文件格式的Windows操作系统已经更换了很多版本,其结构的变化、新特性的增加、文件格式的转换,以及内核的重新定位等,都发生了翻天覆地的变化,硬件架构也从16位发展到现在的64位架构,而这些变化对PE格式的影响却不大。由于PE格式有较好的数据组织方式和数据管理算法,面对如此多的变化却能保持其设计的优雅。

    众所周知,Windows NT继承自VAX® VMS®和UNIX。Windows NT的许多创建者在到Microsoft之前都曾为这些平台设计和编写程序。当他们设计Windows NT时,很自然会使用以前写过的和测试过的工具以尽快开始他们的新项目。这些工具产生的和使用的可执行文件和目标模块的格式被称为COFF(Common Object File Format的首字母,通用目标文件格式)。Microsoft编译器生成的OBJ文件就使用COFF格式。

    PE文件之所以被称为“可移植”是因为Windows NT在各种平台(x86、MIPS®、Alpha等等)上的所有实现都使用同样的可执行文件格式。当然,像CPU指令的二进制编码之类的内容会有所不同。重要的是操作系统加载器和编程工具不需要针对遇到的每种新的CPU再完全重写。Windows NT及其以后版本,Windows 95及其以后版本和Windows CE一直到现在的win10都使用了这个相同的格式,所以说在很大程度上,这个目的达到了。对于64位的Windows,PE格式只是进行了很少的修改。这种新的格式被叫做PE32+。没有加入新的域,只有一个域被去除。剩下的改变只是一些域从32位扩展到了64位。在这种情况下,你能写出和32位与64位PE文件都能一起工作的代码。对于C++代码,Windows头文件的能力使这些改变很不明显。EXE和DLL文件之间的不同完全是语义上的。它们都使用完全相同的PE格式。仅有的区别是用了一个单个的位来指出这个文件应该被作为EXE还是一个DLL。甚至DLL文件的扩展名也是不固定的,一些具有完全不同的扩展名的文件也是DLL,比如.OCX控件和控制面板程序(.CPL文件)。

    PE文件格式主要来自于UNIX操作系统所通用的COFF规范,同时为了保证与旧版本MS-DOS及Windows操作系统的兼容,也保留了MS-DOS中那熟悉的MZ头部。PE格式被公开在WINNT.H头文件中(非常零散)。在WINNT.H文件的中间有一个“Image Format”节。这个节以MS-DOS MZ格式和PE格式开头,后面才是新的PE格式。WINNT.H提供了PE文件使用的原始数据结构的定义。

    2. PE文件分析相关的概念

    在详细了解PE文件结构之前,我们需要先了解几个基本的概念。理解这些概念有利于我们更好地把握和分析PE中的数据结构。

    2.1. 地址

    PE中涉及的地址有四类,他们分别是:

    • 虚拟内存地址(VA)
    • 相对虚拟地址(RVA)
    • 文件偏移地址(FOA)
    • 特殊地址

    2.1.1. 虚拟地址(Virtual Addresses)

    由于Windows NT推出时程序是运行在保护模式下,用户的PE文件被操作系统加载进内存后,PE对应的进程支配了自己独立的4GB虚拟空间。在这个空间中定位的地址称为虚拟内存地址(Virual Address,VA)。到了现在系统运行在X64架构的硬件上(长模式),内存访问可以采用线性地址的方式,同时可访问的内存也突破了4GB的限制,但是独立的进程拥有独立的虚拟地址空间的内存管理机制还在沿用。在PE中,进程本身的VA被解释为:进程的基地址 + 相对虚拟内存地址。

    2.1.2. 相对虚拟地址(Relative Virtual Addresses)

    PE格式大量地使用所谓的RVA(相对虚拟地址)。一个RVA,亦即一个“Relative Virtual Addresses(相对虚拟地址)”,是在你不知道基地址时,被用来描述一个内存地址的。它是需要加上基地址才能获得线性地址的数值。基地址就是PE映象文件被装入内存的地址,并且可能会随着一次又一次的调用而变化。

    在一个可执行文件中,有许多在内存中的地址必须被指定的位置。例如,当引用一个全局变量时就必须指定它的地址。PE文件可以被加载到进程地址空间的任何位置。虽然它们有一个首选加载地址,但你不能依赖于可执行文件真的会被加载到那个位置。因为这个原因,指定一个地址而不依赖于可执行文件的加载位置就很重要。

    为了消除PE文件中对内存地址的硬编码,于是产生了RVA。一个RVA是在内存中相对于PE文件被加载的地址的一个偏移。例如,如果一个EXE文件被加载到地址0x400000,它的代码节位于地址0x401000处。那么代码节的RVA就是:

    (目标地址) 0x401000 - (加载地址)0x400000 = (RVA)0x1000.

    因为PE-文件中的各部分(各节)不需要像已载入的映象文件那样对齐,事情变得复杂起来。例如,文件中的各节常按照512(十六进制的0x200)字节边界对齐,而已载入的映象文件则可能按照4096(十六进制的0x1000)字节边界对齐。参见下面的“SectionAlignment(节对齐)”和“FileAlignment(文件对齐)”。

    因此,为了在PE文件中找到一个特定RVA地址的信息,你得按照文件已被载入时的那样来计算偏移量,但要按照文件的偏移量来跳过。

    试举一例,假若你已知道执行开始处位于RVA 0x1560地址处,并且想从那里开始的代码处反汇编。为了从文件中找到这个地址,你得先查明在RAM(内存)中各节是按照4096字节对齐的,并且“.code”节是从RVA 0x1000地址处开始,有16384字节长;然后你才知道RVA 0x1560地址位于此节的偏移量0x560处。你还要查明在文件中那节是按512字节边界对齐,且“.code”节在文件中从偏移量0x800处开始,然后你就知道在文件中代码的执行开始处就在0x800+0x560=0xd60字节处。

    然后你反汇编它并发现访问一个变量的线性地址位于0x1051d0处。二进制文件的线性地址在装入时将被重定位,并常被假定使用的是优先载入地址。因为你已查明优先载入地址为0x100000,因此我们可开始处理RVA 0x51d0了。因数据节开始于RVA 0x5000处,且有2048字节长,所以它处于数据节中。又因数据节在文件中开始于偏移量0x4800处,所以该变量就可以在文件中的0x4800+0x51d0-0x5000=0x49d0处找到。

    2.1.3. 文件偏移地址

    文件偏移地址(File Offset Address,FOA)和内存无关,他是指某个位置距离文件头的偏移。

    2.1.4. 特殊地址

    在PE结构中海油一种特殊地址,其计算方法并不是从文件头算起,也不是从内存的某个位置的基地址算起,而是从特定的位置算起。这个地址在PE结构中很少见,如:在资源表里就出现过这样的地址。

    2.2. 节(Section)

    无论是结构化程序设计,还是面向对象程序设计,都是倡导程序和数据的独立性,因此,程序中的代码和数据通通常是分开存放的。为了保证程序执行的安全,保证内核的稳定,Windows操作系统通常对不同用途的数据设置不同的权限。比如:代码段中的字节码在程序运行的时候,一般不允许用户进行修改,数据段则允许在程序运行过程中读和写,常量只能读等。Windows操作系统在加载可执行程序时,会为这些具有不同属性的数据分别分配标记有不同属性的页面(当然,相同属性的数据可能会被放到同一个页面),以确保程序运行时的安全。正式基于这个原因,PE中才出现了所谓的节的概念。

    节就是存放不同类型数据(比如代码、数据、常量、资源等)的地方,不同的节具有不同的访问权限。节是PE文件中存放代码和数据的基本单元。例如:一个目标文件中的所有代码可以组合成单个节,或者每个函数独占一格节(如果编译器允许)。增加节的数目会增加文件的开销,但是链接器在链接代码的时候就会有更大的选择余地。一个节中的所有原始数据必须被加载到连续的内存空间中。

    从操作系统加载角度来看,节是相同属性数据的组合。与数据目录不同的是,尽管有些数据类型不同,分别属于不同的数据目录,但是由于其访问属性相同,便被归类到同一个节中。这个节最终可能会占用一个或多个页面;但无论有多少个,所有相关页面均会被赋予相同的页面属性。这些属性包括只读、只写、可读、可写等。

    Windows操作系统在装载PE文件时会对相同和不同类型的节数据执行抛弃、合并、新增、复制等操作。这些不同的操作交叉组合导致了内存中的节和文件中的节会出现很大的不同。例如:”.data”的数据在磁盘中不存在,但是在内存中存在,而”.reloc”重定位表数据却恰恰相反。

    2.3. 对齐(Alignment)

    对齐这个概念并非只在PE文件中出现,许多文件格式都会有对齐的要求。有的对齐是为了美观,有的对齐则是为了效率。PE中规定了三类的对齐:数据在内存中的对齐、数据在文件中的对齐、资源文件中资源数据的对齐。

    2.3.1. 内存对齐(SectionAligment)

    PE 文件头里边的SectionAligment 定义了内存中区块的对齐值。由于Windows操作系统对内存属性的设置以页为单位,所以通常情况下,PE 文件被映射到内存中时,节在内存中的对齐单位必须至少是一个页的大小。对于32位的windows操作系统来说,这个值是4KB(1000h),而对64位操作系统来说,这个值就是8KB(2000h)。

    2.3.2. 文件对齐(FileAligment)

    PE 文件头里边的FileAligment 定义了磁盘区块的对齐值。每一个区块从对齐值的倍数的偏移位置开始存放。而区块的实际代码或数据的大小不一定刚好是这么多,所以在多余的地方一般以00h 来填充,这就是区块间的间隙。为了提高磁盘利用率,对齐单位通常小于内存,以一个物理扇区的大小作为对齐粒度,512字节,200h。

    2.3.3. 资源数据对齐

    资源字节码部分一般要求以双字(4字节)方式对齐。

    3. PE文件结构

    PE 文件格式被组织为一个线性的数据流,它由一个MS-DOS 头部开始,接着是一个是模式的程序残余以及一个PE 文件标志,这之后紧接着PE文件头和可选头部。这些之后是所有的段头部,段头部之后跟随着所有的段实体。文件的结束处是一些其它的区域,其中是一些混杂的信息,包括重分配信息、符号表信息、行号信息以及字串表数据。

    如下图所示,PE文件结构被划分为四大部份,包括:DOS部分、PE头、节表、和节数据。

    这里写图片描述

    PE文件至少包含两个段(节),即数据段和代码段。Windows的应用程序PE文件格式有11个预定义段,这是对Windows应用程序所通用的。例如: .text 、.bss 、.rdata 、.data 、.pdata 和.debug 段,这些段并不是都是必须的,当然,也可以根据需要定义更多的段(比如一些加壳程序)。

    在应用程序中最常出现的段有以下6种:

    • 执行代码段,通常 .text (Microsoft)或 CODE(Borland)命名;
    • 数据段,通常以 .data
      、.rdata 或 .bss(Microsoft)、DATA(Borland)命名;
    • 资源段,通常以 .rsrc命名;
    • 导出表,通常以 .edata命名;
    • 导入表,通常以 .idata命名;
    • 调试信息段,通常以 .debug命名;

    PE文件一个方便的特点是磁盘上的数据结构和加载到内存中的数据结构是相同的。加载一个可执行文件到内存中 (例如,通过调用LoadLibrary)主要就是映射一个PE文件中的几个确定的区域到地址空间中。因此,一个数据结构比如IMAGE_NT_HEADERS (稍后我们会研究到)在磁盘上和在内存中是一样的。关键的一点是如果你知道怎么在一个PE文件中找到一些东西,当这个PE文件被加载到内存中后你几乎能找到相同的信息。

    要注意到PE文件并不仅仅是被映射到内存中作为一个内存映射文件。代替的,Windows加载器分析这个PE文件并决定映射这个文件的哪些部分。当映射到内存中时文件中偏移位置较高的数据映射到较高的内存地址处。一个项目在磁盘文件中的偏移也许不同于它被加载到内存中时的偏移。然而,所有被表现出来的信息都允许你进行从磁盘文件偏移到内存偏移的转换 (参见下图)。

    Windows装载器在装载的时候仅仅建立好虚拟地址和PE文件之间的映射关系,只有真正执行到某个内存页中的指令或访问某一页中的数据时,这个页才会被从磁盘提交到物理内存。但因为装载可执行文件时,有些数据在装入前会被预先处理(如需要重定位的代码),装入以后,数据之间的相对位置也可能发生改变。因此,一个节的偏移和大小在装入内存前后可能是完全不同的。

    这里写图片描述

    这里写图片描述

    4. PE文件结构分析

    4.1. PE文件准备

    为了对PE文件结构进行更好的分析,我们首先准备一个例子,这次我们通过在WIN10 X64环境下使用VS2015编译生成的一个X64架构的release程序来进行分析。这个例子是一个在WIN10 X64下通过TLS实现反调试的小程序。程序清单如下:

    #include <Windows.h>
    #include <tchar.h>
    
    #pragma comment(lib,"ntdll.lib")
    
    extern "C" NTSTATUS NTAPI NtQueryInformationProcess(HANDLE hProcess, ULONG InfoClass, PVOID Buffer, ULONG Length, PULONG ReturnLength);
    
    #define NtCurrentProcess() (HANDLE)-1
    
    
    void NTAPI __stdcall TLS_CALLBACK(PVOID DllHandle, DWORD Reason, PVOID Reserved)
    {
        if (IsDebuggerPresent())
        {
            MessageBoxA(NULL, "TLS_CALLBACK: Debugger Detected!", "TLS Callback", MB_OK);
    //      ExitProcess(1);
        }
        else
        {
            MessageBoxA(NULL, "TLS_CALLBACK: No Debugger Present!...", "TLS Callback", MB_OK);
        }
    }
    
    void NTAPI __stdcall TLS_CALLBACK_2(PVOID DllHandle, DWORD Reason, PVOID Reserved)
    {
        HANDLE DebugPort = NULL;
        if (!NtQueryInformationProcess(
            NtCurrentProcess(),
            7,          // ProcessDebugPort
            &DebugPort, // If debugger is present, it will be set to -1 | Otherwise, it is set to NULL
            sizeof(HANDLE),
            NULL))
        {
            if (DebugPort)
            {
                MessageBoxA(NULL, "TLS_CALLBACK2: Debugger detected!", "TLS callback", MB_ICONSTOP);
            }
    
            else
            {
                MessageBoxA(NULL, "TLS_CALLBACK2: No debugger detected", "TLS callback", MB_ICONINFORMATION);
            }
        }
    }
    
    //linker spec通知链接器PE文件要创建TLS目录,注意X86和X64的区别
    #ifdef _M_IX86
    #pragma comment (linker, "/INCLUDE:__tls_used")
    #pragma comment (linker, "/INCLUDE:__tls_callback")
    #else
    #pragma comment (linker, "/INCLUDE:_tls_used")
    #pragma comment (linker, "/INCLUDE:_tls_callback")
    #endif
    //创建TLS段
    EXTERN_C
    #ifdef _M_X64
    #pragma const_seg (".CRT$XLB")
    const
    #else
    #pragma data_seg (".CRT$XLB")
    #endif
    //end linker
    
    //tls import定义多个回调函数
    PIMAGE_TLS_CALLBACK _tls_callback[] = { TLS_CALLBACK, TLS_CALLBACK_2, 0 };
    #pragma data_seg ()
    #pragma const_seg ()
    //end 
    
    int APIENTRY _tWinMain(HINSTANCE hInstance,
        HINSTANCE hPrevInstance,
        LPTSTR    lpCmdLine,
        int       nCmdShow)
    {
    
        MessageBoxA(NULL, "Hello Wolrd!...:)", "main()", MB_OK);
        return 0;
    
    }

    程序是一个简单的windows小程序,通过使用TLS回调函数来检测调试器的存在,并弹出窗口提示检测到的状态,主程序只是一个简单的hello world消息窗。程序中涉及到PE文件中几个重要的节。程序通过在WIN10 X64环境下使用VS2015编译生成的一个X64架构的release版本tlstest.exe,程序大小为12.0 KB (12,288 字节)。

    这里写图片描述

    4.2. MS-DOS 文件头

    在 image 文件的最开始处就是 DOS 文件头,DOS 文件头包含了 DOS stub 小程序。在 WinNT.h 文件里定义了一个结构来描述 DOS 文件头。

    typedef struct _IMAGE_DOS_HEADER {      // DOS .EXE header
        WORD   e_magic;             // 00000000  4D 5A,Magic number
        WORD   e_cblp;          // 00000002  90 00,Bytes on last page of file
        WORD   e_cp;             // 00000004  03 00,Pages in file
        WORD   e_crlc;            // 00000006  00 00,Relocations
        WORD   e_cparhdr;           // 00000008  04 00,Size of header in paragraphs
        WORD   e_minalloc;        // 0000000A  00 00,Minimum extra paragraphs needed
        WORD   e_maxalloc;          // 0000000C  FF FF,Maximum extra paragraphs needed
        WORD   e_ss;                // 0000000E  00 00,Initial (relative) SS value
        WORD   e_sp;             // 00000010  B8 00,Initial SP value
        WORD   e_csum;          // 00000012  00 00,Checksum
        WORD   e_ip;                // 00000014  00 00,Initial IP value
        WORD   e_cs;                // 00000016  00 00,Initial (relative) CS value
        WORD   e_lfarlc;        // 00000018  40 00,File address of relocation table
        WORD   e_ovno;           // 0000001A  00 00,Overlay number
    WORD   e_res[4];            // 0000001C  00 00 00 00,Reserved words
            // 00000020  00 00 00 00
        WORD   e_oemid;             // 00000024  00 00,OEM identifier (for e_oeminfo)
        WORD   e_oeminfo;           // 00000026  00 00,OEM information; e_oemid specific
    WORD   e_res2[10];          // 00000028  00 00 00 00,Reserved words
            // 0000002C  00 00 00 00
            // 00000030  00 00 00 00
            // 00000034  00 00 00 00
            // 00000038  00 00 00 00
        LONG    e_lfanew;           // 0000003C  F8 00 00 00,File address of new exe header
    } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;

    这个结构名叫 IMAGE_DOS_HEADER 共 64 bytes,以 IMAGE_DOS_HEADER 结构描述的 DOS 文件头结构从 image 的 0x00000000 - 0x0000003F(64 bytes)

    结构的 e_magic 域是 DOS 头文件签名,它的值是:0x5A4D 代表字符 MZ,它在 WinNT.h 里定义为:

    #define IMAGE_DOS_SIGNATURE                 0x5A4D      // MZ

    e_lfanew 域是一个 offset 值,它指出 NT 文件头的位置。

    下面看看tlstest.exe 的 DOS 文件头内容:

    这里写图片描述

    绿色部分是 DOS 签名,蓝色部分是 PE header offset(NT 文件头)值,也就是 IMAGE_DOS_HEADER 里的 e_lfanew 值,表明 NT 文件头在 image 文件的 0x000000F8 处。

    4.2.1. DOS stub 程序

    在 DOS 文件头下面紧跟着一小段 stub 程序,其内容随着链接时使用的链接器不同而不同,在PE中并没有与之对应的相关结构。在本例中从 0x00000040 - 0x0000004D 共 14 bytes是代码,其后是显示数据等内容,这段 dos stub 程序是这样的:

    00000040  0E                push cs
    00000041  1F                pop ds
    00000042  BA0E00       mov dx,0xe
    00000045  B409            mov ah,0x9
    00000047  CD21           int 0x21
    00000049  B8014C       mov ax,0x4c01
    0000004C  CD21          int 0x21

    当 windows 的 PE 文件放在 DOS 上执行时,将会执行这一段 DOS stub 程序,作用是打印信息:This program cannot be run in DOS mode…. 然后调用 int 21 来终止执行返回到 DOS,看看它是怎样运行的:

    00000014  00 00      // ip
    00000016  00 00      // cs
    00000018  40 00      // e_lfarlc

    这个 DOS 执行环境中,CS 和 IP 被初始化为 0(对应值在IMAGE_DOS_HEADER结构中的e_ip、e_cs字段),e_lfarlc 是 DOS 环境的 relocate 表,它的值是 0x40 ,那么信息字符串的位置是:0x0040 + 0x000e = 0x4e,在 image 文件 0x0000004e 正好这字符串的位置。

    4.3. NT 文件头

    NT 文件头是 PE 文件头的核心部分,由 IMAGE_DOS_HEADER 结构的 e_lfanew 域指出它的位置。

    同样 NT 文件头部分由一个结构 IMAGE_NT_HEADER 来描述,在 WinNT.h 里定义如下:

    typedef struct _IMAGE_NT_HEADERS64 {
        DWORD Signature;
        IMAGE_FILE_HEADER FileHeader;
        IMAGE_OPTIONAL_HEADER64 OptionalHeader;
    } IMAGE_NT_HEADERS64, *PIMAGE_NT_HEADERS64;
    typedef struct _IMAGE_NT_HEADERS {
        DWORD Signature;
        IMAGE_FILE_HEADER FileHeader;
        IMAGE_OPTIONAL_HEADER32 OptionalHeader;
    } IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;
    #ifdef _WIN64
    typedef IMAGE_NT_HEADERS64                  IMAGE_NT_HEADERS;
    typedef PIMAGE_NT_HEADERS64                PIMAGE_NT_HEADERS;
    #else
    typedef IMAGE_NT_HEADERS32                  IMAGE_NT_HEADERS;
    typedef PIMAGE_NT_HEADERS32                PIMAGE_NT_HEADERS;
    #endif

    可见这个结构分为 32 和 64 位版本,IMAGE_NT_HEADER 结构分为三大部分:

    • PE 文件签名:Signature
    • IMAGE_FILE_HEADER 文件头:FileHeader
    • IMAGE_OPTINAL_HEADER(32/64) 可选头:OptionalHeader

    IMAGE_NT_HEADERS32 和 IMAGE_NT_HEADERS64 的匹别在于 IMAGE_OPTIONAL_HEADER 结构,分别为:IMAGE_OPTIONAL_HEADERS32 和 IMAGE_OPTIONAL_HEADERS64

    在 Win32 下 IMAGE_NT_HEADERS32 是 248 bytes,在 Win64 下 IMAGE_NT_HEADERS64 是 264 bytes,因此 tlstest.exe的 NT 文件头从 0x000000F8 - 0x000001FF 共 264 bytes

    4.3.1. PE 签名

    在 WinNT.h 文件里定义了 PE 文件的签名,它是:

    #define IMAGE_NT_SIGNATURE                  0x00004550  // PE00

    这个签名值是 32 位,值为:0x00004550 即:PE 的 ASCII 码,下面看看 tlstest.exe 中的 PE 签名:

    这里写图片描述

    4.3.2. IMAGE_FILE_HEADER 文件头结构

    PE 签名接着是 IMAGE_FILE_HEADER 结构,它在 WinNT.h 中的定义为:

    typedef struct _IMAGE_FILE_HEADER {   
        WORD   Machine;               //运行平台 
        WORD   NumberOfSections;     //块(section)数目      
          DWORD    TimeDateStamp;        //时间日期标记     
          DWORD   PointerToSymbolTable;    //COFF符号指针,这是程序调试信息    
         DWORD   NumberOfSymbols;         //符号数  
          WORD   SizeOfOptionalHeader;    //可选部首长度,是IMAGE_OPTIONAL_HEADER的长度    
         WORD   Characteristics;         //文件属性 
    } IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;

    这个 IMAGE_FILE_HEADER 对 PE 文件大致的描述,这个结构共 20 bytes,它的域描述如下:

    size描述
    MachineWORDIMAGE_FILE_MACHINE_xxx表示目标平台 processor 类型,例:IMAGE_FILE_MACHINE_I386
    NumberOfSectionsWORD节数量表示映象中有多少个 section
    TimeDataStampDWORD从1970年1月1日0:00 以来的总秒数表示文件创建的时间
    PointerToSymbolTableDWORDCOFF 符号表偏移量在 image 文件中很少见,总是为 0
    NumberOfSymbolsDWORDCOFF 符号表的个数如果存在的话,表示符号表的个数
    SizeOfOptionalHeaderWORDIMAGE_OPTIONAL_HEADER 结构大小该域表示 IMAGE_NT_HEADER 中的 IMAGE_OPTIONAL_HEADER 结构的大小
    CharacteristicsWORDIMAGE_FILE_xxx表示文件属性,例如:IMAGE_FILE_DLL 属性

    IMAGE_FILE_HEADER 结构中比较重要的域是:Machine 和 SizeOfOptionalHeader, Machine 可以用来判断目标平台,比如:值为 0x8664 是代表 AMD64(即:x64 平台)它也适合 Intel64 平台。SizeOfOptionalHeader 指出 IMAGE_OPTIONAL_HEADER 结构的大小。

    WinNT.h 中定义了一些常量值用来描述 Machine,以 IMAGE_FILE_MACHINE_XXX 开头,下面是一些典型的常量值:

    #define IMAGE_FILE_MACHINE_UNKNOWN           0
    #define IMAGE_FILE_MACHINE_I386                   0x014c  // Intel 386.
    #define IMAGE_FILE_MACHINE_ALPHA                0x0184  // Alpha_AXP
    #define IMAGE_FILE_MACHINE_POWERPC            0x01F0  // IBM PowerPC Little-Endian
    #define IMAGE_FILE_MACHINE_AMD64                0x8664  // AMD64 (K8)

    WinNT.h 中还针对 Characteristics 域定义了一些常量值,以 IMAGE_FILE_XXX 开头,代表目标 image 文件的类型,下面是一些常见的值:

    #define IMAGE_FILE_RELOCS_STRIPPED              0x0001  // Relocation info stripped from file.
    #define IMAGE_FILE_EXECUTABLE_IMAGE          0x0002  // File is executable  (i.e. no unresolved externel references).
    #define IMAGE_FILE_LINE_NUMS_STRIPPED        0x0004  // Line nunbers stripped from file.
    #define IMAGE_FILE_LOCAL_SYMS_STRIPPED     0x0008  // Local symbols stripped from file.
    #define IMAGE_FILE_AGGRESIVE_WS_TRIM         0x0010  // Agressively trim working set
    #define IMAGE_FILE_LARGE_ADDRESS_AWARE  0x0020  // App can handle >2gb addresses
    #define IMAGE_FILE_BYTES_REVERSED_LO         0x0080  // Bytes of machine word are reversed.
    #define IMAGE_FILE_32BIT_MACHINE                 0x0100  // 32 bit word machine.
    #define IMAGE_FILE_DEBUG_STRIPPED               0x0200  // Debugging info stripped from file in .DBG file
    #define IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP   0x0400  // If Image is on removable media, copy and run from the swap file.
    #define IMAGE_FILE_NET_RUN_FROM_SWAP        0x0800  // If Image is on Net, copy and run from the swap file.
    #define IMAGE_FILE_SYSTEM                            0x1000  // System File.
    #define IMAGE_FILE_DLL                                 0x2000  // File is a DLL.
    #define IMAGE_FILE_UP_SYSTEM_ONLY              0x4000  // File should only be run on a UP machine
    #define IMAGE_FILE_BYTES_REVERSED_HI         0x8000  // Bytes of machine word are reversed.

    可以看出Characteristics是以每一位表示文件属性,它的每一个bit代表的含义如下:

             Bit 0 :置1表示文件中没有重定向信息。每个段都有它们自己的重定向信息。
                     这个标志在可执行文件中没有使用,在可执行文件中是用一个叫做基址重定向目录表来表示重定向信息的,这将在下面介绍。
            Bit 1 :置1表示该文件是可执行文件(也就是说不是一个目标文件或库文件)。
         Bit 2 :置1表示没有行数信息;在可执行文件中没有使用。
         Bit 3 :置1表示没有局部符号信息;在可执行文件中没有使用。
         Bit 4Bit 7 
         Bit 8 :表示希望机器为32位机。
         Bit 9 :表示没有调试信息,在可执行文件中没有使用。
         Bit 10:置1表示该程序不能运行于可移动介质中(如软驱或CD-ROM)。在这    种情况下,OS必须把文件拷贝到交换文件中执行。
             Bit 11:置1表示程序不能在网上运行。在这种情况下,OS必须把文件拷贝到交换文件中执行。
             Bit 12:置1表示文件是一个系统文件例如驱动程序。在可执行文件中没有使用。
             Bit 13:置1表示文件是一个动态链接库(DLL)。
             Bit 14:表示文件被设计成不能运行于多处理器系统中。
             Bit 15:表示文件的字节顺序如果不是机器所期望的,那么在读出之前要进行
                     交换。在可执行文件中它们是不可信的(操作系统期望按正确的字节顺序执行程序)。

    NumberOfSections 表示 image 有多个 section,另一个重要的域是:SizeOfOptionalHeader 它指出接下来 IMAGE_OPTIONAL_HEADER 的大小,它有两个 size:Win32 的 0xDC 和 Win64 的 0xF0.

    下面是 tlstest.exe的 IMAGE_FILE_HEADER 结构,从 0x000000F8 - 0x0000010F 共 20 bytes:

    这里写图片描述

    将这些值分解为:

    000000FC  64 86                   // Machine
    000000FE  07 00                   // NumberOfSections
    00000100  F1 71 1E 57           // TimeDateStamp
    00000104  00 00 00 00           // PointerToSymbolTable
    00000108  00 00 00 00           // NumberOfSymbols
    0000010C  F0 00                   // SizeOfOptionalHeader
    0000010E  22 00                   // Characteristics
    • Machine 是 0x0x8664,它的值是 IMAGE_FILE_MACHINE_AMD64,说明这个 image
      文件的目标平台是 AMD64,即:X64 平台
    • NumberOfSections 是 0x08,说明 image 文件内含有 8 个 sections
    • SizeOfOptionalHeader 是 0xF0,说明接下来的 IMAGE_OPTIONAL_HEADERS64 将是
      0xF0(224 bytes)

    它的 Characteristics 是 0x0022 = IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_LARGE_ADDRESS_AWARE,说明这个 image 是 64 位可执行的映像。可以在 >2G 地址上,并且指明了接下来的 IMAGE_OPTIONAL_HEADER 结构是 0xf0 bytes(240 个字节)。

    4.3.3. IMAGE_OPTIONAL_HEADER64 结构

    在 IMAGE_FILE_HEADER 结构里已经指明了 image 是 64 位,并且 IMAGE_OPTIONAL_HEADER 的大小是 240 bytes,那么这个结构就是 IMAGE_OPTIONAL_HEADER64 结构。
    可以根据 IMAGE_FILE_HEAER 结构的 Machine 来判断 image 是 Win32 还是 Win64 平台的。但是 Microsoft 官方推荐及认可的方法是从 IMAGE_OPTIONAL_HEADER 里的 magic 的值来判断目标平台 。

    在 WinNT.h 里 IMAGE_OPTIONAL_HEADER64 的定义如下:

    typedef struct _IMAGE_OPTIONAL_HEADER64 {
    
        WORD          Magic;
        BYTE           MajorLinkerVersion;
        BYTE           MinorLinkerVersion;
        DWORD        SizeOfCode;
        DWORD        SizeOfInitializedData;
        DWORD        SizeOfUninitializedData;
        DWORD        AddressOfEntryPoint;
        DWORD        BaseOfCode;
        ULONGLONG   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;
        ULONGLONG  SizeOfStackReserve;
        ULONGLONG  SizeOfStackCommit;
        ULONGLONG  SizeOfHeapReserve;
        ULONGLONG  SizeOfHeapCommit;
        DWORD        LoaderFlags;
        DWORD        NumberOfRvaAndSizes;
        IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
    } IMAGE_OPTIONAL_HEADER64, *PIMAGE_OPTIONAL_HEADER64;

    64 位的 IMAGE_OPTIONAL_HEADER64 里没有 BaseOfData 域,其它的与 IMAGE_OPTIONAL_HEADER32 结构的域是一样的,只是一些域扩展为 64 位值,它们包括:

    • ImageBase
    • SizeOfStackReserve
    • SizeOfStackCommit
    • SizeOfHeapRerserve
    • SizeOfHeapCommit

    这些域在 64 位结构里被定义为 ULONGLONG 类型。

    IMAGE_OPTIONAL_HEADER64 的定义的各个域含义如下:

    偏移大小字段描述
    02MagicThe unsigned integer that identifies the state of the image file. The most common number is 0x10B, which identifies it as a normal executable file. 0x107 identifies it as a ROM image, and 0x20B identifies it as a PE32+ executable. 确定这是什么类型的头。两个最常用的值是0x10b和0x20b.
    21MajorLinkerVersionThe linker major version number. 创建可执行文件的链接器的主版本号。对于Microsoft的链接器生成的PE文件,这个版本号的Visual Studio的版本号相一致
    31MinorLinkerVersionThe linker minor version number. 创建可执行文件的链接器的次版本号。
    44SizeOfCodeThe size of the code (text) section, or the sum of all code sections if there are multiple sections. 所有具有IMAGE_SCN_CNT_CODE属性的节的总的大小。
    84SizeOfInitializedDataThe size of the initialized data section, or the sum of all such sections if there are multiple data sections. 所有包含已初始数据的节的总的大小。
    124SizeOfUninitializedDataThe size of the uninitialized data section (BSS), or the sum of all such sections if there are multiple BSS sections. 所有包含未初始化数据的节的总的大小。这个域总是0,因为链接器可以把未初始化数据附加到常规数据节的末尾。
    164AddressOfEntryPointThe address of the entry point relative to the image base when the executable file is loaded into memory. For program images, this is the starting address. For device drivers, this is the address of the initialization function. An entry point is optional for DLLs. When no entry point is present, this field must be zero. 文件中将被执行的第一个代码字节的RVA。对于DLL,这个进入点将在进程初始化和关闭时以及线程被创建和销毁时调用。在大多数可执行文件中,这个地址并不直接指向main,WinMain或DllMain函数,而是指向运行时库代码,由运行时库调用前述函数。在DLL中,这个域可以被设为0。链接器选项/NOENTRY可以设置这个域为0。
    204BaseOfCodeThe address that is relative to the image base of the beginning-of-code section when it is loaded into memory. 加载到内存后代码的第一个字节的RVA
    244BaseOfDataThe address that is relative to the image base of the beginning-of-data section when it is loaded into memory. 理论上,它表示加载到内存后数据的第一个字节的RVA。然而,这个域的值对于不同版本的Microsoft链接器是不一致的。在64位的可执行文件中这个域不出现。
    28/244/8ImageBaseThe preferred address of the first byte of image when loaded into memory; must be a multiple of 64 K. The default for DLLs is 0x10000000. The default for Windows CE EXEs is 0x00010000. The default for Windows NT, Windows 2000, Windows XP, Windows 95, Windows 98, and Windows Me is 0x00400000. 文件在内存中的首选加载地址。加载器尽可能地把PE文件加载到这个地址(就是说,如果当前这块内存没有被占用,它是对齐的并且是一个合法的地址,等等)。如果可执行文件被加载到这个地址,加载器就可以跳过进行基址重定位这一步。在Win32下,对于EXE,缺省的ImageBase是0x400000。对于DLL,缺省是0x10000000。在链接时可以通过/BASE 选项来指定ImageBase,或者以后用REBASE工具重新设置。
    32/324SectionAlignmentThe alignment (in bytes) of sections when they are loaded into memory. It must be greater than or equal to FileAlignment. The default is the page size for the architecture. 加载到内存后节的对齐大小。这个值必须大于等于FileAlignment(下一个域)。缺省的对齐值是目标CPU的页大上。对于运行在Windows 9x或Windows Me下的用户模式可执行文件,最小对齐大小是一页(4KB)。这个域可以通过链接器选项/ALIGN来设置。
    36/364FileAlignmentThe alignment factor (in bytes) that is used to align the raw data of sections in the image file. The value should be a power of 2 between 512 and 64 K, inclusive. The default is 512. If the SectionAlignment is less than the architecture’s page size, then FileAlignment must match SectionAlignment. 在PE文件中节的对齐大小。对于x86下的可执行文件,这个值通常是0x200或0x1000。不同版本的Microsoft链接器缺省值不同。这个值必须是2的幂,并且如果SectionAlignment小于CPU的页大小,这个域必须和SectionAlignment相匹配。链接器选项/OPT:WIN98可设置x86可执行文件的文件对齐为0x1000,/OPT:NOWIN98设置文件对齐为0x200。
    40/402MajorOperatingSystemVersionThe major version number of the required operating system. 所要求的操作系统的主版本号。随着那么多版本Windows的出现,这个域的值就变得很不确切。
    42/422MinorOperatingSystemVersionThe minor version number of the required operating system. 所要求的操作系统的次版本号。
    44/442MajorImageVersionThe major version number of the image. 这个文件的主版本号。不被系统使用并可设为0。可以通过链接器选项/VERSION来设置。
    46/462MinorImageVersionThe minor version number of the image. 这个文件的次版本号。
    48/482MajorSubsystemVersionThe major version number of the subsystem. 可执行文件所要求的操作子系统的主版本号。它曾经被用来表示需要较新的Windows 95或Windows NT用户界面,而不是老版本的Windows NT界面。今天随着各种不同版本Windows的出现,这个域已不被系统使用,并且通常被设为4。可通过链接器选项/SUBSYSTEM设置这个域的值。
    50/502MinorSubsystemVersionThe minor version number of the subsystem. 可执行文件所要求的操作子系统的次版本号。
    52/524Win32VersionValueReserved, must be zero. 另一个不被使用的域,通常设为0。
    56/564SizeOfImageThe size (in bytes) of the image, including all headers, as the image is loaded in memory. It must be a multiple of SectionAlignment. 映像的大小。它表示了加载文件到内存中时系统必须保留的内存的数量。这个域的值必须是SectionAlignmnet的倍数。
    60/604SizeOfHeadersThe combined size of an MS-DOS stub, PE header, and section headers rounded up to a multiple of FileAlignment. MS-DOS头,PE头和节表的总的大小。PE文件中所有这些项目出现在任何代码或数据节之前。这个域的值被调整为文件对齐大小的整数倍。
    64/644CheckSumThe image file checksum. The algorithm for computing the checksum is incorporated into IMAGHELP.DLL. The following are checked for validation at load time: all drivers, any DLL loaded at boot time, and any DLL that is loaded into a critical Windows process. 映像的校验和。IMAGEHLP.DLL中的CheckSumMappedFile函数可以计算出这个值。校验和用于内核模式的驱动和一些系统DLL。对于其它的,这个域可以为0。当使用链接器选项/RELEASE时校验和被放入文件中。
    68/682SubsystemThe subsystem that is required to run this image. For more information, see “Windows Subsystem” later in this specification. 指示可执行文件期望的子系统(用户界面类型)的枚举值。这个域只用于EXE。一些重要的值包括:
    IMAGE_SUBSYSTEM_NATIVE // 映像不需要子系统
    IMAGE_SUBSYSTEM_WINDOWS_GUI // 使用Windows GUI IMAGE_SUBSYSTEM_WINDOWS_CUI // 作为控制台程序运行。
    // 运行时,操作系统创建一个控制台
    // 窗口并提供stdin,stdout和stderr
    // 文件句柄。
    70/702DllCharacteristicsFor more information, see “DLL Characteristics” later in this specification. 标记DLL的特性。对应于IMAGE_DLLCHARACTERISTICS_xxx定义。当前的值是:
    IMAGE_DLLCHARACTERISTICS_NO_BIND // 不要绑定这个映像
    IMAGE_DLLCHARACTERISTICS_WDM_DRIVER // WDM模式的驱动程序
    IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE // 当终端服务加载一个不是
    // Terminal- Services-aware 的应用程
    // 序时,它也加载一个包含兼容代码
    // 的DLL。
    72/724/8SizeOfStackReserveThe size of the stack to reserve. Only SizeOfStackCommit is committed; the rest is made available one page at a time until the reserve size is reached. 在EXE文件中,为线程保留的堆栈大小。缺省是1MB,但并不是所有的内存一开始都被提交。
    76/804/8SizeOfStackCommitThe size of the stack to commit. 在EXE文件中,为堆栈初始提交的内存数量。缺省情况下,这个域是4KB。
    80/884/8SizeOfHeapReserveThe size of the local heap space to reserve. Only SizeOfHeapCommit is committed; the rest is made available one page at a time until the reserve size is reached. 在EXE文件中,为默认进程堆初始保留的内存大小。缺省是1MB。然而在当前版本的Windows中,堆不经过用户干涉就能超出这里指定的大小。
    84/964/8SizeOfHeapCommitThe size of the local heap space to commit. 在EXE文件中,提交到堆的内存大小。缺省情况下,这里的值是4KB。
    88/1044LoaderFlagsReserved, must be zero. 不使用。
    92/1084NumberOfRvaAndSizesThe number of data-directory entries in the remainder of the optional header. Each describes a location and size. 在IMAGE_NT_HEADERS结构的末尾是一个IMAGE_DATA_DIRECTORY结构数组。此域包含了这个数组的元素个数。自从最早的Windows NT发布以来这个域的值一直是16。

    上面表格中的 offset 值两个,前面的是 IMAGE_OPTIONAL_HEADER32 的 offset 值,后面的是 IMAGE_OPTIONAL_HEADER64,这是因为在 64 位版本中一些域被扩展为 64 位值,而 BaseOfData 域在 64 位版中是不存在的。
    Magic 域是一个幻数值,在 WinNT.h 里定义了一些常量值:

    #define IMAGE_NT_OPTIONAL_HDR32_MAGIC      0x10b
    #define IMAGE_NT_OPTIONAL_HDR64_MAGIC      0x20b
    #define IMAGE_ROM_OPTIONAL_HDR_MAGIC       0x107
    • 值 0x10b 说明这个 image 是 32 位的,PE 文件格式是 PE32
    • 值 0x20b 说明这个 image 是 64 位的,PE 文件格式是 PE32+

    PE32+ 代表的扩展的 PE 文件格式,扩展为 64 位。在 PE 文件规范中并没有 PE64 这种文件格式,Microsoft 官方的判断 image 文件是 32 位还是 64 位的方法就是通过 Magic 的值来确定。

    在这些基本的域里可以获得 linker 的版本,text 节,data 节以及 bss 节的大小,下面看一看tlstest.exe 的 IMAGE_OPTIONAL_HEADER64 结构,从 0x00000110 - 0x000001FF

    这里写图片描述

    这里写图片描述

    Magic 是 0x020B 表明这个 image 文件是 64 位的 PE32+格式,这里看出 linker 的版本是 14.00
    .text 节的 size 是 0x00001000 bytes,.data 节的 size 是 0x00022000 bytes,还有一个重要的信息,代码的 RVA 入口在 0x00001338,它是基于 ImageBase 的 RVA 值。tlstest.exe 的 ImageBase 是0x0000000140000000,那么 tlstest.exe 映象的入口在:ImageBase + AddressOfEntryPoint = 0x0000000140000000 + 0x00001338 = 0x0000000140001338,这个地址是 __scrt_common_main() 的入口。

    上面的 SectionAlinment 域值为 0x1000 是表示映象被加载到 virtual address 以是 0x1000(4K byte)为单位的倍数,也就是加载在 virtual address 的 4K 边界上。例如:tlstest.exe映象的 .text 节被加载到以 ImageBase(virtual address 为 0x00000001_40000000)为基址的第 1 个 4K 边界上(即:0x00000001_40001000 处),.rdata 节加载到第 2 个 4K 边界上(即:0x00000001_40002000 处)。FileAlinment 域的值为 0x200 表示执行映象从 0x200 为边界开始加载到 virtual address 上。例如,t.exe 映象中 code 位于文件映象的 0x400 处(0x200 边界上),因此,t.exe 文件映象 code 从 0x400 处开始加载到 virtual address。

    4.3.3.1. IMAGE_DATA_DIRECTORY表格

    这里写图片描述

    在 IMAGE_OPTIONAL_HEADER64 未端是一组 IMAGE_DATA_DIRECTORY 结构的数组,上图所示:从 0x00000180 到 0x000001FF。在 WinNT.h 里定义为:

    //
    // Directory format.
    //
    typedef struct _IMAGE_DATA_DIRECTORY {
        DWORD   VirtualAddress;
        DWORD   Size;
    } IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
    #define IMAGE_NUMBEROF_DIRECTORY_ENTRIES    16

    这个结构十分重要,它用来描述 windows 执行映象中所使用的各种表格的位置和大小。VirtualAddress 域是一个 RVA(Relative Virtual Address)值,更明白一点就是:它是一个偏移量(基于 PE 文件头),Size 域表示这个表格有多大。IMAGE_NUMBEROF_DIRECTORY_ENTRIES 的值为 16,因此有 16 个 Directory,也就是表示,在执行映象中最多可以使用 16 个表格。

    这 16 个 Driectory 指引出 16 不同格式的 table,实际上这 16 个表格是固定的,对于这些表格 Microsoft 都作了统一的规定,在 WinNT.h 里都作了定义:

    // 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
    //      IMAGE_DIRECTORY_ENTRY_COPYRIGHT           7   // (X86 usage)
    #define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE    7   // Architecture Specific Data
    #define IMAGE_DIRECTORY_ENTRY_GLOBALPTR         8   // RVA of 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
    #define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT   13   // Delay Load Import Descriptors
    #define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14   // COM Runtime descriptor

    从定义上得出,第 0 项是 export table(导出表),第 1 项是 import table(导入表)等等,在 Microsoft 的 MSDN 网站里有一个知识点介绍:http://msdn.microsoft.com/en-us/library/ms680305(VS.85).aspx
    下面,我将这些表格归纳如下:

    表项表格
    0export table
    1import table
    2resource table
    3exception table
    4certificate table
    5base relocation table
    6debug
    7architecute
    8global pointer
    9TLS table
    10load configuration table
    11bound import
    12import address table
    13delay import descriptor
    14CLR runtime header
    15reserved, must bo zero

    在 WinNT.h 有对这些 table 的结构的全部定义。

    那么,下面我们来看一看tlstest.exe 映象中使用了哪些表?

    这里写图片描述

    上面表格显示我们的示例程序 t.exe 仅仅使用了 8 个 driectory 表格:import table、resource table 、exception table 、relocation table 、debug table、TLS table、load configuration table以及 import address table。

    4.4. section 表

    IMAGE_NT_HEADER 结构后面紧接着就是 section table(节表)结构。现在来看一看tlstest.exe 的 section 表,从 0x00000200 - 0x0000033F,共 320 bytes

    这个节表结构在 WinNT.h 中定义为

    //
    // Section header format.
    //
    #define IMAGE_SIZEOF_SHORT_NAME              8
    typedef struct _IMAGE_SECTION_HEADER {
        BYTE    Name[IMAGE_SIZEOF_SHORT_NAME];
        union {
                DWORD   PhysicalAddress;
                DWORD   VirtualSize;
        } Misc;
        DWORD   VirtualAddress;
        DWORD   SizeOfRawData;
        DWORD   PointerToRawData;
        DWORD   PointerToRelocations;
        DWORD   PointerToLinenumbers;
        WORD     NumberOfRelocations;
        WORD     NumberOfLinenumbers;
        DWORD   Characteristics;
    } IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
    #define IMAGE_SIZEOF_SECTION_HEADER          40

    每个 section 表的大小为 40 bytes,section 表的作用是指出 image 映象 section 所在tlstest.exe 映象的 IMAGE_FILE_HEADER 结构的 NumberOfSections 域里已经指出tlstest.exe 映象中包含有 8 个 sections,因此整个 section 表的大小为:320 bytes。

    tlstest.exe的 section 表如下:

    这里写图片描述

    这 8 个 section 分别是:

    • .text 节
    • .rdata 节
    • .data 节
    • .pdata 节
    • .tls 节
    • .gfids 节
    • .rsrc 节
    • .reloc 节
      这里写图片描述

    在 IMAGE_SECTION_HEADER 结构的第 1 个域 Name,用来标识 section table 的名字。它的长度固定为 8 bytes(前面定义的宏),这将意味着,不存在超过 8 bytes 的节表名。接下来使用 VirtualSize 来用表示 section talbe 大小。VirtualAddress 表示 section table 的 RVA,它是基于 ImageBase 的 RVA 值,它指出 section 的所在,SizeOfRawData 是在 image 文件里占有的空间,它是 FileAlignment 的倍数,即:0x200 的倍数,也就是说 0x200 的边界。PointerToRawData是 section 在 image 文件的位置,同样也是 FileAligment 即:0x200 边界上。

    size描述
    Name8 bytesSection 表名字
    VirtualSizeDWORDSection 表的大小
    VirtualAddressDWORDSection 表的 RVA,即:section 表的位置
    SizeOfRawDataDWORDsection 表占用映像的大小,这个 size 是以 0x200 为单位的
    PointerToRawDataDWORDsection 表在映像中的物理位置,即是:file 位置,而非 virtual 位置
    PointerToRelocationDOWRD
    PointerToLinenumberDWORD
    NumberOfRelocationWORD
    NumberOfLineumbersWORD
    CharacteristicsDWORDsection 的属性 flags,可用于 ‘

    所有的 Characteristics 都在 WinNT.h 中有定义,下面是一些常用的 flags:

    #define IMAGE_SCN_CNT_CODE                            0x00000020  // Section contains code.
    #define IMAGE_SCN_CNT_INITIALIZED_DATA         0x00000040  // Section contains initialized data.
    #define IMAGE_SCN_CNT_UNINITIALIZED_DATA     0x00000080  // Section contains uninitialized data.
    ... ...
    #define IMAGE_SCN_LNK_NRELOC_OVFL                0x01000000  // Section contains extended relocations.
    #define IMAGE_SCN_MEM_DISCARDABLE                0x02000000  // Section can be discarded.
    #define IMAGE_SCN_MEM_NOT_CACHED                 0x04000000  // Section is not cachable.
    #define IMAGE_SCN_MEM_NOT_PAGED                   0x08000000  // Section is not pageable.
    #define IMAGE_SCN_MEM_SHARED                        0x10000000  // Section is shareable.
    #define IMAGE_SCN_MEM_EXECUTE                       0x20000000  // Section is executable.
    #define IMAGE_SCN_MEM_READ                            0x40000000  // Section is readable.
    #define IMAGE_SCN_MEM_WRITE                           0x80000000  // Section is writeable.

    下面以 .text 节为例,看看tlstest.exe的 .text 是什么。

    这里写图片描述

    .text 节的 Name 是 “.text”,VirtualSize 是 0x00000E08 bytes,.text 节在 RVA 为 0x00001000 的位置上,section 的分配单位为 0x1000(4K bytes),第 1 个 section 一般都分配在 0x1000 位置上,SizeOfRawData 为 0x1000,这是映像文件分配单位。PointerToRawData 为 0x400,说明 .text 节在映像文件的 0x400 处。Characteristics 是 0x60000020,说明 .text 是 executable/readable/code 属性。

    展开全文
  • 【问题描述】:关于windows服务器启动程序提示“未找到提供程序,程序可能未正确安装” Exception on EOLeException 【原因分析】:oracle客户端环境问题,系统环境问题 【解决方案】: 1、检查Oracle客户端安装...

    【问题描述】:关于 windows服务器启动程序提示“未找到提供程序,程序可能未正确安装” Exception on EOLeException

    【原因分析】:oracle客户端环境问题,系统环境问题

    【解决方案】:

    1、检查Oracle客户端安装目录\product\11.2.0\client_1\bin下是否存在OraOLEDB*.dll系列(如果DLL存在说明是没有正确注册驱动

    2、打开命令窗口cmd  执行 regsvr32命令注册OraOLEDB*.dll   如:regsvr32 OraOLEDB11.dll   正常会提示某路径下的DLLRegisterServer成功。

    一般到这里就结束了,本人就比较背 注册失败了😭熬了大半夜,别放弃,继续步骤三。

     3、执行上述命令,系统提示注册失败,未成功加载,从正常启动的测试环境copy OraOLEDB*.dll系列文件到生产环境,重新注册后,重启转换机 问题解决。

    如果你也遇到类似问题,建议从其他正常oracle客户端copy “OR阿OLEDB*.dll" 即可。

    注册成功图片:

     

     

     

    展开全文
  • 解决BitLocker反复提示恢复密钥正确而无法进入系统的问题

    解决BitLocker反复提示恢复密钥正确而无法进入系统的问题

    参考文章:

    (1)解决BitLocker反复提示恢复密钥正确而无法进入系统的问题

    (2)https://www.cnblogs.com/izwb003/p/secure_boot_loop_solution.html


    备忘一下。


    展开全文
  • 自动修复你的电脑未正确启动

    千次阅读 2020-11-03 13:30:50
    首先我们点击“高级选项”按钮,再进入“疑难解答”,...不过重启之后,依然无法进入系统,而是提示了恢复,你的电脑/设备需要修复,无法加载操作系统,原因是无法验证文件的数字签名,文件: h ttps://www.fujieace.co
  • 这一周为了这个错误掉了很多头发,然而最绝望的是我按照CSDN上各路大神的做法试了一遍都没有成功,还好在最后无意之间发现了失败的原因,想分享给大家,挽救一些头发。 首先正常的解决方法: ...
  • 3dmax打不开一直加载未响应

    千次阅读 2021-08-04 01:10:09
    3dmax软件打不开一直在加载的解决方法可以参考以下:方法一:可以点击电脑上的任务管理器的悬浮球,查看3dmax软件是不是显示正在运行,如果显示的是“响应”,建议大家点击“一键加速”,退出我们一直在加载的页面...
  • 1 由于近期清理了win10 C盘空间,启动双系统提示如下图,打不开ubuntu。 2 应该是ubuntu启动引导项丢失了,利用easybcd工具进行修复。 3 打开软件,在编辑引导菜单栏,选择ubuntu进行删除。...
  • 最近电脑一切归零,装系统,装SQL,装Vs……然后SQL附加数据库失败,vs出问题,不过这次没有以前那么抓狂了,慢慢找原因,然后一一解决。 首先是SQL,附加数据库失败,解决方法有这么几种: 1、用windows身份验证...
  • 你的电脑正常启动、你的电脑需要修复解决方法 使用win10的时候,有的小伙伴会遇到电脑没办法正常启动的现象(我就是其中一个,心累)遇到的情况如下: 不能正常启动的原因: 出现这种情况一般是因为电脑中有一些...
  • 所以我转的对 Dll断点调试,结果另一问题:“当前不会命中断点,还为文档加载任何符号”。 查找解决办:网点有很多,都不是完美解决问题。其中一个解决办法是: 在 /工具/选项/调试/常规 :取消勾选 "要求源文件...
  • 2天前安装了VC++ 2008 Express和SQL Server 2008,发现visSDK的shapestudio无法与SQL Server连接,接着就把VC++ 2008和SQL Server 2008删除了,结果发现原来的VS2005启动时报错:未能正确加载包“Windows Forms ...
  • win7 64位 web项目OCX控件无法加载原因

    万次阅读 2013-11-16 15:49:04
    多了不说什么 ,直接切入主题   ... 注册成功之后,如果界面依然没有加载控件,则考虑注册表的影响了 ... 其次,看看于控件相关的注册表是否导入到了正确的位置,尤其是64位操作系统,而注册表文件又是从32位系统导
  • 未能加载文件或程序集什么原因

    万次阅读 热门讨论 2018-08-01 11:15:55
    系统找不到指定的文件, 找不到文件就不能调用,有可能就是程序的相关代码的路径错了,然后经过查询发现Bin目录下没有生成相关的DLL文件,就会导致不能加载文件,程序不能正常运行。 在我的bin目录没有发现此DLL...
  • 最近发现好多小伙伴在使用Photoshop Mac端或者win端安装ps扩展面板时,总会遇到Photoshop错误提示无法加载,因为它未经正确签署。今天小编就和大家分享解决Mac/Win端ps扩展面板提示无法加载,因为它未经正确签署解决...
  • Windows日志

    千次阅读 多人点赞 2019-05-29 16:29:26
    文章目录一,Windows事件日志简介二,打开事件查看器命令:eventvwr三,Windows事件日志共有五种事件级别四,Windows日志文件五,对常用安全事件的分析1.用户登录与注销2.追踪硬件变动3.追踪WiFi信息六,日志获取和...
  • Windows加载器与模块初始化

    千次阅读 2011-06-26 00:08:00
    (Microsoft System Journal 1999年9月Under The Hood专栏)译者:SmartTech 电子信箱:zhzhtst@163.com 本文是Matt Pietrek在1999年9月的MSJ杂志上发表的关于Windows加载器与模块初始化方面的文章。...
  • windows socket错误码及出错原因

    千次阅读 2017-06-09 18:30:31
    Windows Sockets在头文件winsock.h中定义了所有的错误码,它们包括以“WSA”打头的Windows Sockets实现返回的错误码和Berkeley Sockets定义的错误码全集。定义Berkeley Sockets错误码是为了确保原有软件的
  • VLC加载插件失败原因及解决

    千次阅读 2014-07-15 23:38:15
    windows+vs2013+QT5.3环境下进行调试。出现了在调用libvlc_new时提示不能找到插件、加载libvlc失败的问题。 原因及解决方法如下: 1: 提示找不到插件,是因为plugins目录位置不对,应该放在和libvlc....
  • 常见Windows电脑蓝屏的解决办法

    千次阅读 2020-03-02 09:53:22
    常见电脑蓝屏的解决办法 在我们使用电脑的过程中,最讨厌的一种颜色那便是“蓝色”了,有时候那突如其来的蓝屏简直让人崩溃。其实,电脑蓝屏也算是常见现象。...原因分析:CPU过于超频。 解决办法:启动...
  • 每当Adobe CC更新一次,就会有很多小伙伴发现,各种好用的插件会出现“无法加载扩展,未经正确签署”的提示,这是怎么回事呢?也许适配新版出现了兼容问题,具体什么原因,咱也不知道,咱也不敢问,直接给出解决方法...
  • Windows设备管理器中的错误代码

    千次阅读 2021-04-14 09:05:26
    适用于:Windows 10 Pro released in July 2015,Windows 10 Enterprise released in July 2015,Windows 8 概要 本文涵盖了 Windows 中由“设备管理器”生成的错误代码。 你可能由于“设备管理器”或其他工具(如...
  • (3)如果网络通,则返回显示为请求超时(request timed out) 此时需要分析网络故障出现的原因,一般可以检查如下几点。 1)网络中是否有这台计算机,或者被测试计算机是否正在运行 2)被侧是计算机是否...
  • 回到vscode,关闭现有terminal,重新开启一个terminal,再按F5,就可以愉快的调试了 强调要重新打开一个terminal的原因是,terminal本身不会自动更新外部配置的环境,重新打开才能加载最新的配置 参考文档 [1] 解决...
  • 使用vs2012打开或创建VC项目工程时候,提示... 在安装vs2012后,如果windows更新或.net framework更新都有可能引起vs2012出现上述成功加载相关包的错误。  解决方法:  针对上述错误,微软已在官网进行说明并给
  • [Windows] 微软错误代码

    千次阅读 2019-04-08 12:23:56
    微软错误代码 0 操作成功完成。 1 功能错误。 2 系统找不到指定的文件。...11 试图加载格式错误的程序。 12 访问码无效。 13 数据无效。 14 存储器不足,无法完成此操作。 15 系统找不到指定的驱...
  • Windows常用shell命令

    万次阅读 多人点赞 2018-08-22 14:27:37
    CMD 命令速查手册 ASSOC 显示或修改文件扩展名关联。 ATTRIB ... 设置 boot.ini 文件的属性以便控制启动加载。 CACLS 显示或修改文件的访问控制列表(ACL)。 ...
  • Windows 系统错误代码

    万次阅读 2016-06-15 14:49:09
    0-操作成功完成。 1-函数不正确。 2-系统找不到指定的文件。 3-系统找不到指定的路径。...11-试图加载格式不正确的程序。 12-访问码无效。 13-数据无效。 14-存储空间不足,无法完成此操作。 15-
  • Windows事件ID详细

    万次阅读 2018-07-23 02:49:08
    请确认网络路径正确并且目标计算机不忙或已关闭。如果 Windows 仍然无法找到网络路径,请与网络管理员联系。  52 由于网络上有重名,没有连接。请到“控制面板”中的“系统”更改计算机名,然后重试。   53 找...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 39,464
精华内容 15,785
关键字:

windows未正确加载原因