mirror of
https://github.com/upx/upx
synced 2025-09-28 19:06:07 +08:00
added an arm/linux based loader/tester for arm/pe files
committer: ml1050 <ml1050> 1145605029 +0000
This commit is contained in:
parent
4f2d1172dd
commit
76734f086d
1
src/stub/util/armpe/.cvsignore
Normal file
1
src/stub/util/armpe/.cvsignore
Normal file
|
@ -0,0 +1 @@
|
|||
armpe_tester
|
1
src/stub/util/armpe/.gitignore
vendored
Normal file
1
src/stub/util/armpe/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
armpe_tester
|
15
src/stub/util/armpe/Makefile
Normal file
15
src/stub/util/armpe/Makefile
Normal file
|
@ -0,0 +1,15 @@
|
|||
# Makefile for armpe_tester
|
||||
|
||||
SHELL = /bin/sh
|
||||
|
||||
all: armpe_tester
|
||||
|
||||
armpe_tester: armpe_tester.c
|
||||
arm-9tdmi-linux-gnu-gcc -Wl,--section-start,.interp=0x1000 -g -Wall -W -o $@ $<
|
||||
|
||||
mostlyclean clean distclean maintainer-clean:
|
||||
rm -f *.d *.o *.obj
|
||||
rm -f armpe_tester
|
||||
|
||||
.PHONY: all mostlyclean clean distclean maintainer-clean
|
||||
|
304
src/stub/util/armpe/armpe_tester.c
Normal file
304
src/stub/util/armpe/armpe_tester.c
Normal file
|
@ -0,0 +1,304 @@
|
|||
/* armpe_tester.c -- ARM/PE loader/tester for arm linux
|
||||
|
||||
This file is part of the UPX executable compressor.
|
||||
|
||||
Copyright (C) 1996-2006 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 1996-2006 Laszlo Molnar
|
||||
Copyright (C) 2000-2006 John F. Reiser
|
||||
All Rights Reserved.
|
||||
|
||||
UPX and the UCL library are free software; you can redistribute them
|
||||
and/or modify them under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; see the file COPYING.
|
||||
If not, write to the Free Software Foundation, Inc.,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
Markus F.X.J. Oberhumer Laszlo Molnar
|
||||
<mfx@users.sourceforge.net> <ml1050@users.sourceforge.net>
|
||||
|
||||
John F. Reiser
|
||||
<jreiser@users.sourceforge.net>
|
||||
*/
|
||||
|
||||
// arm-9tdmi-linux-gnu-gcc -Wl,--section-start,.interp=0x1000 armpe_tester.c
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/mman.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef i386
|
||||
# define UPX_MMAP_ADDRESS 0x20000000
|
||||
#else
|
||||
# define UPX_MMAP_ADDRESS 0x10000
|
||||
#endif
|
||||
|
||||
typedef unsigned short LE16;
|
||||
typedef unsigned long LE32;
|
||||
#define __attribute_packed
|
||||
|
||||
struct ddirs_t
|
||||
{
|
||||
LE32 vaddr;
|
||||
LE32 size;
|
||||
}
|
||||
__attribute_packed;
|
||||
|
||||
struct pe_header_t
|
||||
{
|
||||
// 0x0
|
||||
char _[4];
|
||||
LE16 cpu;
|
||||
LE16 objects;
|
||||
char __[12];
|
||||
LE16 opthdrsize;
|
||||
LE16 flags;
|
||||
// optional header
|
||||
char ___[4];
|
||||
LE32 codesize;
|
||||
// 0x20
|
||||
LE32 datasize;
|
||||
LE32 bsssize;
|
||||
LE32 entry;
|
||||
LE32 codebase;
|
||||
// 0x30
|
||||
LE32 database;
|
||||
// nt specific fields
|
||||
LE32 imagebase;
|
||||
LE32 objectalign;
|
||||
LE32 filealign;
|
||||
// 0x40
|
||||
char ____[16];
|
||||
// 0x50
|
||||
LE32 imagesize;
|
||||
LE32 headersize;
|
||||
LE32 chksum;
|
||||
LE16 subsystem;
|
||||
LE16 dllflags;
|
||||
// 0x60
|
||||
char _____[20];
|
||||
// 0x74
|
||||
LE32 ddirsentries;
|
||||
|
||||
struct ddirs_t ddirs[16];
|
||||
}
|
||||
__attribute_packed;
|
||||
|
||||
struct pe_section_t
|
||||
{
|
||||
char name[8];
|
||||
LE32 vsize;
|
||||
LE32 vaddr;
|
||||
LE32 size;
|
||||
LE32 rawdataptr;
|
||||
char _[12];
|
||||
LE32 flags;
|
||||
}
|
||||
__attribute_packed;
|
||||
|
||||
|
||||
struct exe_header_t
|
||||
{
|
||||
LE16 mz;
|
||||
LE16 m512;
|
||||
LE16 p512;
|
||||
char _[18];
|
||||
LE16 relocoffs;
|
||||
char __[34];
|
||||
LE32 nexepos;
|
||||
}
|
||||
__attribute_packed;
|
||||
|
||||
enum {
|
||||
PEDIR_EXPORT = 0,
|
||||
PEDIR_IMPORT = 1,
|
||||
PEDIR_RESOURCE = 2,
|
||||
PEDIR_EXCEPTION = 3,
|
||||
PEDIR_SEC = 4,
|
||||
PEDIR_RELOC = 5,
|
||||
PEDIR_DEBUG = 6,
|
||||
PEDIR_COPYRIGHT = 7,
|
||||
PEDIR_GLOBALPTR = 8,
|
||||
PEDIR_TLS = 9,
|
||||
PEDIR_LOADCONF = 10,
|
||||
PEDIR_BOUNDIM = 11,
|
||||
PEDIR_IAT = 12,
|
||||
PEDIR_DELAYIMP = 13,
|
||||
PEDIR_COMRT = 14
|
||||
};
|
||||
|
||||
#define get_le32(p) (*(unsigned *) (p))
|
||||
#define set_le32(p, v) (*(unsigned *) (p) = (v))
|
||||
#define get_le16(p) (*(unsigned short *) (p))
|
||||
|
||||
static struct pe_header_t ih;
|
||||
static struct pe_section_t isections[3];
|
||||
static FILE *f;
|
||||
static void *vaddr;
|
||||
|
||||
static int load(const char *file)
|
||||
{
|
||||
struct exe_header_t h;
|
||||
int ic;
|
||||
unsigned pe_offset = 0;
|
||||
|
||||
if ((f = fopen(file, "rb")) == NULL)
|
||||
return printf("can not open file: %s\n", file);
|
||||
|
||||
for (ic = 0; ic < 20; ic++)
|
||||
{
|
||||
if (fseek(f, pe_offset, SEEK_SET)
|
||||
|| fread(&h, sizeof(h), 1, f) != 1)
|
||||
return printf("read error at %u\n", pe_offset);
|
||||
|
||||
if (h.mz == 'M' + 'Z'*256) // dos exe
|
||||
{
|
||||
if (h.relocoffs >= 0x40) // new format exe
|
||||
pe_offset += h.nexepos;
|
||||
else
|
||||
pe_offset += h.p512 * 512 + h.m512 - h.m512 ? 512 : 0;
|
||||
}
|
||||
else if (get_le32(&h) == 'P' + 'E'*256)
|
||||
break;
|
||||
else
|
||||
return printf("bad header at %u\n", pe_offset);
|
||||
}
|
||||
if (ic == 20)
|
||||
return printf("pe header not found\n");
|
||||
if (fseek(f, pe_offset, SEEK_SET)
|
||||
|| fread(&ih, sizeof(ih), 1, f) != 1)
|
||||
return printf("can not load pe header\n");
|
||||
|
||||
if (ih.cpu != 0x1c0 && ih.cpu != 0x1c2)
|
||||
return printf("unsupported processor type: %x\n", ih.cpu);
|
||||
|
||||
if (ih.objects != 3 || fread(isections, sizeof(isections), 1, f) != 1)
|
||||
return printf("error reading section descriptors\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int read(void)
|
||||
{
|
||||
unsigned ic;
|
||||
vaddr = mmap((void *) UPX_MMAP_ADDRESS, ih.imagesize,
|
||||
PROT_WRITE | PROT_READ | PROT_EXEC,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
|
||||
if (((int) vaddr) == -1)
|
||||
return printf("mmap() failed: %d\n", errno);
|
||||
|
||||
for (ic = 1; ic <= 2; ic++)
|
||||
if (fseek(f, isections[ic].rawdataptr, SEEK_SET)
|
||||
|| fread(vaddr + isections[ic].vaddr,
|
||||
isections[ic].vsize, 1, f) != 1)
|
||||
return printf("error reading section %u\n", ic);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dump(char n)
|
||||
{
|
||||
char buf[100];
|
||||
snprintf(buf, sizeof(buf), "/tmp/a.dump%c", n);
|
||||
FILE *f2 = fopen(buf, "wb");
|
||||
fwrite(vaddr + 0x1000, ih.imagesize - 0x1000, 1, f2);
|
||||
fclose(f2);
|
||||
}
|
||||
|
||||
static int loadlibraryw(unsigned short *name)
|
||||
{
|
||||
return name[0] + name[1] * 0x100 + name[2] * 0x10000;
|
||||
}
|
||||
|
||||
static int getprocaddressa(unsigned h, const char *proc)
|
||||
{
|
||||
unsigned p = (unsigned) proc;
|
||||
if (p < 0x10000)
|
||||
{
|
||||
printf("getprocaddressa called %c%c%c, ordinal %u\n",
|
||||
h, h >> 8, h >> 16, p);
|
||||
return h + p * 0x10000;
|
||||
}
|
||||
printf("getprocaddressa called %c%c%c, name %s\n",
|
||||
h, h >> 8, h >> 16, proc);
|
||||
return h + proc[0] * 0x10000 + proc[1] * 0x1000000;
|
||||
}
|
||||
|
||||
static void cachesync(unsigned v)
|
||||
{
|
||||
printf("cachesync called %u\n", v);
|
||||
}
|
||||
|
||||
static int import(void)
|
||||
{
|
||||
if (ih.ddirs[PEDIR_IMPORT].vaddr == 0)
|
||||
return printf("no imports?\n");
|
||||
void *imports = vaddr + ih.ddirs[PEDIR_IMPORT].vaddr;
|
||||
void *coredll_imports = vaddr + get_le32(imports);
|
||||
set_le32(coredll_imports, (unsigned) loadlibraryw);
|
||||
set_le32(coredll_imports + 4, (unsigned) getprocaddressa);
|
||||
set_le32(coredll_imports + 8, (unsigned) cachesync);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int reloc(void)
|
||||
{
|
||||
if (ih.ddirs[PEDIR_RELOC].vaddr == 0)
|
||||
return 0;
|
||||
void *relocs = vaddr + ih.ddirs[PEDIR_RELOC].vaddr;
|
||||
void *page = vaddr + get_le32(relocs);
|
||||
unsigned size = get_le32(relocs + 4);
|
||||
if (size != ih.ddirs[PEDIR_RELOC].size)
|
||||
return printf("only 1 page can be relocated\n");
|
||||
unsigned num = (size - 8) / 2;
|
||||
while (num--)
|
||||
{
|
||||
unsigned pos = get_le16(relocs + 8 + num * 2);
|
||||
if (pos == 0)
|
||||
continue;
|
||||
if ((pos & 0xF000) != 0x3000)
|
||||
return printf("unknown relocation type: %x\n", pos);
|
||||
|
||||
void *r = page + (pos & 0xFFF);
|
||||
set_le32(r, get_le32(r) - ih.imagebase + (unsigned) vaddr);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void call(void)
|
||||
{
|
||||
#ifndef i386
|
||||
void (*entry)(unsigned, unsigned) = vaddr + ih.entry;
|
||||
entry(0, 1);
|
||||
dump('c');
|
||||
#endif
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if (argc != 2)
|
||||
return printf("usage: %s arm_pe_file\n", argv[0]), 1;
|
||||
if (load(argv[1]))
|
||||
return 2;
|
||||
if (read())
|
||||
return 3;
|
||||
dump('0');
|
||||
if (import())
|
||||
return 4;
|
||||
dump('i');
|
||||
if (reloc())
|
||||
return 5;
|
||||
dump('r');
|
||||
|
||||
call();
|
||||
printf("ok.\n");
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user