PE结构解析的代码

0x00 32位程序的PE结构

DOS头

typedef struct _IMAGE_DOS_HEADER {      // DOS .EXE header
    WORD   e_magic;                     // Magic number
    WORD   e_cblp;                      // Bytes on last page of file
    WORD   e_cp;                        // Pages in file
    WORD   e_crlc;                      // Relocations
    WORD   e_cparhdr;                   // Size of header in paragraphs
    WORD   e_minalloc;                  // Minimum extra paragraphs needed
    WORD   e_maxalloc;                  // Maximum extra paragraphs needed
    WORD   e_ss;                        // Initial (relative) SS value
    WORD   e_sp;                        // Initial SP value
    WORD   e_csum;                      // Checksum
    WORD   e_ip;                        // Initial IP value
    WORD   e_cs;                        // Initial (relative) CS value
    WORD   e_lfarlc;                    // File address of relocation table
    WORD   e_ovno;                      // Overlay number
    WORD   e_res[4];                    // Reserved words
    WORD   e_oemid;                     // OEM identifier (for e_oeminfo)
    WORD   e_oeminfo;                   // OEM information; e_oemid specific
    WORD   e_res2[10];                  // Reserved words
    LONG   e_lfanew;                    // File address of new exe header
  } IMAGE_DOS_HEADER;

nt头 = PE标识 + 文件头 + 扩展头

typedef struct _IMAGE_NT_HEADERS {
    DWORD Signature;
    IMAGE_FILE_HEADER FileHeader;
    IMAGE_OPTIONAL_HEADER32 OptionalHeader;
} IMAGE_NT_HEADERS32,

文件头

typedef struct _IMAGE_FILE_HEADER {
    WORD    Machine;
    WORD    NumberOfSections;
    DWORD   TimeDateStamp;
    DWORD   PointerToSymbolTable;
    DWORD   NumberOfSymbols;
    WORD    SizeOfOptionalHeader;
    WORD    Characteristics;
} IMAGE_FILE_HEADER;

扩展头,文件头中的SizeOfOptionalHeader指定了扩展头的大小。

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;

0x01 一份用c实现的代码段起始地址获取

  • 读取dos头,获得nt头的偏移A
  • 文件头的偏移为A+sizeof(DWORD)
int get_text(FILE *file, unsigned int *start, unsigned int *end, unsigned int *vaddr)
{
	/*目标文件为32位*/
	/*获取代码段在二进制文件中的起始和终止地址*/

	FILE *pfile = file;
	unsigned int e_lfanew;
	unsigned int optional_header_size;
	unsigned int section_count;

	IMAGE_DOS_HEADER *dos_header;
	IMAGE_FILE_HEADER *file_header;
	IMAGE_SECTION_HEADER *section_header;

	/*读取dos头*/
	dos_header = (IMAGE_DOS_HEADER *)calloc(1, sizeof(IMAGE_DOS_HEADER));
	fread(dos_header, sizeof(IMAGE_DOS_HEADER), 1, file);
	e_lfanew = dos_header->e_lfanew;
	free(dos_header);

	/*读取文件头*/
	file_header = (IMAGE_FILE_HEADER *)calloc(1, sizeof(IMAGE_FILE_HEADER));
	//文件头的偏移为 e_lfanew + sizeof(DWORD)
	fseek(file, e_lfanew + sizeof(DWORD), SEEK_SET);
	fread(file_header, sizeof(IMAGE_FILE_HEADER), 1 , file);
	optional_header_size = file_header->SizeOfOptionalHeader;
	section_count = file_header->NumberOfSections;
	free(file_header);

	/*读取节表*/
	section_header = (IMAGE_SECTION_HEADER *)calloc(section_count, sizeof(IMAGE_SECTION_HEADER));
	//节表的偏移为 e_lfanew + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER) + optional_header_size
	fseek(file, e_lfanew + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER) + optional_header_size, SEEK_SET);
	fread(section_header, sizeof(IMAGE_SECTION_HEADER), section_count, file);

	for (int i = 0; i < section_count; i++) {
		if (strncmp((char *)(section_header + i)->Name, ".text", 5) == 0) {
			*start = (section_header + i)->PointerToRawData;
			*end = (section_header + i)->PointerToRawData + (section_header + i)->SizeOfRawData;
			*vaddr = (section_header + i)->VirtualAddress;
			break;
		}
	}

	free(section_header);
	return 0;
}

0x02 去除ASLR

dll加载时启用ALSR是由操作系统和二进制文件两方面决定的,Windows 10中的Windows安全中心提供了关闭ASLR的选项,但是启用后并不奏效,使用一些老的方法(修改注册表内存管理中的MoveImages值为零)也失效了,因此直接把二进制文件中的位进行修改。

这是由扩展头中的DllCharacteristics决定的,IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE这一位是关键,将其置零,那么将DllCharacteristics的值与上0xFFBF即可。

// DllCharacteristics Entries

//      IMAGE_LIBRARY_PROCESS_INIT            0x0001     // Reserved.
//      IMAGE_LIBRARY_PROCESS_TERM            0x0002     // Reserved.
//      IMAGE_LIBRARY_THREAD_INIT             0x0004     // Reserved.
//      IMAGE_LIBRARY_THREAD_TERM             0x0008     // Reserved.
#define IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA    0x0020  // Image can handle a high entropy 64-bit virtual address space.
#define IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE 0x0040     // DLL can move.
#define IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY    0x0080     // Code Integrity Image
#define IMAGE_DLLCHARACTERISTICS_NX_COMPAT    0x0100     // Image is NX compatible
#define IMAGE_DLLCHARACTERISTICS_NO_ISOLATION 0x0200     // Image understands isolation and doesn‘t want it
#define IMAGE_DLLCHARACTERISTICS_NO_SEH       0x0400     // Image does not use SEH.  No SE handler may reside in this image
#define IMAGE_DLLCHARACTERISTICS_NO_BIND      0x0800     // Do not bind this image.
#define IMAGE_DLLCHARACTERISTICS_APPCONTAINER 0x1000     // Image should execute in an AppContainer
#define IMAGE_DLLCHARACTERISTICS_WDM_DRIVER   0x2000     // Driver uses WDM model
#define IMAGE_DLLCHARACTERISTICS_GUARD_CF     0x4000     // Image supports Control Flow Guard.
#define IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE     0x8000

一份python脚本

import sys
import pefile
import struct

class Patch(object):
    def __init__(self, filename):
        with open(filename, ‘rb‘) as f:
            self.data = f.read()

    def save_file(self, filename):
        with open(filename, ‘wb‘) as f:
            f.write(self.data)

    def patch_file(self, offset, data):
        if(offset >= 0) and (offset + len(data)) < len(self.data):
            self.data = self.data[0:offset] + data + self.data[offset+len(data):]
            return True
        else:
            return False

def get_dllcharacteristics(pe):
    offset = pe.OPTIONAL_HEADER.get_field_absolute_offset(‘DllCharacteristics‘)
    value = pe.OPTIONAL_HEADER.DllCharacteristics
    return offset, value

def disable_aslr(file):
    pe = pefile.PE(file)
    offset, value = get_dllcharacteristics(pe)
    # IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE = 0
    value &= 0xFFBF

    patch = Patch(file)
    if patch.patch_file(offset, struct.pack(‘<H‘, value)):
        patch.save_file(file + ‘_patch‘)

if __name__ == ‘__main__‘:
    disable_aslr(sys.argv[1])

原文地址:https://www.cnblogs.com/go2sleep/p/12464682.html

时间: 2024-10-06 04:25:05

PE结构解析的代码的相关文章

手写PE结构解析工具

PE格式是 Windows下最常用的可执行文件格式,理解PE文件格式不仅可以了解操作系统的加载流程,还可以更好的理解操作系统对进程和内存相关的管理知识,而有些技术必须建立在了解PE文件格式的基础上,如文件加密与解密,病毒分析,外挂技术等,在PE文件中我们最需要关注,PE结构,导入表,导出表,重定位表,下面将具体介绍PE的关键结构,并使用C语言编程获取到这些结构数据. 参考文献: [琢石成器 Win32汇编语言程序设计 - 罗云彬] 整理学习笔记,精简内容,翻译汇编代码C语言化 在任何一款操作系统

C++PE文件格式解析类(轻松制作自己的PE文件解析器)

PE是Portable Executable File Format(可移植的运行体)简写,它是眼下Windows平台上的主流可运行文件格式. PE文件里包括的内容非常多,详细我就不在这解释了,有兴趣的能够參看之后列出的參考资料及其它相关内容. 近期我也在学习PE文件格式,參考了很多资料.用C++封装了一个高效方便的PE文件格式解析的类. 该类对想学PE文件结构的朋友可算一份可贵的资料.代码均非常易懂,考虑较全面,具有一定的通用性. 同一时候该类也能够让想创建自己的PE文件解析软件的朋能够轻松在

