2009-12-13 13:39:20 -07:00
|
|
|
// Copyright 2009 The Go Authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
// PE (Portable Executable) file writing
|
|
|
|
// http://www.microsoft.com/whdc/system/platform/firmware/PECOFF.mspx
|
|
|
|
|
|
|
|
#include <time.h>
|
|
|
|
|
|
|
|
#include "l.h"
|
|
|
|
#include "../ld/lib.h"
|
|
|
|
#include "../ld/pe.h"
|
|
|
|
|
|
|
|
static int pe64;
|
|
|
|
static int nsect;
|
|
|
|
static int sect_virt_begin;
|
|
|
|
static int sect_raw_begin = PERESERVE;
|
|
|
|
|
|
|
|
static IMAGE_FILE_HEADER fh;
|
|
|
|
static IMAGE_OPTIONAL_HEADER oh;
|
|
|
|
static IMAGE_SECTION_HEADER sh[16];
|
|
|
|
static IMAGE_SECTION_HEADER *textsect, *datsect, *bsssect;
|
|
|
|
|
|
|
|
static IMAGE_SECTION_HEADER*
|
|
|
|
new_section(char *name, int size, int noraw)
|
|
|
|
{
|
|
|
|
IMAGE_SECTION_HEADER *h;
|
|
|
|
|
|
|
|
if(nsect == 16) {
|
|
|
|
diag("too many sections");
|
|
|
|
errorexit();
|
|
|
|
}
|
|
|
|
h = &sh[nsect++];
|
2010-02-01 16:20:19 -07:00
|
|
|
strncpy((char*)h->Name, name, sizeof(h->Name));
|
2009-12-13 13:39:20 -07:00
|
|
|
h->VirtualSize = size;
|
|
|
|
if(!sect_virt_begin)
|
|
|
|
sect_virt_begin = 0x1000;
|
|
|
|
h->VirtualAddress = sect_virt_begin;
|
|
|
|
sect_virt_begin = rnd(sect_virt_begin+size, 0x1000);
|
|
|
|
if(!noraw) {
|
|
|
|
h->SizeOfRawData = rnd(size, PEALIGN);
|
|
|
|
h->PointerToRawData = sect_raw_begin;
|
|
|
|
sect_raw_begin += h->SizeOfRawData;
|
|
|
|
}
|
|
|
|
return h;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
peinit(void)
|
|
|
|
{
|
|
|
|
switch(thechar) {
|
|
|
|
// 64-bit architectures
|
|
|
|
case '6':
|
|
|
|
pe64 = 1;
|
|
|
|
break;
|
|
|
|
// 32-bit architectures
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
pewrite(void)
|
|
|
|
{
|
|
|
|
int i, j;
|
|
|
|
|
|
|
|
strnput("MZ", 0x3c);
|
|
|
|
LPUT(0x40); // file offset to PE header
|
|
|
|
strnput("PE", 4);
|
|
|
|
|
|
|
|
for (i=0; i<sizeof(fh); i++)
|
|
|
|
cput(((char*)&fh)[i]);
|
|
|
|
for (i=0; i<sizeof(oh); i++)
|
|
|
|
cput(((char*)&oh)[i]);
|
|
|
|
for (i=0; i<nsect; i++)
|
|
|
|
for (j=0; j<sizeof(sh[i]); j++)
|
|
|
|
cput(((char*)&sh[i])[j]);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
dope(void)
|
|
|
|
{
|
|
|
|
textsect = new_section(".text", textsize, 0);
|
|
|
|
textsect->Characteristics = IMAGE_SCN_CNT_CODE|
|
|
|
|
IMAGE_SCN_CNT_INITIALIZED_DATA|
|
|
|
|
IMAGE_SCN_MEM_EXECUTE|IMAGE_SCN_MEM_READ;
|
|
|
|
|
|
|
|
datsect = new_section(".data", datsize, 0);
|
|
|
|
datsect->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA|
|
|
|
|
IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE;
|
|
|
|
INITDAT = PEBASE+datsect->VirtualAddress;
|
|
|
|
|
|
|
|
bsssect = new_section(".bss", bsssize, 1);
|
|
|
|
bsssect->Characteristics = IMAGE_SCN_CNT_UNINITIALIZED_DATA|
|
|
|
|
IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE;
|
|
|
|
}
|
|
|
|
|
2010-02-10 01:47:52 -07:00
|
|
|
static void
|
|
|
|
strput(char *s)
|
|
|
|
{
|
|
|
|
while(*s)
|
|
|
|
cput(*s++);
|
|
|
|
cput('\0');
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
add_import_table(void)
|
|
|
|
{
|
|
|
|
IMAGE_IMPORT_DESCRIPTOR ds[2], *d;
|
|
|
|
char *dllname = "kernel32.dll";
|
|
|
|
struct {
|
|
|
|
char *name;
|
|
|
|
uint32 thunk;
|
|
|
|
} *f, fs[] = {
|
|
|
|
{ "GetProcAddress", 0 },
|
|
|
|
{ "LoadLibraryExA", 0 },
|
|
|
|
{ 0, 0 }
|
|
|
|
};
|
|
|
|
|
|
|
|
uint32 size = 0;
|
|
|
|
memset(ds, 0, sizeof(ds));
|
|
|
|
size += sizeof(ds);
|
|
|
|
ds[0].Name = size;
|
|
|
|
size += strlen(dllname) + 1;
|
|
|
|
for(f=fs; f->name; f++) {
|
|
|
|
f->thunk = size;
|
|
|
|
size += sizeof(uint16) + strlen(f->name) + 1;
|
|
|
|
}
|
|
|
|
ds[0].FirstThunk = size;
|
|
|
|
for(f=fs; f->name; f++)
|
|
|
|
size += sizeof(fs[0].thunk);
|
|
|
|
|
|
|
|
IMAGE_SECTION_HEADER *isect;
|
|
|
|
isect = new_section(".idata", size, 0);
|
|
|
|
isect->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA|
|
|
|
|
IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE;
|
|
|
|
|
|
|
|
uint32 va = isect->VirtualAddress;
|
|
|
|
oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = va;
|
|
|
|
oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = isect->VirtualSize;
|
|
|
|
|
|
|
|
ds[0].Name += va;
|
|
|
|
ds[0].FirstThunk += va;
|
|
|
|
for(f=fs; f->name; f++)
|
|
|
|
f->thunk += va;
|
|
|
|
|
|
|
|
vlong off = seek(cout, 0, 1);
|
|
|
|
seek(cout, 0, 2);
|
|
|
|
for(d=ds; ; d++) {
|
|
|
|
lputl(d->OriginalFirstThunk);
|
|
|
|
lputl(d->TimeDateStamp);
|
|
|
|
lputl(d->ForwarderChain);
|
|
|
|
lputl(d->Name);
|
|
|
|
lputl(d->FirstThunk);
|
|
|
|
if(!d->Name)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
strput(dllname);
|
|
|
|
for(f=fs; f->name; f++) {
|
|
|
|
wputl(0);
|
|
|
|
strput(f->name);
|
|
|
|
}
|
|
|
|
for(f=fs; f->name; f++)
|
|
|
|
lputl(f->thunk);
|
|
|
|
strnput("", isect->SizeOfRawData - size);
|
|
|
|
cflush();
|
|
|
|
seek(cout, off, 0);
|
|
|
|
}
|
|
|
|
|
2009-12-13 13:39:20 -07:00
|
|
|
void
|
|
|
|
asmbpe(void)
|
|
|
|
{
|
|
|
|
switch(thechar) {
|
|
|
|
default:
|
|
|
|
diag("unknown PE architecture");
|
|
|
|
errorexit();
|
|
|
|
case '6':
|
|
|
|
fh.Machine = IMAGE_FILE_MACHINE_AMD64;
|
|
|
|
break;
|
|
|
|
case '8':
|
|
|
|
fh.Machine = IMAGE_FILE_MACHINE_I386;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!debug['s']) {
|
|
|
|
IMAGE_SECTION_HEADER *symsect;
|
|
|
|
symsect = new_section(".symdat", 8+symsize+lcsize, 0);
|
|
|
|
symsect->Characteristics = IMAGE_SCN_MEM_READ|
|
|
|
|
IMAGE_SCN_CNT_INITIALIZED_DATA;
|
|
|
|
}
|
|
|
|
|
2010-02-10 01:47:52 -07:00
|
|
|
add_import_table();
|
|
|
|
|
2009-12-13 13:39:20 -07:00
|
|
|
fh.NumberOfSections = nsect;
|
|
|
|
fh.TimeDateStamp = time(0);
|
|
|
|
fh.SizeOfOptionalHeader = sizeof(oh);
|
|
|
|
fh.Characteristics = IMAGE_FILE_RELOCS_STRIPPED|
|
|
|
|
IMAGE_FILE_EXECUTABLE_IMAGE|IMAGE_FILE_DEBUG_STRIPPED;
|
|
|
|
if(thechar == '8')
|
|
|
|
fh.Characteristics |= IMAGE_FILE_32BIT_MACHINE;
|
|
|
|
|
|
|
|
oh.Magic = 0x10b; // PE32
|
|
|
|
oh.MajorLinkerVersion = 1;
|
|
|
|
oh.MinorLinkerVersion = 0;
|
|
|
|
oh.SizeOfCode = textsect->SizeOfRawData;
|
|
|
|
oh.SizeOfInitializedData = datsect->SizeOfRawData;
|
|
|
|
oh.SizeOfUninitializedData = bsssect->SizeOfRawData;
|
|
|
|
oh.AddressOfEntryPoint = entryvalue()-PEBASE;
|
|
|
|
oh.BaseOfCode = textsect->VirtualAddress;
|
|
|
|
oh.BaseOfData = datsect->VirtualAddress;
|
|
|
|
|
|
|
|
oh.ImageBase = PEBASE;
|
|
|
|
oh.SectionAlignment = 0x00001000;
|
|
|
|
oh.FileAlignment = PEALIGN;
|
|
|
|
oh.MajorOperatingSystemVersion = 4;
|
|
|
|
oh.MinorOperatingSystemVersion = 0;
|
|
|
|
oh.MajorImageVersion = 1;
|
|
|
|
oh.MinorImageVersion = 0;
|
|
|
|
oh.MajorSubsystemVersion = 4;
|
|
|
|
oh.MinorSubsystemVersion = 0;
|
|
|
|
oh.SizeOfImage = sect_virt_begin;
|
|
|
|
oh.SizeOfHeaders = PERESERVE;
|
|
|
|
oh.Subsystem = 3; // WINDOWS_CUI
|
|
|
|
oh.SizeOfStackReserve = 0x00200000;
|
|
|
|
oh.SizeOfStackCommit = 0x00001000;
|
|
|
|
oh.SizeOfHeapReserve = 0x00100000;
|
|
|
|
oh.SizeOfHeapCommit = 0x00001000;
|
|
|
|
oh.NumberOfRvaAndSizes = 16;
|
|
|
|
|
|
|
|
pewrite();
|
|
|
|
}
|