热门标签 | 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头

(五).说明:

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





推荐阅读
  • 本文总结了Java初学者需要掌握的六大核心知识点,帮助你更好地理解和应用Java编程。无论你是刚刚入门还是希望巩固基础,这些知识点都是必不可少的。 ... [详细]
  • 【妙】bug称它为数组越界的妙用
    1、聊一聊首先跟大家推荐一首非常温柔的歌曲,跑步的常听。本文主要把自己对C语言中柔性数组、零数组等等的理解分享给大家,并聊聊如何构建一种统一化的学习思想 ... [详细]
  • 本文回顾了作者初次接触Unicode编码时的经历,并详细探讨了ASCII、ANSI、GB2312、UNICODE以及UTF-8和UTF-16编码的区别和应用场景。通过实例分析,帮助读者更好地理解和使用这些编码。 ... [详细]
  • [转]doc,ppt,xls文件格式转PDF格式http:blog.csdn.netlee353086articledetails7920355确实好用。需要注意的是#import ... [详细]
  • 本文总结了一些开发中常见的问题及其解决方案,包括特性过滤器的使用、NuGet程序集版本冲突、线程存储、溢出检查、ThreadPool的最大线程数设置、Redis使用中的问题以及Task.Result和Task.GetAwaiter().GetResult()的区别。 ... [详细]
  • PTArchiver工作原理详解与应用分析
    PTArchiver工作原理及其应用分析本文详细解析了PTArchiver的工作机制,探讨了其在数据归档和管理中的应用。PTArchiver通过高效的压缩算法和灵活的存储策略,实现了对大规模数据的高效管理和长期保存。文章还介绍了其在企业级数据备份、历史数据迁移等场景中的实际应用案例,为用户提供了实用的操作建议和技术支持。 ... [详细]
  • 基于Net Core 3.0与Web API的前后端分离开发:Vue.js在前端的应用
    本文介绍了如何使用Net Core 3.0和Web API进行前后端分离开发,并重点探讨了Vue.js在前端的应用。后端采用MySQL数据库和EF Core框架进行数据操作,开发环境为Windows 10和Visual Studio 2019,MySQL服务器版本为8.0.16。文章详细描述了API项目的创建过程、启动步骤以及必要的插件安装,为开发者提供了一套完整的开发指南。 ... [详细]
  • 在C#编程中,数值结果的格式化展示是提高代码可读性和用户体验的重要手段。本文探讨了多种格式化方法和技巧,如使用格式说明符、自定义格式字符串等,以实现对数值结果的精确控制。通过实例演示,展示了如何灵活运用这些技术来满足不同的展示需求。 ... [详细]
  • 本文深入解析了JDK 8中HashMap的源代码,重点探讨了put方法的工作机制及其内部参数的设定原理。HashMap允许键和值为null,但键为null的情况只能出现一次,因为null键在内部通过索引0进行存储。文章详细分析了capacity(容量)、size(大小)、loadFactor(加载因子)以及红黑树转换阈值的设定原则,帮助读者更好地理解HashMap的高效实现和性能优化策略。 ... [详细]
  • MATLAB字典学习工具箱SPAMS:稀疏与字典学习的详细介绍、配置及应用实例
    SPAMS(Sparse Modeling Software)是一个强大的开源优化工具箱,专为解决多种稀疏估计问题而设计。该工具箱基于MATLAB,提供了丰富的算法和函数,适用于字典学习、信号处理和机器学习等领域。本文将详细介绍SPAMS的配置方法、核心功能及其在实际应用中的典型案例,帮助用户更好地理解和使用这一工具箱。 ... [详细]
  • C语言中类型自动转换的深入解析与应用
    C语言中类型自动转换的深入解析与应用 ... [详细]
  • Python默认字符解析:深入理解Python中的字符串处理
    在Python中,字符串是编程中最基本且常用的数据类型之一。尽管许多初学者是从C语言开始接触字符串,通常通过经典的“Hello, World!”程序入门,但Python对字符串的处理方式更为灵活和强大。本文将深入探讨Python中的字符串处理机制,包括字符串的创建、操作、格式化以及编码解码等方面,帮助读者全面理解Python字符串的特性和应用。 ... [详细]
  • 在VS2013中编译FFMPEG时遇到的问题及解决方案
    在使用VS2013编译旧版本FFMPEG库时遇到了一些问题,因为官方并未提供预编译的LIB和DLL文件。由于对Linux环境不熟悉,只能在Windows环境下进行配置和编译。具体步骤如下:首先,下载FFMPEG的源代码;然后,安装必要的编译工具和依赖项;接着,配置Visual Studio 2013的项目设置;最后,解决编译过程中出现的各种错误和警告。通过这些步骤,最终成功编译出所需的FFMPEG库文件。 ... [详细]
  • 无论是计算机专业学生还是非计算机专业的学习者,在掌握C语言的过程中可能会遇到诸多挑战,不清楚从何入手。为此,本文系统地梳理了2019年福建省C语言的核心知识点,并结合最新的技术进展进行了详细总结,旨在为初学者提供全面的学习指导。文章不仅涵盖了基础语法和数据结构,还深入探讨了指针、内存管理和算法优化等高级主题,帮助读者快速提升编程能力。 ... [详细]
  • 深入解析数据库中的存储过程与触发器技术
    本文深入探讨了数据库中的存储过程与触发器技术。存储过程是一组预编译的SQL语句,经过优化后存储在数据库服务器中,以提高执行效率。在大型数据库系统中,通过调用存储过程的名字,用户可以快速执行复杂的操作,从而提升系统的性能和响应速度。此外,触发器作为一种特殊的存储过程,能够在特定事件发生时自动执行,进一步增强了数据库的自动化管理和数据完整性。 ... [详细]
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社区 版权所有