热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

win32下PE文件分析之NT头

接上一篇的win32下PE文件分析之DOS头(一)win32中PE的NT:    NT头是PE文件中标准PE头和可选PE头的总体称谓,还包含一个PE标识.下面

win32下PE文件分析之NT头

接上一篇的win32下PE文件分析之DOS头

(一)win32中PE的NT:

    NT头是PE文件中标准PE头和可选PE头的总体称谓,还包含一个PE标识.下面是它在Visual C++ 6.0中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;                        //PE标识
    IMAGE_FILE_HEADER FileHeader;           //标准PE头(也称文件头)
    IMAGE_OPTIONAL_HEADER32 OptionalHeader; //可选PE头
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;

    第一个是64bit的NT头定义,第二个是32bit的.这里只探讨32bit的.标准PE头也叫文件头,这不重要,知道是那么个东西就行了,个人不太喜欢动不动就用高端名词,高端名词主要是为了严谨而取出来的,但是很多时候很晦涩,通俗易懂更易让人接受.

(二).NT头中的Signature:

    这就是一个PE标识,说明这是PE的开始位置.它在PE文件中的偏移由DOS头中的最后一个成员e_lfanew决定,上一节解析了它的值为:0xE0,如图:

win32下PE文件分析之NT头

(三).NT头中的标准PE头:

    (1).NT头中的标准PE头数据宽度是0x14个字节,在Visual C++ 6.0中的结构定义如下:

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;

    (2).代码的文件结构如下图:每个解析头函数定义分别放在不同的头文件中,方便逐个头结构的观察,为了可以多熟悉即便各个头的数据结构,每个函数中都重新从头开始解析了一遍,这样效率会降低.后面如果有空,会提供优化了的代码.(优化思路:在解析一开始,就将各个头的地址放进一个unsigned long*的全局数组里面,这样在后面是用的时候就直接调用数组里的地址,而不用每次都重新定义DOS头结构再依计算出各个结构的偏移.)

 win32下PE文件分析之NT头


    (3).解析文件头的代码如下(代码中都只是输出部分重要的数据,博客中代码列数的限制,注释一行放不下,不美观):

    file.h

void Output_File(void* buffer)
{
	void* buf = buffer;
	//计算偏移时有用
	IMAGE_DOS_HEADER* pdos = (IMAGE_DOS_HEADER*)buf;		
	//pnt存放NT头的地址.
	IMAGE_NT_HEADERS32* pnt = (IMAGE_NT_HEADERS32*)((unsigned char*)buf + pdos->e_lfanew);	
	//pfile存放NT头中标准PE头结构所在地址.
	IMAGE_FILE_HEADER* pfile = (IMAGE_FILE_HEADER*)&pnt->FileHeader;	
	printf("\nNT Header:\n");
	//PE标识,值与PE的ascii码一一对应
	printf("PE:	%#X\n", pnt->Signature);	
	printf("File Header:\n");
	//输出程序能在哪种CPU平台上运行.
	printf("Machine:	%#X\n", pfile->Machine);
	//输出PE文件中节的数量
	printf("NumberOfSec:	%#X\n", pfile->NumberOfSections);
	//时间戳,文件的创建时间,一般有编译器填充,修改后不会影响程序运行
	printf("TimeStamp:	%#X\n", pfile->TimeDateStamp);	
	//可选PE头的大小(32bit默认是0xE0,64bit默认是0xF0)	
	printf("SizeOfOpHdr:	%#X\n", pfile->SizeOfOptionalHeader);
	//该文件的属性(标识给文件的类型,如是exe还是dll或其他)	
	printf("Characteristics:	%#X\n", pfile->Characteristics);	
}

    注释掉其他头的解析:运行结果如下:

win32下PE文件分析之NT头(四).NT头中的可选PE头:

    可选PE头结构挺复杂,也最重要,32bit的和64bit的有点不同.在Visual C++ 6.0中winnt.h中定义如下:

