Line | Count | Source (jump to first uncovered line) |
1 | | /* pefile.h -- |
2 | | |
3 | | This file is part of the UPX executable compressor. |
4 | | |
5 | | Copyright (C) 1996-2025 Markus Franz Xaver Johannes Oberhumer |
6 | | Copyright (C) 1996-2025 Laszlo Molnar |
7 | | All Rights Reserved. |
8 | | |
9 | | UPX and the UCL library are free software; you can redistribute them |
10 | | and/or modify them under the terms of the GNU General Public License as |
11 | | published by the Free Software Foundation; either version 2 of |
12 | | the License, or (at your option) any later version. |
13 | | |
14 | | This program is distributed in the hope that it will be useful, |
15 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
17 | | GNU General Public License for more details. |
18 | | |
19 | | You should have received a copy of the GNU General Public License |
20 | | along with this program; see the file COPYING. |
21 | | If not, write to the Free Software Foundation, Inc., |
22 | | 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
23 | | |
24 | | Markus F.X.J. Oberhumer Laszlo Molnar |
25 | | <markus@oberhumer.com> <ezerotven+github@gmail.com> |
26 | | */ |
27 | | |
28 | | #pragma once |
29 | | |
30 | | /************************************************************************* |
31 | | // general/pe handling |
32 | | **************************************************************************/ |
33 | | |
34 | | class PeFile : public Packer { |
35 | | typedef Packer super; |
36 | | public: |
37 | 78.3k | virtual int getVersion() const override { return 13; } |
38 | | protected: |
39 | | class Interval; |
40 | | class Reloc; |
41 | | class Resource; |
42 | | class Export; |
43 | | class ImportLinker; |
44 | | struct pe_section_t; |
45 | | |
46 | | explicit PeFile(InputFile *f); |
47 | | virtual ~PeFile() noexcept; |
48 | | |
49 | | void readSectionHeaders(unsigned objs, unsigned sizeof_ih); |
50 | | unsigned readSections(unsigned objs, unsigned usize, unsigned ih_filealign, |
51 | | unsigned ih_datasize); |
52 | | void checkHeaderValues(unsigned subsystem, unsigned mask, unsigned ih_entry, |
53 | | unsigned ih_filealign); |
54 | | unsigned handleStripRelocs(upx_uint64_t ih_imagebase, upx_uint64_t default_imagebase, |
55 | | LE16 &dllflags); |
56 | | |
57 | | virtual bool needForceOption() const = 0; |
58 | | virtual void callCompressWithFilters(Filter &, int filter_strategy, unsigned ih_codebase); |
59 | | virtual void defineSymbols(unsigned ncsection, unsigned upxsection, unsigned sizeof_oh, |
60 | | unsigned isize_isplit, unsigned s1addr) = 0; |
61 | 0 | virtual void addNewRelocations(Reloc &, unsigned) {} |
62 | | void callProcessStubRelocs(Reloc &rel, unsigned &ic); |
63 | | void callProcessResources(Resource &res, unsigned &ic); |
64 | 0 | virtual unsigned getProcessImportParam(unsigned) { return 0; } |
65 | | virtual void setOhDataBase(const pe_section_t *osection) = 0; |
66 | | virtual void setOhHeaderSize(const pe_section_t *osection) = 0; |
67 | | |
68 | | template <typename LEXX, typename ht> |
69 | | void pack0(OutputFile *fo, ht &ih, ht &oh, unsigned subsystem_mask, |
70 | | upx_uint64_t default_imagebase, bool last_section_rsrc_only); |
71 | | |
72 | | template <typename ht, typename LEXX, typename ord_mask_t> |
73 | | void unpack0(OutputFile *fo, const ht &ih, ht &oh, ord_mask_t ord_mask, bool set_oft); |
74 | | |
75 | | // unpacker capabilities |
76 | 244 | virtual bool canUnpackVersion(int version) const override { |
77 | 244 | return (version >= 12 && version <= 13); |
78 | 244 | } |
79 | | |
80 | | int canUnpack0(unsigned max_sections, unsigned objs, unsigned ih_entry, unsigned ih_size); |
81 | | |
82 | | protected: |
83 | | static int checkMachine(unsigned cpu); |
84 | | virtual int readFileHeader(); |
85 | | virtual bool testUnpackVersion(int version) const override; |
86 | | virtual void readPeHeader() = 0; |
87 | | |
88 | | unsigned pe_offset; |
89 | | |
90 | | template <typename LEXX, typename ord_mask_t> |
91 | | unsigned processImports0(ord_mask_t ord_mask); |
92 | | |
93 | | template <typename LEXX, typename ord_mask_t> |
94 | | void rebuildImports(SPAN_S(byte) & extra_info, ord_mask_t ord_mask, bool set_oft); |
95 | | virtual unsigned processImports() = 0; |
96 | | virtual void processImports2(unsigned, unsigned); |
97 | | MemBuffer mb_oimport; |
98 | | SPAN_0(byte) oimport = nullptr; |
99 | | unsigned soimport; |
100 | | byte *oimpdlls = nullptr; |
101 | | unsigned soimpdlls; |
102 | | ImportLinker *ilinker = nullptr; |
103 | 0 | virtual const char *kernelDll() const { return "KERNEL32.DLL"; } |
104 | | void addKernelImport(const char *); |
105 | | virtual void addStubImports(); |
106 | | upx_uint64_t ilinkerGetAddress(const char *, const char *) const; |
107 | | |
108 | | virtual void processRelocs() = 0; |
109 | | void rebuildRelocs(SPAN_S(byte) &, unsigned bits, unsigned flags, upx_uint64_t imagebase); |
110 | | MemBuffer mb_orelocs; |
111 | | SPAN_0(byte) orelocs = nullptr; |
112 | | unsigned sorelocs; |
113 | | byte *oxrelocs = nullptr; |
114 | | unsigned soxrelocs; |
115 | | |
116 | | void processExports(Export *); |
117 | | void processExports(Export *, unsigned); |
118 | | void rebuildExports(); |
119 | | MemBuffer mb_oexport; |
120 | | SPAN_0(byte) oexport = nullptr; |
121 | | unsigned soexport; |
122 | | |
123 | | void processResources(Resource *); |
124 | | void processResources(Resource *, unsigned); |
125 | | void rebuildResources(SPAN_S(byte) &, unsigned); |
126 | | MemBuffer mb_oresources; |
127 | | SPAN_0(byte) oresources = nullptr; |
128 | | unsigned soresources; |
129 | | |
130 | | template <typename> |
131 | | struct tls_traits; |
132 | | template <typename LEXX> |
133 | | void processTls1(Interval *iv, typename tls_traits<LEXX>::cb_value_t imagebase, |
134 | | unsigned imagesize); // pass 1 |
135 | | template <typename LEXX> |
136 | | void processTls2(Reloc *rel, const Interval *iv, unsigned newaddr, |
137 | | typename tls_traits<LEXX>::cb_value_t imagebase); // pass 2 |
138 | | virtual void processTls(Interval *iv) = 0; |
139 | | virtual void processTls(Reloc *r, const Interval *iv, unsigned a) = 0; |
140 | | |
141 | | void rebuildTls(); |
142 | | MemBuffer mb_otls; |
143 | | SPAN_0(byte) otls = nullptr; |
144 | | unsigned sotls; |
145 | | unsigned tlsindex; |
146 | | unsigned tlscb_ptr; |
147 | | unsigned tls_handler_offset = 0; |
148 | | bool use_tls_callbacks = false; |
149 | | |
150 | | void processLoadConf(Reloc *, const Interval *, unsigned); |
151 | | void processLoadConf(Interval *); |
152 | | MemBuffer mb_oloadconf; |
153 | | byte *oloadconf = nullptr; |
154 | | unsigned soloadconf; |
155 | | |
156 | | unsigned stripDebug(unsigned); |
157 | | |
158 | | unsigned icondir_offset; |
159 | | int icondir_count; |
160 | | |
161 | | bool importbyordinal = false; |
162 | | bool kernel32ordinal = false; |
163 | | unsigned rvamin; |
164 | | unsigned cimports; // rva of preprocessed imports |
165 | | unsigned crelocs; // rva of preprocessed fixups |
166 | | int big_relocs; |
167 | | |
168 | | struct alignas(1) ddirs_t { |
169 | | LE32 vaddr; |
170 | | LE32 size; |
171 | | }; |
172 | | ddirs_t *iddirs = nullptr; |
173 | | ddirs_t *oddirs = nullptr; |
174 | | |
175 | | LE32 &IDSIZE(unsigned x); |
176 | | LE32 &IDADDR(unsigned x); |
177 | | LE32 &ODSIZE(unsigned x); |
178 | | LE32 &ODADDR(unsigned x); |
179 | | const LE32 &IDSIZE(unsigned x) const; |
180 | | const LE32 &IDADDR(unsigned x) const; |
181 | | |
182 | | struct alignas(1) import_desc { |
183 | | LE32 oft; // orig first thunk |
184 | | byte _[8]; |
185 | | LE32 dllname; |
186 | | LE32 iat; // import address table |
187 | | }; |
188 | | |
189 | | struct alignas(1) pe_section_t { |
190 | | char name[8]; |
191 | | LE32 vsize; |
192 | | LE32 vaddr; |
193 | | LE32 size; |
194 | | LE32 rawdataptr; |
195 | | byte _[12]; |
196 | | LE32 flags; |
197 | | }; |
198 | | |
199 | | MemBuffer mb_isection; |
200 | | SPAN_0(pe_section_t) isection = nullptr; |
201 | | bool isdll = false; |
202 | | bool isrtm = false; |
203 | | bool isefi = false; |
204 | | bool use_dep_hack = true; |
205 | | bool use_clear_dirty_stack = true; |
206 | | bool use_stub_relocs = true; |
207 | | |
208 | | static unsigned virta2objnum(unsigned, SPAN_0(pe_section_t), unsigned); |
209 | | unsigned tryremove(unsigned, unsigned); |
210 | | |
211 | | enum { |
212 | | IMAGE_FILE_MACHINE_UNKNOWN = 0, |
213 | | IMAGE_FILE_MACHINE_AMD64 = 0x8664, // win64/pe (amd64) |
214 | | IMAGE_FILE_MACHINE_ARM = 0x01c0, // wince/arm (Windows CE) |
215 | | IMAGE_FILE_MACHINE_ARMNT = 0x01c4, // win32/arm |
216 | | IMAGE_FILE_MACHINE_ARM64 = 0xaa64, // win64/arm64 |
217 | | IMAGE_FILE_MACHINE_ARM64EC = 0xa641, // win64/arm64ec |
218 | | IMAGE_FILE_MACHINE_I386 = 0x014c, // win32/pe (i386) |
219 | | IMAGE_FILE_MACHINE_IA64 = 0x200, |
220 | | IMAGE_FILE_MACHINE_LOONGARCH32 = 0x6232, |
221 | | IMAGE_FILE_MACHINE_LOONGARCH64 = 0x6264, |
222 | | IMAGE_FILE_MACHINE_RISCV32 = 0x5032, |
223 | | IMAGE_FILE_MACHINE_RISCV64 = 0x5064, |
224 | | IMAGE_FILE_MACHINE_RISCV128 = 0x5128, |
225 | | IMAGE_FILE_MACHINE_THUMB = 0x01c2, // wince/arm (Windows CE) |
226 | | }; |
227 | | |
228 | | enum { |
229 | | PEDIR_EXPORT = 0, |
230 | | PEDIR_IMPORT = 1, |
231 | | PEDIR_RESOURCE = 2, |
232 | | PEDIR_EXCEPTION = 3, // Exception table |
233 | | PEDIR_SECURITY = 4, // Certificate table (file pointer) |
234 | | PEDIR_BASERELOC = 5, |
235 | | PEDIR_DEBUG = 6, |
236 | | PEDIR_ARCHITECTURE = 7, // Architecture-specific data |
237 | | PEDIR_GLOBALPTR = 8, // Global pointer |
238 | | PEDIR_TLS = 9, |
239 | | PEDIR_LOAD_CONFIG = 10, // Load Config Table |
240 | | PEDIR_BOUND_IMPORT = 11, |
241 | | PEDIR_IAT = 12, |
242 | | PEDIR_DELAY_IMPORT = 13, // Delay Import Descriptor |
243 | | PEDIR_COM_DESCRIPTOR = 14, // Com+ Runtime Header |
244 | | }; |
245 | | |
246 | | // section flags |
247 | | enum : unsigned { |
248 | | IMAGE_SCN_CNT_CODE = 0x00000020, |
249 | | IMAGE_SCN_CNT_INITIALIZED_DATA = 0x00000040, |
250 | | IMAGE_SCN_CNT_UNINITIALIZED_DATA = 0x00000080, |
251 | | IMAGE_SCN_LNK_OTHER = 0x00000100, |
252 | | IMAGE_SCN_LNK_INFO = 0x00000200, |
253 | | IMAGE_SCN_LNK_REMOVE = 0x00000800, |
254 | | IMAGE_SCN_LNK_COMDAT = 0x00001000, |
255 | | IMAGE_SCN_GPREL = 0x00008000, |
256 | | IMAGE_SCN_MEM_PURGEABLE = 0x00020000, |
257 | | IMAGE_SCN_MEM_16BIT = 0x00020000, |
258 | | IMAGE_SCN_MEM_LOCKED = 0x00040000, |
259 | | IMAGE_SCN_MEM_PRELOAD = 0x00080000, |
260 | | IMAGE_SCN_ALIGN_1BYTES = 0x00100000, |
261 | | IMAGE_SCN_ALIGN_2BYTES = 0x00200000, |
262 | | IMAGE_SCN_ALIGN_4BYTES = 0x00300000, |
263 | | IMAGE_SCN_ALIGN_8BYTES = 0x00400000, |
264 | | IMAGE_SCN_ALIGN_16BYTES = 0x00500000, |
265 | | IMAGE_SCN_ALIGN_32BYTES = 0x00600000, |
266 | | IMAGE_SCN_ALIGN_64BYTES = 0x00700000, |
267 | | IMAGE_SCN_ALIGN_128BYTES = 0x00800000, |
268 | | IMAGE_SCN_ALIGN_256BYTES = 0x00900000, |
269 | | IMAGE_SCN_ALIGN_512BYTES = 0x00A00000, |
270 | | IMAGE_SCN_ALIGN_1024BYTES = 0x00B00000, |
271 | | IMAGE_SCN_ALIGN_2048BYTES = 0x00C00000, |
272 | | IMAGE_SCN_ALIGN_4096BYTES = 0x00D00000, |
273 | | IMAGE_SCN_ALIGN_8192BYTES = 0x00E00000, |
274 | | IMAGE_SCN_LNK_NRELOC_OVFL = 0x01000000, |
275 | | IMAGE_SCN_MEM_DISCARDABLE = 0x02000000, |
276 | | IMAGE_SCN_MEM_NOT_CACHED = 0x04000000, |
277 | | IMAGE_SCN_MEM_NOT_PAGED = 0x08000000, |
278 | | IMAGE_SCN_MEM_SHARED = 0x10000000, |
279 | | IMAGE_SCN_MEM_EXECUTE = 0x20000000, |
280 | | IMAGE_SCN_MEM_READ = 0x40000000, |
281 | | IMAGE_SCN_MEM_WRITE = 0x80000000, |
282 | | }; |
283 | | |
284 | | enum { |
285 | | IMAGE_FILE_RELOCS_STRIPPED = 0x0001, |
286 | | IMAGE_FILE_EXECUTABLE_IMAGE = 0x0002, |
287 | | IMAGE_FILE_LINE_NUMS_STRIPPED = 0x0004, |
288 | | IMAGE_FILE_LOCAL_SYMS_STRIPPED = 0x0008, |
289 | | IMAGE_FILE_AGGRESSIVE_WS_TRIM = 0x0010, |
290 | | IMAGE_FILE_LARGE_ADDRESS_AWARE = 0x0020, |
291 | | IMAGE_FILE_BYTES_REVERSED_LO = 0x0080, |
292 | | IMAGE_FILE_32BIT_MACHINE = 0x0100, |
293 | | IMAGE_FILE_DEBUG_STRIPPED = 0x0200, |
294 | | IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP = 0x0400, |
295 | | IMAGE_FILE_NET_RUN_FROM_SWAP = 0x0800, |
296 | | IMAGE_FILE_SYSTEM = 0x1000, |
297 | | IMAGE_FILE_DLL = 0x2000, |
298 | | IMAGE_FILE_UP_SYSTEM_ONLY = 0x4000, |
299 | | IMAGE_FILE_BYTES_REVERSE_HI = 0x8000, |
300 | | }; |
301 | | |
302 | | enum { |
303 | | IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA = 0x0020, |
304 | | IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE = 0x0040, |
305 | | IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY = 0x0080, |
306 | | IMAGE_DLLCHARACTERISTICS_NX_COMPAT = 0x0100, |
307 | | IMAGE_DLLCHARACTERISTICS_NO_ISOLATION = 0x0200, |
308 | | IMAGE_DLLCHARACTERISTICS_NO_SEH = 0x0400, |
309 | | IMAGE_DLLCHARACTERISTICS_NO_BIND = 0x0800, |
310 | | IMAGE_DLLCHARACTERISTICS_APPCONTAINER = 0x1000, |
311 | | IMAGE_DLLCHARACTERISTICS_WDM_DRIVER = 0x2000, |
312 | | IMAGE_DLLCHARACTERISTICS_GUARD_CF = 0x4000, |
313 | | IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE = 0x8000, |
314 | | }; |
315 | | |
316 | | enum { |
317 | | IMAGE_SUBSYSTEM_UNKNOWN = 0, |
318 | | IMAGE_SUBSYSTEM_NATIVE = 1, |
319 | | IMAGE_SUBSYSTEM_WINDOWS_GUI = 2, // Graphical User Interface |
320 | | IMAGE_SUBSYSTEM_WINDOWS_CUI = 3, // Character User Interface |
321 | | IMAGE_SUBSYSTEM_WINDOWS_OS2_CUI = 5, |
322 | | IMAGE_SUBSYSTEM_WINDOWS_POSIX_CUI = 7, |
323 | | IMAGE_SUBSYSTEM_NATIVE_WINDOWS = 8, |
324 | | IMAGE_SUBSYSTEM_WINDOWS_CE_GUI = 9, |
325 | | IMAGE_SUBSYSTEM_EFI_APPLICATION = 10, |
326 | | IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER = 11, |
327 | | IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER = 12, |
328 | | IMAGE_SUBSYSTEM_EFI_ROM = 13, |
329 | | IMAGE_SUBSYSTEM_XBOX = 14, |
330 | | IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION = 16, |
331 | | }; |
332 | | |
333 | | // predefined Resource Types |
334 | | enum { |
335 | | RT_CURSOR = 1, |
336 | | RT_BITMAP, |
337 | | RT_ICON, |
338 | | RT_MENU, |
339 | | RT_DIALOG, |
340 | | RT_STRING, |
341 | | RT_FONTDIR, |
342 | | RT_FONT, |
343 | | RT_ACCELERATOR, |
344 | | RT_RCDATA, |
345 | | RT_MESSAGETABLE, |
346 | | RT_GROUP_CURSOR, |
347 | | RT_GROUP_ICON = 14, |
348 | | RT_VERSION = 16, |
349 | | RT_DLGINCLUDE, |
350 | | RT_PLUGPLAY = 19, |
351 | | RT_VXD, |
352 | | RT_ANICURSOR, |
353 | | RT_ANIICON, |
354 | | RT_HTML, |
355 | | RT_MANIFEST, |
356 | | RT_LAST |
357 | | }; |
358 | | |
359 | | enum { // 4-bit reloc_type in IMAGE_BASE_RELOCATION relocations |
360 | | IMAGE_REL_BASED_ABSOLUTE = 0, // this relocation is ignored |
361 | | IMAGE_REL_BASED_IGNORE = 0, // (unofficial UPX name) |
362 | | IMAGE_REL_BASED_HIGH = 1, |
363 | | IMAGE_REL_BASED_LOW = 2, |
364 | | IMAGE_REL_BASED_HIGHLOW = 3, |
365 | | IMAGE_REL_BASED_HIGHADJ = 4, |
366 | | IMAGE_REL_BASED_MIPS_JMPADDR = 5, |
367 | | IMAGE_REL_BASED_ARM_MOV32 = 5, |
368 | | IMAGE_REL_BASED_THUMB_MOV32 = 7, |
369 | | IMAGE_REL_BASED_MIPS_JMPADDR16 = 9, |
370 | | IMAGE_REL_BASED_IA64_IMM64 = 9, |
371 | | IMAGE_REL_BASED_DIR64 = 10, |
372 | | }; |
373 | | |
374 | | class Interval final : private upx::noncopyable { |
375 | | SPAN_0(byte) base = nullptr; |
376 | | unsigned ivcapacity = 0; // for ivarr |
377 | | public: |
378 | | struct interval { |
379 | | unsigned start, len; |
380 | | }; |
381 | | struct interval *ivarr = nullptr; |
382 | | unsigned ivnum = 0; |
383 | | |
384 | | explicit Interval(SPAN_P(byte)); |
385 | | ~Interval() noexcept; |
386 | | |
387 | | void add_interval(unsigned start, unsigned len); |
388 | | void add_interval(const void *start, unsigned len); |
389 | | void add_interval(const void *start, const void *end); |
390 | | void add_interval(const Interval *other); |
391 | | void flatten(); |
392 | | |
393 | | void clear(); |
394 | | void dump() const; |
395 | | |
396 | | private: |
397 | | static int __acc_cdecl_qsort compare(const void *p1, const void *p2); |
398 | | }; |
399 | | |
400 | | class Reloc final : private upx::noncopyable { |
401 | | // these are set in the constructor: |
402 | | byte *start = nullptr; |
403 | | unsigned start_size_in_bytes = 0; |
404 | | bool start_did_alloc = false; |
405 | | SPAN_0(byte) start_buf = nullptr; |
406 | | |
407 | | struct alignas(1) BaseReloc { // IMAGE_BASE_RELOCATION |
408 | | LE32 virtual_address; |
409 | | LE32 size_of_block; |
410 | | // LE16 rel1[COUNT]; // actual relocations; COUNT == (size_of_block - 8) / 2 |
411 | | }; |
412 | | struct RelocationBlock { |
413 | | SPAN_0(BaseReloc) rel = nullptr; |
414 | | SPAN_0(LE16) rel1 = nullptr; |
415 | | unsigned count = 0; |
416 | | void reset() noexcept; |
417 | | }; |
418 | | RelocationBlock rb; // current RelocationBlock |
419 | | bool readFromRelocationBlock(byte *); // set rb |
420 | | |
421 | | unsigned counts[16] = {}; |
422 | | |
423 | | void initSpans(); |
424 | | public: |
425 | | explicit Reloc(byte *ptr, unsigned bytes); |
426 | | explicit Reloc(unsigned relocnum); |
427 | | ~Reloc() noexcept; |
428 | | // |
429 | | bool next(unsigned &result_pos, unsigned &result_reloc_type); |
430 | 0 | const unsigned *getcounts() const { return counts; } |
431 | | // |
432 | | void add_reloc(unsigned pos, unsigned reloc_type); |
433 | | void finish(byte *(&result_ptr), unsigned &result_size); // => transfer ownership |
434 | | }; |
435 | | |
436 | | class Resource final : private upx::noncopyable { |
437 | | struct res_dir_entry; |
438 | | struct res_dir; |
439 | | struct res_data; |
440 | | struct upx_rnode; |
441 | | struct upx_rbranch; |
442 | | struct upx_rleaf; |
443 | | |
444 | | MemBuffer mb_start; |
445 | | const byte *start = nullptr; |
446 | | byte *newstart = nullptr; |
447 | | upx_rnode *root = nullptr; |
448 | | upx_rleaf *head = nullptr; |
449 | | upx_rleaf *current = nullptr; |
450 | | unsigned dsize = 0; |
451 | | unsigned ssize = 0; |
452 | | |
453 | | const byte *ibufstart = nullptr; |
454 | | const byte *ibufend = nullptr; |
455 | | |
456 | | void check(const res_dir *, unsigned); |
457 | | upx_rnode *convert(const void *, upx_rnode *, unsigned); |
458 | | void build(const upx_rnode *, unsigned &, unsigned &, unsigned); |
459 | | void clear(byte *, unsigned, Interval *); |
460 | | void dump(const upx_rnode *, unsigned) const; |
461 | | void destroy(upx_rnode *urd, unsigned level) noexcept; |
462 | | |
463 | | void ibufcheck(const void *m, unsigned size); |
464 | | |
465 | | public: |
466 | | explicit Resource(const byte *ibufstart, const byte *ibufen); |
467 | | explicit Resource(const byte *p, const byte *ibufstart, const byte *ibufend); |
468 | | ~Resource() noexcept; |
469 | | void init(const byte *); |
470 | | |
471 | | unsigned dirsize() const; |
472 | | bool next(); |
473 | | |
474 | | unsigned itype() const; |
475 | | const byte *ntype() const; |
476 | | unsigned size() const; |
477 | | unsigned offs() const; |
478 | | unsigned &newoffs(); |
479 | | |
480 | | byte *build(); |
481 | | bool clear(); |
482 | | |
483 | | void dump() const; |
484 | | unsigned iname() const; |
485 | | const byte *nname() const; |
486 | | /* |
487 | | unsigned ilang() const {return current->id;} |
488 | | const byte *nlang() const {return current->name;} |
489 | | */ |
490 | | }; |
491 | | |
492 | | class Export final : private upx::noncopyable { |
493 | | struct alignas(1) export_dir_t { |
494 | | byte _[12]; // flags, timedate, version |
495 | | LE32 name; |
496 | | byte __[4]; // ordinal base |
497 | | LE32 functions; |
498 | | LE32 names; |
499 | | LE32 addrtable; |
500 | | LE32 nameptrtable; |
501 | | LE32 ordinaltable; |
502 | | }; |
503 | | |
504 | | export_dir_t edir; |
505 | | char *ename; |
506 | | char *functionptrs; |
507 | | char *ordinals; |
508 | | char **names; |
509 | | |
510 | | char *base; |
511 | | unsigned size; |
512 | | Interval iv; |
513 | | |
514 | | public: |
515 | | explicit Export(char *_base); |
516 | | ~Export() noexcept; |
517 | | |
518 | | void convert(unsigned eoffs, unsigned esize); |
519 | | void build(char *base, unsigned newoffs); |
520 | 0 | unsigned getsize() const { return size; } |
521 | | }; |
522 | | }; |
523 | | |
524 | | class PeFile32 : public PeFile { |
525 | | typedef PeFile super; |
526 | | protected: |
527 | | explicit PeFile32(InputFile *f); |
528 | | virtual ~PeFile32() noexcept; |
529 | | |
530 | | void pack0(OutputFile *fo, unsigned subsystem_mask, upx_uint64_t default_imagebase, |
531 | | bool last_section_rsrc_only); |
532 | | virtual void unpack(OutputFile *fo) override; |
533 | | virtual tribool canUnpack() override; |
534 | | |
535 | | virtual void readPeHeader() override; |
536 | | |
537 | | virtual unsigned processImports() override; |
538 | | virtual void processRelocs() override; |
539 | | virtual void processTls(Interval *) override; |
540 | | virtual void processTls(Reloc *, const Interval *, unsigned) override; |
541 | | |
542 | | struct alignas(1) pe_header_t { |
543 | | // 0x00 |
544 | | byte _[4]; // pemagic |
545 | | // 0x04 IMAGE_FILE_HEADER |
546 | | LE16 cpu; // IMAGE_FILE_MACHINE_xxx |
547 | | LE16 objects; // NumberOfSections |
548 | | byte __[12]; // timestamp + reserved |
549 | | LE16 opthdrsize; // SizeOfOptionalHeader |
550 | | LE16 flags; // IMAGE_FILE_xxx Characteristics |
551 | | // 0x18 IMAGE_OPTIONAL_HEADER32 |
552 | | LE16 coffmagic; // NEW: Stefan Widmann |
553 | | byte ___[2]; // linkerversion |
554 | | LE32 codesize; |
555 | | // 0x20 |
556 | | LE32 datasize; |
557 | | LE32 bsssize; |
558 | | LE32 entry; |
559 | | LE32 codebase; |
560 | | // 0x30 |
561 | | LE32 database; |
562 | | // nt specific fields |
563 | | LE32 imagebase; |
564 | | LE32 objectalign; |
565 | | LE32 filealign; // should set to 0x200 ? |
566 | | // 0x40 |
567 | | byte ____[16]; // versions |
568 | | // 0x50 |
569 | | LE32 imagesize; |
570 | | LE32 headersize; |
571 | | LE32 chksum; // should set to 0 |
572 | | LE16 subsystem; // IMAGE_SUBSYSTEM_xxx |
573 | | LE16 dllflags; // IMAGE_DLLCHARACTERISTICS_xxx |
574 | | // 0x60 |
575 | | byte _____[20]; // stack + heap sizes |
576 | | // 0x74 |
577 | | LE32 ddirsentries; // usually 16 |
578 | | // 0x78 |
579 | | ddirs_t ddirs[16]; |
580 | | }; |
581 | | |
582 | | pe_header_t ih = {}, oh = {}; |
583 | | }; |
584 | | |
585 | | class PeFile64 : public PeFile { |
586 | | typedef PeFile super; |
587 | | protected: |
588 | | explicit PeFile64(InputFile *f); |
589 | | virtual ~PeFile64() noexcept; |
590 | | |
591 | | void pack0(OutputFile *fo, unsigned subsystem_mask, upx_uint64_t default_imagebase); |
592 | | |
593 | | virtual void unpack(OutputFile *fo) override; |
594 | | virtual tribool canUnpack() override; |
595 | | |
596 | | virtual void readPeHeader() override; |
597 | | |
598 | | virtual unsigned processImports() override; |
599 | | virtual void processRelocs() override; |
600 | | virtual void processTls(Interval *) override; |
601 | | virtual void processTls(Reloc *, const Interval *, unsigned) override; |
602 | | |
603 | | struct alignas(1) pe_header_t { |
604 | | // 0x00 |
605 | | byte _[4]; // pemagic |
606 | | // 0x04 IMAGE_FILE_HEADER |
607 | | LE16 cpu; // IMAGE_FILE_MACHINE_xxx |
608 | | LE16 objects; // NumberOfSections |
609 | | byte __[12]; // timestamp + reserved |
610 | | LE16 opthdrsize; // SizeOfOptionalHeader |
611 | | LE16 flags; // IMAGE_FILE_xxx Characteristics |
612 | | // 0x18 IMAGE_OPTIONAL_HEADER64 |
613 | | LE16 coffmagic; // NEW: Stefan Widmann |
614 | | byte ___[2]; // linkerversion |
615 | | LE32 codesize; |
616 | | // 0x20 |
617 | | LE32 datasize; |
618 | | LE32 bsssize; |
619 | | LE32 entry; // still a 32 bit RVA |
620 | | LE32 codebase; |
621 | | // 0x30 |
622 | | // LE32 database; // field does not exist in PE+! |
623 | | // nt specific fields |
624 | | LE64 imagebase; // LE32 -> LE64 - Stefan Widmann standard is 0x0000000140000000 |
625 | | LE32 objectalign; |
626 | | LE32 filealign; // should set to 0x200 ? |
627 | | // 0x40 |
628 | | byte ____[16]; // versions |
629 | | // 0x50 |
630 | | LE32 imagesize; |
631 | | LE32 headersize; |
632 | | LE32 chksum; // should set to 0 |
633 | | LE16 subsystem; // IMAGE_SUBSYSTEM_xxx |
634 | | LE16 dllflags; // IMAGE_DLLCHARACTERISTICS_xxx |
635 | | // 0x60 |
636 | | byte _____[36]; // stack + heap sizes + loader flag |
637 | | // 0x84 |
638 | | LE32 ddirsentries; // usually 16 |
639 | | // 0x88 |
640 | | ddirs_t ddirs[16]; |
641 | | }; |
642 | | |
643 | | pe_header_t ih = {}, oh = {}; |
644 | | }; |
645 | | |
646 | | /* vim:set ts=4 sw=4 et: */ |