diff --git a/src/Makefile b/src/Makefile index 954a2d1b..0ab78636 100644 --- a/src/Makefile +++ b/src/Makefile @@ -5,7 +5,7 @@ # # build configuration options for this Makefile -BUILD_TYPE_DEBUG ?= 0 +BUILD_TYPE_DEBUG ?= 1 BUILD_TYPE_SANITIZE ?= 0 BUILD_USE_DEPEND ?= 1 diff --git a/src/bele.h b/src/bele.h index 30c7cb85..a5752810 100644 --- a/src/bele.h +++ b/src/bele.h @@ -142,6 +142,24 @@ inline void set_le24(void *p, unsigned v) #endif } +inline unsigned get_le26(const void *p) +{ +#if defined(ACC_UA_GET_LE26) + return ACC_UA_GET_LE26(p); +#else + return acc_ua_get_le26(p); +#endif +} + +inline void set_le26(void *p, unsigned v) +{ +#if defined(ACC_UA_SET_LE26) + ACC_UA_SET_LE26(p, v); +#else + acc_ua_set_le26(p, v); +#endif +} + inline unsigned get_le32(const void *p) { #if defined(ACC_UA_GET_LE32) diff --git a/src/filter/ct.h b/src/filter/ct.h index 8f6ca3ac..12d561dd 100644 --- a/src/filter/ct.h +++ b/src/filter/ct.h @@ -459,4 +459,45 @@ static int s_ct24arm_be(Filter *f) #undef CT24ARM_BE #undef ARMCT_COND +/************************************************************************* +// 26-bit ARM calltrick ("naive") +**************************************************************************/ + +#define CT26ARM_LE(f, cond, addvalue, get, set) \ + upx_byte *b = f->buf; \ + upx_byte *b_end = b + f->buf_len - 4; \ + do { \ + if (cond) \ + { \ + unsigned a = (unsigned) (b - f->buf); \ + f->lastcall = a; \ + set(b, get(b) + (addvalue)); \ + f->calls++; \ + } \ + b += 4; \ + } while (b < b_end); \ + if (f->lastcall) f->lastcall += 4; \ + return 0; + + +#define ARMCT_COND (((b[3] & 0x7C) == 0x14)) + +static int f_ct26arm_le(Filter *f) +{ + CT26ARM_LE(f, ARMCT_COND, a / 4 + f->addvalue, get_le26, set_le26) +} + +static int u_ct26arm_le(Filter *f) +{ + CT26ARM_LE(f, ARMCT_COND, 0 - a / 4 - f->addvalue, get_le26, set_le26) +} + +static int s_ct26arm_le(Filter *f) +{ + CT26ARM_LE(f, ARMCT_COND, a + f->addvalue, get_le26, set_dummy) +} + +#undef CT26ARM_LE +#undef ARMCT_COND + /* vim:set ts=4 sw=4 et: */ diff --git a/src/filteri.cpp b/src/filteri.cpp index 0325764e..b0296ae3 100644 --- a/src/filteri.cpp +++ b/src/filteri.cpp @@ -228,6 +228,9 @@ const FilterImp::FilterEntry FilterImp::filters[] = { { 0x50, 8, 0x01ffffff, f_ct24arm_le, u_ct24arm_le, s_ct24arm_le }, { 0x51, 8, 0x01ffffff, f_ct24arm_be, u_ct24arm_be, s_ct24arm_be }, + // 26-bit calltrick for arm64 + { 0x52, 8, 0x03ffffff, f_ct26arm_le, u_ct26arm_le, s_ct26arm_le }, + // 32-bit cto calltrick with jmp and jcc(swap 0x0f/0x8Y) and relative renumbering { 0x80, 8, 0x00ffffff, f_ctojr32_e8e9_bswap_le, u_ctojr32_e8e9_bswap_le, s_ctojr32_e8e9_bswap_le }, { 0x81, 8, 0x00ffffff, f_ctojr32_e8e9_bswap_le, u_ctojr32_e8e9_bswap_le, s_ctojr32_e8e9_bswap_le }, diff --git a/src/linker.cpp b/src/linker.cpp index 594d2110..391e6dfc 100644 --- a/src/linker.cpp +++ b/src/linker.cpp @@ -541,7 +541,7 @@ void ElfLinker::alignWithByte(unsigned len, unsigned char b) { } void ElfLinker::relocate1(const Relocation *rel, upx_byte *, upx_uint64_t, const char *) { - internal_error("unknown relocation type '%s\n", rel->type); + internal_error("unknown relocation type '%s\n'", rel->type); } /************************************************************************* @@ -600,14 +600,18 @@ void ElfLinkerARM64::relocate1(const Relocation *rel, upx_byte *location, upx_ui if (!strncmp(type, "PREL", 4)) { value -= rel->section->offset + rel->offset; type += 4; - } - if (!strcmp(type, "16")) - set_le16(location, get_le16(location) + value); - else if (!strncmp(type, "32", 2)) // for "32" and "32S" + if (!strcmp(type, "16")) + set_le16(location, get_le16(location) + value); + else if (!strncmp(type, "32", 2)) // for "32" and "32S" + set_le32(location, get_le32(location) + value); + else if (!strcmp(type, "64")) + set_le64(location, get_le64(location) + value); + } else if (!strcmp(type, "ABS32") == 0) { set_le32(location, get_le32(location) + value); - else if (!strcmp(type, "64")) + } else if (!strcmp(type, "ABS64") == 0) { set_le64(location, get_le64(location) + value); + } else super::relocate1(rel, location, value, type); } diff --git a/src/miniacc.h b/src/miniacc.h index 957ec1ea..40f22dac 100644 --- a/src/miniacc.h +++ b/src/miniacc.h @@ -5065,9 +5065,11 @@ ACCLIB_EXTERN(void, acc_ua_set_be24) (acc_hvoid_p, acc_uint32l_t); ACCLIB_EXTERN(void, acc_ua_set_be32) (acc_hvoid_p, acc_uint32l_t); ACCLIB_EXTERN(unsigned, acc_ua_get_le16) (const acc_hvoid_p); ACCLIB_EXTERN(acc_uint32l_t, acc_ua_get_le24) (const acc_hvoid_p); +ACCLIB_EXTERN(acc_uint32l_t, acc_ua_get_le26) (const acc_hvoid_p); ACCLIB_EXTERN(acc_uint32l_t, acc_ua_get_le32) (const acc_hvoid_p); ACCLIB_EXTERN(void, acc_ua_set_le16) (acc_hvoid_p, unsigned); ACCLIB_EXTERN(void, acc_ua_set_le24) (acc_hvoid_p, acc_uint32l_t); +ACCLIB_EXTERN(void, acc_ua_set_le26) (acc_hvoid_p, acc_uint32l_t); ACCLIB_EXTERN(void, acc_ua_set_le32) (acc_hvoid_p, acc_uint32l_t); #if defined(acc_int64l_t) ACCLIB_EXTERN(acc_uint64l_t, acc_ua_get_be64) (const acc_hvoid_p); @@ -6057,6 +6059,12 @@ ACCLIB_PUBLIC(acc_uint32l_t, acc_ua_get_le24) (const acc_hvoid_p p) const acc_hbyte_p b = ACC_CCAST(const acc_hbyte_p, p); return ACC_ICONV(acc_uint32l_t, b[0]) | (ACC_ICONV(acc_uint32l_t, b[1]) << 8) | (ACC_ICONV(acc_uint32l_t, b[2]) << 16); } +ACCLIB_PUBLIC(acc_uint32l_t, acc_ua_get_le26) (const acc_hvoid_p p) +{ + const acc_hbyte_p b = ACC_CCAST(const acc_hbyte_p, p); + return ACC_ICONV(acc_uint32l_t, b[0] ) | ( ACC_ICONV(acc_uint32l_t, b[1]) << 8) | + (ACC_ICONV(acc_uint32l_t, b[2]) << 16) | (((ACC_ICONV(acc_uint32l_t, b[3]) & 3)<< 24)); +} ACCLIB_PUBLIC(acc_uint32l_t, acc_ua_get_le32) (const acc_hvoid_p p) { #if defined(ACC_UA_GET_LE32) @@ -6083,6 +6091,14 @@ ACCLIB_PUBLIC(void, acc_ua_set_le24) (acc_hvoid_p p, acc_uint32l_t v) b[1] = ACC_ICONV(unsigned char, (v >> 8) & 0xff); b[2] = ACC_ICONV(unsigned char, (v >> 16) & 0xff); } +ACCLIB_PUBLIC(void, acc_ua_set_le26) (acc_hvoid_p p, acc_uint32l_t v) +{ + acc_hbyte_p b = ACC_PCAST(acc_hbyte_p, p); + b[0] = ACC_ICONV(unsigned char, (v >> 0) & 0xff); + b[1] = ACC_ICONV(unsigned char, (v >> 8) & 0xff); + b[2] = ACC_ICONV(unsigned char, (v >> 16) & 0xff); + b[3] = ACC_ICONV(unsigned char, (v >> 24) & 0x03) | (0xFC & b[3]); +} ACCLIB_PUBLIC(void, acc_ua_set_le32) (acc_hvoid_p p, acc_uint32l_t v) { #if defined(ACC_UA_SET_LE32) diff --git a/src/p_lx_elf.cpp b/src/p_lx_elf.cpp index 1b517f8c..5ca6fa40 100644 --- a/src/p_lx_elf.cpp +++ b/src/p_lx_elf.cpp @@ -705,7 +705,7 @@ int const * PackLinuxElf64arm::getFilters() const { static const int filters[] = { - 0x4A, + 0x52, FT_END }; return filters; } @@ -1118,85 +1118,6 @@ PackLinuxElf64amd::defineSymbols(Filter const *) //linker->dumpSymbols(); // debug } -void -PackLinuxElf64arm::defineSymbols(Filter const *) -{ - unsigned const hlen = sz_elf_hdrs + sizeof(l_info) + sizeof(p_info); - - // We want to know if compressed data, plus stub, plus a couple pages, - // will fit below the uncompressed program in memory. But we don't - // know the final total compressed size yet, so use the uncompressed - // size (total over all PT_LOAD64) as an upper bound. - unsigned len = 0; - upx_uint64_t lo_va_user = ~0ull; // infinity - for (int j= e_phnum; --j>=0; ) { - if (PT_LOAD64 == get_te32(&phdri[j].p_type)) { - len += (unsigned)get_te64(&phdri[j].p_filesz); - upx_uint64_t const va = get_te64(&phdri[j].p_vaddr); - if (va < lo_va_user) { - lo_va_user = va; - } - } - } - lsize = /*getLoaderSize()*/ 64 * 1024; // XXX: upper bound; avoid circularity - upx_uint64_t lo_va_stub = get_te64(&elfout.phdr[0].p_vaddr); - upx_uint64_t adrc; - upx_uint64_t adrm; - upx_uint64_t adru; - upx_uint64_t adrx; - unsigned cntc; - unsigned lenm; - unsigned lenu; - len += (7&-lsize) + lsize; - is_big = (lo_va_user < (lo_va_stub + len + 2*page_size)); - if (is_big && ehdri.ET_EXEC==get_te16(&ehdri.e_type)) { - set_te64( &elfout.ehdr.e_entry, - get_te64(&elfout.ehdr.e_entry) + lo_va_user - lo_va_stub); - set_te64(&elfout.phdr[0].p_vaddr, lo_va_user); - set_te64(&elfout.phdr[0].p_paddr, lo_va_user); - lo_va_stub = lo_va_user; - adrc = lo_va_stub; - adrm = getbrk(phdri, e_phnum); - adru = page_mask & (~page_mask + adrm); // round up to page boundary - adrx = adru + hlen; - lenm = page_size + len; - lenu = page_size + len; - cntc = len >> 3; // over-estimate; corrected at runtime - } - else { - adrm = lo_va_stub + len; - adrc = adrm; - adru = lo_va_stub; - adrx = lo_va_stub + hlen; - lenm = page_size; - lenu = page_size + len; - cntc = 0; - } - adrm = page_mask & (~page_mask + adrm); // round up to page boundary - adrc = page_mask & (~page_mask + adrc); // round up to page boundary - - //linker->defineSymbol("ADRX", adrx); // compressed input for eXpansion - ACC_UNUSED(adrx); - - // For actual moving, we need the true count, which depends on sz_pack2 - // and is not yet known. So the runtime stub detects "no move" - // if adrm==adrc, and otherwise uses actual sz_pack2 to compute cntc. - //linker->defineSymbol("CNTC", cntc); // count for copy - ACC_UNUSED(cntc); - - linker->defineSymbol("LENU", lenu); // len for unmap - linker->defineSymbol("ADRC", adrc); // addr for copy - //linker->defineSymbol("ADRU", adru); // addr for unmap - ACC_UNUSED(adru); -#define EI_NIDENT 16 /* */ - linker->defineSymbol("JMPU", EI_NIDENT -4 + lo_va_user); // unmap trampoline -#undef EI_NIDENT - linker->defineSymbol("LENM", lenm); // len for map - linker->defineSymbol("ADRM", adrm); // addr for map - - //linker->dumpSymbols(); // debug -} - static const #include "stub/i386-linux.elf-entry.h" static const @@ -3329,6 +3250,51 @@ void PackLinuxElf32armBe::defineSymbols(Filter const *ft) ARM_defineSymbols(ft); } +void PackLinuxElf64arm::defineSymbols(Filter const * /*ft*/) +{ + lsize = /*getLoaderSize()*/ 4 * 1024; // upper bound; avoid circularity + unsigned lo_va_user = ~0u; // infinity + for (int j= e_phnum; --j>=0; ) { + if (PT_LOAD64 == get_te64(&phdri[j].p_type)) { + unsigned const va = get_te64(&phdri[j].p_vaddr); + if (va < lo_va_user) { + lo_va_user = va; + } + } + } + unsigned lo_va_stub = get_te64(&elfout.phdr[0].p_vaddr); + unsigned adrc = 0; // init: pacify c++-analyzer + unsigned adrm = 0; // init: pacify c++-analyzer + + is_big = true; // kernel disallows mapping below 0x8000. + if (is_big) { + set_te64( &elfout.ehdr.e_entry, linker->getSymbolOffset("_start") + + get_te64(&elfout.ehdr.e_entry) + lo_va_user - lo_va_stub); + set_te64(&elfout.phdr[0].p_vaddr, lo_va_user); + set_te64(&elfout.phdr[0].p_paddr, lo_va_user); + lo_va_stub = lo_va_user; + adrc = lo_va_stub; + adrm = getbrk(phdri, e_phnum); + } + adrc = page_mask & (~page_mask + adrc); // round up to page boundary + adrm = page_mask & (~page_mask + adrm); // round up to page boundary + adrm += page_size; // Try: hole so that kernel does not extend the brk(0) + linker->defineSymbol("ADRM", adrm); // addr for map + + linker->defineSymbol("CPR0", 4+ linker->getSymbolOffset("cpr0")); + linker->defineSymbol("LENF", 4+ linker->getSymbolOffset("end_decompress")); + ACC_UNUSED(adrc); + +#define MAP_PRIVATE 2 /* UNIX standard */ +#define MAP_FIXED 0x10 /* UNIX standard */ +#define MAP_ANONYMOUS 0x20 /* UNIX standard */ +#define MAP_PRIVANON 3 /* QNX anonymous private memory */ + unsigned mflg = MAP_PRIVATE | MAP_ANONYMOUS; + //if (ARM_is_QNX()) + // mflg = MAP_PRIVANON; + linker->defineSymbol("MFLG", mflg); +} + void PackLinuxElf32mipseb::defineSymbols(Filter const * /*ft*/) { unsigned const hlen = sz_elf_hdrs + sizeof(l_info) + sizeof(p_info); diff --git a/src/stub/arm64-linux.elf-entry.h b/src/stub/arm64-linux.elf-entry.h index 0515b27f..1511b532 100644 --- a/src/stub/arm64-linux.elf-entry.h +++ b/src/stub/arm64-linux.elf-entry.h @@ -32,8 +32,8 @@ #define STUB_ARM64_LINUX_ELF_ENTRY_SIZE 5317 -#define STUB_ARM64_LINUX_ELF_ENTRY_ADLER32 0x85fe782d -#define STUB_ARM64_LINUX_ELF_ENTRY_CRC32 0x6307b5a0 +#define STUB_ARM64_LINUX_ELF_ENTRY_ADLER32 0x69217770 +#define STUB_ARM64_LINUX_ELF_ENTRY_CRC32 0xb10ced92 unsigned char stub_arm64_linux_elf_entry[5317] = { /* 0x0000 */ 127, 69, 76, 70, 2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -41,9 +41,9 @@ unsigned char stub_arm64_linux_elf_entry[5317] = { /* 0x0020 */ 0, 0, 0, 0, 0, 0, 0, 0, 8, 13, 0, 0, 0, 0, 0, 0, /* 0x0030 */ 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 64, 0, 17, 0, 14, 0, /* 0x0040 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -/* 0x0050 */ 0, 0, 0, 0, 76,255,255, 16,129, 41, 64, 41,139, 53, 65, 41, -/* 0x0060 */ 130, 9, 64,249,107, 1, 12,139, 74, 1, 12,139, 99, 1, 64,185, -/* 0x0070 */ 137, 1, 1,203, 33, 0, 3, 11,224, 3, 2,170, 33, 4, 64,145, +/* 0x0050 */ 0, 0, 0, 0, 0, 0, 32,212, 44,255,255, 16,129, 41, 64, 41, +/* 0x0060 */ 139, 53, 65, 41,107, 1, 12,139, 74, 1, 12,139, 99, 1, 64,185, +/* 0x0070 */ 137, 1, 1,203, 33, 0, 3, 11,128, 9, 64,249, 33, 4, 64,145, /* 0x0080 */ 3, 0,128, 82, 3, 0,130, 82,224,135,189,169,226, 15, 1,169, /* 0x0090 */ 237, 19, 0,249,226, 0,128, 82,163, 1, 28, 50, 5, 0,128,210, /* 0x00a0 */ 4, 0,128, 18,200, 27,128, 82, 1, 0, 0,212,192, 3, 95,214, diff --git a/src/stub/src/arm64-linux.elf-entry.S b/src/stub/src/arm64-linux.elf-entry.S index f52914e0..42b0fad5 100644 --- a/src/stub/src/arm64-linux.elf-entry.S +++ b/src/stub/src/arm64-linux.elf-entry.S @@ -70,7 +70,7 @@ mflg: .long MFLG // MAP_{PRIVATE|ANONYMOUS} // QNX vs linux .xword ADRM // dst for map _start: .globl _start -//// nop; bkpt + brk #0 /* Get some pages: enough to duplicate the entire compressed PT_LOAD, plus 1 page, located just after the brk() of the _un_compressed program. The address is pre-calculated @@ -89,13 +89,12 @@ _start: .globl _start adr x12,start_params -4 // &sz_pack2 ldp w1,w10,[x12] // w1= sz_pack2; w10= LENF ldp w11,w13,[x12,#2*4] // w11= CPRO; w13= MFLG - ldr x2,[x12,#4*4] // x2= ADRM add x11,x11,x12 // cpr0 add x10,x10,x12 // end_decompress ldr w3,[x11,# sz_unc] sub x9,x12,x1 // &our_Elf64_Ehdr add w1,w1,w3 // sz_pack2 + cpr0.sz_unc - mov x0,x2 // ADRM + ldr x0,[x12,#4*4] // ADRM add x1,x1,# PAGE_SIZE section LUNMP000 mov w3,#0<<12 // 0-page crumb