/* $Id: pe.c,v 1.2 2021/11/06 17:35:07 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 #include #include #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]; (void) signature; 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(×tamp, &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; }