Coverage Report

Created: 2026-11-12 07:14

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/upx/src/pefile.cpp
Line
Count
Source
1
/* pefile.cpp --
2
3
   This file is part of the UPX executable compressor.
4
5
   Copyright (C) Markus Franz Xaver Johannes Oberhumer
6
   Copyright (C) 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
#include "conf.h"
29
#include "file.h"
30
#include "filter.h"
31
#include "packer.h"
32
#include "pefile.h"
33
#include "linker.h"
34
35
0
#define FILLVAL 0
36
37
/*************************************************************************
38
//
39
**************************************************************************/
40
41
0
#define IPTR_VAR(type, var, first) SPAN_S_VAR(type, var, first, ibuf)
42
43.1k
#define OPTR_VAR(type, var, first) SPAN_S_VAR(type, var, first, obuf)
43
#define IPTR_VAR_OFFSET(type, var, offset)                                                         \
44
115
    SPAN_S_VAR(type, var, ibuf + (offset), ibuf.getSize() - (offset), ibuf + (offset))
45
46
414
static void xcheck(const void *p) may_throw {
47
414
    if very_unlikely (p == nullptr)
48
8
        throwCantUnpack("xcheck unexpected nullptr pointer; take care!");
49
414
}
50
285
static void xcheck_noexcept(const void *p) noexcept { assert_noexcept(p != nullptr); }
51
12.1k
static void xcheck(const void *p, size_t plen, const void *b, size_t blen) may_throw {
52
12.1k
    const charptr pp = (const charptr) p;
53
12.1k
    const charptr bb = (const charptr) b;
54
12.1k
    if very_unlikely (pp < bb || pp > bb + blen || pp + plen > bb + blen)
55
2
        throwCantUnpack("xcheck pointer out of range; take care!");
56
12.1k
}
57
727
#define ICHECK(p, bytes) xcheck(raw_bytes(p, 0), bytes, ibuf, ibuf.getSize())
58
11.4k
#define OCHECK(p, bytes) xcheck(raw_bytes(p, 0), bytes, obuf, obuf.getSize())
59
60
// #define imemset(a,b,c)      ICHECK(a,c), memset(a,b,c)
61
// #define omemset(a,b,c)      OCHECK(a,c), memset(a,b,c)
62
// #define imemcpy(a,b,c)      ICHECK(a,c), memcpy(a,b,c)
63
391
#define omemcpy(a, b, c)  OCHECK(a, c), memcpy(a, b, c)
64
10.9k
#define omemmove(a, b, c) OCHECK(a, c), memmove(a, b, c)
65
66
static constexpr upx_uint32_t pe_exact_relocs = 1;
67
static constexpr upx_uint32_t pe_exact_imports = 2;
68
69
struct alignas(1) PeExactTrailer {
70
    LE32 flags;
71
    LE32 gap_size;
72
};
73
74
/*************************************************************************
75
//
76
**************************************************************************/
77
78
152k
PeFile::PeFile(InputFile *f) : super(f) {
79
152k
    bele = &N_BELE_RTP::le_policy;
80
152k
    COMPILE_TIME_ASSERT(sizeof(ddirs_t) == 8)
81
152k
    COMPILE_TIME_ASSERT(sizeof(import_desc) == 20)
82
152k
    COMPILE_TIME_ASSERT(sizeof(pe_section_t) == 40)
83
152k
    COMPILE_TIME_ASSERT_ALIGNED1(ddirs_t)
84
152k
    COMPILE_TIME_ASSERT_ALIGNED1(import_desc)
85
152k
    COMPILE_TIME_ASSERT_ALIGNED1(pe_section_t)
86
152k
    COMPILE_TIME_ASSERT(sizeof(PeExactTrailer) == 8)
87
152k
    COMPILE_TIME_ASSERT_ALIGNED1(PeExactTrailer)
88
152k
    COMPILE_TIME_ASSERT(RT_LAST == TABLESIZE(opt->win32_pe.compress_rt))
89
90
152k
    isection = nullptr;
91
152k
    oimport = nullptr;
92
152k
    oimpdlls = nullptr;
93
152k
    orelocs = nullptr;
94
152k
    oexport = nullptr;
95
152k
    otls = nullptr;
96
152k
    oresources = nullptr;
97
152k
    oxrelocs = nullptr;
98
152k
    icondir_offset = 0;
99
152k
    icondir_count = 0;
100
152k
    importbyordinal = false;
101
152k
    kernel32ordinal = false;
102
152k
    tlsindex = 0;
103
152k
    big_relocs = 0;
104
152k
    sorelocs = 0;
105
152k
    soxrelocs = 0;
106
152k
    sotls = 0;
107
152k
    ilinker = nullptr;
108
152k
    use_tls_callbacks = false;
109
152k
    oloadconf = nullptr;
110
152k
    soloadconf = 0;
111
152k
    dbgCET = nullptr;
112
113
152k
    isdll = false;
114
152k
    isrtm = false;
115
152k
    isefi = false;
116
152k
    use_dep_hack = true;
117
152k
    use_clear_dirty_stack = true;
118
152k
    use_stub_relocs = true;
119
152k
}
120
121
278
bool PeFile::testUnpackVersion(int version) const {
122
278
    if (version != ph_version && ph_version != -1)
123
0
        throwCantUnpack("program has been modified; run a virus checker!");
124
278
    if (!canUnpackVersion(version))
125
7
        throwCantUnpack("this program is packed with an obsolete version and cannot be unpacked");
126
271
    return true;
127
278
}
128
129
/*************************************************************************
130
// util
131
**************************************************************************/
132
133
// early check of machine to generate a helpful error message
134
// FIXME/TODO: proper check for ARM64EC
135
// FIXME/TODO: proper check for ARM64X "universal" binary
136
// CHPE   Compiled Hybrid PE: Microsoft internal only?
137
// CHPEV2 Compiled Hybrid PE: ARM64EC, ARM64X
138
2.65k
/*static*/ int PeFile::checkMachine(unsigned cpu) {
139
    // unsupported
140
2.65k
    if (cpu == IMAGE_FILE_MACHINE_IA64)
141
3
        throwCantPack("win64/ia64 is not supported");
142
2.64k
    if (cpu == IMAGE_FILE_MACHINE_LOONGARCH64)
143
3
        throwCantPack("win64/loong64 is not supported");
144
2.64k
    if (cpu == IMAGE_FILE_MACHINE_RISCV64)
145
3
        throwCantPack("win64/riscv64 is not supported");
146
147
    // known but not (yet?) supported
148
2.64k
    if (cpu == IMAGE_FILE_MACHINE_ARMNT)
149
3
        throwCantPack("win32/armnt is not supported"); // obsolete
150
    // FIXME: it seems that arm64ec actually uses MACHINE_AMD64 ???
151
2.64k
    if (cpu == IMAGE_FILE_MACHINE_ARM64EC)
152
3
        throwCantPack("win64/arm64ec is not yet supported");
153
154
    // supported
155
2.63k
    if (cpu == IMAGE_FILE_MACHINE_AMD64)
156
528
        return UPX_F_W64PE_AMD64;
157
2.10k
    if (cpu == IMAGE_FILE_MACHINE_ARM64)
158
43
        return UPX_F_W64PE_ARM64;
159
2.06k
    if (cpu == IMAGE_FILE_MACHINE_ARM || cpu == IMAGE_FILE_MACHINE_THUMB)
160
566
        return UPX_F_WINCE_ARM;
161
1.50k
    if (cpu >= IMAGE_FILE_MACHINE_I386 && cpu <= 0x150) // what is this 0x150 ???
162
1.37k
        return UPX_F_W32PE_I386;
163
164
    // other or unknown (alpha, mips, powerpc, sh, etc.)
165
128
    throwCantPack("pefile: unsupported machine %#x", cpu);
166
0
    return 0; // pacify msvc
167
1.50k
}
168
169
152k
int PeFile::readFileHeader() {
170
152k
    struct alignas(1) ExeHeader final {
171
152k
        LE16 mz;
172
152k
        LE16 m512;
173
152k
        LE16 p512;
174
152k
        char _[18];
175
152k
        LE16 relocoffs;
176
152k
        char __[34];
177
152k
        LE32 nexepos;
178
152k
    };
179
180
152k
    COMPILE_TIME_ASSERT(sizeof(ExeHeader) == 64)
181
152k
    COMPILE_TIME_ASSERT_ALIGNED1(ExeHeader)
182
152k
    COMPILE_TIME_ASSERT(sizeof(((ExeHeader *) nullptr)->_) == 18)
183
152k
    COMPILE_TIME_ASSERT(sizeof(((ExeHeader *) nullptr)->__) == 34)
184
185
152k
    ExeHeader h;
186
152k
    int ic;
187
152k
    pe_offset = 0;
188
189
173k
    for (ic = 0; ic < 20; ic++) {
190
172k
        fi->seek(pe_offset, SEEK_SET);
191
172k
        fi->readx(&h, sizeof(h));
192
193
172k
        if (h.mz == 'M' + 'Z' * 256) // dos exe
194
21.8k
        {
195
21.8k
            if (h.nexepos && h.nexepos < sizeof(ExeHeader)) {
196
                // Overlapping MZ and PE headers by 'leanify', etc.
197
15
                char buf[64];
198
15
                snprintf(buf, sizeof(buf), "PE and MZ header overlap: %#x < %#x",
199
15
                         (unsigned) h.nexepos, (unsigned) sizeof(ExeHeader));
200
15
                throwCantPack(buf);
201
15
            }
202
21.8k
            const unsigned delta = (h.relocoffs >= 0x40)
203
21.8k
                                       ? h.nexepos // new format exe
204
21.8k
                                       : (h.p512 * 512 + h.m512 - h.m512 ? 512 : h.nexepos);
205
206
21.8k
            if ((pe_offset + delta) < delta // wrap-around
207
21.7k
                || (pe_offset + delta) > file_size_u) {
208
264
                char buf[64];
209
264
                snprintf(buf, sizeof(buf), "bad PE delta %#x at offset %#x", delta, pe_offset);
210
264
                throwCantPack(buf);
211
264
            }
212
21.5k
            pe_offset += delta;
213
151k
        } else if (get_le32((const byte *) &h) == 'P' + 'E' * 256)
214
2.79k
            break;
215
148k
        else
216
148k
            return 0;
217
172k
    }
218
3.71k
    if (ic == 20)
219
916
        return 0;
220
2.79k
    fi->seek(pe_offset, SEEK_SET);
221
2.79k
    readPeHeader();
222
2.79k
    return getFormat();
223
3.71k
}
224
225
/*************************************************************************
226
// interval handling
227
**************************************************************************/
228
229
0
PeFile::Interval::Interval(SPAN_P(byte) b) : base(b) {}
230
231
0
PeFile::Interval::~Interval() noexcept { ::free(ivarr); }
232
233
0
int __acc_cdecl_qsort PeFile::Interval::compare(const void *p1, const void *p2) {
234
0
    const interval *i1 = (const interval *) p1;
235
0
    const interval *i2 = (const interval *) p2;
236
0
    if (i1->start < i2->start)
237
0
        return -1;
238
0
    if (i1->start > i2->start)
239
0
        return 1;
240
0
    if (i1->len < i2->len)
241
0
        return 1;
242
0
    if (i1->len > i2->len)
243
0
        return -1;
244
0
    return 0;
245
0
}
246
247
0
void PeFile::Interval::add_interval(unsigned start, unsigned len) {
248
0
    if (ivnum == ivcapacity) {
249
0
        ivcapacity += 15;
250
0
        ivarr = (interval *) ::realloc(ivarr, mem_size(sizeof(interval), ivcapacity));
251
0
        assert_noexcept(ivarr != nullptr);
252
0
    }
253
0
    ivarr[ivnum].start = start;
254
0
    ivarr[ivnum].len = len;
255
0
    ivnum += 1;
256
0
}
257
258
0
void PeFile::Interval::add_interval(const void *start, unsigned len) {
259
0
    add_interval(ptr_udiff_bytes(start, base), len);
260
0
}
261
262
0
void PeFile::Interval::add_interval(const void *start, const void *end) {
263
0
    add_interval(ptr_udiff_bytes(start, base), ptr_udiff_bytes(end, start));
264
0
}
265
266
0
void PeFile::Interval::add_interval(const Interval *other) {
267
0
    for (unsigned ic = 0; ic < other->ivnum; ic++)
268
0
        add_interval(other->ivarr[ic].start, other->ivarr[ic].len);
269
0
}
270
271
0
void PeFile::Interval::flatten() {
272
0
    if (!ivnum)
273
0
        return;
274
0
    upx_qsort(ivarr, ivnum, sizeof(ivarr[0]), Interval::compare);
275
0
    for (unsigned ic = 0; ic < ivnum - 1; ic++) {
276
0
        unsigned jc;
277
0
        for (jc = ic + 1; jc < ivnum && ivarr[ic].start + ivarr[ic].len >= ivarr[jc].start; jc++)
278
0
            if (ivarr[ic].start + ivarr[ic].len < ivarr[jc].start + ivarr[jc].len)
279
0
                ivarr[ic].len = ivarr[jc].start + ivarr[jc].len - ivarr[ic].start;
280
0
        if (jc > ic + 1) {
281
0
            memmove(ivarr + ic + 1, ivarr + jc, sizeof(interval) * (ivnum - jc));
282
0
            ivnum -= jc - ic - 1;
283
0
        }
284
0
    }
285
0
}
286
287
0
void PeFile::Interval::clear() {
288
0
    for (unsigned ic = 0; ic < ivnum; ic++)
289
0
        memset(base + ivarr[ic].start, 0, ivarr[ic].len);
290
0
}
291
292
// cheap sanity check of flatten() output: no wrap-around, sorted, disjoint
293
0
void PeFile::Interval::check_flat() const {
294
0
    for (unsigned ic = 0; ic < ivnum; ic++) {
295
0
        const unsigned start = ivarr[ic].start, end = start + ivarr[ic].len;
296
0
        if (end < start || (ic > 0 && start <= ivarr[ic - 1].start + ivarr[ic - 1].len))
297
0
            throwInternalError("bad Interval");
298
0
    }
299
0
}
300
301
0
void PeFile::Interval::clear(const Interval &keep) {
302
0
    check_flat();
303
0
    keep.check_flat();
304
0
    unsigned jc = 0;
305
0
    for (unsigned ic = 0; ic < ivnum; ic++) {
306
0
        unsigned pos = ivarr[ic].start;
307
0
        const unsigned end = pos + ivarr[ic].len;
308
0
        while (jc < keep.ivnum && keep.ivarr[jc].start + keep.ivarr[jc].len <= pos)
309
0
            jc++;
310
0
        while (pos < end && jc < keep.ivnum && keep.ivarr[jc].start < end) {
311
0
            const unsigned next = keep.ivarr[jc].start;
312
0
            if (pos < next)
313
0
                memset(base + pos, 0, next - pos);
314
0
            pos = UPX_MAX(pos, keep.ivarr[jc].start + keep.ivarr[jc].len);
315
0
            if (pos >= end)
316
0
                break;
317
0
            jc++;
318
0
        }
319
0
        if (pos < end)
320
0
            memset(base + pos, 0, end - pos);
321
0
    }
322
0
}
323
324
0
void PeFile::Interval::dump() const {
325
0
    printf("%d intervals:\n", ivnum);
326
0
    for (unsigned ic = 0; ic < ivnum; ic++)
327
0
        printf("%x %x\n", ivarr[ic].start, ivarr[ic].len);
328
0
}
329
330
/*************************************************************************
331
// relocation handling
332
**************************************************************************/
333
334
// do NOT allow --force to override reloc checks
335
static constexpr bool ALWAYS_CHECK_STRICT_RELOCS = true;
336
337
10
void PeFile::Reloc::RelocationBlock::reset() noexcept {
338
10
    rel = nullptr;  // SPAN_0
339
10
    rel1 = nullptr; // SPAN_0
340
10
    count = 0;
341
10
}
342
343
// TODO later: remove this in-place memory optimization hack and use an extra array
344
static constexpr size_t RELOC_INPLACE_OFFSET = 64 * 1024;
345
346
static constexpr size_t RELOC_ENTRY_SIZE = 5; // encoded size in bytes; actual encoding is private
347
42.6k
static void reloc_entry_encode(SPAN_P(byte) buf, unsigned pos, unsigned reloc_type) {
348
42.6k
    if (reloc_type == 0 || reloc_type >= 16)
349
0
        throwCantPack("bad reloc_type %#x %u", pos, reloc_type);
350
42.6k
    set_ne32(buf, pos);
351
42.6k
    buf[4] = (upx_uint8_t) reloc_type;
352
42.6k
}
353
42.6k
static void reloc_entry_decode(SPAN_P(const byte) buf, unsigned *pos, unsigned *reloc_type) {
354
42.6k
    *pos = get_ne32(buf);
355
42.6k
    *reloc_type = buf[4];
356
42.6k
    assert(*reloc_type > 0 && *reloc_type < 16);
357
42.6k
}
358
274k
static int __acc_cdecl_qsort reloc_entry_compare(const void *a, const void *b) {
359
274k
    const unsigned pos1 = get_ne32(a);
360
274k
    const unsigned pos2 = get_ne32(b);
361
274k
    if (pos1 != pos2)
362
274k
        return pos1 < pos2 ? -1 : 1;
363
0
    const unsigned reloc_type1 = ((const upx_uint8_t *) a)[4];
364
0
    const unsigned reloc_type2 = ((const upx_uint8_t *) b)[4];
365
0
    if (reloc_type1 != reloc_type2)
366
0
        return reloc_type1 < reloc_type2 ? -1 : 1;
367
0
    return 0;
368
0
}
369
370
5
PeFile::Reloc::~Reloc() noexcept {
371
5
    COMPILE_TIME_ASSERT(sizeof(BaseReloc) == 8)
372
5
    COMPILE_TIME_ASSERT_ALIGNED1(BaseReloc)
373
5
    if (start_did_alloc) // don't leak memory on exceptions
374
0
        delete[] start;
375
5
}
376
377
// constructor for compression only
378
0
PeFile::Reloc::Reloc(byte *ptr, unsigned bytes) {
379
0
    assert(opt->cmd == CMD_COMPRESS);
380
0
    start_size_in_bytes = mem_size(1, bytes);
381
0
    start = ptr;
382
0
    initSpans();
383
    // fill counts
384
0
    unsigned pos, reloc_type;
385
0
    while (next(pos, reloc_type))
386
0
        counts[reloc_type]++;
387
0
}
388
389
5
PeFile::Reloc::Reloc(unsigned relocnum) {
390
5
    start_size_in_bytes = mem_size(RELOC_ENTRY_SIZE, relocnum, RELOC_INPLACE_OFFSET, 8192);
391
5
    start = new byte[start_size_in_bytes]; // => transfer ownership to oxrelocs[] in finish()
392
5
    start_did_alloc = true;
393
5
    initSpans();
394
5
}
395
396
5
void PeFile::Reloc::initSpans() {
397
5
    start_buf = SPAN_S_MAKE(byte, start, start_size_in_bytes); // => now is a SPAN_S
398
5
    rb.rel = SPAN_TYPE_CAST(BaseReloc, start_buf);             // SPAN_0
399
5
    rb.rel1 = SPAN_TYPE_CAST(LE16, start_buf);                 // SPAN_0
400
5
    rb.reset();
401
5
}
402
403
// explicitly check values so that we get better error messages (instead of a cryptic SPAN failure)
404
0
bool PeFile::Reloc::readFromRelocationBlock(byte *next_rb) { // set rb
405
0
    assert(!start_did_alloc);
406
0
    const unsigned off = ptr_udiff_bytes(next_rb, start);
407
0
    assert((off & 1) == 0);
408
0
    rb.reset();
409
0
    if (off >= start_size_in_bytes) { // permissive: use ">=" instead of strict "=="
410
0
        if (off > start_size_in_bytes) {
411
            // MAYBE TODO later: could add a warning here?
412
0
        }
413
0
        return false; // EOF
414
0
    }
415
0
    if (start_size_in_bytes - off < 8)
416
0
        throwCantPack("relocs overflow");
417
0
    const unsigned sob = get_le32(start_buf + (off + 4)); // size_of_block
418
0
#if 1
419
    // ignore a dubious single empty relocation block with sob == 0
420
0
    if (sob == 0 && (off == 0 && start_size_in_bytes == 8))
421
0
        return false; // EOF
422
0
#endif
423
0
    if (ALWAYS_CHECK_STRICT_RELOCS) {
424
0
        if (sob < 8)
425
0
            throwCantPack("bad reloc size_of_block %u", sob);
426
0
        if (start_size_in_bytes - off < sob)
427
0
            throwCantPack("overflow reloc size_of_block %u", sob);
428
0
        if ((sob & 1) != 0)
429
0
            throwCantPack("odd reloc size_of_block %u", sob);
430
0
    } else if (!opt->force) {
431
0
        if (sob < 8)
432
0
            throwCantPack("bad reloc size_of_block %u (try --force)", sob);
433
0
        if (start_size_in_bytes - off < sob)
434
0
            throwCantPack("overflow reloc size_of_block %u (try --force)", sob);
435
0
        if ((sob & 1) != 0)
436
0
            throwCantPack("odd reloc size_of_block %u (try --force)", sob);
437
0
    }
438
    // success
439
0
    rb.rel = (BaseReloc *) next_rb;   // SPAN checked
440
0
    rb.rel1 = (LE16 *) (next_rb + 8); // SPAN checked
441
0
    rb.count = sob < 8 ? 0 : (sob - 8) / sizeof(LE16);
442
0
    return true;
443
0
}
444
445
0
bool PeFile::Reloc::next(unsigned &result_pos, unsigned &result_reloc_type) {
446
0
    assert(!start_did_alloc);
447
0
    for (;;) {
448
        // search current block
449
0
        while (rb.count > 0) {
450
0
            rb.count -= 1;
451
0
            const unsigned value = *rb.rel1++;
452
0
            result_pos = rb.rel->virtual_address + (value & 0xfff);
453
0
            result_reloc_type = (value >> 12) & 0xf;
454
0
            NO_printf("Reloc::next %#x %d\n", result_pos, result_reloc_type);
455
0
            if (result_reloc_type != IMAGE_REL_BASED_IGNORE)
456
0
                return true; // success
457
0
        }
458
        // advance to next block
459
0
        byte *next_rb = (rb.rel == nullptr) ? start : (byte *) raw_bytes(rb.rel1, 0);
460
0
        if (!readFromRelocationBlock(next_rb)) {
461
0
            rb.reset();   // rewind
462
0
            return false; // EOF
463
0
        }
464
0
    }
465
0
}
466
467
42.6k
void PeFile::Reloc::add_reloc(unsigned pos, unsigned reloc_type) {
468
42.6k
    assert(start_did_alloc);
469
    // assert(reloc_type != IMAGE_REL_BASED_IGNORE);
470
42.6k
    if (reloc_type == IMAGE_REL_BASED_IGNORE)
471
0
        return;
472
42.6k
    auto entry_ptr = start_buf + mem_size(RELOC_ENTRY_SIZE, counts[0], RELOC_INPLACE_OFFSET);
473
42.6k
    reloc_entry_encode(entry_ptr, pos, reloc_type);
474
42.6k
    counts[0] += 1;
475
42.6k
}
476
477
5
void PeFile::Reloc::finish(byte *(&result_ptr), unsigned &result_size) {
478
5
    assert(start_did_alloc);
479
    // sort in-place relocs
480
5
    upx_qsort(
481
5
        raw_index_bytes(start_buf, RELOC_INPLACE_OFFSET, mem_size(RELOC_ENTRY_SIZE, counts[0])),
482
5
        counts[0], RELOC_ENTRY_SIZE, reloc_entry_compare);
483
484
424
    auto finish_block = [](SPAN_S(BaseReloc) rel) -> byte * {
485
424
        unsigned sob = rel->size_of_block;
486
424
        assert(sob >= 10 && (sob & 1) == 0);
487
424
        auto end = SPAN_TYPE_CAST(byte, rel) + sob;
488
830
        while ((sob & 3) != 0) { // UPX: we want align by 4 here
489
406
            *end++ = 0;          // clear byte (i.e. write IMAGE_REL_BASED_IGNORE)
490
406
            sob += 1;
491
406
        }
492
424
        rel->size_of_block = sob;
493
424
        return raw_bytes(end, 0);
494
424
    };
495
496
5
    rb.reset();
497
5
    unsigned prev_pos = 0;
498
5
    unsigned current_page = 0;
499
42.6k
    for (unsigned ic = 0; ic < counts[0]; ic++) {
500
42.6k
        const auto entry_ptr = start_buf + mem_size(RELOC_ENTRY_SIZE, ic, RELOC_INPLACE_OFFSET);
501
42.6k
        unsigned pos, reloc_type;
502
42.6k
        reloc_entry_decode(entry_ptr, &pos, &reloc_type);
503
42.6k
        if (ic > 0 && pos == prev_pos) {
504
0
            if (ALWAYS_CHECK_STRICT_RELOCS)
505
0
                throwCantPack("duplicate relocs");
506
0
            else if (!opt->force)
507
0
                throwCantPack("duplicate relocs (try --force)");
508
0
        }
509
42.6k
        prev_pos = pos;
510
42.6k
        if (ic == 0 || pos - current_page >= 0x1000) {
511
424
            current_page = pos & ~0xfff; // page start
512
            // prepare next block for writing
513
424
            byte *next_rb = (rb.rel == nullptr) ? start : finish_block(rb.rel);
514
424
            rb.rel = (BaseReloc *) next_rb;
515
424
            rb.rel1 = (LE16 *) (next_rb + 8);
516
424
            rb.rel->virtual_address = current_page;
517
424
            rb.rel->size_of_block = 8;
518
424
        }
519
        // check for in-place overflow
520
42.6k
        if (ptr_diff_bytes(rb.rel1, entry_ptr) >= 0) {
521
            // info: if this is indeed a valid file we must increase RELOC_INPLACE_OFFSET
522
0
            throwCantPack("too many inplace relocs");
523
0
        }
524
        // write LE16 IMAGE_BASE_RELOCATION relocation
525
42.6k
        *rb.rel1++ = (reloc_type << 12) | (pos & 0xfff);
526
42.6k
        rb.rel->size_of_block += 2;
527
42.6k
    }
528
5
    result_size = 0; // result_size can be 0 in 64-bit mode
529
5
    if (rb.rel != nullptr)
530
5
        result_size = ptr_udiff_bytes(finish_block(rb.rel), start);
531
5
    assert((result_size & 3) == 0);
532
    // transfer ownership
533
5
    assert(start_did_alloc);
534
0
    result_ptr = start;
535
5
    start_did_alloc = false;
536
5
#if DEBUG || 1 // safety, as we are really finished
537
5
    ptr_invalidate_and_poison(start);
538
5
    start_size_in_bytes = 0;
539
5
    SPAN_INVALIDATE(start_buf);
540
5
    SPAN_INVALIDATE(rb.rel);
541
5
    SPAN_INVALIDATE(rb.rel1);
542
5
    rb.count = 0xdeaddead;
543
5
#endif
544
5
}
545
546
0
void PeFile32::processRelocs() { // pass1
547
0
    big_relocs = 0;
548
549
0
    const unsigned skip1 = IDADDR(PEDIR_BASERELOC);
550
0
    const unsigned take1 = IDSIZE(PEDIR_BASERELOC);
551
0
    Reloc rel(ibuf.subref("bad reloc %#x", skip1, take1), take1);
552
0
    const unsigned *const counts = rel.getcounts();
553
0
    unsigned relocnum = 0;
554
555
0
    for (unsigned ic = 1; ic < 16; ic++)
556
0
        relocnum += counts[ic];
557
0
    for (unsigned ic = 0; ic < 16; ic++)
558
0
        NO_printf("reloc counts[%u] %u\n", ic, counts[ic]);
559
560
0
    if (opt->win32_pe.strip_relocs || relocnum == 0) {
561
0
        if (IDSIZE(PEDIR_BASERELOC) && !opt->exact) {
562
0
            ibuf.fill(IDADDR(PEDIR_BASERELOC), IDSIZE(PEDIR_BASERELOC), FILLVAL);
563
0
            const unsigned old_objs = ih.objects;
564
0
            ih.objects = tryremove(IDADDR(PEDIR_BASERELOC), ih.objects);
565
0
            if (old_objs != ih.objects && 1) { // was removed
566
0
                IDADDR(PEDIR_BASERELOC) = 0;
567
0
                IDSIZE(PEDIR_BASERELOC) = 0;
568
0
                const unsigned oam1 = ih.objectalign - 1;
569
0
                ih.imagesize =
570
0
                    (isection[-1 + ih.objects].vsize + isection[-1 + ih.objects].vaddr + oam1) &
571
0
                    ~oam1;
572
0
            }
573
0
        }
574
0
        mb_orelocs.alloc(1);
575
0
        mb_orelocs.clear();
576
0
        orelocs = SPAN_S_MAKE(byte, mb_orelocs); // => orelocs now is a SPAN_S
577
0
        sorelocs = 0;
578
0
        return;
579
0
    }
580
581
0
    for (unsigned ic = IMAGE_REL_BASED_HIGHADJ; ic < 16; ic++)
582
0
        if (counts[ic])
583
0
            infoWarning("skipping unsupported relocation type %d (%d)", ic, counts[ic]);
584
585
0
    LE32 *fix[4] = {};
586
0
    auto fix_deleter = upx::ArrayDeleter(fix, 0); // don't leak memory
587
0
    for (unsigned ic = 0; ic <= IMAGE_REL_BASED_HIGHLOW; ic++) {
588
0
        fix[ic] = New(LE32, counts[ic]);
589
0
        fix_deleter.count += 1;
590
0
    }
591
592
0
    unsigned xcounts[4] = {};
593
0
    memset(xcounts, 0, sizeof(xcounts));
594
595
    // prepare sorting
596
0
    unsigned pos, reloc_type;
597
0
    while (rel.next(pos, reloc_type)) {
598
        // FIXME add check for relocations which try to modify the
599
        // PE header or other relocation records
600
0
        if (pos >= ih.imagesize)
601
0
            continue; // skip out-of-bounds record
602
0
        if (reloc_type <= IMAGE_REL_BASED_HIGHLOW)
603
0
            fix[reloc_type][xcounts[reloc_type]++] = pos - rvamin;
604
0
    }
605
606
    // remove duplicated records
607
0
    for (unsigned ic = 1; ic <= IMAGE_REL_BASED_HIGHLOW; ic++) {
608
0
        upx_qsort(fix[ic], xcounts[ic], 4, le32_compare);
609
0
        unsigned prev = ~0u;
610
0
        unsigned jc = 0;
611
0
        for (unsigned kc = 0; kc < xcounts[ic]; kc++)
612
0
            if (fix[ic][kc] != prev)
613
0
                prev = fix[ic][jc++] = fix[ic][kc];
614
615
0
        NO_printf("reloc xcounts[%u] %u->%u\n", ic, xcounts[ic], jc);
616
0
        xcounts[ic] = jc;
617
0
    }
618
619
    // preprocess "type 3" relocation records
620
0
    for (unsigned ic = 0; ic < xcounts[IMAGE_REL_BASED_HIGHLOW]; ic++) {
621
0
        pos = fix[3][ic] + rvamin;
622
0
        unsigned w = get_le32(ibuf.subref("bad reloc type 3 %#x", pos, sizeof(LE32)));
623
0
        set_le32(ibuf + pos, w - ih.imagebase - rvamin);
624
0
    }
625
626
0
    if (!opt->exact)
627
0
        ibuf.fill(IDADDR(PEDIR_BASERELOC), IDSIZE(PEDIR_BASERELOC), FILLVAL);
628
0
    mb_orelocs.alloc(mem_size(4, relocnum, 8192)); // 8192 - safety
629
0
    orelocs = SPAN_S_MAKE(byte, mb_orelocs);       // => orelocs now is a SPAN_S
630
0
    sorelocs = optimizeReloc(xcounts[3], (byte *) fix[3], orelocs, ibuf + rvamin, ibufgood - rvamin,
631
0
                             32, true, &big_relocs, true);
632
633
    // Malware that hides behind UPX often has PE header info that is
634
    // deliberately corrupt.  Sometimes it is even tuned to cause us trouble!
635
    // Use an extra check to avoid AccessViolation (SIGSEGV) when appending
636
    // the relocs into one array.
637
0
    if ((sizeof(LE32) * relocnum + 8192) <
638
0
        (sorelocs +
639
0
         sizeof(LE32) * (2 + xcounts[IMAGE_REL_BASED_LOW] + xcounts[IMAGE_REL_BASED_HIGH])))
640
0
        throwCantUnpack("Invalid relocs");
641
642
    // append relocs type "LOW" then "HIGH"
643
0
    for (unsigned ic = IMAGE_REL_BASED_LOW; ic >= IMAGE_REL_BASED_HIGH; ic--) {
644
0
        memcpy(orelocs + sorelocs, fix[ic], sizeof(LE32) * xcounts[ic]);
645
0
        sorelocs += sizeof(LE32) * xcounts[ic];
646
0
        set_le32(orelocs + sorelocs, 0);
647
0
        if (xcounts[ic]) {
648
0
            sorelocs += 4;
649
0
            big_relocs |= 2 * ic;
650
0
        }
651
0
    }
652
653
0
    info("Relocations: original size: %u bytes, preprocessed size: %u bytes",
654
0
         (unsigned) IDSIZE(PEDIR_BASERELOC), sorelocs);
655
0
}
656
657
// FIXME - this is too similar to PeFile32::processRelocs
658
0
void PeFile64::processRelocs() { // pass1
659
0
    big_relocs = 0;
660
661
0
    const unsigned skip1 = IDADDR(PEDIR_BASERELOC);
662
0
    const unsigned take1 = IDSIZE(PEDIR_BASERELOC);
663
0
    Reloc rel(ibuf.subref("bad reloc %#x", skip1, take1), take1);
664
0
    const unsigned *const counts = rel.getcounts();
665
0
    unsigned relocnum = 0;
666
667
0
    for (unsigned ic = 1; ic < 16; ic++)
668
0
        relocnum += counts[ic];
669
0
    for (unsigned ic = 0; ic < 16; ic++)
670
0
        NO_printf("reloc counts[%u] %u\n", ic, counts[ic]);
671
672
0
    if (opt->win32_pe.strip_relocs || relocnum == 0) {
673
0
        if (IDSIZE(PEDIR_BASERELOC) && !opt->exact) {
674
0
            ibuf.fill(IDADDR(PEDIR_BASERELOC), IDSIZE(PEDIR_BASERELOC), FILLVAL);
675
0
            const unsigned old_objs = ih.objects;
676
0
            ih.objects = tryremove(IDADDR(PEDIR_BASERELOC), ih.objects);
677
0
            if (old_objs != ih.objects && 1) { // was removed
678
0
                IDADDR(PEDIR_BASERELOC) = 0;
679
0
                IDSIZE(PEDIR_BASERELOC) = 0;
680
0
                const unsigned oam1 = ih.objectalign - 1;
681
0
                ih.imagesize =
682
0
                    (isection[-1 + ih.objects].vsize + isection[-1 + ih.objects].vaddr + oam1) &
683
0
                    ~oam1;
684
0
            }
685
0
        }
686
0
        mb_orelocs.alloc(1);
687
0
        mb_orelocs.clear();
688
0
        orelocs = SPAN_S_MAKE(byte, mb_orelocs); // => orelocs now is a SPAN_S
689
0
        sorelocs = 0;
690
0
        return;
691
0
    }
692
693
0
    for (unsigned ic = 0; ic < 16; ic++)
694
0
        if (ic != IMAGE_REL_BASED_DIR64 && counts[ic])
695
0
            infoWarning("skipping unsupported relocation type %d (%d)", ic, counts[ic]);
696
697
0
    LE32 *fix[16] = {};
698
0
    auto fix_deleter = upx::ArrayDeleter(fix, 0); // don't leak memory
699
0
    for (unsigned ic = 0; ic < 16; ic++) {
700
0
        fix[ic] = New(LE32, counts[ic]);
701
0
        fix_deleter.count += 1;
702
0
    }
703
704
0
    unsigned xcounts[16] = {};
705
0
    memset(xcounts, 0, sizeof(xcounts));
706
707
    // prepare sorting
708
0
    unsigned pos, reloc_type;
709
0
    while (rel.next(pos, reloc_type)) {
710
        // FIXME add check for relocations which try to modify the
711
        // PE header or other relocation records
712
0
        if (pos >= ih.imagesize)
713
0
            continue; // skip out-of-bounds record
714
0
        if (reloc_type < 16)
715
0
            fix[reloc_type][xcounts[reloc_type]++] = pos - rvamin;
716
0
    }
717
718
    // remove duplicated records
719
0
    for (unsigned ic = 1; ic < 16; ic++) {
720
0
        upx_qsort(fix[ic], xcounts[ic], 4, le32_compare);
721
0
        unsigned prev = ~0u;
722
0
        unsigned jc = 0;
723
0
        for (unsigned kc = 0; kc < xcounts[ic]; kc++)
724
0
            if (fix[ic][kc] != prev)
725
0
                prev = fix[ic][jc++] = fix[ic][kc];
726
727
0
        NO_printf("xcounts[%u] %u->%u\n", ic, xcounts[ic], jc);
728
0
        xcounts[ic] = jc;
729
0
    }
730
731
    // preprocess "type 10" relocation records
732
0
    for (unsigned ic = 0; ic < xcounts[IMAGE_REL_BASED_DIR64]; ic++) {
733
0
        pos = fix[IMAGE_REL_BASED_DIR64][ic] + rvamin;
734
0
        upx_uint64_t w = get_le64(ibuf.subref("bad reloc 10 %#x", pos, sizeof(LE64)));
735
0
        set_le64(ibuf + pos, w - ih.imagebase - rvamin);
736
0
    }
737
738
0
    if (!opt->exact)
739
0
        ibuf.fill(IDADDR(PEDIR_BASERELOC), IDSIZE(PEDIR_BASERELOC), FILLVAL);
740
0
    mb_orelocs.alloc(mem_size(4, relocnum, 8192)); // 8192 - safety
741
0
    orelocs = SPAN_S_MAKE(byte, mb_orelocs);       // => orelocs now is a SPAN_S
742
0
    sorelocs =
743
0
        optimizeReloc(xcounts[IMAGE_REL_BASED_DIR64], (byte *) fix[IMAGE_REL_BASED_DIR64], orelocs,
744
0
                      ibuf + rvamin, ibufgood - rvamin, 64, true, &big_relocs, true);
745
746
0
    info("Relocations: original size: %u bytes, preprocessed size: %u bytes",
747
0
         (unsigned) IDSIZE(PEDIR_BASERELOC), sorelocs);
748
0
}
749
750
/*************************************************************************
751
// import handling
752
**************************************************************************/
753
754
756
LE32 &PeFile::IDSIZE(unsigned x) { return iddirs[x].size; }
755
427
LE32 &PeFile::IDADDR(unsigned x) { return iddirs[x].vaddr; }
756
547
LE32 &PeFile::ODSIZE(unsigned x) { return oddirs[x].size; }
757
634
LE32 &PeFile::ODADDR(unsigned x) { return oddirs[x].vaddr; }
758
0
const LE32 &PeFile::IDSIZE(unsigned x) const { return iddirs[x].size; }
759
0
const LE32 &PeFile::IDADDR(unsigned x) const { return iddirs[x].vaddr; }
760
761
/*
762
 ImportLinker: 32 and 64 bit import table building.
763
 Import entries (dll name + proc name/ordinal pairs) can be
764
 added in arbitrary order.
765
766
 Internally it works by creating sections with special names,
767
 and adding relocation entries between those sections. The special
768
 names ensure that when the import table is built in the memory
769
 from those sections, a correct table can be generated simply by
770
 sorting the sections by name, and adding all of them to the output
771
 in the sorted order.
772
 */
