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.
This commit is contained in:
Moinak Ghosh 2014-12-20 11:24:09 +05:30
parent 9a5361f010
commit 1db822d866
11 changed files with 456 additions and 15 deletions

View file

@ -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

151
archive/dispack_helper.cpp Normal file
View file

@ -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 <http://www.gnu.org/licenses/>.
*
* moinakg@belenix.org, http://moinakg.wordpress.com/
*
*/
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#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;i<nthdr->FileHeader.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

View file

@ -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);
}

View file

@ -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);

View file

@ -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);
}

View file

@ -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)
{

View file

@ -26,12 +26,12 @@
#define __DIS_HPP__
#include <utils.h>
#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

View file

@ -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

View file

@ -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;

View file

@ -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;
/*

143
utils/winsupport.h Normal file
View file

@ -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 <http://www.gnu.org/licenses/>.
*
* 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