1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
|
From: John Reiser <jreiser@BitWagon.com>
Date: Tue, 21 May 2024 17:14:21 -0700
Subject: ELf stubs: go_lang different placement of DT_STRTAB, DT_SYMTAB
https://github.com/upx/upx/issues/825
modified: p_lx_elf.cpp
Bugs-Debian: https://bugs.debian.org/1071591
Forwarded: not-needed
---
src/p_lx_elf.cpp | 34 ++++++++++++++++++++++++----------
1 file changed, 24 insertions(+), 10 deletions(-)
diff --git a/src/p_lx_elf.cpp b/src/p_lx_elf.cpp
index 9aa664f..98fedcf 100644
--- a/src/p_lx_elf.cpp
+++ b/src/p_lx_elf.cpp
@@ -2106,7 +2106,9 @@ PackLinuxElf32::invert_pt_dynamic(Elf32_Dyn const *dynp, u32_t headway)
unsigned const z_str = dt_table[Elf32_Dyn::DT_STRSZ];
strtab_max = !z_str ? 0 : get_te32(&dynp0[-1+ z_str].d_val);
unsigned const z_tab = dt_table[Elf32_Dyn::DT_STRTAB];
- unsigned const strtab_beg = !z_tab ? 0 : get_te32(&dynp0[-1+ z_tab].d_val);
+ unsigned const strtab_beg = !z_tab ? 0
+ : elf_get_offset_from_address(get_te32(&dynp0[-1+ z_tab].d_val));
+
if (!z_str || !z_tab
|| (this->file_size - strtab_beg) < strtab_max // strtab overlaps EOF
// last string in table must have terminating NUL
@@ -2121,8 +2123,14 @@ PackLinuxElf32::invert_pt_dynamic(Elf32_Dyn const *dynp, u32_t headway)
symnum_max = elf_find_table_size(
Elf32_Dyn::DT_SYMTAB, Elf32_Shdr::SHT_DYNSYM) / sizeof(Elf32_Sym);
- unsigned const x_sym = dt_table[Elf32_Dyn::DT_SYMTAB];
- unsigned const v_hsh = elf_unsigned_dynamic(Elf32_Dyn::DT_HASH);
+ unsigned v_sym = dt_table[Elf32_Dyn::DT_SYMTAB];
+ if (v_sym) {
+ v_sym = elf_get_offset_from_address(get_te32(&dynp0[-1+ v_sym].d_val));
+ }
+ unsigned v_hsh = dt_table[Elf32_Dyn::DT_HASH];
+ if (v_hsh) {
+ v_hsh = elf_get_offset_from_address(get_te32(&dynp0[-1+ v_hsh].d_val));
+ }
if (v_hsh && file_image) {
hashtab = (unsigned const *)elf_find_dynamic(Elf32_Dyn::DT_HASH);
if (!hashtab) {
@@ -2144,7 +2152,6 @@ PackLinuxElf32::invert_pt_dynamic(Elf32_Dyn const *dynp, u32_t headway)
throwCantPack(msg);
}
- unsigned const v_sym = !x_sym ? 0 : get_te32(&dynp0[-1+ x_sym].d_val);
if ((unsigned)(hashend - buckets) < nbucket
|| !v_sym || (unsigned)file_size <= v_sym
|| ((v_hsh < v_sym) && (v_sym - v_hsh) < sizeof(*buckets)*(2+ nbucket))
@@ -2171,6 +2178,7 @@ PackLinuxElf32::invert_pt_dynamic(Elf32_Dyn const *dynp, u32_t headway)
}
unsigned const v_gsh = elf_unsigned_dynamic(Elf32_Dyn::DT_GNU_HASH);
if (v_gsh && file_image) {
+ // Not similar to DT_HASH because DT_GNU_HASH is not small (0x6ffffef5).
gashtab = (unsigned const *)elf_find_dynamic(Elf32_Dyn::DT_GNU_HASH);
if (!gashtab) {
char msg[40]; snprintf(msg, sizeof(msg),
@@ -2230,7 +2238,6 @@ PackLinuxElf32::invert_pt_dynamic(Elf32_Dyn const *dynp, u32_t headway)
}
bmax -= symbias;
- u32_t const v_sym = !x_sym ? 0 : get_te32(&dynp0[-1+ x_sym].d_val);
unsigned r = 0;
if (!n_bucket || !n_bitmask || !v_sym
|| (r=1, ((-1+ n_bitmask) & n_bitmask)) // not a power of 2
@@ -8032,7 +8039,8 @@ PackLinuxElf64::invert_pt_dynamic(Elf64_Dyn const *dynp, upx_uint64_t headway)
unsigned const z_str = dt_table[Elf64_Dyn::DT_STRSZ];
strtab_max = !z_str ? 0 : get_te64(&dynp0[-1+ z_str].d_val);
unsigned const z_tab = dt_table[Elf64_Dyn::DT_STRTAB];
- unsigned const strtab_beg = !z_tab ? 0 : get_te64(&dynp0[-1+ z_tab].d_val);
+ unsigned const strtab_beg = !z_tab ? 0
+ : elf_get_offset_from_address(get_te64(&dynp0[-1+ z_tab].d_val));
if (!z_str || !z_tab
|| (this->file_size - strtab_beg) < strtab_max // strtab overlaps EOF
// last string in table must have terminating NUL
@@ -8047,8 +8055,15 @@ PackLinuxElf64::invert_pt_dynamic(Elf64_Dyn const *dynp, upx_uint64_t headway)
symnum_max = elf_find_table_size(
Elf64_Dyn::DT_SYMTAB, Elf64_Shdr::SHT_DYNSYM) / sizeof(Elf64_Sym);
- unsigned const x_sym = dt_table[Elf64_Dyn::DT_SYMTAB];
- unsigned const v_hsh = elf_unsigned_dynamic(Elf64_Dyn::DT_HASH);
+ unsigned v_sym = dt_table[Elf64_Dyn::DT_SYMTAB];
+ if (v_sym) {
+ v_sym = elf_get_offset_from_address(get_te64(&dynp0[-1+ v_sym].d_val));
+ }
+
+ unsigned v_hsh = dt_table[Elf64_Dyn::DT_HASH];
+ if (v_hsh) {
+ v_hsh = elf_get_offset_from_address(get_te64(&dynp0[-1+ v_hsh].d_val));
+ }
if (v_hsh && file_image) {
hashtab = (unsigned const *)elf_find_dynamic(Elf64_Dyn::DT_HASH);
if (!hashtab) {
@@ -8070,7 +8085,6 @@ PackLinuxElf64::invert_pt_dynamic(Elf64_Dyn const *dynp, upx_uint64_t headway)
throwCantPack(msg);
}
- unsigned const v_sym = !x_sym ? 0 : get_te64(&dynp0[-1+ x_sym].d_val); // UPX_RSIZE_MAX_MEM
if ((unsigned)(hashend - buckets) < nbucket
|| !v_sym || (unsigned)file_size <= v_sym
|| ((v_hsh < v_sym) && (v_sym - v_hsh) < sizeof(*buckets)*(2+ nbucket))
@@ -8097,6 +8111,7 @@ PackLinuxElf64::invert_pt_dynamic(Elf64_Dyn const *dynp, upx_uint64_t headway)
}
unsigned const v_gsh = elf_unsigned_dynamic(Elf64_Dyn::DT_GNU_HASH);
if (v_gsh && file_image) {
+ // Not similar to DT_HASH because DT_GNU_HASH is not small (0x6ffffef5).
gashtab = (unsigned const *)elf_find_dynamic(Elf64_Dyn::DT_GNU_HASH);
if (!gashtab) {
char msg[40]; snprintf(msg, sizeof(msg),
@@ -8156,7 +8171,6 @@ PackLinuxElf64::invert_pt_dynamic(Elf64_Dyn const *dynp, upx_uint64_t headway)
}
bmax -= symbias;
- upx_uint64_t const v_sym = !x_sym ? 0 : get_te64(&dynp0[-1+ x_sym].d_val);
unsigned r = 0;
if (!n_bucket || !n_bitmask || !v_sym
|| (r=1, ((-1+ n_bitmask) & n_bitmask)) // not a power of 2
|