Coverage Report

Created: 2026-06-30 07:09

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