typedef struct _IMAGE_OPTIONAL_HEADER {
    //
    // Standard fields.
    //

    WORD    Magic;
    BYTE    MajorLinkerVersion;
    BYTE    MinorLinkerVersion;
    DWORD   SizeOfCode;
    DWORD   SizeOfInitializedData;
    DWORD   SizeOfUninitializedData;
    DWORD   AddressOfEntryPoint;
    DWORD   BaseOfCode;
    DWORD   BaseOfData;

    //
    // NT additional fields.
    //

    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_HEADER32, *PIMAGE_OPTIONAL_HEADER32;

    解析文件头的代码如下:

void Output_Optional(void* buffer)
{
	void* buf = buffer;
	//计算偏移时使用
	IMAGE_DOS_HEADER* pdos = (IMAGE_DOS_HEADER*)buf;	
	//pop中存放可选PE头的起始位置, 0x4是NT头中PE表示,0x14是NT头中的标准PE头,根据结构计算出可选PE头的偏移
	IMAGE_OPTIONAL_HEADER32* pop = (IMAGE_OPTIONAL_HEADER32*)((unsigned char*)buf + pdos->e_lfanew + 0x4 + 0x14);
	printf("Optional PE Header:\n");
	//说明文件的类型,010B为32bit的PE文件,020B为64bit的PE文件
	printf("Magic:				%#X\n", pop->Magic);
	//所有代码节的和,大小必须是FileAlignment的整数倍,有编译器填充,修改无影响.
	printf("SizeOfCode:			%#X\n",pop->SizeOfCode);	
	//已经初始化数据大小的和.
	printf("SizeOfinitializedData:		%#X\n",pop->SizeOfInitializedData);
	//未初始化数据大小的和.
	printf("SizeOfuninitializedData:	%#X\n",pop->SizeOfUninitializedData);	
	//程序入口OEP
	printf("AddressOfEntryPoint:		%#X\n",pop->AddressOfEntryPoint);
	//内存镜像基址
	printf("ImageBase:			%#X\n", pop->ImageBase);		
	//内存对齐			
	printf("SectionAlignment:		%#X\n", pop->SectionAlignment);	
	//文件对齐
	printf("FileAlignment:			%#X\n", pop->FileAlignment);
	//内存中整个PE文件的映射大小,可比实际的大,必须为内存对齐的整数倍			
	printf("SizeOfImage:			%#X\n", pop->SizeOfImage);
	//所有头+节表文件对齐后的大小,严格按照文件对齐.
	printf("SizeOfHeaders:			%#X\n", pop->SizeOfHeaders);
	//校验和,用来判断文件是否被篡改.比如系统的一些dll加载时会用到.			
	printf("CheckSum:			%#X\n", pop->CheckSum);							
}

    注释掉其他解析部分,运行结果如下图:


win32下PE文件分析之NT头

(五).说明:

    解析过程中最为麻烦的是计算偏移,多算几次,多看下结构图就好了.都是那么过来的.





推荐阅读
  • Mono为何能跨平台
    概念JIT编译(JITcompilation),运行时需要代码时,将Microsoft中间语言(MSIL)转换为机器码的编译。CLR(CommonLa ... [详细]
  • 拥抱Android Design Support Library新变化(导航视图、悬浮ActionBar)
    转载请注明明桑AndroidAndroid5.0Loollipop作为Android最重要的版本之一,为我们带来了全新的界面风格和设计语言。看起来很受欢迎࿰ ... [详细]
  • 本文介绍了PE文件结构中的导出表的解析方法,包括获取区段头表、遍历查找所在的区段等步骤。通过该方法可以准确地解析PE文件中的导出表信息。 ... [详细]
  • Android源码深入理解JNI技术的概述和应用
    本文介绍了Android源码中的JNI技术,包括概述和应用。JNI是Java Native Interface的缩写,是一种技术,可以实现Java程序调用Native语言写的函数,以及Native程序调用Java层的函数。在Android平台上,JNI充当了连接Java世界和Native世界的桥梁。本文通过分析Android源码中的相关文件和位置,深入探讨了JNI技术在Android开发中的重要性和应用场景。 ... [详细]
  • 如何搭建Java开发环境并开发WinCE项目
    本文介绍了如何搭建Java开发环境并开发WinCE项目,包括搭建开发环境的步骤和获取SDK的几种方式。同时还解答了一些关于WinCE开发的常见问题。通过阅读本文,您将了解如何使用Java进行嵌入式开发,并能够顺利开发WinCE应用程序。 ... [详细]
  • 全面介绍Windows内存管理机制及C++内存分配实例(四):内存映射文件
    本文旨在全面介绍Windows内存管理机制及C++内存分配实例中的内存映射文件。通过对内存映射文件的使用场合和与虚拟内存的区别进行解析,帮助读者更好地理解操作系统的内存管理机制。同时,本文还提供了相关章节的链接,方便读者深入学习Windows内存管理及C++内存分配实例的其他内容。 ... [详细]
  • 本文介绍了NetCore WebAPI开发的探索过程,包括新建项目、运行接口获取数据、跨平台部署等。同时还提供了客户端访问代码示例,包括Post函数、服务器post地址、api参数等。详细讲解了部署模式选择、框架依赖和独立部署的区别,以及在Windows和Linux平台上的部署方法。 ... [详细]
  • 本文介绍了使用Rust语言编写、保存和编译程序的简单步骤。首先,打开记事本文件并编写程序代码,然后将代码保存到一个以.rs为扩展名的文件中。接下来,使用rustc命令来编译运行程序。最后,通过命令行运行编译后的程序,得到输出结果。如果遇到编译错误,可以下载Build Tools for Visual Studio 2017来解决。 ... [详细]
  • Introduction(简介)Forbeingapowerfulobject-orientedprogramminglanguage,Cisuseda ... [详细]
  • 本文介绍了lua语言中闭包的特性及其在模式匹配、日期处理、编译和模块化等方面的应用。lua中的闭包是严格遵循词法定界的第一类值,函数可以作为变量自由传递,也可以作为参数传递给其他函数。这些特性使得lua语言具有极大的灵活性,为程序开发带来了便利。 ... [详细]
  • 本文详细介绍了Linux中进程控制块PCBtask_struct结构体的结构和作用,包括进程状态、进程号、待处理信号、进程地址空间、调度标志、锁深度、基本时间片、调度策略以及内存管理信息等方面的内容。阅读本文可以更加深入地了解Linux进程管理的原理和机制。 ... [详细]
  • 加密世界下一个主流叙事领域:L2、跨链桥、GameFi等
    本文介绍了加密世界下一个主流叙事的七个潜力领域,包括L2、跨链桥、GameFi等。L2作为以太坊的二层解决方案,在过去一年取得了巨大成功,跨链桥和互操作性是多链Web3中最重要的因素。去中心化的数据存储领域也具有巨大潜力,未来云存储市场有望达到1500亿美元。DAO和社交代币将成为购买和控制现实世界资产的重要方式,而GameFi作为数字资产在高收入游戏中的应用有望推动数字资产走向主流。衍生品市场也在不断发展壮大。 ... [详细]
  • 本文介绍了在Windows环境下如何配置php+apache环境,包括下载php7和apache2.4、安装vc2015运行时环境、启动php7和apache2.4等步骤。希望对需要搭建php7环境的读者有一定的参考价值。摘要长度为169字。 ... [详细]
  • 3.223.28周学习总结中的贪心作业收获及困惑
    本文是对3.223.28周学习总结中的贪心作业进行总结,作者在解题过程中参考了他人的代码,但前提是要先理解题目并有解题思路。作者分享了自己在贪心作业中的收获,同时提到了一道让他困惑的题目,即input details部分引发的疑惑。 ... [详细]
  • 本文整理了Java中java.lang.NoSuchMethodError.getMessage()方法的一些代码示例,展示了NoSuchMethodErr ... [详细]
author-avatar
杨浩
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有