773
774
class PeFile::ImportLinker final : public ElfLinkerAMD64 {
775
    // temporary string owner, deletes on destruction
776
    struct TStr final : private upx::noncopyable {
777
0
        explicit TStr(char *str) noexcept : s(str) {}
778
0
        ~TStr() noexcept { delete[] s; } // delete!
779
0
        operator char *() noexcept { return s; }
780
0
        operator const char *() const noexcept { return s; }
781
    private:
782
        char *s;
783
    };
784
785
    // encoding of dll and proc names are required, so that our special
786
    // control characters in the name of sections can work as intended
787
0
    static void encode_name(SPAN_P(const char) name, SPAN_S(char) buf) {
788
0
        while (*name) {
789
0
            *buf++ = 'a' + ((*name >> 4) & 0xf);
790
0
            *buf++ = 'a' + (*name & 0xf);
791
0
            name++;
792
0
        }
793
0
        *buf = 0;
794
0
    }
795
796
0
    static char *name_for_dll(const char *dll, char first_char) {
797
0
        assert(dll != nullptr);
798
0
        const unsigned l = strlen(dll);
799
0
        assert(l > 0);
800
0
        const unsigned new_size = 1 + 3 * l + 1;
801
0
        char *const new_name = New(char, new_size);
802
0
        SPAN_S_VAR(char, const name, new_name, new_size);
803
0
        name[0] = first_char;
804
0
        SPAN_S_VAR(char, n, name + (1 + 2 * l));
805
0
        do {
806
0
            *n++ = tolower((uchar) *dll);
807
0
        } while (*dll++);
808
0
        encode_name(new_name + (1 + 2 * l), name + 1);
809
0
        return new_name;
810
0
    }
811
812
0
    static char *name_for_proc(const char *dll, const char *proc, char first_char, char separator) {
813
0
        const unsigned new_size = 1 + 2 * strlen(dll) + 1 + 2 * strlen(proc) + 1 + 1;
814
0
        TStr dll_name(name_for_dll(dll, first_char));
815
0
        char *const new_name = New(char, new_size);
816
0
        SPAN_S_VAR(char, const name, new_name, new_size);
817
0
        upx_safe_snprintf(new_name, new_size, "%s%c", (const char *) dll_name, separator);
818
0
        encode_name(proc, name + strlen(name));
819
0
        return new_name;
820
0
    }
821
822
    static const char zeros[sizeof(import_desc)];
823
824
    enum {
825
        // the order of identifiers is very important below!!
826
        descriptor_id = 'D',
827
        thunk_id,
828
        dll_name_id,
829
        proc_name_id,
830
        ordinal_id,
831
832
        thunk_separator_first,
833
        thunk_separator,
834
        thunk_separator_last,
835
        procname_separator,
836
    };
837
838
    unsigned thunk_size; // 4 or 8 bytes
839
840
0
    void add_import(const char *dll, const char *proc, unsigned ordinal) {
841
0
        TStr sdll(name_for_dll(dll, dll_name_id));
842
0
        TStr desc_name(name_for_dll(dll, descriptor_id));
843
844
0
        char tsep = thunk_separator;
845
0
        if (findSection(sdll, false) == nullptr) {
846
0
            tsep = thunk_separator_first;
847
0
            addSection(sdll, dll, strlen(dll) + 1, 0); // name of the dll
848
0
            addSymbol(sdll, sdll, 0);
849
850
0
            addSection(desc_name, zeros, sizeof(zeros), 0); // descriptor
851
0
            addRelocation(desc_name, offsetof(import_desc, dllname), "R_X86_64_32", sdll, 0);
852
0
        }
853
0
        TStr thunk(proc == nullptr ? name_for_dll(dll, thunk_id)
854
0
                                   : name_for_proc(dll, proc, thunk_id, tsep));
855
856
0
        if (findSection(thunk, false) != nullptr)
857
0
            return; // we already have this dll/proc
858
0
        addSection(thunk, zeros, thunk_size, 0);
859
0
        addSymbol(thunk, thunk, 0);
860
0
        if (tsep == thunk_separator_first) {
861
0
            addRelocation(desc_name, offsetof(import_desc, iat), "R_X86_64_32", thunk, 0);
862
863
0
            TStr last_thunk(name_for_proc(dll, "X", thunk_id, thunk_separator_last));
864
0
            addSection(last_thunk, zeros, thunk_size, 0);
865
0
        }
866
867
0
        const char *reltype = thunk_size == 4 ? "R_X86_64_32" : "R_X86_64_64";
868
0
        if (ordinal != 0u) {
869
0
            addRelocation(thunk, 0, reltype, "*UND*", ordinal | (1ull << (thunk_size * 8 - 1)));
870
0
        } else if (proc != nullptr) {
871
0
            TStr proc_name(name_for_proc(dll, proc, proc_name_id, procname_separator));
872
0
            addSection(proc_name, zeros, 2, 1); // 2 bytes of word aligned "hint"
873
0
            addSymbol(proc_name, proc_name, 0);
874
0
            addRelocation(thunk, 0, reltype, proc_name, 0);
875
876
0
            strcat(proc_name, "X");
877
0
            addSection(proc_name, proc, strlen(proc), 0); // the name of the symbol
878
0
        } else
879
0
            infoWarning("empty import: %s", dll);
880
0
    }
881
882
0
    static int __acc_cdecl_qsort compare(const void *aa, const void *bb) {
883
0
        const Section *a = *(const Section *const *) aa;
884
0
        const Section *b = *(const Section *const *) bb;
885
0
        if (a->sort_id == b->sort_id) // identical object, poor qsort() implementation
886
0
            return 0;
887
0
        int rc = strcmp(a->name, b->name);
888
0
        if (rc != 0)
889
0
            return rc;
890
        // What could remain?
891
        // make sort order deterministic
892
0
        return a->sort_id < b->sort_id ? -1 : 1;
893
0
    }
894
895
0
    virtual void alignCode(unsigned len) override { alignWithByte(len, 0); }
896
897
0
    const Section *getThunk(const char *dll, const char *proc, char tsep) const {
898
0
        assert(dll);
899
0
        assert(proc);
900
0
        TStr thunk(name_for_proc(dll, proc, thunk_id, tsep));
901
0
        return findSection(thunk, false);
902
0
    }
903
904
public:
905
0
    explicit ImportLinker(unsigned thunk_size_) : thunk_size(thunk_size_) {
906
0
        assert(thunk_size == 4 || thunk_size == 8);
907
0
        addSection("*UND*", nullptr, 0, 0);
908
0
        addSymbol("*UND*", "*UND*", 0);
909
0
        addSection("*ZSTART", nullptr, 0, 0);
910
0
        addSymbol("*ZSTART", "*ZSTART", 0);
911
0
        Section *s = addSection("Dzero", zeros, sizeof(import_desc), 0);
912
0
        assert(s->name[0] == descriptor_id);
913
914
        // one trailing 00 byte after the last proc name
915
0
        addSection("Zzero", zeros, 1, 0);
916
0
    }
917
918
    template <typename C>
919
0
    void add_import(const C *dll, unsigned ordinal) {
920
0
        ACC_COMPILE_TIME_ASSERT(sizeof(C) == 1) // "char" or "byte"
921
0
        assert(ordinal < 0x10000);
922
0
        char ord[1 + 5 + 1];
923
0
        upx_safe_snprintf(ord, sizeof(ord), "%c%05u", ordinal_id, ordinal);
924
0
        add_import((const char *) dll, ordinal ? ord : nullptr, ordinal);
925
0
    }
Unexecuted instantiation: void PeFile::ImportLinker::add_import<char>(char const*, unsigned int)
Unexecuted instantiation: void PeFile::ImportLinker::add_import<unsigned char>(unsigned char const*, unsigned int)
926
927
    template <typename C1, typename C2>
928
0
    void add_import(const C1 *dll, const C2 *proc) {
929
0
        ACC_COMPILE_TIME_ASSERT(sizeof(C1) == 1) // "char" or "byte"
930
0
        ACC_COMPILE_TIME_ASSERT(sizeof(C2) == 1) // "char" or "byte"
931
0
        assert(proc);
932
0
        add_import((const char *) dll, (const char *) proc, 0);
933
0
    }
Unexecuted instantiation: void PeFile::ImportLinker::add_import<char, char>(char const*, char const*)
Unexecuted instantiation: void PeFile::ImportLinker::add_import<unsigned char, unsigned char>(unsigned char const*, unsigned char const*)
934
935
0
    unsigned build() {
936
0
        assert(output == nullptr);
937
0
        int osize = 4 + 2 * nsections; // upper limit for alignments
938
0
        for (unsigned ic = 0; ic < nsections; ic++)
939
0
            osize += sections[ic]->size;
940
0
        output_capacity = osize;
941
0
        output = New(byte, output_capacity);
942
0
        outputlen = 0;
943
944
        // sort the sections by name before adding them all
945
        // NOLINTNEXTLINE(bugprone-multi-level-implicit-pointer-conversion)
946
0
        upx_qsort(sections, nsections, sizeof(sections[0]), ImportLinker::compare);
947
948
0
        for (unsigned ic = 0; ic < nsections; ic++)
949
0
            addLoader(sections[ic]->name);
950
0
        addLoader("+40D");
951
0
        assert(outputlen <= osize);
952
953
        // OutputFile::dump("il0.imp", output, outputlen);
954
0
        return outputlen;
955
0
    }
956
957
0
    void relocate_import(unsigned myimport) {
958
0
        assert(nsections > 0);
959
0
        assert(output);
960
0
        defineSymbol("*ZSTART", /*0xffffffffff1000ull + 0 * */ myimport);
961
0
        ElfLinkerAMD64::relocate();
962
        // OutputFile::dump("il1.imp", output, outputlen);
963
0
    }
964
965
    template <typename C1, typename C2>
966
0
    upx_uint64_t getAddress(const C1 *dll, const C2 *proc) const {
967
0
        ACC_COMPILE_TIME_ASSERT(sizeof(C1) == 1) // "char" or "byte"
968
0
        ACC_COMPILE_TIME_ASSERT(sizeof(C2) == 1) // "char" or "byte"
969
0
        const Section *s = getThunk((const char *) dll, (const char *) proc, thunk_separator_first);
970
0
        if (s == nullptr)
971
0
            s = getThunk((const char *) dll, (const char *) proc, thunk_separator);
972
0
        if (s == nullptr)
973
0
            throwInternalError("entry not found");
974
0
        return s->offset;
975
0
    }
976
977
    template <typename C>
978
0
    upx_uint64_t getAddress(const C *dll, unsigned ordinal) const {
979
0
        ACC_COMPILE_TIME_ASSERT(sizeof(C) == 1) // "char" or "byte"
980
0
        assert(ordinal > 0 && ordinal < 0x10000);
981
0
        char ord[1 + 5 + 1];
982
0
        upx_safe_snprintf(ord, sizeof(ord), "%c%05u", ordinal_id, ordinal);
983
0
        const Section *s = getThunk((const char *) dll, ord, thunk_separator_first);
984
0
        if (s == nullptr)
985
0
            s = getThunk((const char *) dll, ord, thunk_separator);
986
0
        if (s == nullptr)
987
0
            throwInternalError("entry not found");
988
0
        return s->offset;
989
0
    }
990
991
    template <typename C>
992
0
    upx_uint64_t getAddress(const C *dll) const {
993
0
        ACC_COMPILE_TIME_ASSERT(sizeof(C) == 1) // "char" or "byte"
994
0
        TStr sdll(name_for_dll((const char *) dll, dll_name_id));
995
0
        return findSection(sdll, true)->offset;
996
0
    }
997
998
    template <typename C>
999
0
    bool hasDll(const C *dll) const {
1000
0
        ACC_COMPILE_TIME_ASSERT(sizeof(C) == 1) // "char" or "byte"
1001
0
        TStr sdll(name_for_dll((const char *) dll, dll_name_id));
1002
0
        return findSection(sdll, false) != nullptr;
1003
0
    }
1004
}; // class PeFile::ImportLinker
1005
1006
/*static*/ const char PeFile::ImportLinker::zeros[sizeof(import_desc)] = {};
1007
1008
0
void PeFile::addKernelImport(const char *name) { ilinker->add_import(kernelDll(), name); }
1009
1010
0
void PeFile::addStubImports() {
1011
0
    addKernelImport("LoadLibraryA");
1012
0
    addKernelImport("GetProcAddress");
1013
0
    if (!isdll)
1014
0
        addKernelImport("ExitProcess");
1015
0
    addKernelImport("VirtualProtect");
1016
0
}
1017
1018
0
void PeFile::processImports2(unsigned myimport, unsigned) { // pass 2
1019
0
    COMPILE_TIME_ASSERT(sizeof(import_desc) == 20)
1020
0
    if (ilinker == nullptr)
1021
0
        return;
1022
0
    ilinker->relocate_import(myimport);
1023
0
    int len;
1024
0
    oimpdlls = ilinker->getLoader(&len);
1025
0
    assert(len == (int) soimpdlls);
1026
    // OutputFile::dump("x1.imp", oimpdlls, soimpdlls);
1027
0
}
1028
1029
template <typename LEXX, typename ord_mask_t>
1030
0
unsigned PeFile::processImports0(ord_mask_t ord_mask) { // pass 1
1031
0
    if (isefi) {
1032
0
        if (IDSIZE(PEDIR_IMPORT))
1033
0
            throwCantPack("imports not supported on EFI");
1034
0
        return 0;
1035
0
    }
1036
1037
0
    unsigned dllnum = 0;
1038
0
    const unsigned skip = IDADDR(PEDIR_IMPORT);
1039
0
    const unsigned take = IDSIZE(PEDIR_IMPORT);
1040
0
    import_desc *const im_start = (import_desc *) ibuf.subref("bad import %#x", skip, take);
1041
0
    if (IDADDR(PEDIR_IMPORT) != 0) {
1042
0
        for (const import_desc *im = im_start;; ++dllnum, ++im) {
1043
0
            const unsigned skip2 = ptr_udiff_bytes(im, ibuf);
1044
0
            (void) ibuf.subref("bad import %#x", skip2, sizeof(*im));
1045
0
            if (im->dllname == 0)
1046
0
                break;
1047
0
        }
1048
0
    }
1049
0
    if (dllnum > 4096) // just some arbitrary limit/sanity check
1050
0
        throwCantPack("too many DLL imports %u", dllnum);
1051
1052
0
    struct UDll final {
1053
0
        const byte *name;
1054
0
        const byte *shname;
1055
0
        unsigned ordinal;
1056
0
        unsigned iat;
1057
0
        const LEXX *lookupt;
1058
0
        unsigned original_position;
1059
0
        bool isk32;
1060
1061
0
        static int __acc_cdecl_qsort compare(const void *aa, const void *bb) {
1062
0
            const UDll *a = *(const UDll *const *) aa;
1063
0
            const UDll *b = *(const UDll *const *) bb;
1064
0
            if (a->original_position == b->original_position) // identical object, poor qsort()
1065
0
                return 0;
1066
0
            if (a->isk32 != b->isk32)
1067
0
                return a->isk32 ? -1 : 1;
1068
0
            if ((*a->lookupt != 0) != (*b->lookupt != 0))
1069
0
                return (*a->lookupt != 0) ? -1 : 1;
1070
0
            int rc = strcasecmp(a->name, b->name);
1071
0
            if (rc != 0)
1072
0
                return rc;
1073
0
            if ((a->ordinal != 0) != (b->ordinal != 0))
1074
0
                return (a->ordinal != 0) ? -1 : 1;
1075
0
            if (a->shname && b->shname) {
1076
0
                rc = (int) (upx_safe_strlen(a->shname) - upx_safe_strlen(b->shname));
1077
0
                if (rc != 0)
1078
0
                    return rc;
1079
0
                rc = strcmp(a->shname, b->shname);
1080
0
                if (rc != 0)
1081
0
                    return rc;
1082
0
            } else if ((a->shname != nullptr) != (b->shname != nullptr))
1083
0
                return (a->shname != nullptr) ? -1 : 1;
1084
            // What could remain?
1085
            // make sort order deterministic
1086
0
            return a->original_position < b->original_position ? -1 : 1;
1087
0
        }
Unexecuted instantiation: PeFile::processImports0<LE32, unsigned int>(unsigned int)::UDll::compare(void const*, void const*)
Unexecuted instantiation: PeFile::processImports0<LE64, unsigned long long>(unsigned long long)::UDll::compare(void const*, void const*)
1088
0
    };
1089
1090
    // +1 for dllnum=0
1091
0
    Array(UDll, dlls, dllnum + 1);
1092
0
    Array(UDll *, idlls, dllnum + 1);
1093
1094
0
    soimport = 1024; // safety
1095
1096
0
    for (unsigned ic = 0; ic < dllnum; ic++) {
1097
0
        const import_desc *const im = im_start + ic;
1098
0
        idlls[ic] = dlls + ic;
1099
0
        dlls[ic].name = ibuf.subref("bad dllname %#x", im->dllname, 1);
1100
0
        dlls[ic].shname = nullptr;
1101
0
        dlls[ic].ordinal = 0;
1102
0
        dlls[ic].iat = im->iat;
1103
0
        const unsigned skip2 = (im->oft ? im->oft : im->iat);
1104
0
        dlls[ic].lookupt = (LEXX *) ibuf.subref("bad dll lookupt %#x", skip2, sizeof(LEXX));
1105
0
        dlls[ic].original_position = ic;
1106
0
        dlls[ic].isk32 = strcasecmp(kernelDll(), dlls[ic].name) == 0;
1107
1108
0
        soimport += strlen(dlls[ic].name) + 1 + 4;
1109
1110
0
        unsigned i_tarr = 0;
1111
0
        for (IPTR_VAR(const LEXX, tarr, dlls[ic].lookupt); *tarr; tarr += 1, i_tarr += 1) {
1112
0
            if (0xfffdu & (*tarr >> 30)) { // UPX_RSIZE_MAX_MEM but allowing (1<<31)
1113
0
                throwCantPack("bad import %s[%#x]:%#llx", dlls[ic].name, i_tarr,
1114
0
                              (unsigned long long) *tarr);
1115
0
            }
1116
0
            if (*tarr & ord_mask) {
1117
0
                importbyordinal = true;
1118
0
                soimport += 2; // ordinal num: 2 bytes
1119
0
                dlls[ic].ordinal = *tarr & 0xffff;
1120
0
            } else {
1121
                // it's an import by name
1122
0
                IPTR_VAR(const byte, const name, ibuf + (*tarr + 2));
1123
0
                unsigned len = strlen(name);
1124
0
                soimport += len + 1;
1125
0
                if (dlls[ic].shname == nullptr || len < strlen(dlls[ic].shname))
1126
0
                    dlls[ic].shname = ibuf + (*tarr + 2);
1127
0
            }
1128
0
            soimport++; // separator
1129
0
        }
1130
0
    }
1131
0
    mb_oimport.alloc(soimport);
1132
0
    mb_oimport.clear();
1133
0
    oimport = SPAN_S_MAKE(byte, mb_oimport); // => now is a SPAN_S
1134
1135
    // NOLINTNEXTLINE(bugprone-multi-level-implicit-pointer-conversion)
1136
0
    upx_qsort(idlls, dllnum, sizeof(idlls[0]), UDll::compare);
1137
1138
0
    info("Processing imports: %d DLLs", dllnum);
1139
0
    for (unsigned ic = 0; ic < dllnum; ic++) {
1140
0
        info("  DLL %3d %s %s", ic, idlls[ic]->name, idlls[ic]->shname);
1141
0
    }
1142
1143
0
    ilinker = new ImportLinker(sizeof(LEXX));
1144
    // create the new import table
1145
0
    addStubImports();
1146
1147
0
    for (unsigned ic = 0; ic < dllnum; ic++) {
1148
0
        if (idlls[ic]->isk32) {
1149
            // for kernel32.dll we need to put all the imported
1150
            // ordinals into the output import table, as on
1151
            // some versions of windows GetProcAddress does not resolve them
1152
0
            if (strcasecmp(idlls[ic]->name, "kernel32.dll"))
1153
0
                continue;
1154
0
            if (idlls[ic]->ordinal)
1155
0
                for (const LEXX *tarr = idlls[ic]->lookupt; *tarr; tarr++) {
1156
0
                    if (*tarr & ord_mask) {
1157
0
                        ilinker->add_import(kernelDll(), *tarr & 0xffff);
1158
0
                        kernel32ordinal = true;
1159
0
                    }
1160
0
                }
1161
0
        } else if (!ilinker->hasDll(idlls[ic]->name)) {
1162
0
            if (idlls[ic]->shname && !idlls[ic]->ordinal)
1163
0
                ilinker->add_import(idlls[ic]->name, idlls[ic]->shname);
1164
0
            else
1165
0
                ilinker->add_import(idlls[ic]->name, idlls[ic]->ordinal);
1166
0
        }
1167
0
    }
1168
1169
0
    soimpdlls = ilinker->build();
1170
1171
0
    Interval names(ibuf), iats(ibuf), lookups(ibuf);
1172
1173
    // create the preprocessed data
1174
0
    SPAN_S_VAR(byte, ppi, oimport); // preprocessed imports
1175
0
    for (unsigned ic = 0; ic < dllnum; ic++) {
1176
0
        const LEXX *tarr = idlls[ic]->lookupt;
1177
0
        set_le32(ppi, ilinker->getAddress(idlls[ic]->name));
1178
0
        set_le32(ppi + 4, idlls[ic]->iat - rvamin);
1179
0
        ppi += 8;
1180
0
        for (; *tarr; tarr++) {
1181
0
            if (*tarr & ord_mask) {
1182
0
                const unsigned ord = *tarr & 0xffff;
1183
0
                if (idlls[ic]->isk32 && kernel32ordinal) {
1184
0
                    *ppi++ = 0xfe; // signed + odd parity
1185
0
                    set_le32(ppi, ilinker->getAddress(idlls[ic]->name, ord));
1186
0
                    ppi += 4;
1187
0
                } else {
1188
0
                    *ppi++ = 0xff;
1189
0
                    set_le16(ppi, ord);
1190
0
                    ppi += 2;
1191
0
                }
1192
0
            } else {
1193
0
                *ppi++ = 1;
1194
0
                const unsigned skip2 = 2 + *tarr;
1195
0
                const unsigned take2 = 1 + strlen(ibuf.subref("bad import name %#x", skip2, 1));
1196
0
                memcpy(ppi, ibuf.subref("bad import name %#x", skip2, take2), take2);
1197
0
                ppi += take2;
1198
0
                names.add_interval(*tarr, 2 + take2);
1199
0
            }
1200
0
        }
1201
0
        ppi++;
1202
1203
0
        const unsigned esize = ptr_udiff_bytes(tarr, idlls[ic]->lookupt);
1204
0
        lookups.add_interval(idlls[ic]->lookupt, esize);
1205
0
        if (ptr_diff_bytes(ibuf.subref("bad import name %#x", idlls[ic]->iat, 1),
1206
0
                           idlls[ic]->lookupt) != 0) {
1207
0
            byte *a = ibuf.subref("bad import name %#x %#x", idlls[ic]->iat, esize);
1208
            // ptr_check_no_overlap(a, esize, idlls[ic]->lookupt, esize);
1209
0
            if (!opt->exact)
1210
0
                memmove(a, idlls[ic]->lookupt, esize);
1211
0
            iats.add_interval(idlls[ic]->iat, esize);
1212
0
        }
1213
0
        names.add_interval(idlls[ic]->name, strlen(idlls[ic]->name) + 1 + 1);
1214
0
    }
1215
0
    ppi += 4;
1216
0
    assert(ppi < oimport + soimport);
1217
0
    soimport = ptr_udiff_bytes(ppi, oimport);
1218
1219
0
    if (soimport == 4)
1220
0
        soimport = 0;
1221
1222
    // OutputFile::dump("x0.imp", oimport, soimport);
1223
1224
0
    unsigned ilen = 0;
1225
0
    names.flatten();
1226
0
    if (names.ivnum > 1) {
1227
        // The area occupied by the dll and imported names is not continuous
1228
        // so to still support uncompression, I can't zero the iat area.
1229
        // This decreases compression ratio, so FIXME somehow.
1230
0
        infoWarning("can't remove unneeded imports");
1231
0
        ilen += sizeof(import_desc) * dllnum;
1232
#if TESTING
1233
        if (opt->verbose > 3)
1234
            names.dump();
1235
#endif
1236
        // do some work for the unpacker
1237
0
        if (!opt->exact)
1238
0
            for (unsigned ic = 0; ic < dllnum; ic++) {
1239
0
                import_desc *const im = im_start + ic;
1240
0
                memset(im, FILLVAL, sizeof(*im));
1241
0
                im->dllname = ptr_udiff_bytes(dlls[idlls[ic]->original_position].name, ibuf);
1242
0
            }
1243
0
    } else if (!opt->exact) {
1244
0
        iats.add_interval(im_start, sizeof(import_desc) * dllnum);
1245
        // zero unneeded data
1246
0
        iats.clear();
1247
0
        lookups.clear();
1248
0
    }
1249
0
    if (!opt->exact)
1250
0
        names.clear();
1251
1252
0
    iats.add_interval(&names);
1253
0
    iats.add_interval(&lookups);
1254
0
    iats.flatten();
1255
0
    for (unsigned ic = 0; ic < iats.ivnum; ic++)
1256
0
        ilen += iats.ivarr[ic].len;
1257
1258
0
    info("Imports: original size: %u bytes, preprocessed size: %u bytes", ilen, soimport);
1259
0
    return names.ivnum == 1 ? names.ivarr[0].start : 0;
1260
0
}
Unexecuted instantiation: unsigned int PeFile::processImports0<LE32, unsigned int>(unsigned int)
Unexecuted instantiation: unsigned int PeFile::processImports0<LE64, unsigned long long>(unsigned long long)
1261
1262
/*************************************************************************
1263
// export handling
1264
**************************************************************************/
1265
1266
0
PeFile::Export::Export(char *_base) : base(_base), iv((byte *) _base) {
1267
0
    COMPILE_TIME_ASSERT(sizeof(export_dir_t) == 40)
1268
0
    COMPILE_TIME_ASSERT_ALIGNED1(export_dir_t)
1269
0
    ename = functionptrs = ordinals = nullptr;
1270
0
    names = nullptr;
1271
0
    mem_clear(&edir);
1272
0
    size = 0;
1273
0
}
1274
1275
0
PeFile::Export::~Export() noexcept {
1276
0
    ::free(ename);
1277
0
    delete[] functionptrs;
1278
0
    delete[] ordinals;
1279
0
    if (names) {
1280
0
        const unsigned limit = edir.names + edir.functions;
1281
0
        for (unsigned ic = 0; ic < limit; ic++)
1282
0
            if (names[ic])
1283
0
                ::free(names[ic]); // allocated by strdup()
1284
0
        delete[] names;
1285
0
    }
1286
0
}
1287
1288
0
void PeFile::Export::convert(unsigned eoffs, unsigned esize) {
1289
0
    memcpy(&edir, base + eoffs, sizeof(export_dir_t));
1290
0
    size = sizeof(export_dir_t);
1291
0
    iv.add_interval(eoffs, size);
1292
1293
0
    if (!edir.name || eoffs + esize <= (unsigned) edir.name) {
1294
0
        char msg[50];
1295
0
        snprintf(msg, sizeof(msg), "bad export directory name RVA %#x", (unsigned) edir.name);
1296
0
        throwInternalError(msg);
1297
0
    }
1298
0
    unsigned len = strlen(base + edir.name) + 1;
1299
0
    ename = ::strdup(base + edir.name);
1300
0
    assert_noexcept(ename != nullptr);
1301
0
    size += len;
1302
0
    iv.add_interval(edir.name, len);
1303
1304
    // This test is weak because it does not consider other necessary storage.
1305
    // But it does detect outrageous individual members.
1306
    // Note: sizeof(LE32) <= sizeof(char *)
1307
0
    if (UPX_RSIZE_MAX_MEM / sizeof(char *) <= edir.functions ||
1308
0
        UPX_RSIZE_MAX_MEM / sizeof(char *) <= edir.names) {
1309
0
        throwCantPack("export directory too big:  functions=%#x  names=%#x",
1310
0
                      (unsigned) edir.functions, (unsigned) edir.names);
1311
0
    }
1312
    // edir.name is checked above; the address/name/ordinal tables and the
1313
    // individual name RVAs are read from base with the same trust but were
1314
    // never confined to the export directory, so a crafted table RVA reads
1315
    // out of bounds. Keep every access within [eoffs, eoffs + esize).
1316
0
    const unsigned end = eoffs + esize;
1317
0
    len = sizeof(LE32) * edir.functions;
1318
0
    if (edir.addrtable >= end || len > end - edir.addrtable)
1319
0
        throwCantPack("bad export address table RVA %#x", (unsigned) edir.addrtable);
1320
0
    functionptrs = New(char, len + 1);
1321
0
    memcpy(functionptrs, base + edir.addrtable, len);
1322
0
    size += len;
1323
0
    iv.add_interval(edir.addrtable, len);
1324
1325
0
    names = New(char *, edir.names + edir.functions + 1);
1326
0
    if (edir.nameptrtable >= end || sizeof(LE32) * edir.names > end - edir.nameptrtable)
1327
0
        throwCantPack("bad export name pointer table RVA %#x", (unsigned) edir.nameptrtable);
1328
0
    for (unsigned ic = 0; ic < edir.names; ic++) {
1329
0
        const unsigned namerva = get_le32(base + (edir.nameptrtable + ic * sizeof(LE32)));
1330
0
        if (namerva >= end)
1331
0
            throwCantPack("bad export name RVA %#x", namerva);
1332
0
        const char *n = base + namerva;
1333
0
        len = strlen(n) + 1;
1334
0
        names[ic] = ::strdup(n);
1335
0
        assert_noexcept(names[ic] != nullptr);
1336
0
        size += len;
1337
0
        iv.add_interval(namerva, len);
1338
0
    }
1339
0
    iv.add_interval(edir.nameptrtable, sizeof(LE32) * edir.names);
1340
0
    size += sizeof(LE32) * edir.names;
1341
1342
0
    LE32 *fp = (LE32 *) functionptrs;
1343
    // export forwarders
1344
0
    for (unsigned ic = 0; ic < edir.functions; ic++) {
1345
0
        if (fp[ic] >= eoffs && fp[ic] < eoffs + esize) {
1346
0
            const char *forw = base + fp[ic];
1347
0
            len = strlen(forw) + 1;
1348
0
            iv.add_interval(forw, len);
1349
0
            size += len;
1350
0
            names[ic + edir.names] = ::strdup(forw);
1351
0
            assert_noexcept(names[ic + edir.names] != nullptr);
1352
0
        } else {
1353
0
            names[ic + edir.names] = nullptr;
1354
0
        }
1355
0
    }
1356
1357
0
    len = 2 * edir.names;
1358
0
    if (edir.ordinaltable >= end || len > end - edir.ordinaltable)
1359
0
        throwCantPack("bad export ordinal table RVA %#x", (unsigned) edir.ordinaltable);
1360
0
    ordinals = New(char, len + 1);
1361
0
    memcpy(ordinals, base + edir.ordinaltable, len);
1362
0
    size += len;
1363
0
    iv.add_interval(edir.ordinaltable, len);
1364
0
    iv.flatten();
1365
0
    if (iv.ivnum == 1 && !opt->exact)
1366
0
        iv.clear();
1367
#if TESTING
1368
    else
1369
        iv.dump();
1370
#endif
1371
0
}
1372
1373
0
void PeFile::Export::build(char *newbase, unsigned newoffs) {
1374
0
    char *const functionp = newbase + sizeof(edir);
1375
0
    char *const namep = functionp + sizeof(LE32) * edir.functions;
1376
0
    char *const ordinalp = namep + sizeof(LE32) * edir.names;
1377
0
    char *const enamep = ordinalp + 2 * edir.names;
1378
0
    char *exports = enamep + strlen(ename) + 1;
1379
1380
0
    edir.addrtable = newoffs + ptr_diff_bytes(functionp, newbase);
1381
0
    edir.ordinaltable = newoffs + ptr_diff_bytes(ordinalp, newbase);
1382
0
    assert(ordinals != nullptr); // pacify clang-tidy
1383
0
    memcpy(ordinalp, ordinals, 2 * edir.names);
1384
1385
0
    edir.name = newoffs + ptr_diff_bytes(enamep, newbase);
1386
0
    strcpy(enamep, ename);
1387
0
    edir.nameptrtable = newoffs + ptr_diff_bytes(namep, newbase);
1388
0
    unsigned ic;
1389
0
    for (ic = 0; ic < edir.names; ic++) {
1390
0
        strcpy(exports, names[ic]);
1391
0
        set_le32(namep + sizeof(LE32) * ic, newoffs + ptr_diff_bytes(exports, newbase));
1392
0
        exports += strlen(exports) + 1;
1393
0
    }
1394
1395
0
    memcpy(functionp, functionptrs, sizeof(LE32) * edir.functions);
1396
0
    for (ic = 0; ic < edir.functions; ic++)
1397
0
        if (names[edir.names + ic]) {
1398
0
            strcpy(exports, names[edir.names + ic]);
1399
0
            set_le32(functionp + sizeof(LE32) * ic, newoffs + ptr_diff_bytes(exports, newbase));
1400
0
            exports += strlen(exports) + 1;
1401
0
        }
1402
1403
0
    memcpy(newbase, &edir, sizeof(edir));
1404
0
    assert(exports - newbase == (int) size);
1405
0
}
1406
1407
0
void PeFile::processExports(Export *xport) { // pass1
1408
0
    soexport = ALIGN_UP(IDSIZE(PEDIR_EXPORT), 4u);
1409
0
    if (soexport == 0)
1410
0
        return;
1411
0
    if (!isdll && opt->win32_pe.compress_exports) {
1412
0
        infoWarning("exports compressed, --compress-exports=0 might be needed");
1413
0
        soexport = 0;
1414
0
        return;
1415
0
    }
1416
0
    xport->convert(IDADDR(PEDIR_EXPORT), IDSIZE(PEDIR_EXPORT));
1417
0
    soexport = ALIGN_UP(xport->getsize(), 4u);
1418
0
    mb_oexport.alloc(soexport);
1419
0
    mb_oexport.clear();
1420
0
    oexport = SPAN_S_MAKE(byte, mb_oexport); // => now is a SPAN_S
1421
0
}
1422
1423
0
void PeFile::processExports(Export *xport, unsigned newoffs) { // pass2
1424
0
    if (soexport)
1425
0
        xport->build((char *) raw_bytes(oexport, 0), newoffs);
1426
0
}
1427
1428
/*************************************************************************
1429
// TLS handling
1430
**************************************************************************/
1431
1432
// thanks for theowl for providing me some docs, so that now I understand
1433
// what I'm doing here :)
1434
1435
// 1999-10-17: this was tricky to find:
1436
// when the fixup records and the tls area are on the same page, then
1437
// the tls area is not relocated, because the relocation is done by
1438
// the virtual memory manager only for pages which are not yet loaded.
1439
// of course it was impossible to debug this ;-)
1440
1441
template <>
1442
struct PeFile::tls_traits<LE32> final {
1443
    struct alignas(1) tls {
1444
        LE32 datastart; // VA tls init data start
1445
        LE32 dataend;   // VA tls init data end
1446
        LE32 tlsindex;  // VA tls index
1447
        LE32 callbacks; // VA tls callbacks
1448
        byte _[8];      // zero init, characteristics
1449
    };
1450
1451
    static constexpr unsigned sotls = 24;
1452
    static constexpr unsigned cb_size = 4;
1453
    typedef unsigned cb_value_t;
1454
    static constexpr unsigned reloc_type = IMAGE_REL_BASED_HIGHLOW;
1455
    static constexpr int tls_handler_offset_reloc = 4;
1456
};
1457
1458
template <>
1459
struct PeFile::tls_traits<LE64> final {
1460
    struct alignas(1) tls {
1461
        LE64 datastart; // VA tls init data start
1462
        LE64 dataend;   // VA tls init data end
1463
        LE64 tlsindex;  // VA tls index
1464
        LE64 callbacks; // VA tls callbacks
1465
        byte _[8];      // zero init, characteristics
1466
    };
1467
1468
    static constexpr unsigned sotls = 40;
1469
    static constexpr unsigned cb_size = 8;
1470
    typedef upx_uint64_t cb_value_t;
1471
    static constexpr unsigned reloc_type = IMAGE_REL_BASED_DIR64;
1472
    static constexpr int tls_handler_offset_reloc = -1; // no need to relocate
1473
};
1474
1475
template <typename LEXX>
1476
void PeFile::processTls1(Interval *iv, typename tls_traits<LEXX>::cb_value_t imagebase,
1477
0
                         unsigned imagesize) { // pass 1
1478
0
    typedef typename tls_traits<LEXX>::tls tls;
1479
0
    typedef typename tls_traits<LEXX>::cb_value_t cb_value_t;
1480
0
    constexpr unsigned cb_size = tls_traits<LEXX>::cb_size;
1481
1482
0
    COMPILE_TIME_ASSERT(sizeof(tls) == tls_traits<LEXX>::sotls)
1483
0
    COMPILE_TIME_ASSERT_ALIGNED1(tls)
1484
1485
0
    if (isefi && IDSIZE(PEDIR_TLS))
1486
0
        throwCantPack("TLS not supported on EFI");
1487
1488
0
    const unsigned take = ALIGN_UP(IDSIZE(PEDIR_TLS), 4u);
1489
0
    sotls = take;
1490
0
    if (!sotls)
1491
0
        return;
1492
0
    const unsigned skip = IDADDR(PEDIR_TLS);
1493
0
    const tls *const tlsp = (const tls *) ibuf.subref("bad tls %#x", skip, sizeof(tls));
1494
0
    if (tlsp->dataend <= tlsp->datastart) {   // includes wrap-around
1495
0
        if (tlsp->dataend == tlsp->datastart) // lazy compiler
1496
0
            infoWarning("TLS empty region");
1497
0
        else
1498
0
            throwCantPack("TLS illegal region");
1499
0
    }
1500
1501
    // note: TLS callbacks are not implemented in Windows 95/98/ME
1502
0
    if (tlsp->callbacks) {
1503
0
        if (tlsp->callbacks < imagebase)
1504
0
            throwCantPack("invalid TLS callback");
1505
0
        else if (tlsp->callbacks - imagebase + 4 >= imagesize)
1506
0
            throwCantPack("invalid TLS callback");
1507
0
        cb_value_t v =
1508
0
            *(LEXX *) ibuf.subref("bad TLS %#x", (tlsp->callbacks - imagebase), sizeof(LEXX));
1509
1510
0
        if (v != 0) {
1511
            // count number of callbacks, just for information string - Stefan Widmann
1512
0
            unsigned num_callbacks = 0;
1513
0
            unsigned callback_offset = 0;
1514
0
            while (*(LEXX *) ibuf.subref(
1515
0
                "bad TLS %#x", tlsp->callbacks - imagebase + callback_offset, sizeof(LEXX))) {
1516
                // increment number of callbacks
1517
0
                num_callbacks++;
1518
0
                callback_offset += cb_size;
1519
0
            }
1520
0
            info("TLS: %u callback(s) found, adding TLS callback handler", num_callbacks);
1521
            // set flag to include necessary sections in loader
1522
0
            use_tls_callbacks = true;
1523
            // define linker symbols
1524
0
            tlscb_ptr = tlsp->callbacks;
1525
0
        }
1526
0
    }
1527
1528
0
    if (tlsp->datastart < imagebase || tlsp->dataend < imagebase)
1529
0
        throwCantPack("TLS below imagebase");
1530
0
    const unsigned tlsdatastart = tlsp->datastart - imagebase;
1531
0
    const unsigned tlsdataend = tlsp->dataend - imagebase;
1532
1533
    // now some ugly stuff: find the relocation entries in the tls data area
1534
0
    const unsigned skip2 = IDADDR(PEDIR_BASERELOC);
1535
0
    const unsigned take2 = IDSIZE(PEDIR_BASERELOC);
1536
0
    Reloc rel(ibuf.subref("bad tls reloc %#x", skip2, take2), take2);
1537
0
    unsigned pos, type;
1538
0
    while (rel.next(pos, type))
1539
0
        if (pos >= tlsdatastart && pos < tlsdataend)
1540
0
            iv->add_interval(pos, type);
1541
1542
0
    sotls = sizeof(tls) + tlsdataend - tlsdatastart;
1543
    // if TLS callbacks are used, we need two more {D|Q}WORDS at the end of the TLS
1544
    // ... and those dwords should be correctly aligned
1545
0
    if (use_tls_callbacks)
1546
0
        sotls = ALIGN_UP(sotls, cb_size) + 2 * cb_size;
1547
0
    const unsigned aligned_sotls = ALIGN_UP(sotls, usizeof(LEXX));
1548
1549
    // the PE loader wants this stuff uncompressed
1550
0
    mb_otls.alloc(aligned_sotls);
1551
0
    mb_otls.clear();
1552
0
    otls = SPAN_S_MAKE(byte, mb_otls); // => otls now is a SPAN_S
1553
0
    const unsigned skip1 = IDADDR(PEDIR_TLS);
1554
0
    const unsigned take1 = sizeof(tls);
1555
0
    memcpy(otls, ibuf.subref("bad tls %#x", skip1, take1), take1);
1556
    // WARNING: this can access data in BSS
1557
0
    const unsigned take3 = sotls - sizeof(tls);
1558
0
    memcpy(otls + sizeof(tls), ibuf.subref("bad tls %#x", tlsdatastart, take3), take3);
1559
0
    tlsindex = tlsp->tlsindex - imagebase;
1560
    // NEW: subtract two dwords if TLS callbacks are used - Stefan Widmann
1561
0
    info("TLS: %u bytes tls data and %u relocations added",
1562
0
         sotls - (unsigned) sizeof(tls) - (use_tls_callbacks ? 2 * cb_size : 0), iv->ivnum);
1563
1564
    // makes sure tls index is zero after decompression
1565
0
    if (tlsindex && tlsindex < imagesize && !opt->exact)
1566
0
        set_le32(ibuf.subref("bad tlsindex %#x", tlsindex, sizeof(LE32)), 0);
1567
0
}
Unexecuted instantiation: void PeFile::processTls1<LE32>(PeFile::Interval*, PeFile::tls_traits<LE32>::cb_value_t, unsigned int)
Unexecuted instantiation: void PeFile::processTls1<LE64>(PeFile::Interval*, PeFile::tls_traits<LE64>::cb_value_t, unsigned int)
1568
1569
template <typename LEXX>
1570
void PeFile::processTls2(Reloc *const rel, const Interval *const iv, unsigned newaddr,
1571
0
                         typename tls_traits<LEXX>::cb_value_t imagebase) { // pass 2
1572
0
    typedef typename tls_traits<LEXX>::tls tls;
1573
0
    typedef typename tls_traits<LEXX>::cb_value_t cb_value_t;
1574
0
    constexpr unsigned cb_size = tls_traits<LEXX>::cb_size;
1575
0
    constexpr unsigned reloc_type = tls_traits<LEXX>::reloc_type;
1576
0
    static_assert(reloc_type > IMAGE_REL_BASED_IGNORE && reloc_type < 16);
1577
0
    constexpr int tls_handler_offset_reloc = tls_traits<LEXX>::tls_handler_offset_reloc;
1578
1579
0
    if (sotls == 0)
1580
0
        return;
1581
1582
    // add new relocation entries
1583
0
    if (tls_handler_offset > 0 && tls_handler_offset_reloc > 0)
1584
0
        rel->add_reloc(tls_handler_offset + tls_handler_offset_reloc, reloc_type);
1585
1586
    // NEW: if TLS callbacks are used, relocate the VA of the callback chain, too - Stefan Widmann
1587
0
    for (unsigned ic = 0; ic < (unsigned) (use_tls_callbacks ? 4 : 3); ic++)
1588
0
        rel->add_reloc(newaddr + ic * cb_size, reloc_type);
1589
1590
0
    SPAN_S_VAR(tls, const tlsp, mb_otls);
1591
    // now the relocation entries in the tls data area
1592
0
    for (unsigned ic = 0; ic < iv->ivnum; ic++) {
1593
0
        SPAN_S_VAR(byte, const pp,
1594
0
                   otls + (iv->ivarr[ic].start - (tlsp->datastart - imagebase) + sizeof(tls)));
1595
0
        LEXX *const p = (LEXX *) raw_bytes(pp, sizeof(LEXX));
1596
0
        cb_value_t kc = *p;
1597
0
        if (kc >= tlsp->datastart && kc < tlsp->dataend) {
1598
            // add a relocation entry referring to an address inside of the original tls data area
1599
            // - as the new tls area is moved, the referred address have to be also adjusted
1600
0
            kc += newaddr + sizeof(tls) - tlsp->datastart;
1601
0
            *p = kc + imagebase;
1602
0
            rel->add_reloc(kc, iv->ivarr[ic].len);
1603
0
        } else {
1604
            // add a relocation entry referring to an address outside of the original tls data area
1605
            // by adding the difference of the new tlsdatastart and the old tlsdatastart to
1606
            // the address of the original relocation record
1607
0
            const unsigned a =
1608
0
                iv->ivarr[ic].start + (newaddr + sizeof(tls)) - (tlsp->datastart - imagebase);
1609
            // Must not overwrite compressed data
1610
0
            if (a < newaddr && !opt->win32_pe.strip_relocs)
1611
0
                throwCantPack("relocation too low (%#x < %#x); try --strip-relocs", a, newaddr);
1612
0
            rel->add_reloc(a, iv->ivarr[ic].len);
1613
0
        }
1614
0
    }
1615
1616
0
    const unsigned tls_data_size = tlsp->dataend - tlsp->datastart;
1617
0
    tlsp->datastart = newaddr + sizeof(tls) + imagebase;
1618
0
    tlsp->dataend = tlsp->datastart + tls_data_size;
1619
1620
    // NEW: if we have TLS callbacks to handle, we create a pointer to the new callback chain -
1621
    // Stefan Widmann
1622
0
    tlsp->callbacks = (use_tls_callbacks ? newaddr + sotls + imagebase - 2 * cb_size : 0);
1623
1624
0
    if (use_tls_callbacks) {
1625
        // set handler offset
1626
0
        SPAN_S_VAR(byte, pp, otls);
1627
0
        pp = otls + (sotls - 2 * cb_size);
1628
0
        *(LEXX *) raw_bytes(pp, sizeof(LEXX)) = tls_handler_offset + imagebase;
1629
0
        pp = otls + (sotls - 1 * cb_size);
1630
0
        *(LEXX *) raw_bytes(pp, sizeof(LEXX)) = 0; // end of one-item list
1631
        // add relocation for TLS handler offset
1632
0
        rel->add_reloc(newaddr + sotls - 2 * cb_size, reloc_type);
1633
0
    }
1634
0
}
Unexecuted instantiation: void PeFile::processTls2<LE32>(PeFile::Reloc*, PeFile::Interval const*, unsigned int, PeFile::tls_traits<LE32>::cb_value_t)
Unexecuted instantiation: void PeFile::processTls2<LE64>(PeFile::Reloc*, PeFile::Interval const*, unsigned int, PeFile::tls_traits<LE64>::cb_value_t)
1635
1636
/*************************************************************************
1637
// Load Configuration handling
1638
**************************************************************************/
1639
1640
0
void PeFile::processLoadConf(Interval *iv) { // pass 1
1641
0
    if (IDSIZE(PEDIR_LOAD_CONFIG) == 0)
1642
0
        return;
1643
1644
0
    const unsigned lcaddr = IDADDR(PEDIR_LOAD_CONFIG);
1645
0
    const byte *const loadconf = ibuf.subref("bad loadconf %#x", lcaddr, 4);
1646
0
    soloadconf = get_le32(loadconf);
1647
0
    if (soloadconf == 0)
1648
0
        return;
1649
0
    static constexpr unsigned MAX_SOLOADCONF = 256; // XXX FIXME: Why?
1650
0
    if (soloadconf > MAX_SOLOADCONF)
1651
0
        info("Load Configuration directory %u > %u", soloadconf, MAX_SOLOADCONF);
1652
0
    if (lcaddr + soloadconf > ibuf.getSize()) {
1653
0
        throwCantPack("load config size exceeds file bounds");
1654
0
    }
1655
1656
    // if there were relocation entries referring to the load config table
1657
    // then we need them for the copy of the table too
1658
0
    const unsigned skip = IDADDR(PEDIR_BASERELOC);
1659
0
    const unsigned take = IDSIZE(PEDIR_BASERELOC);
1660
0
    Reloc rel(ibuf.subref("bad reloc %#x", skip, take), take);
1661
0
    unsigned pos, type;
1662
0
    while (rel.next(pos, type))
1663
0
        if (pos >= lcaddr && pos < lcaddr + soloadconf) {
1664
0
            iv->add_interval(pos - lcaddr, type);
1665
0
            NO_printf("loadconf reloc detected: %x\n", pos);
1666
0
        }
1667
1668
0
    mb_oloadconf.alloc(soloadconf);
1669
0
    oloadconf = (byte *) mb_oloadconf.getVoidPtr();
1670
0
    memcpy(oloadconf, loadconf, soloadconf);
1671
0
}
1672
1673
void PeFile::processLoadConf(Reloc *rel, const Interval *iv,
1674
0
                             unsigned newaddr) { // pass2
1675
    // now we have the address of the new load config table
1676
    // so we can create the new relocation entries
1677
0
    for (unsigned ic = 0; ic < iv->ivnum; ic++) {
1678
0
        rel->add_reloc(iv->ivarr[ic].start + newaddr, iv->ivarr[ic].len);
1679
0
        NO_printf("loadconf reloc added: %x %d\n", iv->ivarr[ic].start + newaddr,
1680
0
                  iv->ivarr[ic].len);
1681
0
    }
1682
0
}
1683
1684
/*************************************************************************
1685
// resource handling
1686
**************************************************************************/
1687
1688
struct alignas(1) PeFile::Resource::res_dir_entry final {
1689
    LE32 tnl; // Type | Name | Language id - depending on level
1690
    LE32 child;
1691
};
1692
1693
struct alignas(1) PeFile::Resource::res_dir final {
1694
    byte _[12]; // flags, timedate, version
1695
    LE16 namedentr;
1696
    LE16 identr;
1697
    // it's usually safe to assume that every res_dir contains
1698
    // at least one res_dir_entry - check() complains otherwise
1699
    res_dir_entry entries[1];
1700
1701
306
    unsigned Sizeof() const { return 16 + mem_size(sizeof(res_dir_entry), namedentr + identr); }
1702
};
1703
1704
struct alignas(1) PeFile::Resource::res_data final {
1705
    LE32 offset;
1706
    LE32 size;
1707
    byte _[8]; // codepage, reserved
1708
};
1709
1710
struct PeFile::Resource::upx_rnode /*not_final*/ {
1711
    unsigned id = 0;
1712
    byte *name = nullptr;
1713
    upx_rnode *parent = nullptr;
1714
};
1715
1716
struct PeFile::Resource::upx_rbranch final : public PeFile::Resource::upx_rnode {
1717
    unsigned nc = 0;
1718
    upx_rnode **children = nullptr;
1719
    res_dir data;
1720
};
1721
1722
struct PeFile::Resource::upx_rleaf final : public PeFile::Resource::upx_rnode {
1723
    upx_rleaf *next = nullptr;
1724
    unsigned newoffset = 0;
1725
    res_data data;
1726
};
1727
1728
0
PeFile::Resource::Resource(const byte *ibufstart_, const byte *ibufend_) : root(nullptr) {
1729
0
    ibufstart = ibufstart_;
1730
0
    ibufend = ibufend_;
1731
0
}
1732
1733
92
PeFile::Resource::Resource(const byte *p, const byte *ibufstart_, const byte *ibufend_) {
1734
92
    ibufstart = ibufstart_;
1735
92
    ibufend = ibufend_;
1736
92
    newstart = nullptr;
1737
92
    init(p);
1738
92
}
1739
1740
58
PeFile::Resource::~Resource() noexcept {
1741
58
    if (root) {
1742
39
        destroy(root, 0);
1743
39
        root = nullptr;
1744
39
    }
1745
58
}
1746
1747
317
unsigned PeFile::Resource::dirsize() const { return ALIGN_UP(dsize + ssize, 4u); }
1748
1749
134
bool PeFile::Resource::next() {
1750
    // wow, builtin autorewind... :-)
1751
134
    current = current ? current->next : head;
1752
134
    return current != nullptr;
1753
134
}
1754
1755
0
unsigned PeFile::Resource::itype() const { return current->parent->parent->id; }
1756
1757
0
const byte *PeFile::Resource::ntype() const { return current->parent->parent->name; }
1758
1759
150
unsigned PeFile::Resource::size() const { return ALIGN_UP(current->data.size, 4u); }
1760
1761
0
unsigned PeFile::Resource::rawsize() const { return current->data.size; }
1762
1763
316
unsigned PeFile::Resource::offs() const { return current->data.offset; }
1764
1765
58
unsigned &PeFile::Resource::newoffs() { return current->newoffset; }
1766
1767
0
void PeFile::Resource::dump() const { dump(root, 0); }
1768
1769
0
unsigned PeFile::Resource::iname() const { return current->parent->id; }
1770
1771
0
const byte *PeFile::Resource::nname() const { return current->parent->name; }
1772
1773
/*
1774
    unsigned ilang() const {return current->id;}
1775
    const byte *nlang() const {return current->name;}
1776
*/
1777
1778
92
void PeFile::Resource::init(const byte *res) {
1779
92
    COMPILE_TIME_ASSERT(sizeof(res_dir_entry) == 8)
1780
92
    COMPILE_TIME_ASSERT(sizeof(res_dir) == 16 + 8)
1781
92
    COMPILE_TIME_ASSERT(sizeof(res_data) == 16)
1782
92
    COMPILE_TIME_ASSERT_ALIGNED1(res_dir_entry)
1783
92
    COMPILE_TIME_ASSERT_ALIGNED1(res_dir)
1784
92
    COMPILE_TIME_ASSERT_ALIGNED1(res_data)
1785
1786
92
    start = res;
1787
92
    root = head = current = nullptr;
1788
92
    dsize = ssize = 0;
1789
92
    check((const res_dir *) start, 0);
1790
92
    root = convert(start, nullptr, 0);
1791
92
}
1792
1793
337
void PeFile::Resource::check(const res_dir *node, unsigned level) {
1794
337
    ibufcheck(node, sizeof(*node));
1795
337
    int ic = node->identr + node->namedentr;
1796
337
    if (ic == 0)
1797
30
        return;
1798
1.33k
    for (const res_dir_entry *rde = node->entries; --ic >= 0; rde++) {
1799
1.03k
        ibufcheck(rde, sizeof(*rde));
1800
1.03k
        if (((rde->child & 0x80000000) == 0) ^ (level == 2))
1801
12
            throwCantPack("unsupported resource structure");
1802
1.02k
        else if (level != 2)
1803
245
            check((const res_dir *) (start + (rde->child & 0x7fffffff)), level + 1);
1804
1.03k
    }
1805
307
}
1806
1807
1.75k
void PeFile::Resource::ibufcheck(const void *m, unsigned siz) {
1808
1.75k
    if (m < ibufstart || m > ibufend - siz)
1809
14
        throwCantUnpack("corrupted resources");
1810
1.75k
}
1811
1812
PeFile::Resource::upx_rnode *PeFile::Resource::convert(const void *rnode, upx_rnode *parent,
1813
378
                                                       unsigned level) {
1814
378
    if (level == 3) {
1815
116
        const res_data *node = ACC_STATIC_CAST(const res_data *, rnode);
1816
116
        ibufcheck(node, sizeof(*node));
1817
116
        upx_rleaf *leaf = new upx_rleaf;
1818
116
        leaf->id = 0;
1819
116
        leaf->name = nullptr;
1820
116
        leaf->parent = parent;
1821
116
        leaf->next = head;
1822
116
        leaf->newoffset = 0;
1823
116
        leaf->data = *node;
1824
1825
116
        head = leaf; // append node to a linked list for traversal
1826
116
        dsize += sizeof(res_data);
1827
116
        return leaf;
1828
116
    }
1829
1830
262
    const res_dir *node = ACC_STATIC_CAST(const res_dir *, rnode);
1831
262
    ibufcheck(node, sizeof(*node));
1832
262
    int ic = node->identr + node->namedentr;
1833
262
    if (ic == 0)
1834
27
        return nullptr;
1835
1836
235
    upx_rbranch *branch = new upx_rbranch;
1837
235
    branch->id = 0;
1838
235
    branch->name = nullptr;
1839
235
    branch->parent = parent;
1840
235
    branch->children = New0(upx_rnode *, ic);
1841
235
    branch->nc = ic;
1842
235
    branch->data = *node;
1843
235
    if (!root)         // first one
1844
56
        root = branch; // prevent leak if xcheck throws (hacked unpack or test)
1845
1846
538
    for (const res_dir_entry *rde = node->entries + ic - 1; --ic >= 0; rde--) {
1847
303
        upx_rnode *child = convert(start + (rde->child & 0x7fffffff), branch, level + 1);
1848
303
        branch->children[ic] = child;
1849
303
        xcheck(child);
1850
303
        child->id = rde->tnl;
1851
303
        if (child->id & 0x80000000) {
1852
4
            const byte *p = start + (child->id & 0x7fffffff);
1853
4
            ibufcheck(p, 2);
1854
4
            const unsigned len = 2 + 2 * get_le16(p);
1855
4
            ibufcheck(p, len);
1856
4
            child->name = New(byte, len);
1857
4
            memcpy(child->name, p, len); // copy unicode string
1858
4
            ssize += len;                // size of unicode strings
1859
4
        }
1860
303
    }
1861
235
    dsize += node->Sizeof();
1862
235
    return branch;
1863
262
}
1864
1865
void PeFile::Resource::build(const upx_rnode *node, unsigned &bpos, unsigned &spos,
1866
160
                             unsigned level) {
1867
160
    if (level == 3) {
1868
51
        if (bpos + sizeof(res_data) > dirsize())
1869
0
            throwCantUnpack("corrupted resources");
1870
1871
51
        res_data *l = (res_data *) (newstart + bpos);
1872
51
        const upx_rleaf *leaf = (const upx_rleaf *) node;
1873
51
        *l = leaf->data;
1874
51
        if (leaf->newoffset)
1875
32
            l->offset = leaf->newoffset;
1876
51
        bpos += sizeof(*l);
1877
51
        return;
1878
51
    }
1879
109
    if (bpos + sizeof(res_dir) > dirsize())
1880
0
        throwCantUnpack("corrupted resources");
1881
1882
109
    res_dir *const b = (res_dir *) (newstart + bpos);
1883
109
    const upx_rbranch *branch = (const upx_rbranch *) node;
1884
109
    *b = branch->data;
1885
109
    bpos += b->Sizeof();
1886
109
    res_dir_entry *be = b->entries;
1887
246
    for (unsigned ic = 0; ic < branch->nc; ic++, be++) {
1888
137
        xcheck(branch->children[ic]);
1889
137
        be->tnl = branch->children[ic]->id;
1890
137
        be->child = bpos + ((level < 2) ? 0x80000000 : 0);
1891
1892
137
        const byte *p;
1893
137
        if ((p = branch->children[ic]->name) != nullptr) {
1894
0
            be->tnl = spos + 0x80000000;
1895
0
            if (spos + get_le16(p) * 2 + 2 > dirsize())
1896
0
                throwCantUnpack("corrupted resources");
1897
0
            memcpy(newstart + spos, p, get_le16(p) * 2 + 2);
1898
0
            spos += get_le16(p) * 2 + 2;
1899
0
        }
1900
1901
137
        build(branch->children[ic], bpos, spos, level + 1);
1902
137
    }
1903
109
}
1904
1905
23
byte *PeFile::Resource::build() {
1906
23
    mb_start.dealloc();
1907
23
    newstart = nullptr;
1908
23
    if (dirsize()) {
1909
23
        mb_start.alloc(dirsize());
1910
23
        newstart = static_cast<byte *>(mb_start.getVoidPtr());
1911
23
        unsigned bpos = 0, spos = dsize;
1912
23
        build(root, bpos, spos, 0);
1913
1914
        // dirsize() is 4 bytes aligned, so we may need to zero
1915
        // up to 2 bytes to make valgrind happy
1916
23
        while (spos < dirsize())
1917
0
            newstart[spos++] = 0;
1918
23
    }
1919
1920
23
    return newstart;
1921
23
}
1922
1923
285
void PeFile::Resource::destroy(upx_rnode *node, unsigned level) noexcept {
1924
285
    xcheck_noexcept(node);
1925
285
    if (level == 3) {
1926
96
        upx_rleaf *leaf = ACC_STATIC_CAST(upx_rleaf *, node);
1927
96
        delete[] leaf->name;
1928
96
        leaf->name = nullptr;
1929
96
        delete leaf;
1930
189
    } else {
1931
189
        upx_rbranch *branch = ACC_STATIC_CAST(upx_rbranch *, node);
1932
189
        delete[] branch->name;
1933
189
        branch->name = nullptr;
1934
435
        for (int ic = branch->nc; --ic >= 0;)
1935
246
            if (branch->children[ic] != nullptr)
1936
246
                destroy(branch->children[ic], level + 1);
1937
189
        delete[] branch->children;
1938
189
        branch->children = nullptr;
1939
189
        delete branch;
1940
189
    }
1941
285
}
1942
1943
0
static void lame_print_unicode(const byte *p) {
1944
0
    for (unsigned ic = 0; ic < get_le16(p); ic++)
1945
0
        printf("%c", (char) p[ic * 2 + 2]);
1946
0
}
1947
1948
0
void PeFile::Resource::dump(const upx_rnode *node, unsigned level) const {
1949
0
    if (level) {
1950
0
        for (unsigned ic = 1; ic < level; ic++)
1951
0
            printf("\t\t");
1952
0
        if (node->name)
1953
0
            lame_print_unicode(node->name);
1954
0
        else
1955
0
            printf("0x%x", node->id);
1956
0
        printf("\n");
1957
0
    }
1958
0
    if (level == 3)
1959
0
        return;
1960
0
    const upx_rbranch *const branch = (const upx_rbranch *) node;
1961
0
    for (unsigned ic = 0; ic < branch->nc; ic++)
1962
0
        dump(branch->children[ic], level + 1);
1963
0
}
1964
1965
0
void PeFile::Resource::clear(byte *node, unsigned level, Interval *iv) {
1966
0
    if (level == 3)
1967
0
        iv->add_interval(node, sizeof(res_data));
1968
0
    else {
1969
0
        const res_dir *const rd = (res_dir *) node;
1970
0
        const unsigned n = rd->identr + rd->namedentr;
1971
0
        const res_dir_entry *rde = rd->entries;
1972
0
        for (unsigned ic = 0; ic < n; ic++, rde++)
1973
0
            clear(newstart + (rde->child & 0x7fffffff), level + 1, iv);
1974
0
        iv->add_interval(rd, rd->Sizeof());
1975
0
    }
1976
0
}
1977
1978
0
bool PeFile::Resource::clear() {
1979
0
    newstart = const_cast<byte *>(start);
1980
0
    Interval iv(newstart);
1981
0
    clear(newstart, 0, &iv);
1982
0
    iv.flatten();
1983
0
    if (iv.ivnum == 1)
1984
0
        iv.clear();
1985
#if TESTING
1986
    if (opt->verbose > 3)
1987
        iv.dump();
1988
#endif
1989
0
    return iv.ivnum == 1;
1990
0
}
1991
1992
0
void PeFile::processResources(Resource *res, unsigned newaddr) {
1993
0
    if (IDSIZE(PEDIR_RESOURCE) == 0)
1994
0
        return;
1995
0
    while (res->next())
1996
0
        if (res->newoffs())
1997
0
            res->newoffs() += newaddr;
1998
0
    if (res->dirsize()) {
1999
0
        byte *p = res->build();
2000
0
        memcpy(oresources, p, res->dirsize());
2001
0
    }
2002
0
}
2003
2004
static bool match(unsigned itype, const byte *ntype, unsigned iname, const byte *nname,
2005
0
                  const char *keep) {
2006
    // format of string keep: type1[/name1],type2[/name2], ....
2007
    // typex and namex can be string or number
2008
    // hopefully resource names do not have '/' or ',' characters inside
2009
2010
0
    struct Helper final {
2011
0
        static bool match(unsigned num, const byte *unistr, const char *mkeep) {
2012
0
            if (!unistr)
2013
0
                return (unsigned) atoi(mkeep) == num;
2014
0
            unsigned ic;
2015
0
            for (ic = 0; ic < get_le16(unistr); ic++)
2016
0
                if (unistr[2 + ic * 2] != (byte) mkeep[ic])
2017
0
                    return false;
2018
0
            return mkeep[ic] == 0 || mkeep[ic] == ',' || mkeep[ic] == '/';
2019
0
        }
2020
0
    };
2021
2022
    // FIXME this comparison is not too exact
2023
0
    for (;;) {
2024
0
        const char *delim1 = strchr(keep, '/');
2025
0
        const char *delim2 = strchr(keep, ',');
2026
0
        if (Helper::match(itype, ntype, keep)) {
2027
0
            if (!delim1)
2028
0
                return true;
2029
0
            if (delim2 && delim2 < delim1)
2030
0
                return true;
2031
0
            if (Helper::match(iname, nname, delim1 + 1))
2032
0
                return true;
2033
0
        }
2034
0
        if (delim2 == nullptr)
2035
0
            break;
2036
0
        keep = delim2 + 1;
2037
0
    }
2038
0
    return false;
2039
0
}
2040
2041
0
void PeFile::processResources(Resource *res) {
2042
0
    const unsigned vaddr = IDADDR(PEDIR_RESOURCE);
2043
0
    if ((soresources = IDSIZE(PEDIR_RESOURCE)) == 0)
2044
0
        return;
2045
2046
    // setup default options for resource compression
2047
0
    if (opt->win32_pe.compress_resources.isThird())
2048
0
        opt->win32_pe.compress_resources = !isefi;
2049
0
    if (!opt->win32_pe.compress_resources) {
2050
0
        opt->win32_pe.compress_icons = false;
2051
0
        for (int i = 0; i < RT_LAST; i++)
2052
0
            opt->win32_pe.compress_rt[i] = false;
2053
0
    }
2054
0
    if (opt->win32_pe.compress_rt[RT_STRING].isThird()) {
2055
        // by default, don't compress RT_STRINGs of screensavers (".scr")
2056
0
        opt->win32_pe.compress_rt[RT_STRING] = true;
2057
0
        if (fn_has_ext(fi->getName(), "scr"))
2058
0
            opt->win32_pe.compress_rt[RT_STRING] = false;
2059
0
    }
2060
2061
0
    res->init(ibuf.subref("bad res %#x", vaddr, 1));
2062
2063
0
    for (soresources = res->dirsize(); res->next(); soresources += 4 + res->size())
2064
0
        ;
2065
0
    if (!soresources)
2066
0
        return; // empty .rsrc Section
2067
0
    mb_oresources.alloc(soresources);
2068
0
    mb_oresources.clear();
2069
0
    oresources = SPAN_S_MAKE(byte, mb_oresources); // => now is a SPAN_S
2070
0
    SPAN_S_VAR(byte, ores, oresources + res->dirsize());
2071
2072
0
    char *keep_icons = nullptr; // icon ids in the first icon group
2073
0
    const auto keep_icons_deleter = upx::ArrayDeleter(&keep_icons, 1); // don't leak memory
2074
0
    unsigned iconsin1stdir = 0;
2075
0
    if (opt->win32_pe.compress_icons == 2)
2076
0
        while (res->next()) // there is no rewind() in Resource
2077
0
            if (res->itype() == RT_GROUP_ICON && iconsin1stdir == 0) {
2078
0
                iconsin1stdir = get_le16(ibuf.subref("bad resoff %#x", res->offs() + 4, 2));
2079
0
                delete[] keep_icons;
2080
0
                keep_icons = nullptr;
2081
0
                keep_icons = New(char, 1 + iconsin1stdir * 9);
2082
0
                *keep_icons = 0;
2083
0
                for (unsigned ic = 0; ic < iconsin1stdir; ic++)
2084
0
                    upx_safe_snprintf(
2085
0
                        keep_icons + strlen(keep_icons), 9, "3/%u,",
2086
0
                        get_le16(ibuf.subref("bad resoff %#x", res->offs() + 6 + ic * 14 + 12, 2)));
2087
0
                if (*keep_icons)
2088
0
                    keep_icons[strlen(keep_icons) - 1] = 0;
2089
0
            }
2090
2091
    // the icon id which should not be compressed when compress_icons == 1
2092
0
    unsigned first_icon_id = (unsigned) -1;
2093
0
    if (opt->win32_pe.compress_icons == 1)
2094
0
        while (res->next())
2095
0
            if (res->itype() == RT_GROUP_ICON && first_icon_id == (unsigned) -1)
2096
0
                first_icon_id = get_le16(ibuf.subref("bad resoff %#x", res->offs() + 6 + 12, 2));
2097
2098
0
    bool compress_icon = opt->win32_pe.compress_icons > 1;
2099
0
    bool compress_idir = opt->win32_pe.compress_icons == 3;
2100
2101
    // some statistics
2102
0
    unsigned usize = 0;
2103
0
    unsigned csize = 0;
2104
0
    unsigned unum = 0;
2105
0
    unsigned cnum = 0;
2106
2107
0
    Interval clear_resources(ibuf), keep_resources(ibuf);
2108
0
    while (res->next()) {
2109
0
        const unsigned rtype = res->itype();
2110
0
        bool do_compress = true;
2111
0
        if (!opt->win32_pe.compress_resources)
2112
0
            do_compress = false;
2113
0
        else if (rtype == RT_ICON) // icon
2114
0
        {
2115
0
            if (opt->win32_pe.compress_icons == 0)
2116
0
                do_compress = false;
2117
0
            else if (opt->win32_pe.compress_icons == 1)
2118
0
                if ((first_icon_id == (unsigned) -1 || first_icon_id == res->iname()))
2119
0
                    do_compress = compress_icon;
2120
0
        } else if (rtype == RT_GROUP_ICON) // icon directory
2121
0
            do_compress = compress_idir && opt->win32_pe.compress_icons;
2122
0
        else if (rtype > 0 && rtype < RT_LAST)
2123
0
            do_compress = opt->win32_pe.compress_rt[rtype] ? true : false;
2124
2125
0
        if (do_compress && keep_icons)
2126
0
            do_compress &=
2127
0
                !match(res->itype(), res->ntype(), res->iname(), res->nname(), keep_icons);
2128
0
        if (do_compress)
2129
0
            do_compress &= !match(res->itype(), res->ntype(), res->iname(), res->nname(),
2130
0
                                  "TYPELIB,REGISTRY,16");
2131
0
        if (do_compress)
2132
0
            do_compress &= !match(res->itype(), res->ntype(), res->iname(), res->nname(),
2133
0
                                  opt->win32_pe.keep_resource);
2134
2135
0
        if (do_compress) {
2136
0
            if (!opt->exact) {
2137
0
                ICHECK(ibuf + res->offs(), res->rawsize());
2138
0
                keep_resources.add_interval(res->offs(), res->rawsize());
2139
0
            }
2140
0
            csize += res->size();
2141
0
            cnum++;
2142
0
            continue;
2143
0
        }
2144
2145
0
        usize += res->size();
2146
0
        unum++;
2147
2148
0
        set_le32(ores, res->offs()); // save original offset
2149
0
        ores += 4;
2150
0
        const unsigned take = res->size();
2151
0
        ICHECK(ibuf + res->offs(), take);
2152
0
        memcpy(ores, ibuf.subref("bad resoff %#x", res->offs(), take), take);
2153
0
        if (!opt->exact)
2154
0
            clear_resources.add_interval(res->offs(), take);
2155
0
        res->newoffs() = ptr_diff_bytes(ores, oresources);
2156
0
        if (rtype == RT_ICON && opt->win32_pe.compress_icons == 1)
2157
0
            compress_icon = true;
2158
0
        else if (rtype == RT_GROUP_ICON) {
2159
0
            if (opt->win32_pe.compress_icons == 1) {
2160
0
                icondir_offset = 4 + ptr_diff_bytes(ores, oresources);
2161
0
                icondir_count = get_le16(oresources + icondir_offset);
2162
0
                set_le16(oresources + icondir_offset, 1);
2163
0
            }
2164
0
            compress_idir = true;
2165
0
        }
2166
0
        ores += res->size();
2167
0
    }
2168
0
    soresources = ptr_diff_bytes(ores, oresources);
2169
2170
0
    if (!opt->exact) {
2171
        // Copy all uncompressed resources before clearing their source bytes:
2172
        // aligned sizes can overlap a neighbour, regardless of traversal order.
2173
        // Still clear alignment holes, but preserve any resource data that will
2174
        // be compressed in place (including data overlapping a copied resource).
2175
0
        clear_resources.flatten();
2176
0
        keep_resources.flatten();
2177
0
        clear_resources.clear(keep_resources);
2178
0
    }
2179
2180
0
    if (!opt->exact && !res->clear()) {
2181
        // The area occupied by the resource directory is not continuous
2182
        // so to still support uncompression, I can't zero this area.
2183
        // This decreases compression ratio, so FIXME somehow.
2184
0
        infoWarning("can't remove unneeded resource directory");
2185
0
    }
2186
0
    info("Resources: compressed %u (%u bytes), not compressed %u (%u bytes)", cnum, csize, unum,
2187
0
         usize);
2188
0
}
2189
2190
/*static*/
2191
0
unsigned PeFile::virta2objnum(unsigned addr, SPAN_0(const pe_section_t) sect, unsigned objs) {
2192
0
    unsigned ic;
2193
0
    for (ic = 0; ic < objs; ic++) {
2194
        // if (sect->vaddr >= addr && sect->vaddr + sect->vsize < addr) // ???
2195
0
        if (sect->vaddr <= addr && sect->vaddr + sect->vsize > addr)
2196
0
            return ic;
2197
0
        sect++;
2198
0
    }
2199
    // throwCantPack("virta2objnum() failed");
2200
0
    return ic;
2201
0
}
2202
2203
0
unsigned PeFile::tryremove(unsigned vaddr, unsigned objs) {
2204
0
    unsigned ic = virta2objnum(vaddr, isection, objs);
2205
0
    if (ic && ic == objs - 1) {
2206
0
        NO_fprintf(stderr, "removed section: %d size: 0x%x\n", ic, (int) isection[ic].size);
2207
0
        info("removed section: %d size: 0x%x", ic, (int) isection[ic].size);
2208
0
        objs--;
2209
0
    }
2210
0
    return objs;
2211
0
}
2212
2213
0
unsigned PeFile::stripDebug(unsigned overlaystart) {
2214
0
    if (IDADDR(PEDIR_DEBUG) == 0)
2215
0
        return overlaystart;
2216
2217
0
    COMPILE_TIME_ASSERT(sizeof(DebugDir) == 28)
2218
0
    COMPILE_TIME_ASSERT_ALIGNED1(DebugDir)
2219
2220
0
    const unsigned skip = IDADDR(PEDIR_DEBUG);
2221
0
    const unsigned take = IDSIZE(PEDIR_DEBUG);
2222
0
    DebugDir *const dd0 = (DebugDir *) ibuf.subref("bad debug %#x", skip, take);
2223
0
    DebugDir *dd = dd0;
2224
0
    for (unsigned ic = 0; ic < IDSIZE(PEDIR_DEBUG) / sizeof(DebugDir); ic++, dd++) {
2225
0
        if (IMAGE_DEBUG_TYPE_EX_DLLCHARACTERISTICS == dd->type && dd->size == sizeof(LE32) &&
2226
0
            dd->fpos <= (file_size_u - sizeof(LE32))) {
2227
            // fpos need not belong to any PEDIR_* section.
2228
            // Read directly from input file, but keep position (paranoia).
2229
0
            LE32 word = {};
2230
0
            const upx_off_t now_pos = fi->tell();
2231
0
            fi->seek(dd->fpos, SEEK_SET);
2232
0
            fi->readx(&word, sizeof(word));
2233
0
            fi->seek(now_pos, SEEK_SET);
2234
0
            if (IMAGE_DLLCHARACTERISTICS_EX_CET_COMPAT & word) {
2235
0
                dbgCET = opt->exact ? &dbgCET_storage : dd0;
2236
0
                *dbgCET = *dd;
2237
0
            }
2238
0
        }
2239
0
        if (!opt->exact && overlaystart == dd->fpos)
2240
0
            overlaystart += dd->size;
2241
0
    }
2242
0
    if (!opt->exact)
2243
0
        ibuf.fill((!dbgCET ? 0 : sizeof(DebugDir)) + IDADDR(PEDIR_DEBUG),
2244
0
                  (!dbgCET ? 0 : -(int) sizeof(DebugDir)) + IDSIZE(PEDIR_DEBUG), FILLVAL);
2245
0
    return overlaystart;
2246
0
}
2247
2248
/*************************************************************************
2249
// pack
2250
**************************************************************************/
2251
2252
0
void PeFile::readSectionHeaders(unsigned objs) {
2253
0
    if (objs == 0)
2254
0
        return;
2255
0
    mb_isection.alloc(mem_size(sizeof(pe_section_t), objs));
2256
0
    isection = SPAN_S_MAKE(pe_section_t, mb_isection); // => isection now is a SPAN_S
2257
0
    if (file_size_u < pe_offset + sizeof_ih + sizeof(pe_section_t) * objs) {
2258
0
        char buf[32];
2259
0
        snprintf(buf, sizeof(buf), "too many sections %d", objs);
2260
0
        throwCantPack(buf);
2261
0
    }
2262
0
    fi->seek(pe_offset + sizeof_ih, SEEK_SET);
2263
0
    fi->readx(isection, sizeof(pe_section_t) * objs);
2264
0
    rvamin = isection[0].vaddr;
2265
0
    const unsigned rvalast = isection[-1 + objs].vsize + isection[-1 + objs].vaddr;
2266
0
    for (unsigned j = 0; j < objs; ++j) { // expect: first is min, last is max
2267
0
        unsigned lo = isection[j].vaddr, hi = isection[j].vsize + lo;
2268
0
        if (hi < lo) { // this checks first and last sections, too!
2269
0
            char buf[64];
2270
0
            snprintf(buf, sizeof(buf), "bad section[%d] wrap-around %#x %#x", j, lo, hi - lo);
2271
0
            throwCantPack(buf);
2272
0
        }
2273
0
        if (lo < rvamin) {
2274
0
            char buf[64];
2275
0
            snprintf(buf, sizeof(buf), "bad section .rva [%d] %#x < [0] %#x", j, lo, rvamin);
2276
0
            throwCantPack(buf);
2277
0
        }
2278
0
        if (rvalast < hi) {
2279
0
            char buf[80];
2280
0
            snprintf(buf, sizeof(buf), "bad section .rva+.vsize  [%d] %#x > [%d] %#x", j, hi,
2281
0
                     (-1 + objs), rvalast);
2282
0
            throwCantPack(buf);
2283
0
        }
2284
0
    }
2285
2286
0
    infoHeader("[Processing %s, format %s, %d sections]", fn_basename(fi->getName()), getName(),
2287
0
               objs);
2288
0
}
2289
2290
void PeFile::checkHeaderValues(unsigned subsystem, unsigned mask, unsigned ih_entry,
2291
0
                               unsigned ih_filealign) {
2292
0
    if ((1u << subsystem) & ~mask) {
2293
0
        char buf[100];
2294
0
        upx_safe_snprintf(buf, sizeof(buf), "PE: subsystem %u is not supported", subsystem);
2295
0
        throwCantPack(buf);
2296
0
    }
2297
    // check CLR Runtime Header directory entry
2298
0
    if (IDSIZE(PEDIR_COM_DESCRIPTOR))
2299
0
        throwCantPack(".NET files are not yet supported");
2300
2301
0
    if (isection == nullptr)
2302
0
        throwCantPack("No section was found");
2303
2304
0
    if (memcmp(isection[0].name, "UPX", 3) == 0)
2305
0
        throwAlreadyPackedByUPX();
2306
2307
0
    if (!opt->force && IDSIZE(15))
2308
0
        throwCantPack("file is possibly packed/protected (try --force)");
2309
2310
0
    if (ih_entry && ih_entry < rvamin)
2311
0
        throwCantPack("run a virus scanner on this file!");
2312
2313
0
    const unsigned fam1 = ih_filealign - 1;
2314
0
    if (!upx::has_single_bit(ih_filealign)) { // ih_filealign is not a power of 2
2315
0
        char buf[32];
2316
0
        snprintf(buf, sizeof(buf), "bad file alignment %#x", 1 + fam1);
2317
0
        throwCantPack(buf);
2318
0
    }
2319
0
}
2320
2321
unsigned PeFile::handleStripRelocs(upx_uint64_t ih_imagebase, upx_uint64_t default_imagebase,
2322
0
                                   LE16 &dllflags) {
2323
0
    if (opt->win32_pe.strip_relocs < 0) {
2324
0
        if (isdll || isefi || dllflags & IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE)
2325
0
            opt->win32_pe.strip_relocs = false;
2326
0
        else
2327
0
            opt->win32_pe.strip_relocs = ih_imagebase >= default_imagebase;
2328
0
    }
2329
0
    if (opt->win32_pe.strip_relocs) {
2330
0
        if (isdll || isefi)
2331
0
            throwCantPack("--strip-relocs is not allowed with DLL and EFI images");
2332
0
        if (dllflags & IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE) {
2333
0
            if (opt->force) { // Disable ASLR
2334
                // The bit is set, so clear it with XOR
2335
0
                dllflags ^= IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE;
2336
                // HIGH_ENTROPY_VA has no effect without DYNAMIC_BASE, so clear
2337
                // it also if set
2338
0
                dllflags &= ~(unsigned) IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA;
2339
0
            } else
2340
0
                throwCantPack("--strip-relocs is not allowed with ASLR (use "
2341
0
                              "with --force to remove)");
2342
0
        }
2343
0
        if (!opt->force && ih_imagebase < default_imagebase)
2344
0
            throwCantPack("--strip-relocs may not support this imagebase (try "
2345
0
                          "with --force)");
2346
0
        return IMAGE_FILE_RELOCS_STRIPPED;
2347
0
    } else
2348
0
        info("Base relocations stripping is disabled for this image");
2349
0
    return 0;
2350
0
}
2351
2352
unsigned PeFile::getRawSectionOrder(SPAN_0(const pe_section_t) sections, unsigned objs,
2353
0
                                    SPAN_0(unsigned) order) {
2354
0
    unsigned count = 0;
2355
0
    for (unsigned ic = 0; ic < objs; ic++) {
2356
0
        if (!sections[ic].rawdataptr)
2357
0
            continue;
2358
0
        unsigned pos = count;
2359
0
        while (pos != 0 && sections[order[pos - 1]].rawdataptr > sections[ic].rawdataptr) {
2360
0
            order[pos] = order[pos - 1];
2361
0
            pos--;
2362
0
        }
2363
0
        order[pos] = ic;
2364
0
        count++;
2365
0
    }
2366
0
    return count;
2367
0
}
2368
2369
unsigned PeFile::readSections(unsigned objs, unsigned usize, unsigned ih_filealign,
2370
0
                              unsigned ih_datasize) {
2371
0
    exact_gap_size = 0;
2372
0
    if (opt->exact) {
2373
0
        Array(unsigned, raw_order, objs);
2374
0
        const unsigned raw_count = getRawSectionOrder(isection, objs, raw_order);
2375
0
        if (raw_count == 0)
2376
0
            throwCantPack("exact PE requires a raw-backed section");
2377
0
        upx_uint64_t raw_end = pe_offset + sizeof_ih + objs * sizeof(*isection);
2378
0
        for (unsigned ii = 0; ii < raw_count; ii++) {
2379
0
            const unsigned ic = raw_order[ii];
2380
0
            const upx_uint64_t raw_start = isection[ic].rawdataptr;
2381
0
            const upx_uint64_t section_end = raw_start + isection[ic].size;
2382
0
            if (raw_start < raw_end || section_end > file_size_u)
2383
0
                throwCantPack("overlapping or invalid raw sections");
2384
0
            for (unsigned jj = 0; jj < ii; jj++) {
2385
0
                const pe_section_t &other = isection[raw_order[jj]];
2386
0
                if (isection[ic].vaddr < (upx_uint64_t) other.vaddr + other.size &&
2387
0
                    other.vaddr < (upx_uint64_t) isection[ic].vaddr + isection[ic].size)
2388
0
                    throwCantPack("overlapping virtual sections cannot be preserved exactly");
2389
0
            }
2390
0
            const unsigned gap = raw_start - raw_end;
2391
0
            exact_gap_size += gap;
2392
0
            raw_end = section_end;
2393
0
        }
2394
0
    }
2395
0
    const unsigned xtrasize = UPX_MAX(ih_datasize, 65536u) + IDSIZE(PEDIR_IMPORT) +
2396
0
                              IDSIZE(PEDIR_BOUND_IMPORT) + IDSIZE(PEDIR_IAT) +
2397
0
                              IDSIZE(PEDIR_DELAY_IMPORT) + IDSIZE(PEDIR_BASERELOC) + exact_gap_size;
2398
0
    ibuf.alloc(usize + xtrasize);
2399
2400
    // BOUND IMPORT support. FIXME: is this ok?
2401
0
    ibufgood = isection[0].rawdataptr;
2402
0
    fi->seek(0, SEEK_SET);
2403
0
    fi->readx(ibuf, ibufgood);
2404
2405
    // Interval holes(ibuf);
2406
2407
0
    unsigned ic, jc, overlaystart = 0;
2408
0
    ibuf.clear(0, usize);
2409
0
    for (ic = jc = 0; ic < objs; ic++) {
2410
0
        if (isection[ic].rawdataptr && overlaystart < isection[ic].rawdataptr + isection[ic].size) {
2411
0
            const unsigned raw_end = isection[ic].rawdataptr + isection[ic].size;
2412
0
            overlaystart = opt->exact ? raw_end : ALIGN_UP(raw_end, ih_filealign);
2413
0
        }
2414
0
        if (isection[ic].vsize == 0)
2415
0
            isection[ic].vsize = isection[ic].size;
2416
0
        if (isection[ic].rawdataptr == 0 ||
2417
0
            (!opt->exact && ((isection[ic].flags & IMAGE_SCN_CNT_UNINITIALIZED_DATA) ||
2418
0
                             (isection[ic].flags & IMAGE_SCN_LNK_INFO)))) {
2419
            // holes.add_interval(isection[ic].vaddr, isection[ic].vsize);
2420
0
            continue;
2421
0
        }
2422
0
        if ((upx_uint64_t) isection[ic].vaddr + isection[ic].size > usize)
2423
0
            throwCantPack("section size problem");
2424
0
        if (!isrtm && ((isection[ic].flags & (IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_SHARED)) ==
2425
0
                       (IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_SHARED)))
2426
0
            if (!opt->force)
2427
0
                throwCantPack("writable shared sections not supported (try --force)");
2428
0
        if (!opt->exact && jc && isection[ic].rawdataptr - jc > ih_filealign && !opt->force)
2429
0
            throwCantPack("superfluous data between sections (try --force)");
2430
0
        fi->seek(isection[ic].rawdataptr, SEEK_SET);
2431
0
        jc = isection[ic].size;
2432
0
        if (jc > isection[ic].vsize && !opt->exact)
2433
0
            jc = isection[ic].vsize;
2434
0
        if (isection[ic].vsize == 0) // hack for some tricky programs - may this break other progs?
2435
0
            jc = isection[ic].vsize = isection[ic].size;
2436
0
        if (isection[ic].vaddr + jc > ibuf.getSize())
2437
0
            throwInternalError("buffer too small 1");
2438
0
        fi->readx(ibuf.subref("bad section %#x", isection[ic].vaddr, jc), jc);
2439
0
        ibufgood = upx::umax(ibufgood, jc + isection[ic].vaddr); // FIXME: simplistic
2440
0
        jc += isection[ic].rawdataptr;
2441
0
    }
2442
0
    return overlaystart;
2443
0
}
2444
2445
0
void PeFile::callCompressWithFilters(Filter &ft, int filter_strategy, unsigned ih_codebase) {
2446
0
    compressWithFilters(&ft, 2048, NULL_cconf, filter_strategy, ih_codebase, rvamin, 0, nullptr, 0);
2447
0
}
2448
2449
0
void PeFile::callProcessStubRelocs(Reloc &rel, unsigned &ic) {
2450
    // WinCE wants relocation data at the beginning of a section
2451
0
    rel.finish(oxrelocs, soxrelocs);
2452
0
    if (opt->win32_pe.strip_relocs)
2453
0
        soxrelocs = 0;
2454
0
    ODADDR(PEDIR_BASERELOC) = soxrelocs ? ic : 0;
2455
0
    ODSIZE(PEDIR_BASERELOC) = soxrelocs;
2456
0
    ic += soxrelocs;
2457
0
}
2458
2459
0
void PeFile::callProcessResources(Resource &res, unsigned &ic) {
2460
0
    if (soresources)
2461
0
        processResources(&res, ic);
2462
0
    ODADDR(PEDIR_RESOURCE) = soresources ? ic : 0;
2463
0
    ODSIZE(PEDIR_RESOURCE) = soresources;
2464
0
    ic += soresources;
2465
0
}
2466
2467
template <typename LEXX, typename ht>
2468
void PeFile::pack0(OutputFile *fo, ht &ih, ht &oh, unsigned subsystem_mask,
2469
0
                   upx_uint64_t default_imagebase, bool last_section_rsrc_only) {
2470
0
    ph.version = opt->exact ? pe_exact_version : pe_version;
2471
0
    if (opt->exact && (isefi || ih.subsystem == IMAGE_SUBSYSTEM_WINDOWS_CE_GUI))
2472
0
        throwCantPackExact();
2473
0
    const unsigned objs = ih.objects;
2474
0
    readSectionHeaders(objs);
2475
0
    if (ih.codebase == 0 && rvamin != 0) { // trickster, or bad linker
2476
        // throwCantPack("bad ih.codebase %#x", (unsigned) ih.codebase);
2477
0
        infoWarning("bad ih.codebase %#x -> %#x", (unsigned) ih.codebase, rvamin);
2478
0
        ih.codebase = rvamin; // silently fix pecadillo
2479
0
    }
2480
2481
0
    if (!opt->force && needForceOption())
2482
0
        throwCantPack("unexpected value in PE header (try --force)");
2483
2484
0
    if (ih.dllflags & IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY) {
2485
0
        if (opt->force)
2486
0
            ih.dllflags &= ~(unsigned) IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY;
2487
0
        else
2488
0
            throwCantPack("image forces integrity check (use --force to remove)");
2489
0
    }
2490
0
    checkHeaderValues(ih.subsystem, subsystem_mask, ih.entry, ih.filealign);
2491
2492
    // remove certificate directory entry
2493
0
    if (IDSIZE(PEDIR_SECURITY))
2494
0
        IDSIZE(PEDIR_SECURITY) = IDADDR(PEDIR_SECURITY) = 0;
2495
2496
0
    if (opt->exact && !(ih.flags & IMAGE_FILE_RELOCS_STRIPPED))
2497
0
        opt->win32_pe.strip_relocs = false;
2498
0
    if (ih.flags & IMAGE_FILE_RELOCS_STRIPPED)
2499
0
        opt->win32_pe.strip_relocs = true;
2500
0
    else
2501
0
        ih.flags |= handleStripRelocs(ih.imagebase, default_imagebase, ih.dllflags);
2502
2503
0
    if (isefi) {
2504
        // PIC for EFI only to avoid false positive detections of Win32 images
2505
        // without relocations fixed address is smaller
2506
0
        if (!opt->win32_pe.strip_relocs)
2507
0
            use_stub_relocs = false;
2508
2509
        // EFI build tools already clear DOS stub
2510
        // and small file alignment benefits from extra space
2511
0
        byte stub[0x40];
2512
0
        memset(stub, 0, sizeof(stub));
2513
0
        set_le16(stub, 'M' + 'Z' * 256);
2514
0
        set_le32(stub + sizeof(stub) - sizeof(LE32), sizeof(stub));
2515
0
        fo->write(stub, sizeof(stub));
2516
0
        pe_offset = sizeof(stub);
2517
0
    } else
2518
0
        handleStub(fi, fo, pe_offset);
2519
0
    const unsigned overlaystart = readSections(objs, ih.imagesize, ih.filealign, ih.datasize);
2520
0
    unsigned overlay = file_size_u - stripDebug(overlaystart);
2521
0
    if (overlay >= file_size_u)
2522
0
        overlay = 0;
2523
0
    checkOverlay(overlay);
2524
2525
0
    unsigned packed_guard_flags_offset = 0;
2526
0
    if (ih.dllflags & IMAGE_DLLCHARACTERISTICS_GUARD_CF) {
2527
0
        if (opt->force) {
2528
0
            const unsigned lcsize = IDSIZE(PEDIR_LOAD_CONFIG);
2529
0
            const unsigned lcaddr = IDADDR(PEDIR_LOAD_CONFIG);
2530
0
            const unsigned gfpos = 14 * sizeof(ih.imagebase) + 6 * sizeof(LE32) + 4 * sizeof(LE16);
2531
0
            if (lcaddr && lcsize >= gfpos + sizeof(LE32)) {
2532
0
                if (opt->exact)
2533
0
                    packed_guard_flags_offset = gfpos;
2534
0
                else
2535
                    // GuardFlags: Set IMAGE_GUARD_SECURITY_COOKIE_UNUSED
2536
                    // and clear the rest
2537
0
                    set_le32(ibuf.subref("bad guard flags at %#x", lcaddr + gfpos, sizeof(LE32)),
2538
0
                             0x00000800);
2539
0
            }
2540
0
            ih.dllflags ^= IMAGE_DLLCHARACTERISTICS_GUARD_CF;
2541
0
        } else
2542
0
            throwCantPack("GUARD_CF enabled PE files are not supported (use --force to disable)");
2543
0
    }
2544
2545
0
    Resource res(ibuf, ibuf + ibuf.getSize());
2546
0
    Interval tlsiv(ibuf);
2547
0
    Interval loadconfiv(ibuf);
2548
0
    Export xport((char *) (byte *) ibuf);
2549
2550
0
    const unsigned dllstrings = processImports();
2551
0
    processTls(&tlsiv); // call before processRelocs!!
2552
0
    processLoadConf(&loadconfiv);
2553
0
    if (packed_guard_flags_offset && soloadconf >= packed_guard_flags_offset + sizeof(LE32))
2554
0
        set_le32(mb_oloadconf.subref("bad packed guard flags at %#x", packed_guard_flags_offset,
2555
0
                                     sizeof(LE32)),
2556
0
                 0x00000800);
2557
0
    processResources(&res);
2558
0
    processExports(&xport);
2559
0
    processRelocs();
2560
2561
    // OutputFile::dump("x1", ibuf, usize);
2562
2563
    // some checks for broken linkers - disable filter if necessary
2564
0
    bool allow_filter = true;
2565
0
    if (ih.codebase) {
2566
0
        if (/*FIXME ih.codebase == ih.database
2567
0
            ||*/ ih.codebase + ih.codesize > ih.imagesize ||
2568
0
            (isection[virta2objnum(ih.codebase, isection, objs)].flags & IMAGE_SCN_CNT_CODE) == 0)
2569
0
            allow_filter = false;
2570
0
    }
2571
2572
0
    const unsigned oam1 = ih.objectalign - 1;
2573
0
    if (!upx::has_single_bit(ih.objectalign)) { // ih.objectalign is not a power of 2
2574
0
        char buf[32];
2575
0
        snprintf(buf, sizeof(buf), "bad object alignment %#x", 1 + oam1);
2576
0
        throwCantPack(buf);
2577
0
    }
2578
2579
    // FIXME: if the last object has a bss then this won't work
2580
    // newvsize = (isection[objs-1].vaddr + isection[objs-1].size + oam1) &~ oam1;
2581
    // temporary solution:
2582
0
    unsigned newvsize = (isection[objs - 1].vaddr + isection[objs - 1].vsize + oam1) & ~oam1;
2583
2584
0
    if (opt->exact)
2585
0
        for (unsigned ic = 0; ic < objs; ic++)
2586
0
            if (isection[ic].rawdataptr &&
2587
0
                (upx_uint64_t) isection[ic].vaddr + isection[ic].size > newvsize)
2588
0
                throwCantPackExact();
2589
2590
0
    NO_fprintf(stderr, "newvsize=%x objs=%d\n", newvsize, objs);
2591
0
    if ((upx_uint64_t) newvsize + soimport + sorelocs > ibuf.getSize())
2592
0
        throwInternalError("buffer too small 2");
2593
0
    memcpy(ibuf + newvsize, oimport, soimport);
2594
0
    memcpy(ibuf + newvsize + soimport, orelocs, sorelocs);
2595
2596
0
    cimports = newvsize - rvamin;  // rva of preprocessed imports
2597
0
    crelocs = cimports + soimport; // rva of preprocessed fixups
2598
2599
0
    ph.u_len = newvsize + soimport + sorelocs;
2600
2601
    // some extra_info data for uncompression support
2602
    // p1 is a raw pointer, so reserve all of the extra_info written below.
2603
    // newvsize comes from the last section and is not bounded by imagesize.
2604
0
    const unsigned sizeof_xi = sizeof_ih + mem_size(sizeof(*isection), ih.objects) +
2605
0
                               (soimport ? 8 : 0) + (sorelocs ? 5 : 0) + (soresources ? 2 : 0) +
2606
0
                               (opt->exact ? exact_gap_size + sizeof(PeExactTrailer) : 0) + 4;
2607
0
    unsigned s = 0;
2608
0
    byte *const p1 = ibuf.subref("bad ph.u_len %#x", ph.u_len, sizeof_xi);
2609
0
    if (opt->exact) {
2610
0
        s = sizeof_ih + mem_size(sizeof(*isection), objs);
2611
0
        fi->seek(pe_offset, SEEK_SET);
2612
0
        fi->readx(ibuf.subref("bad original PE header", ph.u_len, s), s);
2613
0
    } else {
2614
0
        memcpy(p1 + s, &ih, sizeof_ih);
2615
0
        s += sizeof_ih;
2616
0
        memcpy(p1 + s, isection, ih.objects * sizeof(*isection));
2617
0
        s += ih.objects * sizeof(*isection);
2618
0
    }
2619
0
    if (soimport) {
2620
0
        set_le32(p1 + s, cimports);
2621
0
        set_le32(p1 + s + 4, dllstrings);
2622
0
        s += 8;
2623
0
    }
2624
0
    if (sorelocs) {
2625
0
        set_le32(p1 + s, crelocs);
2626
0
        p1[s + 4] = (byte) (big_relocs & 6);
2627
0
        s += 5;
2628
0
    }
2629
0
    if (soresources) {
2630
0
        set_le16(p1 + s, icondir_count);
2631
0
        s += 2;
2632
0
    }
2633
    // end of extra_info data
2634
2635
0
    if (opt->exact) {
2636
0
        Array(unsigned, raw_order, objs);
2637
0
        const unsigned raw_count = getRawSectionOrder(isection, objs, raw_order);
2638
0
        unsigned raw_end = pe_offset + sizeof_ih + objs * sizeof(*isection);
2639
0
        for (unsigned ii = 0; ii < raw_count; ii++) {
2640
0
            const unsigned ic = raw_order[ii];
2641
0
            const unsigned gap = isection[ic].rawdataptr - raw_end;
2642
0
            if (gap) {
2643
0
                fi->seek(raw_end, SEEK_SET);
2644
0
                fi->readx(ibuf.subref("bad exact gaps", ph.u_len + s, gap), gap);
2645
0
                s += gap;
2646
0
            }
2647
0
            raw_end = isection[ic].rawdataptr + isection[ic].size;
2648
0
        }
2649
0
        PeExactTrailer trailer = {};
2650
0
        trailer.flags = (sorelocs ? pe_exact_relocs : 0) | (soimport ? pe_exact_imports : 0);
2651
0
        trailer.gap_size = exact_gap_size;
2652
0
        memcpy(p1 + s, &trailer, sizeof(trailer));
2653
0
        s += sizeof(trailer);
2654
0
    }
2655
0
    set_le32(p1 + s, ptr_diff_bytes(p1, ibuf) - rvamin);
2656
0
    s += 4;
2657
0
    ph.u_len += s;
2658
0
    obuf.allocForCompression(ph.u_len);
2659
2660
    // prepare packheader
2661
0
    if (ph.u_len < rvamin) { // readSectionHeaders() should have caught this
2662
0
        char buf[64];
2663
0
        snprintf(buf, sizeof(buf), "bad PE header  ph.u_len=%#x  rvamin=%#x", ph.u_len, rvamin);
2664
0
        throwInternalError(buf);
2665
0
    }
2666
0
    ph.u_len -= rvamin;
2667
    // prepare filter
2668
0
    Filter ft(ph.level);
2669
0
    ft.buf_len = ih.codesize;
2670
0
    ft.addvalue = ih.codebase - rvamin;
2671
    // compress
2672
0
    int filter_strategy = allow_filter ? 0 : -3;
2673
2674
    // disable filters for files with broken headers
2675
0
    if (ih.codebase + ih.codesize > ph.u_len) {
2676
0
        ft.buf_len = 1;
2677
0
        filter_strategy = -3;
2678
0
    }
2679
2680
0
    callCompressWithFilters(ft, filter_strategy, ih.codebase);
2681
    // info: see buildLoader()
2682
0
    newvsize = (ph.u_len + rvamin + ph.overlap_overhead + oam1) & ~oam1;
2683
    // The loader-assigned TLS index must survive decompression for DLLs
2684
    // and exact-packed EXEs with a retained on-disk initializer.
2685
0
    if (tlsindex && !isdll && !opt->exact &&
2686
0
        ((newvsize - ph.c_len - 1024 + oam1) & ~oam1) > tlsindex + 4)
2687
0
        tlsindex = 0;
2688
2689
0
    const int oh_filealign = UPX_MIN(ih.filealign, 0x200u);
2690
0
    const unsigned fam1 = oh_filealign - 1;
2691
2692
0
    int identsize = 0;
2693
0
    const unsigned codesize = getLoaderSection("IDENTSTR", &identsize);
2694
0
    assert(identsize > 0);
2695
0
    unsigned ic;
2696
0
    getLoaderSection("UPX1HEAD", (int *) &ic);
2697
0
    identsize += ic;
2698
2699
0
    const bool has_oxrelocs =
2700
0
        !opt->win32_pe.strip_relocs && (use_stub_relocs || sotls || loadconfiv.ivnum);
2701
0
    const bool has_ncsection = has_oxrelocs || soimpdlls || soexport || soresources;
2702
0
    const unsigned oobjs = last_section_rsrc_only ? 4 : has_ncsection ? 3 : 2;
2703
    ////pe_section_t osection[oobjs];
2704
0
    pe_section_t osection[4];
2705
0
    memset(osection, 0, sizeof(osection));
2706
    // section 0 : bss
2707
    //         1 : [ident + header] + packed_data + unpacker + tls + loadconf
2708
    //         2 : not compressed data
2709
    //         3 : resource data -- wince/arm 5 needs a new section for this
2710
2711
    // the last section should start with the resource data, because lots of lame
2712
    // windoze codes assume that resources starts on the beginning of a section
2713
2714
    // note: there should be no data in the last section which needs fixup
2715
2716
    // identsplit - number of ident + (upx header) bytes to put into the PE header
2717
0
    const unsigned sizeof_osection = sizeof(osection[0]) * oobjs;
2718
0
    int identsplit = pe_offset + sizeof_osection + sizeof(ht);
2719
0
    if ((identsplit & fam1) == 0)
2720
0
        identsplit = 0;
2721
0
    else if (((identsplit + identsize) ^ identsplit) < oh_filealign)
2722
0
        identsplit = identsize;
2723
0
    else
2724
0
        identsplit = ALIGN_UP_GAP(identsplit, oh_filealign);
2725
0
    ic = identsize - identsplit;
2726
2727
0
    const unsigned c_len =
2728
0
        ((ph.c_len + ic) & 15) == 0 ? ph.c_len : ph.c_len + 16 - ((ph.c_len + ic) & 15);
2729
0
    obuf.clear(ph.c_len, c_len - ph.c_len);
2730
2731
0
    const unsigned aligned_sotls = ALIGN_UP(sotls, usizeof(LEXX));
2732
0
    const unsigned s1size = ALIGN_UP(ic + c_len + codesize, usizeof(LEXX)) + aligned_sotls +
2733
0
                            soloadconf + (dbgCET ? (sizeof(LE32) + sizeof(*dbgCET)) : 0);
2734
0
    const unsigned s1addr = (newvsize - (ic + c_len) + oam1) & ~oam1;
2735
2736
0
    const unsigned ncsection = (s1addr + s1size + oam1) & ~oam1;
2737
0
    const unsigned upxsection = s1addr + ic + c_len;
2738
2739
0
    Reloc rel(1024); // new stub relocations are put here
2740
0
    addNewRelocations(rel, upxsection);
2741
2742
    // new PE header
2743
0
    memcpy(&oh, &ih, sizeof_oh);
2744
0
    oh.filealign = oh_filealign; // identsplit depends on this
2745
2746
0
    oh.entry = upxsection;
2747
0
    oh.objects = oobjs;
2748
0
    oh.chksum = 0;
2749
2750
    // fill the data directory
2751
0
    ODADDR(PEDIR_DEBUG) = 0; // dbgCET later
2752
0
    ODSIZE(PEDIR_DEBUG) = 0;
2753
0
    ODADDR(PEDIR_IAT) = 0;
2754
0
    ODSIZE(PEDIR_IAT) = 0;
2755
0
    ODADDR(PEDIR_BOUND_IMPORT) = 0;
2756
0
    ODSIZE(PEDIR_BOUND_IMPORT) = 0;
2757
2758
    // tls & loadconf are put into section 1
2759
0
    ic = s1addr + s1size - aligned_sotls - soloadconf -
2760
0
         (dbgCET ? (sizeof(LE32) + sizeof(*dbgCET)) : 0);
2761
2762
0
    if (use_tls_callbacks)
2763
0
        tls_handler_offset = linker->getSymbolOffset("PETLSC2") + upxsection;
2764
2765
0
    processTls(&rel, &tlsiv, ic);
2766
0
    ODADDR(PEDIR_TLS) = aligned_sotls ? ic : 0;
2767
0
    ODSIZE(PEDIR_TLS) = aligned_sotls ? (sizeof(LEXX) == 4 ? 0x18 : 0x28) : 0;
2768
0
    ic += aligned_sotls;
2769
2770
0
    processLoadConf(&rel, &loadconfiv, ic);
2771
0
    ODADDR(PEDIR_LOAD_CONFIG) = soloadconf ? ic : 0;
2772
0
    ODSIZE(PEDIR_LOAD_CONFIG) = soloadconf;
2773
0
    ic += soloadconf;
2774
2775
0
    if (dbgCET) {
2776
0
        int delta = ic - dbgCET->rva;
2777
0
        dbgCET->rva = ic;
2778
0
        dbgCET->fpos += delta;
2779
0
        ODADDR(PEDIR_DEBUG) = ic;
2780
0
        ODSIZE(PEDIR_DEBUG) = sizeof(*dbgCET);
2781
0
        ic += sizeof(LE32) + ODSIZE(PEDIR_DEBUG);
2782
0
    }
2783
0
    const bool rel_at_sections_start = last_section_rsrc_only;
2784
2785
0
    ic = ncsection;
2786
0
    if (!last_section_rsrc_only)
2787
0
        callProcessResources(res, ic);
2788
0
    if (rel_at_sections_start)
2789
0
        callProcessStubRelocs(rel, ic);
2790
2791
0
    processImports2(ic, getProcessImportParam(upxsection));
2792
0
    ODADDR(PEDIR_IMPORT) = soimpdlls ? ic : 0;
2793
0
    ODSIZE(PEDIR_IMPORT) = soimpdlls;
2794
0
    ic += soimpdlls;
2795
2796
0
    processExports(&xport, ic);
2797
0
    ODADDR(PEDIR_EXPORT) = soexport ? ic : 0;
2798
0
    ODSIZE(PEDIR_EXPORT) = soexport;
2799
0
    if (!isdll && opt->win32_pe.compress_exports) {
2800
0
        ODADDR(PEDIR_EXPORT) = IDADDR(PEDIR_EXPORT);
2801
0
        ODSIZE(PEDIR_EXPORT) = IDSIZE(PEDIR_EXPORT);
2802
0
    }
2803
0
    ic += soexport;
2804
2805
0
    if (!rel_at_sections_start)
2806
0
        callProcessStubRelocs(rel, ic);
2807
2808
    // when the resource is put alone into section 3
2809
0
    const unsigned res_start = (ic + oam1) & ~oam1;
2810
0
    if (last_section_rsrc_only)
2811
0
        callProcessResources(res, ic = res_start);
2812
2813
0
    defineSymbols(ncsection, upxsection, identsize - identsplit, s1addr);
2814
0
    defineFilterSymbols(&ft);
2815
0
    relocateLoader();
2816
0
    const unsigned lsize = getLoaderSize();
2817
0
    MemBuffer loader(lsize);
2818
0
    memcpy(loader, getLoader(), lsize);
2819
0
    patchPackHeader(loader, lsize);
2820
2821
0
    const unsigned ncsize =
2822
0
        soxrelocs + soimpdlls + soexport + (!last_section_rsrc_only ? soresources : 0);
2823
0
    assert((soxrelocs == 0) == !has_oxrelocs);
2824
0
    assert((ncsize == 0) == !has_ncsection);
2825
2826
    // this one is tricky: it seems windoze touches 4 bytes after
2827
    // the end of the relocation data - so we have to increase
2828
    // the virtual size of this section
2829
0
    const unsigned ncsize_virt_increase = soxrelocs && (ncsize & oam1) == 0 ? 8 : 0;
2830
2831
    // fill the sections
2832
0
    strcpy(osection[0].name, "UPX0");
2833
0
    strcpy(osection[1].name, "UPX1");
2834
    // after some windoze debugging I found that the name of the sections
2835
    // DOES matter :( .rsrc is used by oleaut32.dll (TYPELIBS)
2836
    // and because of this lame dll, the resource stuff must be the
2837
    // first in the 3rd section - the author of this dll seems to be
2838
    // too idiot to use the data directories... M$ suxx 4 ever!
2839
    // ... even worse: exploder.exe in NiceTry also depends on this to
2840
    // locate version info
2841
0
    strcpy(osection[2].name, !last_section_rsrc_only && soresources ? ".rsrc" : "UPX2");
2842
2843
0
    osection[0].vaddr = rvamin;
2844
0
    osection[1].vaddr = s1addr;
2845
0
    osection[2].vaddr = ncsection;
2846
2847
0
    osection[0].size = 0;
2848
0
    osection[1].size = (s1size + fam1) & ~fam1;
2849
0
    osection[2].size = (ncsize + fam1) & ~fam1;
2850
2851
0
    osection[0].vsize = osection[1].vaddr - osection[0].vaddr;
2852
0
    if (!last_section_rsrc_only) {
2853
0
        osection[1].vsize = (osection[1].size + oam1) & ~oam1;
2854
0
        osection[2].vsize = (osection[2].size + ncsize_virt_increase + oam1) & ~oam1;
2855
0
        oh.imagesize = osection[2].vaddr + osection[2].vsize;
2856
0
        osection[0].rawdataptr = (pe_offset + sizeof(ht) + sizeof_osection + fam1) & ~(size_t) fam1;
2857
0
        osection[1].rawdataptr = osection[0].rawdataptr;
2858
0
    } else {
2859
0
        osection[1].vsize = osection[1].size;
2860
0
        osection[2].vsize = osection[2].size;
2861
0
        osection[0].rawdataptr = 0;
2862
0
        osection[1].rawdataptr = (pe_offset + sizeof(ht) + sizeof_osection + fam1) & ~(size_t) fam1;
2863
0
    }
2864
0
    osection[2].rawdataptr = osection[1].rawdataptr + osection[1].size;
2865
2866
0
    osection[0].flags = IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ |
2867
0
                        IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_EXECUTE;
2868
0
    osection[1].flags = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE |
2869
0
                        IMAGE_SCN_MEM_EXECUTE;
2870
0
    osection[2].flags = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE;
2871
2872
0
    if (last_section_rsrc_only) {
2873
0
        strcpy(osection[3].name, ".rsrc");
2874
0
        osection[3].vaddr = res_start;
2875
0
        osection[3].size = (soresources + fam1) & ~fam1;
2876
0
        osection[3].vsize = osection[3].size;
2877
0
        osection[3].rawdataptr = osection[2].rawdataptr + osection[2].size;
2878
0
        osection[2].flags = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ;
2879
0
        osection[3].flags = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ;
2880
0
        oh.imagesize = (osection[3].vaddr + osection[3].vsize + oam1) & ~oam1;
2881
0
        if (soresources == 0) {
2882
0
            oh.objects = 3;
2883
0
            mem_clear(&osection[3]);
2884
0
        }
2885
0
    }
2886
2887
0
    oh.bsssize = osection[0].vsize;
2888
0
    oh.datasize = osection[2].vsize + (oobjs > 3 ? osection[3].vsize : 0);
2889
0
    setOhDataBase(osection);
2890
0
    oh.codesize = osection[1].vsize;
2891
0
    oh.codebase = osection[1].vaddr;
2892
0
    setOhHeaderSize(osection);
2893
0
    if (rvamin < osection[0].rawdataptr) {
2894
0
        throwCantPack("object alignment too small rvamin=%#x oraw=%#x", rvamin,
2895
0
                      unsigned(osection[0].rawdataptr));
2896
0
    }
2897
2898
0
    if (opt->win32_pe.strip_relocs)
2899
0
        oh.flags |= IMAGE_FILE_RELOCS_STRIPPED;
2900
2901
0
    ibuf.clear(0, oh.filealign);
2902
2903
0
    info("Image size change: %u -> %u KiB", ih.imagesize / 1024, oh.imagesize / 1024);
2904
2905
0
    infoHeader("[Writing compressed file]");
2906
2907
    // write loader + compressed file
2908
0
    fo->write(&oh, sizeof_oh);
2909
0
    fo->write(osection, sizeof(osection[0]) * oobjs);
2910
    // some alignment
2911
0
    if (identsplit == identsize) {
2912
0
        unsigned n = osection[!last_section_rsrc_only ? 0 : 1].rawdataptr - fo->getBytesWritten() -
2913
0
                     identsize;
2914
0
        assert(n <= oh.filealign);
2915
0
        fo->write(ibuf, n);
2916
0
    }
2917
0
    fo->write(loader + codesize, identsize);
2918
0
    infoWriting("loader", fo->getBytesWritten());
2919
0
    fo->write(obuf, c_len);
2920
0
    infoWriting("compressed data", c_len);
2921
0
    fo->write(loader, codesize);
2922
0
    if (opt->debug.dump_stub_loader)
2923
0
        OutputFile::dump(opt->debug.dump_stub_loader, loader, codesize);
2924
0
    if ((ic = fo->getBytesWritten() & (sizeof(LEXX) - 1)) != 0)
2925
0
        fo->write(ibuf, sizeof(LEXX) - ic);
2926
0
    fo->write(otls, aligned_sotls);
2927
0
    fo->write(oloadconf, soloadconf);
2928
0
    if (dbgCET) {
2929
0
        ic = fo->getBytesWritten();
2930
0
        dbgCET->fpos = ic + sizeof(*dbgCET);
2931
0
        dbgCET->rva = osection[1].vaddr + dbgCET->fpos - osection[1].rawdataptr;
2932
0
        LE32 word;
2933
0
        set_le32(&word, IMAGE_DLLCHARACTERISTICS_EX_CET_COMPAT);
2934
0
        if (0) { // set all bytes t0 zero
2935
0
            memset(dbgCET, 0, sizeof(*dbgCET));
2936
0
            set_le32(&word, 0);
2937
0
        }
2938
0
        fo->write(dbgCET, sizeof(*dbgCET));
2939
0
        fo->write(&word, sizeof(word));
2940
0
    }
2941
0
    if ((ic = fo->getBytesWritten() & fam1) != 0)
2942
0
        fo->write(ibuf, oh.filealign - ic);
2943
0
    if (!last_section_rsrc_only)
2944
0
        fo->write(oresources, soresources);
2945
0
    else
2946
0
        fo->write(oxrelocs, soxrelocs);
2947
0
    fo->write(oimpdlls, soimpdlls);
2948
0
    fo->write(oexport, soexport);
2949
0
    if (!last_section_rsrc_only)
2950
0
        fo->write(oxrelocs, soxrelocs);
2951
2952
0
    if ((ic = fo->getBytesWritten() & fam1) != 0)
2953
0
        fo->write(ibuf, oh.filealign - ic);
2954
2955
0
    if (last_section_rsrc_only) {
2956
0
        fo->write(oresources, soresources);
2957
0
        if ((ic = fo->getBytesWritten() & fam1) != 0)
2958
0
            fo->write(ibuf, oh.filealign - ic);
2959
0
    }
2960
2961
#if 0 // (debug) print section sizes
2962
    printf("%-13s: program hdr  : %8d bytes\n", getName(), (int) sizeof_oh);
2963
    printf("%-13s: sections     : %8d bytes\n", getName(), (int) sizeof(osection[0]) * oobjs);
2964
    printf("%-13s: ident        : %8d bytes\n", getName(), (int) identsize);
2965
    printf("%-13s: compressed   : %8d bytes\n", getName(), (int) c_len);
2966
    printf("%-13s: decompressor : %8d bytes\n", getName(), (int) codesize);
2967
    printf("%-13s: tls          : %8d bytes\n", getName(), (int) sotls);
2968
    printf("%-13s: aligned_tls  : %8d bytes\n", getName(), (int) aligned_sotls);
2969
    printf("%-13s: resources    : %8d bytes\n", getName(), (int) soresources);
2970
    printf("%-13s: imports      : %8d bytes\n", getName(), (int) soimpdlls);
2971
    printf("%-13s: exports      : %8d bytes\n", getName(), (int) soexport);
2972
    printf("%-13s: relocs       : %8d bytes\n", getName(), (int) soxrelocs);
2973
    printf("%-13s: loadconf     : %8d bytes\n", getName(), (int) soloadconf);
2974
    // linker->dumpSymbols();
2975
#endif
2976
2977
    // verify
2978
0
    verifyOverlappingDecompression();
2979
2980
    // copy the overlay
2981
0
    copyOverlay(fo, overlay, obuf);
2982
2983
    // finally check the compression ratio
2984
0
    if (!checkFinalCompressionRatio(fo))
2985
0
        throwNotCompressible();
2986
0
}
Unexecuted instantiation: void PeFile::pack0<LE32, PeFile32::pe_header_t>(OutputFile*, PeFile32::pe_header_t&, PeFile32::pe_header_t&, unsigned int, unsigned long long, bool)
Unexecuted instantiation: void PeFile::pack0<LE64, PeFile64::pe_header_t>(OutputFile*, PeFile64::pe_header_t&, PeFile64::pe_header_t&, unsigned int, unsigned long long, bool)
2987
2988
/*************************************************************************
2989
// unpack
2990
**************************************************************************/
2991
2992
void PeFile::rebuildRelocs(SPAN_S(byte) & extra_info, unsigned bits, unsigned flags,
2993
106
                           upx_uint64_t imagebase, bool exact) {
2994
106
    assert(bits == 32 || bits == 64);
2995
106
    if (!ODADDR(PEDIR_BASERELOC) || !ODSIZE(PEDIR_BASERELOC) ||
2996
5
        (flags & IMAGE_FILE_RELOCS_STRIPPED))
2997
101
        return;
2998
2999
5
    if (ODSIZE(PEDIR_BASERELOC) == 8) { // some tricky dlls use this
3000
0
        omemcpy(obuf + (ODADDR(PEDIR_BASERELOC) - rvamin), "\x0\x0\x0\x0\x8\x0\x0\x0", 8);
3001
0
        return;
3002
0
    }
3003
3004
    // Comments at end of this file say that compressed relocs are optional.
3005
    // Try to detect their presence.  There might be no compressed relocs.
3006
5
#if WITH_XSPAN >= 2 && 1
3007
5
    const size_t headway = extra_info.size_bytes();
3008
#else
3009
    // FIXME: last 4 bytes of extra_info are the file offset of extra_info,
3010
    // so they should be excluded from the count of data bytes.
3011
    // Something is peculiar unless WITH_XSPAN >= 2.
3012
    // Also, optional icondir_count is strange following compressed relocs.
3013
    const size_t headway = 9;
3014
#endif
3015
5
    unsigned orig_crelocs = 0;
3016
5
    byte big = 0;
3017
5
    if (headway >= 8) {
3018
5
        orig_crelocs = mem_size(1, get_le32(extra_info));
3019
5
        extra_info += 4;
3020
5
        if (headway >= 9) {
3021
5
            big = extra_info[0];
3022
5
            extra_info += 1;
3023
5
        }
3024
5
    }
3025
3026
5
    SPAN_S_VAR(const byte, rdata, obuf + orig_crelocs, obuf);
3027
5
    MemBuffer mb_wrkmem;
3028
5
    unsigned relocnum = unoptimizeReloc(rdata, mb_wrkmem, obuf, orig_crelocs, bits, true);
3029
3030
    // 16-bit relocations
3031
5
    unsigned r16 = 0;
3032
5
    if (big & 6) { // count 16-bit relocations
3033
0
        SPAN_S_VAR(const LE32, q, SPAN_TYPE_CAST(const LE32, rdata));
3034
0
        while (*q++)
3035
0
            r16++;
3036
0
        if ((big & 6) == 6)
3037
0
            while (*++q)
3038
0
                r16++;
3039
0
    }
3040
5
    Reloc rel(relocnum + r16);
3041
5
    if (big & 6) { // add 16-bit relocations
3042
0
        SPAN_S_VAR(const LE32, q, SPAN_TYPE_CAST(const LE32, rdata));
3043
0
        while (*q)
3044
0
            rel.add_reloc(*q++ + rvamin, (big & 4) ? IMAGE_REL_BASED_LOW : IMAGE_REL_BASED_HIGH);
3045
0
        if ((big & 6) == 6)
3046
0
            while (*++q)
3047
0
                rel.add_reloc(*q + rvamin, IMAGE_REL_BASED_HIGH);
3048
        // rdata = (const byte *) raw_bytes(q, 0); // advance rdata
3049
0
    }
3050
3051
5
    SPAN_S_VAR(byte, const wrkmem, mb_wrkmem);
3052
42.6k
    for (unsigned ic = 0; ic < relocnum; ic++) {
3053
42.6k
        OPTR_VAR(byte, const p, obuf + get_le32(wrkmem + sizeof(LE32) * ic));
3054
42.6k
        if (bits == 32)
3055
27.3k
            set_le32(p, get_le32(p) + imagebase + rvamin);
3056
15.2k
        else
3057
15.2k
            set_le64(p, get_le64(p) + imagebase + rvamin);
3058
42.6k
        rel.add_reloc(rvamin + get_le32(wrkmem + sizeof(LE32) * ic),
3059
42.6k
                      bits == 32 ? IMAGE_REL_BASED_HIGHLOW : IMAGE_REL_BASED_DIR64);
3060
42.6k
    }
3061
5
    if (exact) {
3062
0
        mb_wrkmem.dealloc();
3063
0
        return;
3064
0
    }
3065
5
    rel.finish(oxrelocs, soxrelocs);
3066
3067
5
    omemcpy(obuf + (ODADDR(PEDIR_BASERELOC) - rvamin), oxrelocs, soxrelocs);
3068
5
    delete[] oxrelocs;
3069
5
    oxrelocs = nullptr;
3070
5
    mb_wrkmem.dealloc();
3071
3072
5
    ODSIZE(PEDIR_BASERELOC) = soxrelocs;
3073
    // FIXME?:  ODADDR(PEDIR_BASERELOC) for compressed relocs?
3074
5
}
3075
3076
106
void PeFile::rebuildExports() {
3077
106
    if (ODSIZE(PEDIR_EXPORT) == 0 || ODADDR(PEDIR_EXPORT) == IDADDR(PEDIR_EXPORT))
3078
106
        return; // nothing to do
3079
3080
0
    opt->win32_pe.compress_exports = 0;
3081
0
    Export xport((char *) (byte *) ibuf - isection[2].vaddr);
3082
0
    processExports(&xport);
3083
0
    processExports(&xport, ODADDR(PEDIR_EXPORT));
3084
0
    omemcpy(obuf + (ODADDR(PEDIR_EXPORT) - rvamin), oexport, soexport);
3085
0
}
3086
3087
106
void PeFile::rebuildTls() {
3088
    // this is an easy one : just do nothing ;-)
3089
106
}
3090
3091
namespace {
3092
template <class T>
3093
struct VPtr final { // "virtual pointer" pointing before a buffer
3094
    static_assert(sizeof(T) == 1);
3095
    SPAN_S(T) base;
3096
    size_t x;
3097
    // return base + (n - x)
3098
23.2k
    SPAN_S(T) operator+(size_t n) const { return base + mem_size_get_n(sizeof(T), n - x); }
pefile.cpp:(anonymous namespace)::VPtr<unsigned char const>::operator+(unsigned long) const
Line
Count
Source
3098
316
    SPAN_S(T) operator+(size_t n) const { return base + mem_size_get_n(sizeof(T), n - x); }
pefile.cpp:(anonymous namespace)::VPtr<unsigned char>::operator+(unsigned long) const
Line
Count
Source
3098
22.8k
    SPAN_S(T) operator+(size_t n) const { return base + mem_size_get_n(sizeof(T), n - x); }
3099
};
3100
} // namespace
3101
3102
106
void PeFile::rebuildResources(SPAN_S(byte) & extra_info, unsigned lastvaddr) {
3103
106
    if (ODSIZE(PEDIR_RESOURCE) == 0 || IDSIZE(PEDIR_RESOURCE) == 0)
3104
8
        return;
3105
3106
98
    icondir_count = get_le16(extra_info);
3107
98
    extra_info += 2;
3108
3109
98
    const unsigned vaddr = IDADDR(PEDIR_RESOURCE);
3110
3111
98
    if (vaddr < lastvaddr || (vaddr - lastvaddr) > ibuf.getSize())
3112
6
        throwCantUnpack("corrupted PE header");
3113
3114
    // INFO: use VPtr for "virtual pointer" pointing before a buffer
3115
    //// const byte *const r = ibuf.raw_bytes(0) - lastvaddr;
3116
92
    const VPtr<const byte> r{ibuf, lastvaddr};
3117
92
    Resource res(raw_bytes(r + vaddr, 0), ibuf, ibuf + ibuf.getSize());
3118
184
    while (res.next())
3119
92
        if (res.offs() > vaddr) {
3120
62
            ICHECK(r + (res.offs() - 4), 4);
3121
62
            unsigned origoffs = get_le32(r + (res.offs() - 4));
3122
62
            res.newoffs() = origoffs;
3123
62
            ICHECK(r + res.offs(), res.size());
3124
62
            omemcpy(obuf + (origoffs - rvamin), r + res.offs(), res.size());
3125
62
            if (icondir_count && res.itype() == RT_GROUP_ICON) {
3126
0
                set_le16(obuf + (origoffs - rvamin + 4), icondir_count);
3127
0
                icondir_count = 0;
3128
0
            }
3129
62
        }
3130
92
    if (res.dirsize()) {
3131
23
        byte *p = res.build();
3132
23
        OCHECK(obuf + (ODADDR(PEDIR_RESOURCE) - rvamin), 16);
3133
        // write back when the original is zeroed
3134
23
        if (get_le32(obuf + (ODADDR(PEDIR_RESOURCE) - rvamin + 12)) == 0)
3135
23
            omemcpy(obuf + (ODADDR(PEDIR_RESOURCE) - rvamin), p, res.dirsize());
3136
23
    }
3137
92
}
3138
3139
template <typename LEXX, typename ord_mask_t>
3140
115
void PeFile::rebuildImports(SPAN_S(byte) & extra_info, ord_mask_t ord_mask, bool set_oft) {
3141
115
    if (ODADDR(PEDIR_IMPORT) == 0 || ODSIZE(PEDIR_IMPORT) <= sizeof(import_desc))
3142
0
        return;
3143
3144
115
    OPTR_VAR(const byte, const imdata, obuf + mem_size(1, get_le32(extra_info)));
3145
115
    const unsigned inamespos = mem_size(1, get_le32(extra_info + 4));
3146
115
    extra_info += 8;
3147
3148
115
    unsigned sdllnames = 0;
3149
3150
115
    IPTR_VAR_OFFSET(const byte, const my_import, IDADDR(PEDIR_IMPORT) - isection[2].vaddr);
3151
115
    OPTR_VAR(const byte, p, raw_bytes(imdata, 4));
3152
3153
417
    for (; get_le32(p) != 0; ++p) {
3154
302
        const byte *dname = raw_bytes(my_import + mem_size(1, get_le32(p)), 1);
3155
302
        const unsigned dlen = strlen(dname);
3156
302
        ICHECK(dname, dlen + 1);
3157
3158
302
        sdllnames += dlen + 1;
3159
11.2k
        for (p += 8; *p;)
3160
10.9k
            if (*p == 1)
3161
10.9k
                p += 1 + strlen(p + 1) + 1;
3162
0
            else if (*p == 0xff)
3163
0
                p += 3; // ordinal
3164
0
            else
3165
0
                p += 5;
3166
302
    }
3167
115
    sdllnames = ALIGN_UP(sdllnames, 2u);
3168
3169
    // INFO: use VPtr for "virtual pointer" pointing before a buffer
3170
    //// byte *const Obuf = obuf.raw_bytes(0) - rvamin;
3171
115
    const VPtr<byte> Obuf{obuf, rvamin};
3172
115
    SPAN_S_VAR(import_desc, im, (import_desc *) raw_bytes(Obuf + ODADDR(PEDIR_IMPORT), 0), obuf);
3173
115
    SPAN_0_VAR(byte, dllnames, inamespos ? raw_bytes(Obuf + inamespos, 0) : nullptr, obuf);
3174
115
    SPAN_0_VAR(byte, const importednames_start, inamespos ? dllnames + sdllnames : nullptr);
3175
115
    SPAN_0_VAR(byte, importednames, importednames_start);
3176
3177
416
    for (p = imdata; get_le32(p) != 0; ++p) {
3178
        // restore the name of the dll
3179
301
        const byte *dname = raw_bytes(my_import + get_le32(p), 1);
3180
301
        const unsigned dlen = strlen(dname);
3181
301
        ICHECK(dname, dlen + 1);
3182
3183
301
        const unsigned iatoffs = get_le32(p + 4) + rvamin;
3184
301
        if (inamespos) {
3185
            // now I rebuild the dll names
3186
0
            omemcpy(dllnames, dname, dlen + 1);
3187
0
            im->dllname = ptr_udiff_bytes(dllnames, obuf) + rvamin;
3188
            //;;;printf("\ndll: %s:",dllnames);
3189
0
            dllnames += dlen + 1;
3190
301
        } else {
3191
301
            omemcpy(Obuf + im->dllname, dname, dlen + 1);
3192
301
        }
3193
301
        im->iat = iatoffs;
3194
301
        if (set_oft)
3195
14
            im->oft = iatoffs;
3196
3197
301
        OPTR_VAR(LEXX, newiat, (LEXX *) raw_bytes(Obuf + iatoffs, 0));
3198
3199
        // restore the imported names+ordinals
3200
11.2k
        for (p += 8; *p; ++newiat)
3201
10.9k
            if (*p == 1) {
3202
10.9k
                const unsigned ilen = strlen(++p) + 1;
3203
10.9k
                if (inamespos) {
3204
0
                    if (ptr_udiff_bytes(importednames, importednames_start) & 1)
3205
0
                        importednames -= 1;
3206
0
                    omemcpy(importednames + 2, p, ilen);
3207
                    //;;;printf(" %s",importednames+2);
3208
0
                    *newiat = ptr_udiff_bytes(importednames, obuf) + rvamin;
3209
0
                    importednames += 2 + ilen;
3210
10.9k
                } else {
3211
                    // Beware overlap!
3212
10.9k
                    omemmove(Obuf + (*newiat + 2), p, ilen);
3213
10.9k
                }
3214
10.9k
                p += ilen;
3215
10.9k
            } else if (*p == 0xff) {
3216
0
                *newiat = get_le16(p + 1) + ord_mask;
3217
                //;;;printf(" %x",(unsigned)*newiat);
3218
0
                p += 3;
3219
0
            } else {
3220
0
                *newiat = *(const LEXX *) raw_bytes(my_import + get_le32(p + 1), sizeof(LEXX));
3221
0
                assert(*newiat & ord_mask);
3222
0
                p += 5;
3223
0
            }
3224
301
        *newiat = 0;
3225
301
        im++;
3226
301
    }
3227
    // memset(imdata, 0, ptr_udiff_bytes(p, imdata));
3228
115
}
void PeFile::rebuildImports<LE32, unsigned int>(XSpan::Span<unsigned char>&, unsigned int, bool)
Line
Count
Source
3140
101
void PeFile::rebuildImports(SPAN_S(byte) & extra_info, ord_mask_t ord_mask, bool set_oft) {
3141
101
    if (ODADDR(PEDIR_IMPORT) == 0 || ODSIZE(PEDIR_IMPORT) <= sizeof(import_desc))
3142
0
        return;
3143
3144
101
    OPTR_VAR(const byte, const imdata, obuf + mem_size(1, get_le32(extra_info)));
3145
101
    const unsigned inamespos = mem_size(1, get_le32(extra_info + 4));
3146
101
    extra_info += 8;
3147
3148
101
    unsigned sdllnames = 0;
3149
3150
101
    IPTR_VAR_OFFSET(const byte, const my_import, IDADDR(PEDIR_IMPORT) - isection[2].vaddr);
3151
101
    OPTR_VAR(const byte, p, raw_bytes(imdata, 4));
3152
3153
379
    for (; get_le32(p) != 0; ++p) {
3154
278
        const byte *dname = raw_bytes(my_import + mem_size(1, get_le32(p)), 1);
3155
278
        const unsigned dlen = strlen(dname);
3156
278
        ICHECK(dname, dlen + 1);
3157
3158
278
        sdllnames += dlen + 1;
3159
10.1k
        for (p += 8; *p;)
3160
9.82k
            if (*p == 1)
3161
9.82k
                p += 1 + strlen(p + 1) + 1;
3162
0
            else if (*p == 0xff)
3163
0
                p += 3; // ordinal
3164
0
            else
3165
0
                p += 5;
3166
278
    }
3167
101
    sdllnames = ALIGN_UP(sdllnames, 2u);
3168
3169
    // INFO: use VPtr for "virtual pointer" pointing before a buffer
3170
    //// byte *const Obuf = obuf.raw_bytes(0) - rvamin;
3171
101
    const VPtr<byte> Obuf{obuf, rvamin};
3172
101
    SPAN_S_VAR(import_desc, im, (import_desc *) raw_bytes(Obuf + ODADDR(PEDIR_IMPORT), 0), obuf);
3173
101
    SPAN_0_VAR(byte, dllnames, inamespos ? raw_bytes(Obuf + inamespos, 0) : nullptr, obuf);
3174
101
    SPAN_0_VAR(byte, const importednames_start, inamespos ? dllnames + sdllnames : nullptr);
3175
101
    SPAN_0_VAR(byte, importednames, importednames_start);
3176
3177
378
    for (p = imdata; get_le32(p) != 0; ++p) {
3178
        // restore the name of the dll
3179
277
        const byte *dname = raw_bytes(my_import + get_le32(p), 1);
3180
277
        const unsigned dlen = strlen(dname);
3181
277
        ICHECK(dname, dlen + 1);
3182
3183
277
        const unsigned iatoffs = get_le32(p + 4) + rvamin;
3184
277
        if (inamespos) {
3185
            // now I rebuild the dll names
3186
0
            omemcpy(dllnames, dname, dlen + 1);
3187
0
            im->dllname = ptr_udiff_bytes(dllnames, obuf) + rvamin;
3188
            //;;;printf("\ndll: %s:",dllnames);
3189
0
            dllnames += dlen + 1;
3190
277
        } else {
3191
277
            omemcpy(Obuf + im->dllname, dname, dlen + 1);
3192
277
        }
3193
277
        im->iat = iatoffs;
3194
277
        if (set_oft)
3195
14
            im->oft = iatoffs;
3196
3197
277
        OPTR_VAR(LEXX, newiat, (LEXX *) raw_bytes(Obuf + iatoffs, 0));
3198
3199
        // restore the imported names+ordinals
3200
10.1k
        for (p += 8; *p; ++newiat)
3201
9.82k
            if (*p == 1) {
3202
9.82k
                const unsigned ilen = strlen(++p) + 1;
3203
9.82k
                if (inamespos) {
3204
0
                    if (ptr_udiff_bytes(importednames, importednames_start) & 1)
3205
0
                        importednames -= 1;
3206
0
                    omemcpy(importednames + 2, p, ilen);
3207
                    //;;;printf(" %s",importednames+2);
3208
0
                    *newiat = ptr_udiff_bytes(importednames, obuf) + rvamin;
3209
0
                    importednames += 2 + ilen;
3210
9.82k
                } else {
3211
                    // Beware overlap!
3212
9.82k
                    omemmove(Obuf + (*newiat + 2), p, ilen);
3213
9.82k
                }
3214
9.82k
                p += ilen;
3215
9.82k
            } else if (*p == 0xff) {
3216
0
                *newiat = get_le16(p + 1) + ord_mask;
3217
                //;;;printf(" %x",(unsigned)*newiat);
3218
0
                p += 3;
3219
0
            } else {
3220
0
                *newiat = *(const LEXX *) raw_bytes(my_import + get_le32(p + 1), sizeof(LEXX));
3221
0
                assert(*newiat & ord_mask);
3222
0
                p += 5;
3223
0
            }
3224
277
        *newiat = 0;
3225
277
        im++;
3226
277
    }
3227
    // memset(imdata, 0, ptr_udiff_bytes(p, imdata));
3228
101
}
void PeFile::rebuildImports<LE64, unsigned long long>(XSpan::Span<unsigned char>&, unsigned long long, bool)
Line
Count
Source
3140
14
void PeFile::rebuildImports(SPAN_S(byte) & extra_info, ord_mask_t ord_mask, bool set_oft) {
3141
14
    if (ODADDR(PEDIR_IMPORT) == 0 || ODSIZE(PEDIR_IMPORT) <= sizeof(import_desc))
3142
0
        return;
3143
3144
14
    OPTR_VAR(const byte, const imdata, obuf + mem_size(1, get_le32(extra_info)));
3145
14
    const unsigned inamespos = mem_size(1, get_le32(extra_info + 4));
3146
14
    extra_info += 8;
3147
3148
14
    unsigned sdllnames = 0;
3149
3150
14
    IPTR_VAR_OFFSET(const byte, const my_import, IDADDR(PEDIR_IMPORT) - isection[2].vaddr);
3151
14
    OPTR_VAR(const byte, p, raw_bytes(imdata, 4));
3152
3153
38
    for (; get_le32(p) != 0; ++p) {
3154
24
        const byte *dname = raw_bytes(my_import + mem_size(1, get_le32(p)), 1);
3155
24
        const unsigned dlen = strlen(dname);
3156
24
        ICHECK(dname, dlen + 1);
3157
3158
24
        sdllnames += dlen + 1;
3159
1.13k
        for (p += 8; *p;)
3160
1.11k
            if (*p == 1)
3161
1.11k
                p += 1 + strlen(p + 1) + 1;
3162
0
            else if (*p == 0xff)
3163
0
                p += 3; // ordinal
3164
0
            else
3165
0
                p += 5;
3166
24
    }
3167
14
    sdllnames = ALIGN_UP(sdllnames, 2u);
3168
3169
    // INFO: use VPtr for "virtual pointer" pointing before a buffer
3170
    //// byte *const Obuf = obuf.raw_bytes(0) - rvamin;
3171
14
    const VPtr<byte> Obuf{obuf, rvamin};
3172
14
    SPAN_S_VAR(import_desc, im, (import_desc *) raw_bytes(Obuf + ODADDR(PEDIR_IMPORT), 0), obuf);
3173
14
    SPAN_0_VAR(byte, dllnames, inamespos ? raw_bytes(Obuf + inamespos, 0) : nullptr, obuf);
3174
14
    SPAN_0_VAR(byte, const importednames_start, inamespos ? dllnames + sdllnames : nullptr);
3175
14
    SPAN_0_VAR(byte, importednames, importednames_start);
3176
3177
38
    for (p = imdata; get_le32(p) != 0; ++p) {
3178
        // restore the name of the dll
3179
24
        const byte *dname = raw_bytes(my_import + get_le32(p), 1);
3180
24
        const unsigned dlen = strlen(dname);
3181
24
        ICHECK(dname, dlen + 1);
3182
3183
24
        const unsigned iatoffs = get_le32(p + 4) + rvamin;
3184
24
        if (inamespos) {
3185
            // now I rebuild the dll names
3186
0
            omemcpy(dllnames, dname, dlen + 1);
3187
0
            im->dllname = ptr_udiff_bytes(dllnames, obuf) + rvamin;
3188
            //;;;printf("\ndll: %s:",dllnames);
3189
0
            dllnames += dlen + 1;
3190
24
        } else {
3191
24
            omemcpy(Obuf + im->dllname, dname, dlen + 1);
3192
24
        }
3193
24
        im->iat = iatoffs;
3194
24
        if (set_oft)
3195
0
            im->oft = iatoffs;
3196
3197
24
        OPTR_VAR(LEXX, newiat, (LEXX *) raw_bytes(Obuf + iatoffs, 0));
3198
3199
        // restore the imported names+ordinals
3200
1.13k
        for (p += 8; *p; ++newiat)
3201
1.11k
            if (*p == 1) {
3202
1.11k
                const unsigned ilen = strlen(++p) + 1;
3203
1.11k
                if (inamespos) {
3204
0
                    if (ptr_udiff_bytes(importednames, importednames_start) & 1)
3205
0
                        importednames -= 1;
3206
0
                    omemcpy(importednames + 2, p, ilen);
3207
                    //;;;printf(" %s",importednames+2);
3208
0
                    *newiat = ptr_udiff_bytes(importednames, obuf) + rvamin;
3209
0
                    importednames += 2 + ilen;
3210
1.11k
                } else {
3211
                    // Beware overlap!
3212
1.11k
                    omemmove(Obuf + (*newiat + 2), p, ilen);
3213
1.11k
                }
3214
1.11k
                p += ilen;
3215
1.11k
            } else if (*p == 0xff) {
3216
0
                *newiat = get_le16(p + 1) + ord_mask;
3217
                //;;;printf(" %x",(unsigned)*newiat);
3218
0
                p += 3;
3219
0
            } else {
3220
0
                *newiat = *(const LEXX *) raw_bytes(my_import + get_le32(p + 1), sizeof(LEXX));
3221
0
                assert(*newiat & ord_mask);
3222
0
                p += 5;
3223
0
            }
3224
24
        *newiat = 0;
3225
24
        im++;
3226
24
    }
3227
    // memset(imdata, 0, ptr_udiff_bytes(p, imdata));
3228
14
}
3229
3230
template <typename ht, typename LEXX, typename ord_mask_t>
3231
242
void PeFile::unpack0(OutputFile *fo, const ht &ih, ht &oh, ord_mask_t ord_mask, bool set_oft) {
3232
    // infoHeader("[Processing %s, format %s, %d sections]", fn_basename(fi->getName()), getName(),
3233
    // objs);
3234
3235
242
    handleStub(fi, fo, pe_offset);
3236
242
    if (ih.filealign == 0)
3237
4
        throwCantUnpack("unexpected value in the PE header");
3238
3239
238
    const unsigned iobjs = ih.objects;
3240
238
    const unsigned overlay =
3241
238
        file_size_u -
3242
238
        ALIGN_UP(isection[iobjs - 1].rawdataptr + isection[iobjs - 1].size, ih.filealign);
3243
238
    checkOverlay(overlay);
3244
3245
238
    ibuf.alloc(ph.c_len);
3246
238
    obuf.allocForDecompression(ph.u_len);
3247
238
    fi->seek(isection[1].rawdataptr - 64 + ph.buf_offset + ph.getPackHeaderSize(), SEEK_SET);
3248
238
    fi->readx(ibuf, ibufgood = ph.c_len);
3249
3250
    // decompress
3251
238
    decompress(ibuf, obuf);
3252
238
    const bool exact = ph.version == pe_exact_version;
3253
238
    PeExactTrailer trailer = {};
3254
238
    const unsigned trailer_size = sizeof(trailer) + sizeof(LE32);
3255
238
    if (exact) {
3256
0
        if (ph.u_len < trailer_size)
3257
0
            throwCantUnpack("corrupted exact metadata");
3258
0
        memcpy(&trailer, obuf + (ph.u_len - trailer_size), sizeof(trailer));
3259
0
    }
3260
238
    const unsigned stored_gap_size = exact ? (unsigned) trailer.gap_size : 0;
3261
238
    const unsigned exact_gap_offset = exact ? ph.u_len - trailer_size - stored_gap_size : 0;
3262
238
    unsigned exact_gap_used = 0;
3263
238
    if (exact) {
3264
0
        if (trailer.flags & ~(pe_exact_relocs | pe_exact_imports))
3265
0
            throwCantUnpack("unknown exact flags");
3266
0
        obuf.subref("bad exact gaps", exact_gap_offset, stored_gap_size);
3267
0
    }
3268
238
    unsigned skip = get_le32(obuf + (ph.u_len - 4));
3269
238
    unsigned take = sizeof_oh;
3270
238
    SPAN_S_VAR(byte, extra_info, obuf);
3271
238
    extra_info = obuf.subref("bad extra_info offset %#x", skip, take);
3272
    // byte *const eistart = raw_bytes(extra_info, 0);
3273
3274
238
    memcpy(&oh, extra_info, take);
3275
238
    extra_info += take;
3276
238
    skip += take;
3277
238
    const unsigned objs = oh.objects;
3278
3279
238
    if ((int) objs <= 0 || (iobjs > 2 && isection[2].size == 0))
3280
4
        throwCantUnpack("unexpected value in the PE header");
3281
234
    Array(pe_section_t, osection, objs);
3282
234
    take = sizeof(pe_section_t) * objs;
3283
234
    extra_info = obuf.subref("bad extra section size at %#x", skip, take);
3284
234
    memcpy(osection, extra_info, take);
3285
234
    extra_info += take;
3286
234
    skip += take;
3287
234
    rvamin = osection[0].vaddr;
3288
3289
234
    if (iobjs > 2) {
3290
        // read the noncompressed section
3291
122
        const unsigned size = isection[2].size;
3292
122
        ibuf.dealloc();
3293
122
        ibuf.alloc(size + 1);
3294
122
        fi->seek(isection[2].rawdataptr, SEEK_SET);
3295
122
        fi->readx(ibuf, ibufgood = size);
3296
122
        ibuf[size] = 0; // allow strlen() up to 'size'
3297
122
    }
3298
3299
    // unfilter
3300
234
    if (ph.filter) {
3301
115
        const unsigned codebase = exact && oh.codebase == 0 ? rvamin : (unsigned) oh.codebase;
3302
115
        Filter ft(ph.level);
3303
115
        ft.init(ph.filter, codebase - rvamin);
3304
115
        ft.cto = (byte) ph.filter_cto;
3305
115
        OCHECK(obuf + (codebase - rvamin), oh.codesize);
3306
115
        ft.unfilter(obuf + (codebase - rvamin), oh.codesize);
3307
115
    }
3308
3309
    // FIXME: ih.flags is checked here because of a bug in UPX 0.92
3310
234
    if (!exact && (ih.flags & IMAGE_FILE_RELOCS_STRIPPED)) {
3311
105
        oh.flags |= IMAGE_FILE_RELOCS_STRIPPED;
3312
105
        ODADDR(PEDIR_BASERELOC) = 0;
3313
105
        ODSIZE(PEDIR_BASERELOC) = 0;
3314
105
    }
3315
3316
234
    if (exact) {
3317
0
        if (trailer.flags & pe_exact_imports)
3318
0
            extra_info += 8;
3319
234
    } else {
3320
234
        rebuildImports<LEXX>(extra_info, ord_mask, set_oft);
3321
234
    }
3322
234
    if (!exact || (trailer.flags & pe_exact_relocs))
3323
106
        rebuildRelocs(extra_info, sizeof(ih.imagebase) * 8, oh.flags, oh.imagebase, exact);
3324
234
    rebuildTls();
3325
234
    if (!exact)
3326
106
        rebuildExports();
3327
3328
234
    if (iobjs > 3) {
3329
        // read the resource section if present
3330
7
        ibuf.dealloc();
3331
7
        ibuf.alloc(isection[3].size);
3332
7
        fi->seek(isection[3].rawdataptr, SEEK_SET);
3333
7
        fi->readx(ibuf, ibufgood = isection[3].size);
3334
7
    }
3335
3336
234
    if (!exact)
3337
106
        rebuildResources(extra_info, isection[ih.objects - 1].vaddr);
3338
3339
    // FIXME: this does bad things if the relocation section got removed
3340
    //  during compression ...
3341
    // memset(eistart, 0, ptr_udiff_bytes(extra_info, eistart) + 4);
3342
3343
    // fill the data directory
3344
234
    if (!exact) {
3345
50
        ODADDR(PEDIR_IAT) = 0;
3346
50
        ODSIZE(PEDIR_IAT) = 0;
3347
50
        ODADDR(PEDIR_BOUND_IMPORT) = 0;
3348
50
        ODSIZE(PEDIR_BOUND_IMPORT) = 0;
3349
50
    }
3350
3351
234
    if (!exact) {
3352
50
        setOhHeaderSize(osection);
3353
50
        oh.chksum = 0;
3354
50
    }
3355
3356
    // write decompressed file
3357
234
    if (fo) {
3358
38
        unsigned ic = 0;
3359
38
        while (ic < objs && osection[ic].rawdataptr == 0)
3360
0
            ic++;
3361
38
        if (ic >= objs)
3362
0
            throwCantUnpack("no section with raw data");
3363
3364
38
        ibuf.dealloc();
3365
38
        if (!exact) {
3366
38
            ibuf.alloc(osection[ic].rawdataptr);
3367
38
            ibuf.clear();
3368
38
        }
3369
38
        infoHeader("[Writing uncompressed file]");
3370
3371
        // write header + decompressed file
3372
38
        fo->write(&oh, sizeof_oh);
3373
38
        fo->write(osection, objs * sizeof(pe_section_t));
3374
38
        if (!exact) {
3375
38
            fo->write(ibuf, osection[ic].rawdataptr - fo->getBytesWritten());
3376
301
            for (ic = 0; ic < objs; ic++)
3377
263
                if (osection[ic].rawdataptr) {
3378
228
                    const unsigned seclen = ALIGN_UP(osection[ic].size, oh.filealign);
3379
228
                    fo->write(obuf.subref("bad section %#x", osection[ic].vaddr - rvamin, seclen),
3380
228
                              seclen);
3381
228
                }
3382
38
        } else {
3383
0
            Array(unsigned, raw_order, objs);
3384
0
            const unsigned raw_count = getRawSectionOrder(osection, objs, raw_order);
3385
0
            for (unsigned ii = 0; ii < raw_count; ii++) {
3386
0
                ic = raw_order[ii];
3387
0
                const unsigned written = fo->getBytesWritten();
3388
0
                if (written > osection[ic].rawdataptr)
3389
0
                    throwCantUnpack("overlapping raw sections");
3390
0
                const unsigned gap = osection[ic].rawdataptr - written;
3391
0
                if (gap > stored_gap_size - exact_gap_used)
3392
0
                    throwCantUnpack("corrupted exact gaps");
3393
0
                fo->write(obuf + (exact_gap_offset + exact_gap_used), gap);
3394
0
                exact_gap_used += gap;
3395
0
                fo->write(obuf.subref("bad exact section", osection[ic].vaddr - rvamin,
3396
0
                                      osection[ic].size),
3397
0
                          osection[ic].size);
3398
0
            }
3399
0
            if (exact_gap_used != stored_gap_size)
3400
0
                throwCantUnpack("unused exact gaps");
3401
0
        }
3402
38
        copyOverlay(fo, overlay, obuf);
3403
38
    }
3404
234
    ibuf.dealloc();
3405
234
}
void PeFile::unpack0<PeFile32::pe_header_t, LE32, unsigned int>(OutputFile*, PeFile32::pe_header_t const&, PeFile32::pe_header_t&, unsigned int, bool)
Line
Count
Source
3231
204
void PeFile::unpack0(OutputFile *fo, const ht &ih, ht &oh, ord_mask_t ord_mask, bool set_oft) {
3232
    // infoHeader("[Processing %s, format %s, %d sections]", fn_basename(fi->getName()), getName(),
3233
    // objs);
3234
3235
204
    handleStub(fi, fo, pe_offset);
3236
204
    if (ih.filealign == 0)
3237
2
        throwCantUnpack("unexpected value in the PE header");
3238
3239
202
    const unsigned iobjs = ih.objects;
3240
202
    const unsigned overlay =
3241
202
        file_size_u -
3242
202
        ALIGN_UP(isection[iobjs - 1].rawdataptr + isection[iobjs - 1].size, ih.filealign);
3243
202
    checkOverlay(overlay);
3244
3245
202
    ibuf.alloc(ph.c_len);
3246
202
    obuf.allocForDecompression(ph.u_len);
3247
202
    fi->seek(isection[1].rawdataptr - 64 + ph.buf_offset + ph.getPackHeaderSize(), SEEK_SET);
3248
202
    fi->readx(ibuf, ibufgood = ph.c_len);
3249
3250
    // decompress
3251
202
    decompress(ibuf, obuf);
3252
202
    const bool exact = ph.version == pe_exact_version;
3253
202
    PeExactTrailer trailer = {};
3254
202
    const unsigned trailer_size = sizeof(trailer) + sizeof(LE32);
3255
202
    if (exact) {
3256
0
        if (ph.u_len < trailer_size)
3257
0
            throwCantUnpack("corrupted exact metadata");
3258
0
        memcpy(&trailer, obuf + (ph.u_len - trailer_size), sizeof(trailer));
3259
0
    }
3260
202
    const unsigned stored_gap_size = exact ? (unsigned) trailer.gap_size : 0;
3261
202
    const unsigned exact_gap_offset = exact ? ph.u_len - trailer_size - stored_gap_size : 0;
3262
202
    unsigned exact_gap_used = 0;
3263
202
    if (exact) {
3264
0
        if (trailer.flags & ~(pe_exact_relocs | pe_exact_imports))
3265
0
            throwCantUnpack("unknown exact flags");
3266
0
        obuf.subref("bad exact gaps", exact_gap_offset, stored_gap_size);
3267
0
    }
3268
202
    unsigned skip = get_le32(obuf + (ph.u_len - 4));
3269
202
    unsigned take = sizeof_oh;
3270
202
    SPAN_S_VAR(byte, extra_info, obuf);
3271
202
    extra_info = obuf.subref("bad extra_info offset %#x", skip, take);
3272
    // byte *const eistart = raw_bytes(extra_info, 0);
3273
3274
202
    memcpy(&oh, extra_info, take);
3275
202
    extra_info += take;
3276
202
    skip += take;
3277
202
    const unsigned objs = oh.objects;
3278
3279
202
    if ((int) objs <= 0 || (iobjs > 2 && isection[2].size == 0))
3280
2
        throwCantUnpack("unexpected value in the PE header");
3281
200
    Array(pe_section_t, osection, objs);
3282
200
    take = sizeof(pe_section_t) * objs;
3283
200
    extra_info = obuf.subref("bad extra section size at %#x", skip, take);
3284
200
    memcpy(osection, extra_info, take);
3285
200
    extra_info += take;
3286
200
    skip += take;
3287
200
    rvamin = osection[0].vaddr;
3288
3289
200
    if (iobjs > 2) {
3290
        // read the noncompressed section
3291
106
        const unsigned size = isection[2].size;
3292
106
        ibuf.dealloc();
3293
106
        ibuf.alloc(size + 1);
3294
106
        fi->seek(isection[2].rawdataptr, SEEK_SET);
3295
106
        fi->readx(ibuf, ibufgood = size);
3296
106
        ibuf[size] = 0; // allow strlen() up to 'size'
3297
106
    }
3298
3299
    // unfilter
3300
200
    if (ph.filter) {
3301
101
        const unsigned codebase = exact && oh.codebase == 0 ? rvamin : (unsigned) oh.codebase;
3302
101
        Filter ft(ph.level);
3303
101
        ft.init(ph.filter, codebase - rvamin);
3304
101
        ft.cto = (byte) ph.filter_cto;
3305
101
        OCHECK(obuf + (codebase - rvamin), oh.codesize);
3306
101
        ft.unfilter(obuf + (codebase - rvamin), oh.codesize);
3307
101
    }
3308
3309
    // FIXME: ih.flags is checked here because of a bug in UPX 0.92
3310
200
    if (!exact && (ih.flags & IMAGE_FILE_RELOCS_STRIPPED)) {
3311
96
        oh.flags |= IMAGE_FILE_RELOCS_STRIPPED;
3312
96
        ODADDR(PEDIR_BASERELOC) = 0;
3313
96
        ODSIZE(PEDIR_BASERELOC) = 0;
3314
96
    }
3315
3316
200
    if (exact) {
3317
0
        if (trailer.flags & pe_exact_imports)
3318
0
            extra_info += 8;
3319
200
    } else {
3320
200
        rebuildImports<LEXX>(extra_info, ord_mask, set_oft);
3321
200
    }
3322
200
    if (!exact || (trailer.flags & pe_exact_relocs))
3323
96
        rebuildRelocs(extra_info, sizeof(ih.imagebase) * 8, oh.flags, oh.imagebase, exact);
3324
200
    rebuildTls();
3325
200
    if (!exact)
3326
96
        rebuildExports();
3327
3328
200
    if (iobjs > 3) {
3329
        // read the resource section if present
3330
7
        ibuf.dealloc();
3331
7
        ibuf.alloc(isection[3].size);
3332
7
        fi->seek(isection[3].rawdataptr, SEEK_SET);
3333
7
        fi->readx(ibuf, ibufgood = isection[3].size);
3334
7
    }
3335
3336
200
    if (!exact)
3337
96
        rebuildResources(extra_info, isection[ih.objects - 1].vaddr);
3338
3339
    // FIXME: this does bad things if the relocation section got removed
3340
    //  during compression ...
3341
    // memset(eistart, 0, ptr_udiff_bytes(extra_info, eistart) + 4);
3342
3343
    // fill the data directory
3344
200
    if (!exact) {
3345
44
        ODADDR(PEDIR_IAT) = 0;
3346
44
        ODSIZE(PEDIR_IAT) = 0;
3347
44
        ODADDR(PEDIR_BOUND_IMPORT) = 0;
3348
44
        ODSIZE(PEDIR_BOUND_IMPORT) = 0;
3349
44
    }
3350
3351
200
    if (!exact) {
3352
44
        setOhHeaderSize(osection);
3353
44
        oh.chksum = 0;
3354
44
    }
3355
3356
    // write decompressed file
3357
200
    if (fo) {
3358
34
        unsigned ic = 0;
3359
34
        while (ic < objs && osection[ic].rawdataptr == 0)
3360
0
            ic++;
3361
34
        if (ic >= objs)
3362
0
            throwCantUnpack("no section with raw data");
3363
3364
34
        ibuf.dealloc();
3365
34
        if (!exact) {
3366
34
            ibuf.alloc(osection[ic].rawdataptr);
3367
34
            ibuf.clear();
3368
34
        }
3369
34
        infoHeader("[Writing uncompressed file]");
3370
3371
        // write header + decompressed file
3372
34
        fo->write(&oh, sizeof_oh);
3373
34
        fo->write(osection, objs * sizeof(pe_section_t));
3374
34
        if (!exact) {
3375
34
            fo->write(ibuf, osection[ic].rawdataptr - fo->getBytesWritten());
3376
247
            for (ic = 0; ic < objs; ic++)
3377
213
                if (osection[ic].rawdataptr) {
3378
180
                    const unsigned seclen = ALIGN_UP(osection[ic].size, oh.filealign);
3379
180
                    fo->write(obuf.subref("bad section %#x", osection[ic].vaddr - rvamin, seclen),
3380
180
                              seclen);
3381
180
                }
3382
34
        } else {
3383
0
            Array(unsigned, raw_order, objs);
3384
0
            const unsigned raw_count = getRawSectionOrder(osection, objs, raw_order);
3385
0
            for (unsigned ii = 0; ii < raw_count; ii++) {
3386
0
                ic = raw_order[ii];
3387
0
                const unsigned written = fo->getBytesWritten();
3388
0
                if (written > osection[ic].rawdataptr)
3389
0
                    throwCantUnpack("overlapping raw sections");
3390
0
                const unsigned gap = osection[ic].rawdataptr - written;
3391
0
                if (gap > stored_gap_size - exact_gap_used)
3392
0
                    throwCantUnpack("corrupted exact gaps");
3393
0
                fo->write(obuf + (exact_gap_offset + exact_gap_used), gap);
3394
0
                exact_gap_used += gap;
3395
0
                fo->write(obuf.subref("bad exact section", osection[ic].vaddr - rvamin,
3396
0
                                      osection[ic].size),
3397
0
                          osection[ic].size);
3398
0
            }
3399
0
            if (exact_gap_used != stored_gap_size)
3400
0
                throwCantUnpack("unused exact gaps");
3401
0
        }
3402
34
        copyOverlay(fo, overlay, obuf);
3403
34
    }
3404
200
    ibuf.dealloc();
3405
200
}
void PeFile::unpack0<PeFile64::pe_header_t, LE64, unsigned long long>(OutputFile*, PeFile64::pe_header_t const&, PeFile64::pe_header_t&, unsigned long long, bool)
Line
Count
Source
3231
38
void PeFile::unpack0(OutputFile *fo, const ht &ih, ht &oh, ord_mask_t ord_mask, bool set_oft) {
3232
    // infoHeader("[Processing %s, format %s, %d sections]", fn_basename(fi->getName()), getName(),
3233
    // objs);
3234
3235
38
    handleStub(fi, fo, pe_offset);
3236
38
    if (ih.filealign == 0)
3237
2
        throwCantUnpack("unexpected value in the PE header");
3238
3239
36
    const unsigned iobjs = ih.objects;
3240
36
    const unsigned overlay =
3241
36
        file_size_u -
3242
36
        ALIGN_UP(isection[iobjs - 1].rawdataptr + isection[iobjs - 1].size, ih.filealign);
3243
36
    checkOverlay(overlay);
3244
3245
36
    ibuf.alloc(ph.c_len);
3246
36
    obuf.allocForDecompression(ph.u_len);
3247
36
    fi->seek(isection[1].rawdataptr - 64 + ph.buf_offset + ph.getPackHeaderSize(), SEEK_SET);
3248
36
    fi->readx(ibuf, ibufgood = ph.c_len);
3249
3250
    // decompress
3251
36
    decompress(ibuf, obuf);
3252
36
    const bool exact = ph.version == pe_exact_version;
3253
36
    PeExactTrailer trailer = {};
3254
36
    const unsigned trailer_size = sizeof(trailer) + sizeof(LE32);
3255
36
    if (exact) {
3256
0
        if (ph.u_len < trailer_size)
3257
0
            throwCantUnpack("corrupted exact metadata");
3258
0
        memcpy(&trailer, obuf + (ph.u_len - trailer_size), sizeof(trailer));
3259
0
    }
3260
36
    const unsigned stored_gap_size = exact ? (unsigned) trailer.gap_size : 0;
3261
36
    const unsigned exact_gap_offset = exact ? ph.u_len - trailer_size - stored_gap_size : 0;
3262
36
    unsigned exact_gap_used = 0;
3263
36
    if (exact) {
3264
0
        if (trailer.flags & ~(pe_exact_relocs | pe_exact_imports))
3265
0
            throwCantUnpack("unknown exact flags");
3266
0
        obuf.subref("bad exact gaps", exact_gap_offset, stored_gap_size);
3267
0
    }
3268
36
    unsigned skip = get_le32(obuf + (ph.u_len - 4));
3269
36
    unsigned take = sizeof_oh;
3270
36
    SPAN_S_VAR(byte, extra_info, obuf);
3271
36
    extra_info = obuf.subref("bad extra_info offset %#x", skip, take);
3272
    // byte *const eistart = raw_bytes(extra_info, 0);
3273
3274
36
    memcpy(&oh, extra_info, take);
3275
36
    extra_info += take;
3276
36
    skip += take;
3277
36
    const unsigned objs = oh.objects;
3278
3279
36
    if ((int) objs <= 0 || (iobjs > 2 && isection[2].size == 0))
3280
2
        throwCantUnpack("unexpected value in the PE header");
3281
34
    Array(pe_section_t, osection, objs);
3282
34
    take = sizeof(pe_section_t) * objs;
3283
34
    extra_info = obuf.subref("bad extra section size at %#x", skip, take);
3284
34
    memcpy(osection, extra_info, take);
3285
34
    extra_info += take;
3286
34
    skip += take;
3287
34
    rvamin = osection[0].vaddr;
3288
3289
34
    if (iobjs > 2) {
3290
        // read the noncompressed section
3291
16
        const unsigned size = isection[2].size;
3292
16
        ibuf.dealloc();
3293
16
        ibuf.alloc(size + 1);
3294
16
        fi->seek(isection[2].rawdataptr, SEEK_SET);
3295
16
        fi->readx(ibuf, ibufgood = size);
3296
16
        ibuf[size] = 0; // allow strlen() up to 'size'
3297
16
    }
3298
3299
    // unfilter
3300
34
    if (ph.filter) {
3301
14
        const unsigned codebase = exact && oh.codebase == 0 ? rvamin : (unsigned) oh.codebase;
3302
14
        Filter ft(ph.level);
3303
14
        ft.init(ph.filter, codebase - rvamin);
3304
14
        ft.cto = (byte) ph.filter_cto;
3305
14
        OCHECK(obuf + (codebase - rvamin), oh.codesize);
3306
14
        ft.unfilter(obuf + (codebase - rvamin), oh.codesize);
3307
14
    }
3308
3309
    // FIXME: ih.flags is checked here because of a bug in UPX 0.92
3310
34
    if (!exact && (ih.flags & IMAGE_FILE_RELOCS_STRIPPED)) {
3311
9
        oh.flags |= IMAGE_FILE_RELOCS_STRIPPED;
3312
9
        ODADDR(PEDIR_BASERELOC) = 0;
3313
9
        ODSIZE(PEDIR_BASERELOC) = 0;
3314
9
    }
3315
3316
34
    if (exact) {
3317
0
        if (trailer.flags & pe_exact_imports)
3318
0
            extra_info += 8;
3319
34
    } else {
3320
34
        rebuildImports<LEXX>(extra_info, ord_mask, set_oft);
3321
34
    }
3322
34
    if (!exact || (trailer.flags & pe_exact_relocs))
3323
10
        rebuildRelocs(extra_info, sizeof(ih.imagebase) * 8, oh.flags, oh.imagebase, exact);
3324
34
    rebuildTls();
3325
34
    if (!exact)
3326
10
        rebuildExports();
3327
3328
34
    if (iobjs > 3) {
3329
        // read the resource section if present
3330
0
        ibuf.dealloc();
3331
0
        ibuf.alloc(isection[3].size);
3332
0
        fi->seek(isection[3].rawdataptr, SEEK_SET);
3333
0
        fi->readx(ibuf, ibufgood = isection[3].size);
3334
0
    }
3335
3336
34
    if (!exact)
3337
10
        rebuildResources(extra_info, isection[ih.objects - 1].vaddr);
3338
3339
    // FIXME: this does bad things if the relocation section got removed
3340
    //  during compression ...
3341
    // memset(eistart, 0, ptr_udiff_bytes(extra_info, eistart) + 4);
3342
3343
    // fill the data directory
3344
34
    if (!exact) {
3345
6
        ODADDR(PEDIR_IAT) = 0;
3346
6
        ODSIZE(PEDIR_IAT) = 0;
3347
6
        ODADDR(PEDIR_BOUND_IMPORT) = 0;
3348
6
        ODSIZE(PEDIR_BOUND_IMPORT) = 0;
3349
6
    }
3350
3351
34
    if (!exact) {
3352
6
        setOhHeaderSize(osection);
3353
6
        oh.chksum = 0;
3354
6
    }
3355
3356
    // write decompressed file
3357
34
    if (fo) {
3358
4
        unsigned ic = 0;
3359
4
        while (ic < objs && osection[ic].rawdataptr == 0)
3360
0
            ic++;
3361
4
        if (ic >= objs)
3362
0
            throwCantUnpack("no section with raw data");
3363
3364
4
        ibuf.dealloc();
3365
4
        if (!exact) {
3366
4
            ibuf.alloc(osection[ic].rawdataptr);
3367
4
            ibuf.clear();
3368
4
        }
3369
4
        infoHeader("[Writing uncompressed file]");
3370
3371
        // write header + decompressed file
3372
4
        fo->write(&oh, sizeof_oh);
3373
4
        fo->write(osection, objs * sizeof(pe_section_t));
3374
4
        if (!exact) {
3375
4
            fo->write(ibuf, osection[ic].rawdataptr - fo->getBytesWritten());
3376
54
            for (ic = 0; ic < objs; ic++)
3377
50
                if (osection[ic].rawdataptr) {
3378
48
                    const unsigned seclen = ALIGN_UP(osection[ic].size, oh.filealign);
3379
48
                    fo->write(obuf.subref("bad section %#x", osection[ic].vaddr - rvamin, seclen),
3380
48
                              seclen);
3381
48
                }
3382
4
        } else {
3383
0
            Array(unsigned, raw_order, objs);
3384
0
            const unsigned raw_count = getRawSectionOrder(osection, objs, raw_order);
3385
0
            for (unsigned ii = 0; ii < raw_count; ii++) {
3386
0
                ic = raw_order[ii];
3387
0
                const unsigned written = fo->getBytesWritten();
3388
0
                if (written > osection[ic].rawdataptr)
3389
0
                    throwCantUnpack("overlapping raw sections");
3390
0
                const unsigned gap = osection[ic].rawdataptr - written;
3391
0
                if (gap > stored_gap_size - exact_gap_used)
3392
0
                    throwCantUnpack("corrupted exact gaps");
3393
0
                fo->write(obuf + (exact_gap_offset + exact_gap_used), gap);
3394
0
                exact_gap_used += gap;
3395
0
                fo->write(obuf.subref("bad exact section", osection[ic].vaddr - rvamin,
3396
0
                                      osection[ic].size),
3397
0
                          osection[ic].size);
3398
0
            }
3399
0
            if (exact_gap_used != stored_gap_size)
3400
0
                throwCantUnpack("unused exact gaps");
3401
0
        }
3402
4
        copyOverlay(fo, overlay, obuf);
3403
4
    }
3404
34
    ibuf.dealloc();
3405
34
}
3406
3407
773
int PeFile::canUnpack0(unsigned max_sections, unsigned objs, unsigned ih_entry, unsigned ih_size) {
3408
773
    const unsigned min_sections = isefi ? 2 : 3;
3409
773
    if (objs < min_sections)
3410
5
        return -1;
3411
768
    mb_isection.alloc(mem_size(sizeof(pe_section_t), objs));
3412
768
    isection = SPAN_S_MAKE(pe_section_t, mb_isection); // => isection now is a SPAN_S
3413
768
    fi->seek(pe_offset + ih_size, SEEK_SET);
3414
768
    fi->readx(isection, sizeof(pe_section_t) * objs);
3415
768
    bool is_packed = (objs <= max_sections && (IDSIZE(15) || ih_entry > isection[1].vaddr));
3416
768
    bool found_ph = false;
3417
768
    if (memcmp(isection[0].name, "UPX", 3) == 0) {
3418
        // current version
3419
308
        fi->seek(isection[1].rawdataptr - 64, SEEK_SET);
3420
308
        found_ph = readPackHeader(1024);
3421
308
        if (!found_ph) {
3422
            // old versions
3423
73
            fi->seek(isection[2].rawdataptr, SEEK_SET);
3424
73
            found_ph = readPackHeader(1024);
3425
73
        }
3426
308
    }
3427
768
    if (is_packed && found_ph)
3428
248
        return true;
3429
520
    if (!is_packed && !found_ph)
3430
65
        return -1;
3431
455
    if (is_packed && ih_entry < isection[2].vaddr) {
3432
189
        byte buf[256];
3433
189
        bool x = false;
3434
3435
189
        memset(buf, 0, sizeof(buf));
3436
189
        try {
3437
189
            fi->seek(ih_entry - isection[1].vaddr + isection[1].rawdataptr, SEEK_SET);
3438
189
            fi->read(buf, sizeof(buf));
3439
3440
            // FIXME this is for x86
3441
189
            static const byte magic[] = "\x8b\x1e\x83\xee\xfc\x11\xdb";
3442
            // mov ebx, [esi];    sub esi, -4;    adc ebx,ebx
3443
3444
189
            int offset = find(buf, sizeof(buf), magic, 7);
3445
189
            if (offset >= 0 && find(buf + offset + 1, sizeof(buf) - offset - 1, magic, 7) >= 0)
3446
26
                x = true;
3447
189
        } catch (...) {
3448
            // x = true;
3449
99
        }
3450
189
        if (x)
3451
26
            throwCantUnpack("file is modified/hacked/protected; take care!!!");
3452
163
        else
3453
163
            throwCantUnpack("file is possibly modified/hacked/protected; take care!");
3454
0
        return false; // not reached
3455
189
    }
3456
3457
    // FIXME: what should we say here ?
3458
    // throwCantUnpack("file is possibly modified/hacked/protected; take care!");
3459
266
    return false;
3460
455
}
3461
3462
0
upx_uint64_t PeFile::ilinkerGetAddress(const char *d, const char *n) const {
3463
0
    return ilinker->getAddress(d, n);
3464
0
}
3465
3466
152k
PeFile::~PeFile() noexcept {
3467
152k
    oimpdlls = nullptr;
3468
152k
    delete[] oxrelocs;
3469
152k
    delete ilinker;
3470
    // delete res;
3471
152k
}
3472
3473
/*************************************************************************
3474
// PeFile32
3475
**************************************************************************/
3476
3477
75.6k
PeFile32::PeFile32(InputFile *f) : super(f) {
3478
75.6k
    COMPILE_TIME_ASSERT(sizeof(pe_header_t) == 248)
3479
75.6k
    COMPILE_TIME_ASSERT_ALIGNED1(pe_header_t)
3480
3481
75.6k
    sizeof_oh = sizeof_ih = sizeof(ih); // default with .ddirsentries == 16
3482
75.6k
    iddirs = ih.ddirs;
3483
75.6k
    oddirs = oh.ddirs;
3484
75.6k
}
3485
3486
PeFile32::~PeFile32() noexcept {}
3487
3488
1.02k
void PeFile32::readPeHeader() {
3489
1.02k
    fi->readx(&ih, sizeof_ih);
3490
1.02k
    unsigned nddirs = ih.ddirsentries;
3491
1.02k
    if (nddirs > 16) {
3492
        // throwCantPack("bad ih.ddirsentries %u", nddirs);
3493
729
        infoWarning("bad ih.ddirsentries %u -> 16", nddirs);
3494
729
        nddirs = 16;
3495
729
    }
3496
1.02k
    sizeof_oh = sizeof_ih =
3497
1.02k
        ((const char *) &ih.ddirs - (const char *) &ih) + nddirs * sizeof(ddirs_t);
3498
1.02k
    const unsigned missing = (16 - nddirs) * sizeof(ddirs_t);
3499
1.02k
    memset(&ih.ddirs[nddirs], 0, missing);
3500
3501
1.02k
    if (31 < (unsigned) ih.subsystem) {
3502
26
        throwCantPack("bad ih.subsystem 0x%x", (unsigned) ih.subsystem);
3503
26
    }
3504
999
    isefi = ((1u << ih.subsystem) &
3505
999
             ((1u << IMAGE_SUBSYSTEM_EFI_APPLICATION) |
3506
999
              (1u << IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER) |
3507
999
              (1u << IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) | (1u << IMAGE_SUBSYSTEM_EFI_ROM))) != 0;
3508
999
    isdll = !isefi && (ih.flags & IMAGE_FILE_DLL) != 0;
3509
999
    use_dep_hack &= !isefi;
3510
999
    use_clear_dirty_stack &= !isefi;
3511
999
}
3512
3513
void PeFile32::pack0(OutputFile *fo, unsigned subsystem_mask, upx_uint64_t default_imagebase,
3514
0
                     bool last_section_rsrc_only) {
3515
0
    super::pack0<LE32>(fo, ih, oh, subsystem_mask, default_imagebase, last_section_rsrc_only);
3516
    // infoWarning("End of PeFile32::pack0");
3517
0
}
3518
3519
204
void PeFile32::unpack(OutputFile *fo) {
3520
204
    bool set_oft = getFormat() == UPX_F_WINCE_ARM;
3521
204
    unpack0<pe_header_t, LE32>(fo, ih, oh, 1U << 31, set_oft);
3522
204
}
3523
3524
75.6k
tribool PeFile32::canUnpack() {
3525
75.6k
    if (!canPack()) // this calls readFileHeader() and readPeHeader()
3526
74.7k
        return false;
3527
835
    return canUnpack0(getFormat() == UPX_F_WINCE_ARM ? 4 : 3, ih.objects, ih.entry, sizeof_ih);
3528
75.6k
}
3529
3530
0
unsigned PeFile32::processImports() { // pass 1
3531
0
    return processImports0<LE32>(1u << 31);
3532
0
}
3533
3534
0
void PeFile32::processTls(Interval *iv) { processTls1<LE32>(iv, ih.imagebase, ih.imagesize); }
3535
3536
0
void PeFile32::processTls(Reloc *r, const Interval *iv, unsigned a) {
3537
0
    processTls2<LE32>(r, iv, a, ih.imagebase);
3538
0
}
3539
3540
/*************************************************************************
3541
// PeFile64
3542
**************************************************************************/
3543
3544
76.6k
PeFile64::PeFile64(InputFile *f) : super(f) {
3545
76.6k
    COMPILE_TIME_ASSERT(sizeof(pe_header_t) == 264)
3546
76.6k
    COMPILE_TIME_ASSERT_ALIGNED1(pe_header_t)
3547
3548
76.6k
    sizeof_oh = sizeof_ih = sizeof(ih); // default with .ddirsentries == 16
3549
76.6k
    iddirs = ih.ddirs;
3550
76.6k
    oddirs = oh.ddirs;
3551
76.6k
}
3552
3553
PeFile64::~PeFile64() noexcept {}
3554
3555
1.77k
void PeFile64::readPeHeader() {
3556
1.77k
    fi->readx(&ih, sizeof_ih);
3557
1.77k
    unsigned nddirs = ih.ddirsentries;
3558
1.77k
    if (nddirs > 16) {
3559
        // throwCantPack("bad ih.ddirsentries %u", nddirs);
3560
1.42k
        infoWarning("bad ih.ddirsentries %u -> 16", nddirs);
3561
1.42k
        nddirs = 16;
3562
1.42k
    }
3563
1.77k
    sizeof_oh = sizeof_ih =
3564
1.77k
        ((const char *) &ih.ddirs - (const char *) &ih) + nddirs * sizeof(ddirs_t);
3565
1.77k
    const unsigned missing = (16 - nddirs) * sizeof(ddirs_t);
3566
1.77k
    memset(&ih.ddirs[nddirs], 0, missing);
3567
3568
1.77k
    if (31 < (unsigned) ih.subsystem) {
3569
23
        throwCantPack("bad ih.subsystem 0x%x", (unsigned) ih.subsystem);
3570
23
    }
3571
1.74k
    isefi = ((1u << ih.subsystem) &
3572
1.74k
             ((1u << IMAGE_SUBSYSTEM_EFI_APPLICATION) |
3573
1.74k
              (1u << IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER) |
3574
1.74k
              (1u << IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) | (1u << IMAGE_SUBSYSTEM_EFI_ROM))) != 0;
3575
1.74k
    isdll = !isefi && (ih.flags & IMAGE_FILE_DLL) != 0;
3576
1.74k
    use_dep_hack &= !isefi;
3577
1.74k
    use_clear_dirty_stack &= !isefi;
3578
1.74k
}
3579
3580
0
void PeFile64::pack0(OutputFile *fo, unsigned subsystem_mask, upx_uint64_t default_imagebase) {
3581
0
    super::pack0<LE64>(fo, ih, oh, subsystem_mask, default_imagebase, false);
3582
0
}
3583
3584
38
void PeFile64::unpack(OutputFile *fo) { unpack0<pe_header_t, LE64>(fo, ih, oh, 1ULL << 63, false); }
3585
3586
76.6k
tribool PeFile64::canUnpack() {
3587
76.6k
    if (!canPack()) // this calls readFileHeader() and readPeHeader()
3588
75.6k
        return false;
3589
975
    return canUnpack0(3, ih.objects, ih.entry, sizeof_ih);
3590
76.6k
}
3591
3592
0
unsigned PeFile64::processImports() { // pass 1
3593
0
    return processImports0<LE64>(1ULL << 63);
3594
0
}
3595
3596
0
void PeFile64::processTls(Interval *iv) { processTls1<LE64>(iv, ih.imagebase, ih.imagesize); }
3597
3598
0
void PeFile64::processTls(Reloc *r, const Interval *iv, unsigned a) {
3599
0
    processTls2<LE64>(r, iv, a, ih.imagebase);
3600
0
}
3601
3602
/*
3603
 extra_info added to help uncompression:
3604
3605
 <ih sizeof(pe_head)>
3606
 <pe_section_t objs*sizeof(pe_section_t)>
3607
 <start of compressed imports 4> - optional           \
3608
 <start of the names from uncompressed imports> - opt /
3609
 <start of compressed relocs 4> - optional   \
3610
 <relocation type indicator 1> - optional    /
3611
 <icondir_count 2> - optional
3612
 <offset of extra info 4>
3613
*/
3614
3615
/* vim:set ts=4 sw=4 et: */