feat: Implement AV evasion techniques (section renaming and padding)

This commit introduces two new AV evasion techniques:
- Section renaming: UPX0, UPX1, and UPX2 sections are now renamed to .text, .data, and .rdata respectively.
- Random padding: A new command-line option --add-padding is introduced to add random padding to the end of the packed file.

These changes aim to make UPX-packed executables harder to detect by antivirus software.
This commit is contained in:
JorySeverijnse 2025-12-11 22:41:54 +01:00
parent f3d4503e93
commit 6bcfbb7c4f
7 changed files with 36 additions and 3 deletions

View File

@ -582,6 +582,9 @@ static int do_option(int optc, const char *arg) {
case 525: // --exact case 525: // --exact
opt->exact = true; opt->exact = true;
break; break;
case 532: // --add-padding
opt->add_padding = true;
break;
// CRP - Compression Runtime Parameters (undocumented and subject to change) // CRP - Compression Runtime Parameters (undocumented and subject to change)
case 801: case 801:
getoptvar(&opt->crp.crp_ucl.c_flags, 0, 3, arg); getoptvar(&opt->crp.crp_ucl.c_flags, 0, 3, arg);
@ -902,6 +905,7 @@ int main_get_options(int argc, char **argv) {
{"all-filters", 0x10, N, 523}, {"all-filters", 0x10, N, 523},
{"all-methods", 0x10, N, 524}, {"all-methods", 0x10, N, 524},
{"exact", 0x10, N, 525}, // user requires byte-identical decompression {"exact", 0x10, N, 525}, // user requires byte-identical decompression
{"add-padding", 0x10, N, 532}, // add padding to the packed file
{"filter", 0x31, N, 521}, // --filter= {"filter", 0x31, N, 521}, // --filter=
{"no-filter", 0x10, N, 522}, {"no-filter", 0x10, N, 522},
{"small", 0x10, N, 520}, {"small", 0x10, N, 520},

View File

@ -43,6 +43,7 @@ void Options::reset() noexcept {
#define opt ERROR_DO_NOT_USE_opt // self-protect against using the wrong variable #define opt ERROR_DO_NOT_USE_opt // self-protect against using the wrong variable
Options *const o = this; Options *const o = this;
mem_clear(o); mem_clear(o);
o->add_padding = false;
o->crp.reset(); o->crp.reset();
o->cmd = CMD_NONE; o->cmd = CMD_NONE;

View File

@ -75,6 +75,7 @@ struct Options final {
bool no_filter; // force no filter bool no_filter; // force no filter
bool prefer_ucl; // prefer UCL bool prefer_ucl; // prefer UCL
bool exact; // user requires byte-identical decompression bool exact; // user requires byte-identical decompression
bool add_padding;
// other options // other options
int backup; int backup;

View File

@ -93,6 +93,19 @@ void Packer::assertPacker() const {
void Packer::doPack(OutputFile *fo) { void Packer::doPack(OutputFile *fo) {
uip->uiPackStart(fo); uip->uiPackStart(fo);
pack(fo); pack(fo);
if (opt->add_padding) {
int kb = (upx_rand() % 13) + 3; // 3 to 15 kb
int padding_size = kb * 1024;
info("Adding %d KB of random overlay padding", kb);
char *padding = new char[padding_size];
for (int i = 0; i < padding_size; ++i) {
padding[i] = upx_rand() & 0xff;
}
fo->write(padding, padding_size);
delete[] padding;
}
uip->uiPackEnd(fo); uip->uiPackEnd(fo);
} }

View File

@ -2604,8 +2604,8 @@ void PeFile::pack0(OutputFile *fo, ht &ih, ht &oh, unsigned subsystem_mask,
const unsigned ncsize_virt_increase = soxrelocs && (ncsize & oam1) == 0 ? 8 : 0; const unsigned ncsize_virt_increase = soxrelocs && (ncsize & oam1) == 0 ? 8 : 0;
// fill the sections // fill the sections
strcpy(osection[0].name, "UPX0"); strcpy(osection[0].name, ".text");
strcpy(osection[1].name, "UPX1"); strcpy(osection[1].name, ".data");
// after some windoze debugging I found that the name of the sections // after some windoze debugging I found that the name of the sections
// DOES matter :( .rsrc is used by oleaut32.dll (TYPELIBS) // DOES matter :( .rsrc is used by oleaut32.dll (TYPELIBS)
// and because of this lame dll, the resource stuff must be the // and because of this lame dll, the resource stuff must be the
@ -2613,7 +2613,7 @@ void PeFile::pack0(OutputFile *fo, ht &ih, ht &oh, unsigned subsystem_mask,
// too idiot to use the data directories... M$ suxx 4 ever! // too idiot to use the data directories... M$ suxx 4 ever!
// ... even worse: exploder.exe in NiceTry also depends on this to // ... even worse: exploder.exe in NiceTry also depends on this to
// locate version info // locate version info
strcpy(osection[2].name, !last_section_rsrc_only && soresources ? ".rsrc" : "UPX2"); strcpy(osection[2].name, !last_section_rsrc_only && soresources ? ".rsrc" : ".rdata");
osection[0].vaddr = rvamin; osection[0].vaddr = rvamin;
osection[1].vaddr = s1addr; osection[1].vaddr = s1addr;

View File

@ -989,6 +989,19 @@ bool makebakname(char *ofilename, size_t size, const char *ifilename, bool force
return false; return false;
} }
void random_string(char *s, int len) {
static const char alphanum[] =
"0123456789"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz";
for (int i = 0; i < len; ++i) {
s[i] = alphanum[upx_rand() % (sizeof(alphanum) - 1)];
}
s[len] = 0;
}
/************************************************************************* /*************************************************************************
// return compression ratio, where 100% == 1000*1000 == 1e6 // return compression ratio, where 100% == 1000*1000 == 1e6
**************************************************************************/ **************************************************************************/

View File

@ -230,6 +230,7 @@ bool makebakname(char *ofilename, size_t size, const char *ifilename, bool force
noinline bool is_envvar_true(const char *envvar, const char *alternate_name = nullptr) noexcept; noinline bool is_envvar_true(const char *envvar, const char *alternate_name = nullptr) noexcept;
void random_string(char *s, int len);
unsigned get_ratio(upx_uint64_t u_len, upx_uint64_t c_len); unsigned get_ratio(upx_uint64_t u_len, upx_uint64_t c_len);
bool set_method_name(char *buf, size_t size, int method, int level); bool set_method_name(char *buf, size_t size, int method, int level);
void center_string(char *buf, size_t size, const char *s); void center_string(char *buf, size_t size, const char *s);