win32/pe using nrv2e converted to ElfLinker

This commit is contained in:
László Molnár
2006-07-03 09:21:51 +02:00
parent ed9fd3f0e0
commit f0f465411f
5 changed files with 1667 additions and 856 deletions
+61 -61
View File
@@ -31,6 +31,7 @@
#include "filter.h" #include "filter.h"
#include "packer.h" #include "packer.h"
#include "p_w32pe.h" #include "p_w32pe.h"
#include "linker.h"
static const static const
#include "stub/i386-win32.pe.h" #include "stub/i386-win32.pe.h"
@@ -198,6 +199,12 @@ const int *PackW32Pe::getFilters() const
} }
Linker* PackW32Pe::newLinker() const
{
return new ElfLinkerX86;
}
bool PackW32Pe::testUnpackVersion(int version) const bool PackW32Pe::testUnpackVersion(int version) const
{ {
if (version != ph_version && ph_version != -1) if (version != ph_version && ph_version != -1)
@@ -259,6 +266,20 @@ int PackW32Pe::readFileHeader()
} }
static bool defineFilterSymbols(Linker *linker, const Filter *ft)
{
if (ft->id == 0)
return false;
assert(ft->calls > 0);
linker->defineSymbol("filter_cto", ft->cto);
linker->defineSymbol("filter_length",
(ft->id & 0xf) % 3 == 0 ? ft->calls :
ft->lastcall - ft->calls * 4);
return true;
}
/************************************************************************* /*************************************************************************
// interval handling // interval handling
**************************************************************************/ **************************************************************************/
@@ -1711,7 +1732,7 @@ int PackW32Pe::buildLoader(const Filter *ft)
addLoader("PEDEPHAK", NULL); addLoader("PEDEPHAK", NULL);
addLoader("PEMAIN20", NULL); addLoader("PEMAIN20", NULL);
if (use_clear_dirty_stack) if (use_clear_dirty_stack)
addLoader(ih.entry ? "PEDOJUMP_CLEARSTACK" : "PERETURN_CLEARSTACK", NULL); addLoader("CLEARSTACK", NULL);
addLoader("PEMAIN21", NULL); addLoader("PEMAIN21", NULL);
addLoader(ih.entry ? "PEDOJUMP" : "PERETURN", addLoader(ih.entry ? "PEDOJUMP" : "PERETURN",
"IDENTSTR,UPX1HEAD", "IDENTSTR,UPX1HEAD",
@@ -1930,11 +1951,6 @@ void PackW32Pe::pack(OutputFile *fo)
if (tlsindex && ((newvsize - ph.c_len - 1024 + oam1) &~ oam1) > tlsindex + 4) if (tlsindex && ((newvsize - ph.c_len - 1024 + oam1) &~ oam1) > tlsindex + 4)
tlsindex = 0; tlsindex = 0;
const unsigned lsize = getLoaderSize();
MemBuffer loader(lsize);
memcpy(loader,getLoader(),lsize);
patchPackHeader(loader, lsize);
int identsize = 0; int identsize = 0;
const unsigned codesize = getLoaderSection("IDENTSTR",&identsize); const unsigned codesize = getLoaderSection("IDENTSTR",&identsize);
assert(identsize > 0); assert(identsize > 0);
@@ -1970,11 +1986,7 @@ void PackW32Pe::pack(OutputFile *fo)
const unsigned myimport = ncsection + soresources - rvamin; const unsigned myimport = ncsection + soresources - rvamin;
// patch loader // patch loader
if (ih.entry) linker->defineSymbol("original_entry", ih.entry);
{
unsigned jmp_pos = find_le32(loader,codesize + 4,get_le32("JMPO"));
patch_le32(loader,codesize + 4,"JMPO",ih.entry - upxsection - jmp_pos - 4);
}
if (use_dep_hack) if (use_dep_hack)
{ {
// This works around a "protection" introduced in MSVCRT80, which // This works around a "protection" introduced in MSVCRT80, which
@@ -2003,70 +2015,58 @@ void PackW32Pe::pack(OutputFile *fo)
#else #else
// make sure we only touch the minimum number of pages // make sure we only touch the minimum number of pages
const unsigned addr = 0u - rvamin + swri; const unsigned addr = 0u - rvamin + swri;
patch_le32(loader, codesize, "SWRI", addr & 0xfff); // page offset linker->defineSymbol("swri", addr & 0xfff); // page offset
// check whether osection[0].flags and osection[1].flags // check whether osection[0].flags and osection[1].flags
// are on the same page // are on the same page
if ((addr & 0xfff) + 0x28 >= 0x1000) linker->defineSymbol("vp_size", ((addr & 0xfff) + 0x28 >= 0x1000) ?
patch_le32(loader, codesize, "IMGL", 0x2000); // two pages 0x2000 : 0x1000); // 2 pages or 1 page
else linker->defineSymbol("vp_base", addr &~ 0xfff); // page mask
patch_le32(loader, codesize, "IMGL", 0x1000); // one page
patch_le32(loader, codesize, "IMGB", addr &~ 0xfff); // page mask
#endif #endif
patch_le32(loader, codesize, "VPRO", myimport + get_le32(oimpdlls + 16) + 8); linker->defineSymbol("VirtualProtect", myimport + get_le32(oimpdlls + 16) + 8);
}
if (big_relocs & 6)
patch_le32(loader,codesize,"DELT", 0u - (unsigned) ih.imagebase - rvamin);
if (sorelocs && (soimport == 0 || soimport + cimports != crelocs))
patch_le32(loader,codesize,"BREL",crelocs);
if (soimport)
{
if (!isdll)
patch_le32(loader,codesize,"EXIT",myimport + get_le32(oimpdlls + 16) + 20);
patch_le32(loader,codesize,"GETP",myimport + get_le32(oimpdlls + 16) + 4);
if (kernel32ordinal)
patch_le32(loader,codesize,"K32O",myimport);
patch_le32(loader,codesize,"LOAD",myimport + get_le32(oimpdlls + 16));
patch_le32(loader,codesize,"IMPS",myimport);
patch_le32(loader,codesize,"BIMP",cimports);
} }
linker->defineSymbol("reloc_delt", 0u - (unsigned) ih.imagebase - rvamin);
linker->defineSymbol("start_of_relocs", crelocs);
linker->defineSymbol("ExitProcess", myimport + get_le32(oimpdlls + 16) + 20);
linker->defineSymbol("GetProcAddress", myimport + get_le32(oimpdlls + 16) + 4);
linker->defineSymbol("kernel32_ordinals", myimport);
linker->defineSymbol("LoadLibraryA", myimport + get_le32(oimpdlls + 16));
linker->defineSymbol("start_of_imports", myimport);
linker->defineSymbol("compressed_imports", cimports);
#if 0 #if 0
patch_le32(loader, codesize, "VALL", myimport + get_le32(oimpdlls + 16) + 12); patch_le32(loader, codesize, "VALL", myimport + get_le32(oimpdlls + 16) + 12);
patch_le32(loader, codesize, "VFRE", myimport + get_le32(oimpdlls + 16) + 16); patch_le32(loader, codesize, "VFRE", myimport + get_le32(oimpdlls + 16) + 16);
#endif #endif
if (patchFilter32(loader, codesize, &ft)) defineFilterSymbols(linker, &ft);
{ linker->defineSymbol("filter_buffer_start", ih.codebase - rvamin);
const unsigned texv = ih.codebase - rvamin; // FIXME patchDecompressor(loader, codesize);
if (texv)
patch_le32(loader, codesize, "TEXV", texv);
} // in case of overlapping decompression, this hack is needed,
patchDecompressor(loader, codesize); // because windoze zeroes the word pointed by tlsindex before
if (tlsindex) // it starts programs
{ linker->defineSymbol("tls_value", (tlsindex + 4 > s1addr) ?
// in case of overlapping decompression, this hack is needed, get_le32(obuf + tlsindex - s1addr - ic) : 0);
// because windoze zeroes the word pointed by tlsindex before linker->defineSymbol("tls_address", tlsindex - rvamin);
// it starts programs
if (tlsindex + 4 > s1addr) linker->defineSymbol("icon_delta", icondir_count - 1);
patch_le32(loader,codesize,"TLSV",get_le32(obuf + tlsindex - s1addr - ic)); linker->defineSymbol("icon_offset", ncsection + icondir_offset - rvamin);
else
patch_le32(loader,codesize,"TLSV",0); // bad guess
patch_le32(loader,codesize,"TLSA",tlsindex - rvamin);
}
if (icondir_count > 1)
{
if (icondir_count > 2)
patch_le16(loader,codesize,"DR",icondir_count - 1);
patch_le32(loader,codesize,"ICON",ncsection + icondir_offset - rvamin);
}
const unsigned esi0 = s1addr + ic; const unsigned esi0 = s1addr + ic;
patch_le32(loader,codesize,"EDI0", 0u - esi0 + rvamin); linker->defineSymbol("start_of_uncompressed", 0u - esi0 + rvamin);
patch_le32(loader,codesize,"ESI0", esi0 + ih.imagebase); linker->defineSymbol("start_of_compressed", esi0 + ih.imagebase);
ic = getLoaderSection("PEMAIN01") + 2 + upxsection;
linker->defineSymbol(isdll ? "PEISDLL1" : "PEMAIN01", upxsection);
linker->relocate();
const unsigned lsize = getLoaderSize();
MemBuffer loader(lsize);
memcpy(loader,getLoader(),lsize);
patchPackHeader(loader, lsize);
Reloc rel(1024); // new relocations are put here Reloc rel(1024); // new relocations are put here
rel.add(ic,3); rel.add(linker->getSymbolOffset("PEMAIN01") + 2, 3);
// new PE header // new PE header
memcpy(&oh,&ih,sizeof(oh)); memcpy(&oh,&ih,sizeof(oh));
+1
View File
@@ -68,6 +68,7 @@ protected:
virtual bool testUnpackVersion(int version) const; virtual bool testUnpackVersion(int version) const;
virtual int buildLoader(const Filter *ft); virtual int buildLoader(const Filter *ft);
virtual Linker* newLinker() const;
unsigned pe_offset; unsigned pe_offset;
bool isrtm; bool isrtm;
+5 -3
View File
@@ -509,9 +509,11 @@ i386-linux.kernel%.h : $(srcdir)/src/$$T.asm
i386-win32.pe% : tc_list = arch-i386 default i386-win32.pe% : tc_list = arch-i386 default
i386-win32.pe.h : $(srcdir)/src/$$T.asm i386-win32.pe.h : $(srcdir)/src/$$T.asm
$(call tc,pp-nasm) --MMD=$@ $< -o tmp/$T.tmp1 $(call tc,gcc) -c -x assembler-with-cpp $< -o tmp/$T.bin
$(call tc,app-nasm) tmp/$T.tmp1 tmp/$T.tmp2 $(call tc,m-objcopy) --strip-unneeded tmp/$T.bin
$(call tc,nasm) -f bin -l tmp/$T.bin.lst tmp/$T.tmp2 -o tmp/$T.bin $(call tc,m-objcopy) -R .text -R .data -R .bss tmp/$T.bin
$(call tc,m-objcopy) -R .note -R .comment tmp/$T.bin
$(call tc,m-objdump) -trwh tmp/$T.bin >> tmp/$T.bin
$(call tc,bin2h) --ident=nrv_loader tmp/$T.bin $@ $(call tc,bin2h) --ident=nrv_loader tmp/$T.bin $@
+1473 -629
View File
File diff suppressed because it is too large Load Diff
+127 -163
View File
@@ -1,3 +1,4 @@
/*
; l_w32pe.asm -- loader & decompressor for the w32/pe format ; l_w32pe.asm -- loader & decompressor for the w32/pe format
; ;
; This file is part of the UPX executable compressor. ; This file is part of the UPX executable compressor.
@@ -24,267 +25,230 @@
; Markus F.X.J. Oberhumer Laszlo Molnar ; Markus F.X.J. Oberhumer Laszlo Molnar
; <mfx@users.sourceforge.net> <ml1050@users.sourceforge.net> ; <mfx@users.sourceforge.net> <ml1050@users.sourceforge.net>
; ;
*/
#define UPX102 1
#include "arch/i386/macros2.ash"
%define UPX102 1
%define jmps jmp short
%define jmpn jmp near
%define jnzn jnz near
%define jbn jb near
%include "arch/i386/macros.ash"
BITS 32
SECTION .text
ORG 0
CPU 386 CPU 386
; ============= // =============
; ============= ENTRY POINT // ============= ENTRY POINT
; ============= // =============
%ifdef __PEISDLL1__ section PEISDLL1
cmp byte [esp + 8], 1 cmpb [esp + 8], 1
jnzn reloc_end_jmp jnz reloc_end_jmp
%endif; __PEMAIN01__ section PEMAIN01
pushad pusha
mov esi, 'ESI0' ; relocated mov esi, offset start_of_compressed // relocated
lea edi, [esi + 'EDI0'] lea edi, [esi + start_of_uncompressed]
%ifdef __PEICONS1__ section PEICONS1
inc word [edi + 'ICON'] incw [edi + icon_offset]
%else; __PEICONS2__ section PEICONS2
add word [edi + 'ICON'],'DR' addw [edi + icon_offset], offset icon_delta
%endif; __PEICONSZ__ section PETLSHAK
%ifdef __PETLSHAK__ movw [edi + tls_address], offset tls_value
mov dword [edi + 'TLSA'],'TLSV' section PEMAIN02
%endif; __PEMAIN02__
push edi push edi
mpass: or ebp, -1
or ebp, byte -1
; ============= // =============
; ============= DECOMPRESSION // ============= DECOMPRESSION
; ============= // =============
%include "arch/i386/nrv2b_d32.ash" //#include "arch/i386/nrv2b_d32.ash"
%include "arch/i386/nrv2d_d32.ash" //#include "arch/i386/nrv2d_d32.ash"
%include "arch/i386/nrv2e_d32.ash" //#include "arch/i386/nrv2e_d32.ash"
%include "arch/i386/lzma_d.ash" #include "arch/i386/nrv2e_d32_2.ash"
//#include "arch/i386/lzma_d.ash"
; ============= // =============
section PEMAIN10
pop esi // load vaddr
%ifdef __PEMULTIP__ // =============
lodsd // ============= CALLTRICK
add edi, eax // =============
jbn mpass
%endif; __PEMAIN10__
; ============= section PECTTPOS
pop esi ; load vaddr lea edi, [esi + filter_buffer_start]
section PECTTNUL
; =============
; ============= CALLTRICK
; =============
%ifdef __PECALLTR__
%ifdef __PECTTPOS__
lea edi, [esi + 'TEXV']
%else; __PECTTNUL__
mov edi, esi mov edi, esi
%endif; __PEDUMMY0__ // section PEDUMMY0
cjt32 esi cjt32 esi
%endif; __PEDUMMY1__
; ============= // =============
; ============= IMPORTS // ============= IMPORTS
; ============= // =============
%ifdef __PEIMPORT__ section PEIMPORT
lea edi, [esi + 'BIMP'] lea edi, [esi + compressed_imports]
next_dll: next_dll:
mov eax, [edi] mov eax, [edi]
or eax, eax or eax, eax
jz imports_done jzs imports_done
mov ebx, [edi+4] ; iat mov ebx, [edi+4] // iat
lea eax, [eax + esi + 'IMPS'] lea eax, [eax + esi + start_of_imports]
add ebx, esi add ebx, esi
push eax push eax
add edi, byte 8 add edi, 8
call [esi + 'LOAD'] ; LoadLibraryA call [esi + LoadLibraryA]
xchg eax, ebp xchg eax, ebp
next_func: next_func:
mov al, [edi] mov al, [edi]
inc edi inc edi
or al, al or al, al
jz next_dll jz next_dll
mov ecx, edi ; something > 0 mov ecx, edi // something > 0
%ifdef __PEIBYORD__ section PEIBYORD
jns byname jnss byname
%ifdef __PEK32ORD__ section PEK32ORD
jpe not_kernel32 jpe not_kernel32
mov eax, [edi] mov eax, [edi]
add edi, byte 4 add edi, 4
mov eax, [eax + esi + 'K32O'] mov eax, [eax + esi + kernel32_ordinals]
jmps next_imp jmps next_imp
not_kernel32: not_kernel32:
%endif; __PEIMORD1__ section PEIMORD1
movzx eax, word [edi] movzxw eax, [edi]
inc edi inc edi
push eax push eax
inc edi inc edi
db 0xb9 ; mov ecx,xxxx .byte 0xb9 // mov ecx,xxxx
byname: byname:
%endif; __PEIMPOR2__ section PEIMPOR2
push edi push edi
dec eax dec eax
repne repne
scasb scasb
push ebp push ebp
call [esi + 'GETP'] ; GetProcAddr call [esi + GetProcAddress]
or eax, eax or eax, eax
jz imp_failed jz imp_failed
next_imp: next_imp:
mov [ebx], eax mov [ebx], eax
add ebx, byte 4 add ebx, 4
jmps next_func jmps next_func
imp_failed: imp_failed:
%ifdef __PEIERDLL__ section PEIERDLL
popad popa
xor eax, eax xor eax, eax
retn 0x0c ret 0x0c
%else; __PEIEREXE__ section PEIEREXE
call [esi + 'EXIT'] ; ExitProcess call [esi + ExitProcess]
%endif; __PEIMDONE__ section PEIMDONE
imports_done: imports_done:
%endif; __PEIMPOR9__
; ============= // =============
; ============= RELOCATION // ============= RELOCATION
; ============= // =============
%ifdef __PERELOC1__ section PERELOC1
lea edi, [esi + 'BREL'] lea edi, [esi + start_of_relocs]
; __PERELOC2__ section PERELOC2
add edi, byte 4 add edi, 4
; __PERELOC3__ section PERELOC3
lea ebx, [esi - 4] lea ebx, [esi - 4]
reloc32 edi, ebx, esi reloc32 edi, ebx, esi
%endif; __PERELOC9__
; ============= // =============
; FIXME: depends on that in PERELOC1 edi is set!! // FIXME: depends on that in PERELOC1 edi is set!!
%ifdef __PERLOHI0__ section PERLOHI0
xchg edi, esi xchg edi, esi
lea ecx, [edi + 'DELT'] lea ecx, [edi + reloc_delt]
%endif; __PERLOHIZ__
%ifdef __PERELLO0__ section PERELLO0
db 0xA9 .byte 0xA9
rello0: rello0:
add [edi + eax], cx add [edi + eax], cx
lodsd lodsd
or eax, eax or eax, eax
jnz rello0 jnz rello0
%endif; __PERELLOZ__
; ============= // =============
%ifdef __PERELHI0__ section PERELHI0
shr ecx, 16 shr ecx, 16
db 0xA9 .byte 0xA9
relhi0: relhi0:
add [edi + eax], cx add [edi + eax], cx
lodsd lodsd
or eax, eax or eax, eax
jnz relhi0 jnz relhi0
%endif; __PERELHIZ__
; ============= // =============
%ifdef __PEDEPHAK__ section PEDEPHAK
mov ebp, [esi + 'VPRO'] ; VirtualProtect mov ebp, [esi + VirtualProtect]
lea edi, [esi + 'IMGB'] lea edi, [esi + vp_base]
mov ebx, 'IMGL' ; 0x1000 or 0x2000 mov ebx, offset vp_size // 0x1000 or 0x2000
push eax ; provide 4 bytes stack push eax // provide 4 bytes stack
push esp ; &lpflOldProtect on stack push esp // &lpflOldProtect on stack
push byte 4 ; PAGE_READWRITE push 4 // PAGE_READWRITE
push ebx push ebx
push edi push edi
call ebp call ebp
%if 0 #if 0
or eax, eax or eax, eax
jz pedep9 ; VirtualProtect failed jz pedep9 // VirtualProtect failed
%endif #endif
lea eax, [edi + 'SWRI'] lea eax, [edi + swri]
and byte [eax], 0x7f ; marks UPX0 non writeable andb [eax], 0x7f // marks UPX0 non writeable
and byte [eax + 0x28], 0x7f ; marks UPX1 non writeable andb [eax + 0x28], 0x7f // marks UPX1 non writeable
%if 0 #if 0
push esp push esp
push byte 2 ; PAGE_READONLY push 2 // PAGE_READONLY
%else #else
pop eax pop eax
push eax push eax
push esp push esp
push eax ; restore protection push eax // restore protection
%endif #endif
push ebx push ebx
push edi push edi
call ebp call ebp
pedep9: pedep9:
pop eax ; restore stack pop eax // restore stack
%endif; __PEDEPHAX__
; __PEMAIN20__ section PEMAIN20
popad popa
; clear the dirty stack // clear the dirty stack
%macro clearstack128 1 .macro clearstack128 tmp_reg
lea %1, [esp - 128] lea \tmp_reg, [esp - 128]
%%clearst0: c1:
push byte 0 push 0
cmp esp, %1 cmp esp, \tmp_reg
jnz %%clearst0 jnzs c1
sub esp, byte -128 sub esp, -128
%endmacro .endm
%ifdef __PERETURN_CLEARSTACK__ section CLEARSTACK
clearstack128 eax clearstack128 eax
%endif; __PERETURN_CLEARSTACK9__
%ifdef __PEDOJUMP_CLEARSTACK__
clearstack128 eax
%endif; __PEDOJUMP_CLEARSTACK9__
section PEMAIN21
; __PEMAIN21__
reloc_end_jmp: reloc_end_jmp:
%ifdef __PERETURN__ section PERETURN
xor eax, eax xor eax, eax
inc eax inc eax
retn 0x0C ret 0x0C
%else; __PEDOJUMP__ section PEDOJUMP
jmpn .1+'JMPO' jmp original_entry
.1:
%endif; __PEDUMMY3__
; ============= // =============
; ============= CUT HERE // ============= CUT HERE
; ============= // =============
%include "include/header.ash" #include "include/header2.ash"
eof: // vi:ts=8:et:nowrap
; __PETHEEND__
section .data
dd -1
dw eof
; vi:ts=8:et:nowrap