Skip to content

Instantly share code, notes, and snippets.

@shinaisan
Created July 10, 2012 14:13
Show Gist options
  • Save shinaisan/3083539 to your computer and use it in GitHub Desktop.
Save shinaisan/3083539 to your computer and use it in GitHub Desktop.
Example generation of a PE file targeted for Windows CE/MIPS. (getchar() -> MessageBoxW())
/* Example generation of a PE file targeted for Windows CE/MIPS. (getchar() -> MessageBoxW()) */
/* To build w/ MSVC: cl pegen.c */
/* To generate a PE: pegen <arbitrary_number> <output_file_name.exe> */
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
typedef uint32_t inst_t;
/* Configuration start. */
static char text[512] = {0};
static char idata[512] = {0};
inst_t addr_image = 0x00010000;
inst_t addr_text_base = 0x1000;
inst_t addr_idata_base = 0x2000;
inst_t addr_data_base = 0x3000;
/* Configuration end. */
/* These are determined at run time. */
static int idata_size = 0;
inst_t addr_MessageBoxW = 0;
inst_t addr_wsprintfW = 0;
inst_t addr_getchar;
inst_t addr_buffer = 0;
inst_t addr_format = 0;
inst_t addr_caption = 0;
/* A total of 32 registers. */
typedef enum {
REG_ZERO = 0,
REG_AT,
REG_V0,
REG_V1,
REG_A0,
REG_A1,
REG_A2,
REG_A3,
REG_T0,
REG_T1,
REG_T2,
REG_T3,
REG_T4,
REG_T5,
REG_T6,
REG_T7,
REG_S0,
REG_S1,
REG_S2,
REG_S3,
REG_S4,
REG_S5,
REG_S6,
REG_S7,
REG_T8,
REG_T9,
REG_K0,
REG_K1,
REG_GP,
REG_SP,
REG_FP,
REG_RA,
} mips_reg_t;
#define MIPS_INST_NOP (0x00000000)
#define MIPS_INST_ADDIU(reg0, reg1, imm) (0x24000000 | (reg0 << 16) | (reg1 << 21) | (imm & 0xffff))
#define MIPS_INST_SB(reg0, reg1, disp) (0xa0000000 | (reg0 << 16) | (reg1 << 21) | (disp & 0xffff))
#define MIPS_INST_SW(reg0, reg1, disp) (0xac000000 | (reg0 << 16) | (reg1 << 21) | (disp & 0xffff))
#define MIPS_INST_LB(reg0, reg1, disp) (0x80000000 | (reg0 << 16) | (reg1 << 21) | (disp & 0xffff))
#define MIPS_INST_LW(reg0, reg1, disp) (0x8c000000 | (reg0 << 16) | (reg1 << 21) | (disp & 0xffff))
#define MIPS_INST_ADD(reg0, reg1, reg2) (0x00000020 | (reg0 << 11) | (reg1 << 21) | (reg2 << 16))
#define MIPS_INST_AND(reg0, reg1, reg2) (0x00000024 | (reg0 << 11) | (reg1 << 21) | (reg2 << 16))
#define MIPS_INST_ADDU(reg0, reg1, reg2) (0x00000021 | (reg0 << 11) | (reg1 << 21) | (reg2 << 16))
#define MIPS_INST_ADDI(reg0, reg1, imm) (0x20000000 | (reg0 << 16) | (reg1 << 21) | (imm & 0xffff))
#define MIPS_INST_ANDI(reg0, reg1, imm) (0x30000000 | (reg0 << 16) | (reg1 << 21) | (imm & 0xffff))
#define MIPS_INST_SRL(reg0, reg1, sa) (0x00000002 | (reg0 << 11) | (reg1 << 16) | (sa << 6))
#define MIPS_INST_MOVE(reg0, reg1) MIPS_INST_ADDU(reg0, REG_ZERO, reg1)
#define MIPS_INST_LUI(reg0, imm) (0x3c000000 | (reg0 << 16) | (imm & 0xffff))
#define MIPS_INST_ORI(reg0, reg1, imm) (0x34000000 | (reg0 << 16) | (reg1 << 21) | (imm & 0xffff))
#define MIPS_INST_LI(reg0, imm) MIPS_INST_ORI(reg0, REG_ZERO, imm)
#define MIPS_INST_JR(reg0) (0x00000008 | (reg0 << 21))
#define MIPS_INST_JALR(ret, dest) (0x00000009 | (ret << 11) | (dest << 21))
#define MIPS_INST_BEQ(reg0, reg1, dest) (0x10000000 | (reg0 << 21) | (reg1 << 16) | (dest & 0xffff))
#define MIPS_INST_BEQZ(reg0, dest) MIPS_INST_BEQ(reg0, REG_ZERO, dest)
#define MIPS_INST_B(dest) MIPS_INST_BEQ(REG_ZERO, REG_ZERO, dest)
#define MIPS_INST_BREAK (0x0000000d)
int make_text(inst_t *dest, int inst_max) {
int idx = 0;
if (inst_max < 32) {
/* The lower limit of 32 is not carefully chosen but it's enough for holding the prolog and epilog. */
printf("Output buffer is too short: %d, expected more than (or equal to) 32.\n", inst_max);
return (-1);
}
memset((void *)dest, 0, inst_max * sizeof(inst_t));
/* addiu $sp, $sp, -24 */
dest[idx++] = MIPS_INST_ADDIU(REG_SP, REG_SP, -24);
/* sw $ra, 16($sp) */
dest[idx++] = MIPS_INST_SW(REG_RA, REG_SP, 16);
/* sw $s3, 12($sp) */
dest[idx++] = MIPS_INST_SW(REG_S3, REG_SP, 12);
/* sw $s2, 8($sp) */
dest[idx++] = MIPS_INST_SW(REG_S2, REG_SP, 8);
/* sw $s1, 4($sp) */
dest[idx++] = MIPS_INST_SW(REG_S1, REG_SP, 4);
/* sw $s0, 0($sp) */
dest[idx++] = MIPS_INST_SW(REG_S0, REG_SP, 0);
/* move $v0, $zero */
dest[idx++] = MIPS_INST_MOVE(REG_V0, REG_ZERO);
/* lui $v0, (getchar >> 16) */
dest[idx++] = MIPS_INST_LUI(REG_V0, (addr_getchar >> 16));
/* ori $v0, $v0, (getchar & 0xffff) */
dest[idx++] = MIPS_INST_ORI(REG_V0, REG_V0, (addr_getchar & 0xffff));
/* lw $v0, 0($v0) */
dest[idx++] = MIPS_INST_LW(REG_V0, REG_V0, 0);
/* jalr $v0 */
dest[idx++] = MIPS_INST_JALR(REG_RA, REG_V0);
/* nop */
dest[idx++] = MIPS_INST_NOP;
/* lui $a0, 0x0001 */
dest[idx++] = MIPS_INST_LUI(REG_A0, (addr_buffer >> 16));
/* ori $a0, $a0, 0x3020 */
dest[idx++] = MIPS_INST_ORI(REG_A0, REG_A0, (addr_buffer & 0xffff)); /* buffer */
/* lui $a1, 0x0001 */
dest[idx++] = MIPS_INST_LUI(REG_A1, (addr_format >> 16));
/* ori $a1, $a1, 0x3010 */
dest[idx++] = MIPS_INST_ORI(REG_A1, REG_A1, (addr_format & 0xffff)); /* %d */
/* move $a2, $v0(getchar) */
dest[idx++] = MIPS_INST_MOVE(REG_A2, REG_V0);
/* move $v0, $zero */
dest[idx++] = MIPS_INST_MOVE(REG_V0, REG_ZERO);
/* lui $v0, (wsprintfW >> 16) */
dest[idx++] = MIPS_INST_LUI(REG_V0, (addr_wsprintfW >> 16));
/* ori $v0, $v0, (wsprintfW & 0xffff) */
dest[idx++] = MIPS_INST_ORI(REG_V0, REG_V0, (addr_wsprintfW & 0xffff));
/* lw $v0, 0($v0) */
dest[idx++] = MIPS_INST_LW(REG_V0, REG_V0, 0);
/* jalr $v0 */
dest[idx++] = MIPS_INST_JALR(REG_RA, REG_V0);
/* nop */
dest[idx++] = MIPS_INST_NOP;
/* move $a0, $zero */
dest[idx++] = MIPS_INST_MOVE(REG_A0, REG_ZERO);
/* lui $a1, 0x0001 */
dest[idx++] = MIPS_INST_LUI(REG_A1, (addr_buffer >> 16));
/* ori $a1, $a1, 0x3020 */
dest[idx++] = MIPS_INST_ORI(REG_A1, REG_A1, (addr_buffer & 0xffff)); /* buffer */
/* lui $a2, 0x0001 */
dest[idx++] = MIPS_INST_LUI(REG_A2, (addr_caption >> 16));
/* ori $a2, $a2, 0x3000 */
dest[idx++] = MIPS_INST_ORI(REG_A2, REG_A2, (addr_caption & 0xffff)); /* Message */
/* move $a3, $zero */
dest[idx++] = MIPS_INST_MOVE(REG_A3, REG_ZERO);
/* move $v0, $zero */
dest[idx++] = MIPS_INST_MOVE(REG_V0, REG_ZERO);
/* lui $v0, (MessageBoxW >> 16) */
dest[idx++] = MIPS_INST_LUI(REG_V0, (addr_MessageBoxW >> 16));
/* ori $v0, $v0, (MessageBoxW & 0xffff) */
dest[idx++] = MIPS_INST_ORI(REG_V0, REG_V0, (addr_MessageBoxW & 0xffff));
/* lw $v0, 0($v0) */
dest[idx++] = MIPS_INST_LW(REG_V0, REG_V0, 0);
/* jalr $v0 */
dest[idx++] = MIPS_INST_JALR(REG_RA, REG_V0);
/* nop */
dest[idx++] = MIPS_INST_NOP;
/* lw $s0, 0($sp) */
dest[idx++] = MIPS_INST_LW(REG_S0, REG_SP, 0);
/* lw $s1, 4($sp) */
dest[idx++] = MIPS_INST_LW(REG_S1, REG_SP, 4);
/* lw $s2, 8($sp) */
dest[idx++] = MIPS_INST_LW(REG_S2, REG_SP, 8);
/* lw $s3, 12($sp) */
dest[idx++] = MIPS_INST_LW(REG_S3, REG_SP, 12);
/* lw $ra, 16($sp) */
dest[idx++] = MIPS_INST_LW(REG_RA, REG_SP, 16);
/* jr $ra */
dest[idx++] = MIPS_INST_JR(REG_RA);
/* addiu $sp, $sp, 24 */
dest[idx++] = MIPS_INST_ADDIU(REG_SP, REG_SP, 24);
return (idx);
}
void write_padding(FILE *fp, int n) {
while (n-- > 0) {
fputc(0, fp);
}
}
void write_string(FILE *fp, int len, char *str) {
while ((*str) && (len-- > 0)) {
fputc(*str++, fp);
}
while (len-- > 0) {
fputc(0, fp);
}
}
void write_pe_header(FILE *fp) {
static unsigned char stub[] = {
/* 00-3b: DOS Header */
'M', 'Z', 0x50, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x00,
0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 3c-3f: Pointer to PE Header (=80) */
0x80, 0x00, 0x00, 0x00,
/* 40-7f: DOS stub */
0xba, 0x10, 0x00, 0x0e, 0x1f, 0xb4, 0x09, 0xcd, 0x21, 0xb8, 0x01, 0x4c, 0xcd, 0x21, 0x90, 0x90,
'T', 'h', 'i', 's', ' ', 'p', 'r', 'o', 'g', 'r', 'a', 'm', ' ', 'c', 'a', 'n',
'n', 'o', 't', ' ', 'b', 'e', ' ', 'r', 'u', 'n', ' ', 'i', 'n', ' ', 'D', 'O',
'S', ' ', 'm', 'o', 'd', 'e', '.', '\r', '\n', '$', 0, 0, 0, 0, 0, 0,
/* 80-83: PE Signature */
'P', 'E', 0, 0
};
IMAGE_FILE_HEADER coff = {
0x0166, 3, 0, 0, 0, sizeof(IMAGE_OPTIONAL_HEADER32), 0x030f
};
IMAGE_OPTIONAL_HEADER32 opt = {
0x010b, /* Magic */
6, 0, /* MajorLinkerVersion, MinorLinkerVersion */
sizeof(text), /* SizeOfCode */
512, /* SizeOfInitializedData */
0, /* SizeOfUninitializedData */
addr_text_base, /* AddressOfEntryPoint */
addr_text_base, /* BaseOfCode */
addr_data_base, /* BaseOfData */
addr_image, /* ImageBase */
0x1000, /* SectionAlignment */
0x0200, /* FileAlignment */
4, 0, /* MajorOperatingSystemVersion, MinorOperatingSystemVersion */
0, 0, /* MajorImageVersion, MinorImageVersion */
2, 0, /* MajorSubsystemVersion, MinorSubsystemVersion */
0, /* Win32VersionValue */
0x00004000, /* SizeOfImage */
0x200, /* SizeOfHeaders */
0, /* CheckSum */
9, /* Subsystem */
0, /* DllCharacteristics */
1024*1024, /* SizeOfStackReserve */
8*1024, /* SizeOfStackCommit */
1024*1024, /* SizeOfHeapReserve */
4*1024, /* SizeOfHeapCommit */
0, /* LoaderFlags */
16 /* NumberOfRvaAndSizes */
};
IMAGE_SECTION_HEADER sects[3];
fwrite(stub, sizeof(stub), 1, fp);
fwrite(&coff, sizeof(coff), 1, fp);
memset(opt.DataDirectory, 0, sizeof(opt.DataDirectory));
opt.DataDirectory[1].VirtualAddress = addr_idata_base; /* import table */
opt.DataDirectory[1].Size = idata_size;
fwrite(&opt, sizeof(opt), 1, fp);
memset(sects, 0, sizeof(sects));
strcpy((char *)sects[0].Name, ".text");
sects[0].Misc.VirtualSize = sizeof(text);
sects[0].VirtualAddress = addr_text_base;
sects[0].SizeOfRawData = (sizeof(text) + 511) / 512 * 512;
sects[0].PointerToRawData = 0x600;
sects[0].Characteristics = 0x60000020;
strcpy((char *)sects[1].Name, ".idata");
sects[1].Misc.VirtualSize = idata_size;
sects[1].VirtualAddress = addr_idata_base;
sects[1].SizeOfRawData = 512;
sects[1].PointerToRawData = 0x200;
sects[1].Characteristics = 0xc0000040;
strcpy((char *)sects[2].Name, ".data");
sects[2].Misc.VirtualSize = 512;
sects[2].VirtualAddress = addr_data_base;
sects[2].SizeOfRawData = 512;
sects[2].PointerToRawData = 0x400;
sects[2].Characteristics = 0xc0000040;
fwrite(sects, sizeof(sects), 1, fp);
write_padding(fp, 0x200 - ftell(fp));
}
/* Should be called before write_pe_header(). */
int make_idata(char *buf) {
int size = 0;
int cpysize = 0;
int idt[] = {
// IDT 1
0x2028, 0, 0, 0x2038, 0x2048,
// IDT (Terminator)
0, 0, 0, 0, 0
};
int ilt_iat[] = {0x2058, 0x2066, 0x2072, 0};
addr_MessageBoxW = addr_image + 0x2048;
addr_wsprintfW = addr_MessageBoxW + 4;
addr_getchar = addr_wsprintfW + 4;
// IDT
cpysize = sizeof(idt);
memcpy((void *)buf, (void *)&idt[0], cpysize);
buf += cpysize;
size += cpysize;
// ILT
cpysize = sizeof(ilt_iat);
memcpy((void *)buf, (void *)&ilt_iat[0], cpysize);
buf += cpysize;
size += cpysize;
// DLL
cpysize = 16;
memset(buf, 0, cpysize);
strcpy(buf, "coredll.dll");
buf += cpysize;
size += cpysize;
// IAT
cpysize = sizeof(ilt_iat);
memcpy((void *)buf, (void *)&ilt_iat[0], cpysize);
buf += cpysize;
size += cpysize;
// MessageBoxW
cpysize = 14;
memset(buf, 0, cpysize);
buf += 2;
strcpy(buf, "MessageBoxW");
buf += (cpysize - 2);
size += cpysize;
// wsprintfW
cpysize = 12;
memset(buf, 0, cpysize);
buf += 2;
strcpy(buf, "wsprintfW");
buf += (cpysize - 2);
size += cpysize;
// getchar
cpysize = 10;
memset(buf, 0, cpysize);
buf += 2;
strcpy(buf, "getchar");
buf += (cpysize - 2);
size += cpysize;
return (idata_size = size);
}
void write_data(FILE *fp) {
addr_caption = addr_image + addr_data_base;
addr_format = addr_caption + 16;
addr_buffer = addr_format + 16;
fwrite("M\0e\0s\0s\0a\0g\0e\0\0\0", 1, 16, fp);
fwrite("%\0d\0", 1, 4, fp);
write_padding(fp, 0x600 - ftell(fp));
}
int write_pe(FILE *out) {
memset(idata, 0, sizeof(idata));
make_idata(idata);
write_pe_header(out);
fwrite(idata, 1, sizeof(idata), out);
write_data(out);
make_text((inst_t *)(&text[0]), sizeof(text) / sizeof(inst_t));
fwrite(text, 1, sizeof(text), out);
return (0);
}
int main(int argc, char *argv[]) {
char *exe_path = NULL;
FILE *exe_file = NULL;
int ret = 0;
if (argc < 2) {
printf("[USAGE] %s <output file name(exe)>\n", argv[0]);
return (-1);
}
exe_path = argv[1];
exe_file = fopen(exe_path, "wb");
if (!exe_file) {
printf("Cannot create file: %s\n", exe_path);
ret = -1;
goto main_end;
}
write_pe(exe_file);
main_end:
if (exe_file) {
fclose(exe_file);
}
return (ret);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment