From 1db822d8660ba0fae76571cda176d8525835c18c Mon Sep 17 00:00:00 2001 From: Moinak Ghosh Date: Sat, 20 Dec 2014 11:24:09 +0530 Subject: [PATCH] Add Dispack file-level filter in the libarchive chain. Add new file type for Win32-PE executables (Dispack). Reset file type flag after filter processing for better compression. Fix array index handling for file type list. --- Makefile.in | 4 +- archive/dispack_helper.cpp | 151 +++++++++++++++++++++++++++++++++++++ archive/pc_arc_filter.c | 118 ++++++++++++++++++++++++++++- archive/pc_arc_filter.h | 1 + archive/pc_archive.c | 6 +- filters/dispack/dis.cpp | 22 +++++- filters/dispack/dis.hpp | 7 +- filters/dispack/types.hpp | 4 +- pcompress.c | 10 ++- utils/utils.h | 5 +- utils/winsupport.h | 143 +++++++++++++++++++++++++++++++++++ 11 files changed, 456 insertions(+), 15 deletions(-) create mode 100644 archive/dispack_helper.cpp create mode 100644 utils/winsupport.h diff --git a/Makefile.in b/Makefile.in index d013488..4ea6c36 100644 --- a/Makefile.in +++ b/Makefile.in @@ -156,7 +156,7 @@ PPNMOBJS = $(PPNMSRCS:.cpp=.o) WAVPKSRCS = archive/wavpack_helper.c WAVPKOBJS = $(WAVPKSRCS:.c=.o) -DISPACKSRCS = filters/dispack/dis.cpp +DISPACKSRCS = filters/dispack/dis.cpp archive/dispack_helper.cpp DISPACKHDRS = filters/dispack/dis.hpp filters/dispack/types.hpp DISPACKOBJS = $(DISPACKSRCS:.cpp=.o) @@ -235,7 +235,7 @@ BASE_CPPFLAGS = -I. -I./lzma -I./lzfx -I./lz4 -I./rabin -I./bsdiff -DNODEFAULT_P -I./crypto/scrypt -I./crypto/aes -I./crypto @KEYLEN@ -I./rabin/global \ -I./crypto/keccak -I./filters/transpose -I./crypto/blake2 $(EXTRA_CPPFLAGS) \ -I./crypto/xsalsa20 -I./archive -pedantic -Wall -I./filters -fno-strict-aliasing \ - -Wno-unused-but-set-variable -Wno-enum-compare -I./filters/analyzer \ + -Wno-unused-but-set-variable -Wno-enum-compare -I./filters/analyzer -I./filters/dispack \ @COMPAT_CPPFLAGS@ @XSALSA20_DEBUG@ -I@LIBARCHIVE_DIR@/libarchive -I./filters/packjpg \ -I./filters/packpnm @ENABLE_WAVPACK@ COMMON_CPPFLAGS = $(BASE_CPPFLAGS) -std=gnu99 diff --git a/archive/dispack_helper.cpp b/archive/dispack_helper.cpp new file mode 100644 index 0000000..ca2e55b --- /dev/null +++ b/archive/dispack_helper.cpp @@ -0,0 +1,151 @@ +/* + * This file is a part of Pcompress, a chunked parallel multi- + * algorithm lossless compression and decompression program. + * + * Copyright (C) 2014 Moinak Ghosh. All rights reserved. + * Use is subject to license terms. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program. + * If not, see . + * + * moinakg@belenix.org, http://moinakg.wordpress.com/ + * + */ + +#include +#include +#include +#include +#include +#include + +#include "utils.h" +#include "winsupport.h" +#include "types.hpp" +#include "dis.hpp" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef unsigned char uchar_t; + +#pragma pack(1) +struct FileHeader +{ + sU32 SizeBefore; // number of bytes before start of code section + sU32 SizeAfter; // number of bytes after code section + sU32 SizeTransformed; // size of transformed code section + sU32 SizeOriginal; // size of untransformed code section + sU32 Origin; // virtual address of first byte +}; +#pragma pack() + +size_t +dispack_filter_encode(uchar_t *inData, size_t len, uchar_t **out_buf) +{ + uchar_t *pos; + FileHeader hdr; + + *out_buf = (uchar_t *)malloc(len); + if (*out_buf == NULL) + return (0); + + // assume the input file is a PE executable. + IMAGE_DOS_HEADER *doshdr = (IMAGE_DOS_HEADER *) inData; + IMAGE_NT_HEADERS *nthdr = (IMAGE_NT_HEADERS *) (inData + doshdr->e_lfanew); + + if (nthdr->FileHeader.Machine != IMAGE_FILE_MACHINE_I386 || + nthdr->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + // Only 32-bit PE files for x86 supported + return (0); + } + + sU32 imageBase = nthdr->OptionalHeader.ImageBase; + sU32 codeStart = nthdr->OptionalHeader.BaseOfCode; + sU32 codeSize = nthdr->OptionalHeader.SizeOfCode; + sU32 fileOffs = 0; // find file offset of first section + + // find section containing code + IMAGE_SECTION_HEADER *sec = IMAGE_FIRST_SECTION(nthdr); + for (sInt i=0;iFileHeader.NumberOfSections;i++) { + if (codeStart >= sec[i].VirtualAddress && codeStart < + sec[i].VirtualAddress + sec[i].SizeOfRawData) + fileOffs = sec[i].PointerToRawData + (codeStart - sec[i].VirtualAddress); + } + + if (fileOffs == 0) { + // Code section not found! + return (0); + } + + // Keep space for header + pos = *out_buf + sizeof (hdr); + + // transform code + sU32 transSize = len - sizeof (hdr); + if (DisFilter(inData + fileOffs, codeSize, imageBase + codeStart, pos, transSize) == NULL) + return (0); + pos += transSize; + + // Now plonk the header + hdr.SizeBefore = fileOffs; + hdr.SizeAfter = len - (fileOffs + codeSize); + hdr.SizeTransformed = transSize; + hdr.SizeOriginal = codeSize; + hdr.Origin = imageBase + codeStart; + memcpy(*out_buf, &hdr, sizeof (hdr)); + + // Copy rest of the data + memcpy(pos, inData, hdr.SizeBefore); + pos += hdr.SizeBefore; + memcpy(pos, inData + (fileOffs + codeSize), hdr.SizeAfter); + pos += hdr.SizeAfter; + + return (pos - *out_buf); +} + +size_t +dispack_filter_decode(uchar_t *inData, size_t len, uchar_t **out_buf) +{ + uchar_t *decoded; + FileHeader *hdr = (FileHeader *)inData; + + sU8 *transformed = inData + sizeof (FileHeader); + sU8 *before = transformed + hdr->SizeTransformed; + sU8 *after = before + hdr->SizeBefore; + + // alloc buffer for unfiltered code + *out_buf = (uchar_t *)malloc(len); + if (*out_buf == NULL) + return (0); + + decoded = *out_buf; + memcpy(decoded, before, hdr->SizeBefore); + decoded += hdr->SizeBefore; + + if (!DisUnFilter(transformed, hdr->SizeTransformed, decoded, + hdr->SizeOriginal, hdr->Origin)) { + return (0); + } + decoded += hdr->SizeOriginal; + memcpy(decoded, after, hdr->SizeAfter); + decoded += hdr->SizeAfter; + + return (decoded - *out_buf); +} + +#ifdef __cplusplus +} +#endif diff --git a/archive/pc_arc_filter.c b/archive/pc_arc_filter.c index b4121d1..55b9949 100644 --- a/archive/pc_arc_filter.c +++ b/archive/pc_arc_filter.c @@ -61,6 +61,10 @@ extern size_t wavpack_filter_decode(uchar_t *in_buf, size_t len, uchar_t **out_b ssize_t wavpack_filter(struct filter_info *fi, void *filter_private); #endif +size_t dispack_filter_encode(uchar_t *inData, size_t len, uchar_t **out_buf); +size_t dispack_filter_decode(uchar_t *inData, size_t len, uchar_t **out_buf); +ssize_t dispack_filter(struct filter_info *fi, void *filter_private); + void add_filters_by_type(struct type_data *typetab, struct filter_flags *ff) { @@ -90,6 +94,18 @@ add_filters_by_type(struct type_data *typetab, struct filter_flags *ff) } #endif + if (ff->exe_preprocess) { + if (!sdat) { + sdat = (struct scratch_buffer *)malloc(sizeof (struct scratch_buffer)); + sdat->in_buff = NULL; + sdat->in_bufflen = 0; + } + slot = TYPE_EXE32_PE >> 3; + typetab[slot].filter_private = sdat; + typetab[slot].filter_func = dispack_filter; + typetab[slot].filter_name = "Dispack"; + } + #ifdef _ENABLE_WAVPACK_ if (ff->enable_wavpack) { if (!sdat) { @@ -111,7 +127,7 @@ type_tag_from_filter_name(struct type_data *typetab, const char *fname, size_t l { size_t i; - for (i = 0; i < NUM_SUB_TYPES; i++) + for (i = 0; i <= NUM_SUB_TYPES; i++) { if (typetab[i].filter_name && strncmp(fname, typetab[i].filter_name, len) == 0) @@ -507,3 +523,103 @@ wavpack_filter(struct filter_info *fi, void *filter_private) } #endif /* _ENABLE_WAVPACK_ */ +ssize_t +dispack_filter(struct filter_info *fi, void *filter_private) +{ + struct scratch_buffer *sdat = (struct scratch_buffer *)filter_private; + uchar_t *mapbuf, *out; + uint64_t len, in_size = 0, len1; + + len = archive_entry_size(fi->entry); + len1 = len; + if (len > WVPK_FILE_SIZE_LIMIT) // Bork on massive files + return (FILTER_RETURN_SKIP); + + if (fi->compressing) { + mapbuf = mmap(NULL, len, PROT_READ, MAP_SHARED, fi->fd, 0); + if (mapbuf == NULL) { + log_msg(LOG_ERR, 1, "Mmap failed in Dispack filter."); + return (FILTER_RETURN_ERROR); + } + + /* + * No check for supported 32-bit exe here. EXE types are always + * detected by file header analysis. So no need to duplicate here. + */ + } else { + /* + * Allocate input buffer and read archive data stream for the entry + * into this buffer. + */ + ensure_buffer(sdat, len); + if (sdat->in_buff == NULL) { + log_msg(LOG_ERR, 1, "Out of memory."); + return (FILTER_RETURN_ERROR); + } + + in_size = copy_archive_data(fi->source_arc, sdat->in_buff); + if (in_size != len) { + log_msg(LOG_ERR, 0, "Failed to read archive data."); + return (FILTER_RETURN_ERROR); + } + + /* + * First 8 bytes in the data is the compressed size of the entry. + * LibArchive always zero-pads entries to their original size so + * we need to separately store the compressed size. + */ + in_size = LE64(U64_P(sdat->in_buff)); + mapbuf = sdat->in_buff + 8; + + /* + * No check for supported EXE types needed here since supported + * and filtered files are tagged in the archive using xattrs during + * compression. + */ + } + + /* + * Compression case. + */ + if (fi->compressing) { + out = NULL; + len = dispack_filter_encode(mapbuf, len, &out); + if (len == 0 || len >= (len1 - 8)) { + munmap(mapbuf, len1); + free(out); + return (FILTER_RETURN_SKIP); + } + munmap(mapbuf, len1); + + fi->fout->output_type = FILTER_OUTPUT_MEM; + fi->fout->out = out; + fi->fout->out_size = len; + fi->fout->hdr.in_size = LE64(len1); + return (ARCHIVE_OK); + } + + /* + * Decompression case. + */ + out = NULL; + if ((len = dispack_filter_decode(mapbuf, in_size, &out)) == 0) { + /* + * If filter failed we indicate a soft error to continue the + * archive extraction. + */ + free(out); + out = malloc(len); + memcpy(out, sdat->in_buff, len); + + fi->fout->output_type = FILTER_OUTPUT_MEM; + fi->fout->out = out; + fi->fout->out_size = len; + return (FILTER_RETURN_SOFT_ERROR); + } + + fi->fout->output_type = FILTER_OUTPUT_MEM; + fi->fout->out = out; + fi->fout->out_size = len; + return (ARCHIVE_OK); +} + diff --git a/archive/pc_arc_filter.h b/archive/pc_arc_filter.h index 9bda44f..8978a64 100644 --- a/archive/pc_arc_filter.h +++ b/archive/pc_arc_filter.h @@ -90,6 +90,7 @@ struct filter_info { struct filter_flags { int enable_packjpg; int enable_wavpack; + int exe_preprocess; }; typedef ssize_t (*filter_func_ptr)(struct filter_info *fi, void *filter_private); diff --git a/archive/pc_archive.c b/archive/pc_archive.c index dfe0ba5..7da9608 100644 --- a/archive/pc_archive.c +++ b/archive/pc_archive.c @@ -63,7 +63,7 @@ static struct ext_hash_entry { int type; } *exthtab = NULL; -static struct type_data typetab[NUM_SUB_TYPES]; +static struct type_data typetab[NUM_SUB_TYPES+1]; /* AE_IFREG Regular file @@ -1100,6 +1100,7 @@ copy_file_data(pc_ctx_t *pctx, struct archive *arc, struct archive_entry *entry, &fout, 1, pctx->level); if (rv != FILTER_RETURN_SKIP && rv != FILTER_RETURN_ERROR) { + pctx->ctype = TYPE_UNKNOWN; // Force analyzer on filter output if (fout.output_type == FILTER_OUTPUT_MEM) { archive_entry_xattr_add_entry(entry, FILTER_XATTR_ENTRY, fname, strlen(fname)); @@ -1176,6 +1177,7 @@ do_map: &fout, 1, pctx->level); if (rv != FILTER_RETURN_SKIP && rv != FILTER_RETURN_ERROR) { + pctx->ctype = TYPE_UNKNOWN; // Force analyzer on filter output if (fout.output_type == FILTER_OUTPUT_MEM) { archive_entry_xattr_add_entry(entry, FILTER_XATTR_ENTRY, @@ -1997,7 +1999,7 @@ detect_type_by_data(uchar_t *buf, size_t len) if (id == 0x8664) return (TYPE_BINARY|TYPE_EXE64); else - return (TYPE_BINARY|TYPE_EXE32); + return (TYPE_BINARY|TYPE_EXE32_PE); } else { return (TYPE_BINARY); } diff --git a/filters/dispack/dis.cpp b/filters/dispack/dis.cpp index 9273435..113281b 100644 --- a/filters/dispack/dis.cpp +++ b/filters/dispack/dis.cpp @@ -637,10 +637,10 @@ struct DisFilterCtx /****************************************************************************/ -static sU8 * -DisFilter(DisFilterCtx &ctx, sU8 *src, sU32 size, sU32 origin, sU8 *dst, sU32 &outputSize) +sU8 * +DisFilter(sU8 *src, sU32 size, sU32 origin, sU8 *dst, sU32 &outputSize) { -// DisFilterCtx ctx(origin,origin+size); + DisFilterCtx ctx(origin,origin+size); // main loop: handle everything but the last few bytes sU32 pos = 0; @@ -707,7 +707,7 @@ static inline sU32 Copy32(sU8 *&d,sU8 *&s) { sU32 v = Fetch32B(s); Write32(d, #define Copy16Chk(strm) do { CheckSrcDst(strm,2); Copy16(dest,stream[strm]); } while(0) #define Copy32Chk(strm) do { CheckSrcDst(strm,4); Copy32(dest,stream[strm]); } while(0) -static sBool +sBool DisUnFilter(sU8 *source,sU32 sourceSize,sU8 *dest,sU32 destSize,sU32 memStart) { sU8 *stream[ST_MAX]; @@ -902,6 +902,10 @@ DisUnFilter(sU8 *source,sU32 sourceSize,sU8 *dest,sU32 destSize,sU32 memStart) return sTRUE; } +/* + * NOTE: function unused. Retained for future need. + */ +#if 0 /* * Try to estimate if the given data block contains 32-bit x86 instructions * especially of the call and jmp variety. @@ -926,6 +930,7 @@ is_x86_code(uchar_t *buf, int len) avgFreq = ln>>8; return (freq[0x8b] > avgFreq && freq[0x00] > avgFreq * 2 && freq[0xE8] > 6); } +#endif #ifdef __cplusplus extern "C" { @@ -1007,6 +1012,10 @@ Inverse_E89(uint8_t *src, uint64_t sz) return (0); } +/* + * NOTE: function unused. Retained for future need. + */ +#if 0 /* * 32-bit x86 executable packer top-level routines. Detected x86 executable data * are passed through these encoding routines. The data chunk is split into 32KB @@ -1106,7 +1115,12 @@ dispack_encode(uchar_t *from, uint64_t fromlen, uchar_t *to, uint64_t *dstlen) #endif return (0); } +#endif +/* + * This function retained for ability to decode older archives encoded using raw block + * dispack. + */ int dispack_decode(uchar_t *from, uint64_t fromlen, uchar_t *to, uint64_t *dstlen) { diff --git a/filters/dispack/dis.hpp b/filters/dispack/dis.hpp index 73c8da7..723c044 100644 --- a/filters/dispack/dis.hpp +++ b/filters/dispack/dis.hpp @@ -26,12 +26,12 @@ #define __DIS_HPP__ #include +#include "types.hpp" #ifdef __cplusplus extern "C" { #endif -int dispack_encode(uchar_t *from, uint64_t fromlen, uchar_t *to, uint64_t *_dstlen); int dispack_decode(uchar_t *from, uint64_t fromlen, uchar_t *to, uint64_t *dstlen); int Forward_E89(uint8_t *src, uint64_t sz); @@ -41,4 +41,9 @@ int Inverse_E89(uint8_t *src, uint64_t sz); } #endif +#ifdef __cplusplus +sU8 *DisFilter(sU8 *src, sU32 size, sU32 origin, sU8 *dst, sU32 &outputSize); +sBool DisUnFilter(sU8 *source,sU32 sourceSize,sU8 *dest,sU32 destSize,sU32 memStart); +#endif + #endif diff --git a/filters/dispack/types.hpp b/filters/dispack/types.hpp index f672e1f..c382f98 100644 --- a/filters/dispack/types.hpp +++ b/filters/dispack/types.hpp @@ -39,12 +39,14 @@ typedef uint64_t sU64; typedef int64_t sS64; typedef int sInt; typedef char sChar; -typedef bool sBool; typedef float sF32; typedef double sF64; +#ifdef __cplusplus +typedef bool sBool; #define sTRUE true #define sFALSE false +#endif #define _byteswap_ushort htons #define _byteswap_ulong htonl diff --git a/pcompress.c b/pcompress.c index 817592f..4458b3f 100644 --- a/pcompress.c +++ b/pcompress.c @@ -223,7 +223,6 @@ preproc_compress(pc_ctx_t *pctx, compress_func_ptr cmp_func, void *src, uint64_t stype = PC_SUBTYPE(btype); dict = 0; analyzed = 0; - if (btype == TYPE_UNKNOWN || stype == TYPE_ARCHIVE_TAR || stype == TYPE_PDF || interesting) { analyze_buffer(src, srclen, &actx); analyzed = 1; @@ -3140,6 +3139,7 @@ init_pc_context(pc_ctx_t *pctx, int argc, char *argv[]) pctx->advanced_opts = 0; ff.enable_packjpg = 0; ff.enable_wavpack = 0; + ff.exe_preprocess = 0; pthread_mutex_lock(&opt_parse); while ((opt = getopt(argc, argv, "dc:s:l:pt:MCDGEe:w:LPS:B:Fk:avmKjxiTn")) != -1) { @@ -3315,6 +3315,7 @@ init_pc_context(pc_ctx_t *pctx, int argc, char *argv[]) case 'x': pctx->advanced_opts = 1; pctx->exe_preprocess = 1; + ff.exe_preprocess = 1; break; case 'T': @@ -3625,10 +3626,13 @@ init_pc_context(pc_ctx_t *pctx, int argc, char *argv[]) ff.enable_packjpg = 1; ff.enable_wavpack = 1; } + if (pctx->level > 8) { + pctx->exe_preprocess = 1; + ff.exe_preprocess = 1; + } init_filters(&ff); pctx->enable_packjpg = ff.enable_packjpg; pctx->enable_wavpack = ff.enable_wavpack; - if (pctx->level > 8) pctx->exe_preprocess = 1; } /* @@ -3658,8 +3662,10 @@ init_pc_context(pc_ctx_t *pctx, int argc, char *argv[]) */ ff.enable_packjpg = 1; ff.enable_wavpack = 1; + ff.exe_preprocess = 1; pctx->enable_packjpg = 1; pctx->enable_wavpack = 1; + pctx->exe_preprocess = 1; init_filters(&ff); } pctx->inited = 1; diff --git a/utils/utils.h b/utils/utils.h index e1bf39d..73de3c2 100644 --- a/utils/utils.h +++ b/utils/utils.h @@ -278,7 +278,7 @@ typedef enum { /* * Sub-types. */ -#define NUM_SUB_TYPES 34 +#define NUM_SUB_TYPES 35 TYPE_EXE32 = 8, TYPE_JPEG = 16, TYPE_MARKUP = 24, @@ -312,7 +312,8 @@ typedef enum { TYPE_PACKPNM = 248, TYPE_WAV = 256, TYPE_ENGLISH = 264, - TYPE_MEDIA_BSC = 272 + TYPE_MEDIA_BSC = 272, + TYPE_EXE32_PE = 280 } data_type_t; /* diff --git a/utils/winsupport.h b/utils/winsupport.h new file mode 100644 index 0000000..1f759c0 --- /dev/null +++ b/utils/winsupport.h @@ -0,0 +1,143 @@ +/* + * This file is a part of Pcompress, a chunked parallel multi- + * algorithm lossless compression and decompression program. + * + * Copyright (C) 2014 Moinak Ghosh. All rights reserved. + * Use is subject to license terms. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program. + * If not, see . + * + * moinakg@belenix.org, http://moinakg.wordpress.com/ + * + */ + +#ifndef __WINSUPPORT_H__ +#define __WINSUPPORT_H__ + +/* + * Windows data types. + */ +typedef unsigned char BYTE; +typedef unsigned short WORD; +typedef unsigned int DWORD; +typedef long LONG; +typedef int INT; + +#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16 +#define IMAGE_SIZEOF_SHORT_NAME 8 +#define IMAGE_FILE_MACHINE_I386 0x014c +#define IMAGE_FILE_MACHINE_AMD64 0x8664 +#define IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x10b +#define IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20b + +typedef struct _IMAGE_DOS_HEADER +{ + WORD e_magic; + WORD e_cblp; + WORD e_cp; + WORD e_crlc; + WORD e_cparhdr; + WORD e_minalloc; + WORD e_maxalloc; + WORD e_ss; + WORD e_sp; + WORD e_csum; + WORD e_ip; + WORD e_cs; + WORD e_lfarlc; + WORD e_ovno; + WORD e_res[4]; + WORD e_oemid; + WORD e_oeminfo; + WORD e_res2[10]; + INT e_lfanew; +} IMAGE_DOS_HEADER; + +typedef struct _IMAGE_DATA_DIRECTORY { + DWORD VirtualAddress; + DWORD Size; +} IMAGE_DATA_DIRECTORY; + +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; + +typedef struct _IMAGE_FILE_HEADER { + WORD Machine; + WORD NumberOfSections; + DWORD TimeDateStamp; + DWORD PointerToSymbolTable; + DWORD NumberOfSymbols; + WORD SizeOfOptionalHeader; + WORD Characteristics; +} IMAGE_FILE_HEADER; + +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; + +typedef struct _IMAGE_NT_HEADERS { + DWORD Signature; + IMAGE_FILE_HEADER FileHeader; + IMAGE_OPTIONAL_HEADER OptionalHeader; +} IMAGE_NT_HEADERS; + +#define IMAGE_FIRST_SECTION(ntheader) \ + ((IMAGE_SECTION_HEADER *)((unsigned char *)&((IMAGE_NT_HEADERS *)(ntheader))->OptionalHeader + \ + ((IMAGE_NT_HEADERS *)(ntheader))->FileHeader.SizeOfOptionalHeader)) + +#endif