ÜberWall

UWfirmforce

/* $Id: pe.c,v 1.1 2009/02/21 21:25:20 khorben Exp $ */
/* Copyright (c) 2007 khorben of Uberwall */
/* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation version 2 of the License.
*
* 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; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include <stdint.h>
#include <string.h>
#include <time.h>
#include "plugin.h"
/* pe */
/* public */
/* types */
#pragma pack(1)
struct pe_hdr
{
char sig[4];
uint16_t machine;
uint16_t sectioncnt;
uint32_t timestamp;
uint32_t symbol;
uint32_t symbolcnt;
uint16_t opthdrsize;
uint16_t flags;
};
#pragma pack()
/* variables */
/* magic */
static unsigned char mz[] = "MZ";
static unsigned char dosmode[] = "This program cannot be run in DOS mode";
static unsigned char win32[] = "This program must be run under Win32";
static unsigned char pe[] = "PE\0\0";
static PluginMagic pe_magic[] =
{
{ 0, 0, pe, sizeof(pe)-1 },
{ 0, 78, dosmode, sizeof(dosmode)-1 },
{ 0, 80, win32, sizeof(win32)-1 },
{ 0, 0, mz, sizeof(mz)-1 },
{ 0, 0, NULL, 0 }
};
/* functions */
static int pe_callback(PluginHelper * ph, int signature, FILE * fp);
/* plugin */
Plugin plugin =
{
PT_EXECUTABLE,
"PE",
pe_magic,
pe_callback
};
/* private */
/* functions */
/* pe_callback */
static int _callback_mz(PluginHelper * ph, char * buf);
static int _callback_pe(PluginHelper * ph, char * buf);
static int pe_callback(PluginHelper * ph, int signature, FILE * fp)
{
char buf[260];
if(fread(buf, sizeof(char), sizeof(buf), fp) != sizeof(buf))
return -1;
if(buf[0] == 'M' && buf[1] == 'Z')
return _callback_mz(ph, buf);
if(memcmp(buf, pe, sizeof(pe)-1) != 0)
return -1;
return _callback_pe(ph, buf);
}
static int _callback_mz(PluginHelper * ph, char * buf)
{
uint8_t offset = buf[0x3c];
if(memcmp(&buf[offset], pe, sizeof(pe)-1) != 0)
{
ph->printf(ph, "%s", "no PE header found\n");
return 0;
}
ph->printf(ph, "%s%x\n", "PE header is at 0x", offset);
return 100;
}
static void _pe_endian(struct pe_hdr * pe);
static int _pe_machine(PluginHelper * ph, uint16_t machine);
static int _pe_timestamp(PluginHelper * ph, time_t timestamp);
static int _pe_flags(PluginHelper * ph, uint16_t flags);
static int _callback_pe(PluginHelper * ph, char * buf)
{
int score = 0;
struct pe_hdr * pe = (struct pe_hdr *)buf;
_pe_endian(pe);
score += _pe_machine(ph, pe->machine);
ph->printf(ph, "%s%u%s", ", ", pe->sectioncnt, " sections");
if(pe->sectioncnt < 96)
score += 100;
score += _pe_timestamp(ph, pe->timestamp);
if(pe->symbol == 0)
score += 100;
if(pe->symbolcnt == 0)
score += 100;
score += _pe_flags(ph, pe->flags);
ph->printf(ph, "\n");
return score / 6;
}
static void _pe_endian(struct pe_hdr * pe)
{
pe->machine = htol16(pe->machine);
pe->sectioncnt = htol16(pe->sectioncnt);
pe->timestamp = htol32(pe->timestamp);
pe->flags = htol16(pe->flags);
}
static int _pe_machine(PluginHelper * ph, uint16_t machine)
{
struct
{
uint16_t machine;
char * name;
} mn[] =
{
{ 0x0000, "any" },
{ 0x01d3, "Matsushita AM33" },
{ 0x8664, "x64" },
{ 0x01c0, "ARM little-endian" },
{ 0x0ebc, "EFI byte code" },
{ 0x014c, "i386" },
{ 0x0200, "Itanium" },
{ 0x9041, "Mitsubishi M32R little-endian" },
{ 0x0266, "MIPS16" },
{ 0x0366, "MIPS with FPU" },
{ 0x0466, "MIPS16 with FPU" },
{ 0x01f0, "PPC little-endian" },
{ 0x01f1, "PPC with FPU" },
{ 0x0166, "MIPS little-endian" },
{ 0x01a2, "Hitachi SH3" },
{ 0x01a3, "Hitachi SH3 DSP" },
{ 0x01a6, "Hitachi SH4" },
{ 0x01a8, "Hitachi SH5" },
{ 0x01c2, "Thumb" },
{ 0x0169, "MIPS little-endian WCE v2" },
{ 0x0000, NULL }
};
size_t i;
for(i = 0; mn[i].name != NULL && mn[i].machine != machine; i++);
if(mn[i].name == NULL)
{
ph->printf(ph, "%s", "unknown machine");
return 0;
}
ph->printf(ph, "%s%s", "machine ", mn[i].name);
return 100;
}
static int _pe_timestamp(PluginHelper * ph, time_t timestamp)
{
struct tm tm;
char tmp[22] = "";
if(gmtime_r(&timestamp, &tm) == NULL || strftime(tmp, sizeof(tmp),
", %d/%m/%Y %H:%M:%S", &tm) == 0)
{
ph->printf(ph, "%s", ", unknown date");
return 0;
}
ph->printf(ph, "%s", tmp);
return timestamp < time(NULL) ? 100 : 0;
}
static int _pe_flags(PluginHelper * ph, uint16_t flags)
{
int score = 0;
struct
{
uint16_t flag;
char * name;
int score;
} fns[] =
{
{ 0x0001, "not relocatable", 100 },
{ 0x0002, "executable", 100 },
{ 0x0004, "lines stripped", 50 },
{ 0x0008, "symbols stripped", 50 },
{ 0x0010, "aggressive", 0 },
{ 0x0020, "large addresses", 100 },
{ 0x0040, "reserved", 0 },
{ 0x0080, "little-endian", 0 },
{ 0x0100, "32-bits", 100 },
{ 0x0200, "stripped", 100 },
{ 0x0400, "cache if removable", 100 },
{ 0x0800, "cache if network", 100 },
{ 0x1000, "system file", 100 },
{ 0x2000, "DLL", 100 },
{ 0x4000, "uniprocessor", 100 },
{ 0x8000, "big-endian", 0 },
{ 0x0000, NULL, 0 }
};
size_t i;
int cnt;
char * sep = "";
ph->printf(ph, "%s%04x%s", ", flags 0x", flags, " (");
for(i = 0, cnt = 0; fns[i].name != NULL; i++)
{
if((flags & fns[i].flag) != fns[i].flag)
continue;
cnt++;
ph->printf(ph, "%s%s", sep, fns[i].name);
score += fns[i].score;
sep = "|";
}
ph->printf(ph, ")");
return cnt != 0 ? score / cnt : 0;
}