PE文件解析 基础篇

PE文件解析 基础篇 来源 https://bbs.pediy.com/thread-247114.htm 前言 之前学习了PE格式,为了更好的理解,决定写一个类似LoadPE的小工具. 编译器是VS2015,采用MFC框架. 此系列文章采用边介绍知识点,边写代码的形式,以免变的无聊丧失兴趣. PE知识请参照<加密与解密>第10章 文章有错误或则不清楚的地方还请您指出. PE文件格式 1.PE文件基本概念 PE文件是windows系统中遵循PE结构的文件,比如以.exe   .dll为后缀名的

MYSQL 源代码 编译原理 AST和解析树 代码语法解析

MYSQL 源代码 编译原理 AST和解析树 代码语法解析 http://blog.csdn.net/wfp458113181wfp/article/details/17082355 使用AST树 分类:             antlr              2013-12-02 22:39     255人阅读     评论(0)     收藏     举报 目录(?)[+] 第五章使用AST树中间结果来计算表达式值 创建ASTS 第五章.使用AST树中间结果来计算表达式值 现在我们已

Redis源码解析:18Hiredis同步API和回复解析API代码解析.docx

Redis的sentinel模式使用了Hiredis代码,Hiredis是redis数据库一个轻量级的C语言客户端库.它实现的向Redis发送命令的API函数redisCommand,使用方法类似于printf.因此只要熟悉redis命令,就可以很容易的使用该函数将redis命令字符串,转换成统一请求协议格式之后,发送给Redis服务器. Hiredis库包含三类API:同步操作API.异步操作API和回复解析API.本文主要介绍同步操作API和回复解析API,下一篇介绍异步操作API. 一:同

PE结构、SEH相关知识学习笔记

原文:http://www.pediy.com/kssd/index.html -- 病毒技术 -- 病毒知识 -- Anti Virus专题 PE结构的学习 原文中用fasm自己构造了一个pe,这里贴一个用masm的,其实是使用WriteFile API将编写的PE数据写成文件~也没啥好说的,PE结构在这里没有仔细介绍,需要可以另外查询,剩下要说的的基本都在代码注释里了 参考:点击打开链接(PEDIY技术之新思路(二)_用'高级'编译器MASM实现自定义PE文件结构) Pe.asm: REMO

MBR结构解析与fdisk的bash实现

一.MBR结构解析 首先我们先介绍一些MBR的基本知识基础,再晾图片分析. MBR主要分为三大块各自是: 1.载入引导程序(446K) 2.分区表(64k) 3.标志结束位(2k) 载入引导程序:内容是因机器而异它里面正如其名.就是存放载入引导程序.如今基本的载入引导程序是LILO(LInux LOader)和 GNU GRUB(GRand Unified Boot loader). 分区表:里面主要记录4个16K主分区的信息.我们将在下文进行具体介绍. 表示结束位:就是标志MBR结束.通常是0

OD 实验 - 对 PE 结构的简单分析

载入程序,按 Alt+M 查看内存空间 双击进入程序的 PE 头 这些为 DOS 环境下才会运行的 这个执行 PE 的地址,PE 结构的偏移地址为 C0 找到这个地址 以 PE 开头 SizeOfCode 为代码段的大小 SizeOfInitializedData 为所有含已初始化数据的块的大小 这两个值明显太大了,可能被恶意修改过了,可以把他们修改一下 右键 -> 二进制 -> 编辑,快捷键为 Ctrl+E 或者右键 -> 修改整数 SizeOfCode 可能为 400,SizeOfI

编写自定义PE结构的程序(如何手写一个PE,高级编译器都是编译好的PE头部,例如MASM,TASM等,NASM,FASM是低级编译器.可以自定义结构)

正在学PE结构...感谢个位大哥的文章和资料...这里先说声谢谢 一般高级编译器都是编译好的PE头部,例如MASM,TASM等一直都说NASM,FASM是低级编译器.可以自定义结构但是苦于无人发布相关文章说明..我这里就简单的用NASM写一下由于刚学PE结构许多东西都不太懂希望个位大侠指点如何打造一个迷你的PE结构..我暂只只能作到617字节下面随着学习的深入...还有更迷你的PE出现... 代码可以直接编译..编译参数:nasmw -fbin MsgBoxA.asm -o MsgBoxA.ex