diff --git a/src/stub/util/armpe/.cvsignore b/src/stub/util/armpe/.cvsignore new file mode 100644 index 00000000..daeb35b4 --- /dev/null +++ b/src/stub/util/armpe/.cvsignore @@ -0,0 +1 @@ +armpe_tester diff --git a/src/stub/util/armpe/.gitignore b/src/stub/util/armpe/.gitignore new file mode 100644 index 00000000..daeb35b4 --- /dev/null +++ b/src/stub/util/armpe/.gitignore @@ -0,0 +1 @@ +armpe_tester diff --git a/src/stub/util/armpe/Makefile b/src/stub/util/armpe/Makefile new file mode 100644 index 00000000..c4a5badd --- /dev/null +++ b/src/stub/util/armpe/Makefile @@ -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 + diff --git a/src/stub/util/armpe/armpe_tester.c b/src/stub/util/armpe/armpe_tester.c new file mode 100644 index 00000000..8805c084 --- /dev/null +++ b/src/stub/util/armpe/armpe_tester.c @@ -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 + + + John F. Reiser + +*/ + +// arm-9tdmi-linux-gnu-gcc -Wl,--section-start,.interp=0x1000 armpe_tester.c + +#include +#include +#include +#include + +#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; +}