/* trimexe.c * * A small program for extracting PE files from small chunks * of raw data. This is designed to fish executables out of the * reassembled raw data you can get from "follow TCP stream" in * wireshark, for example. * * At the moment it finds the first PE file in the stream and uses * the PE coff and section header data to compute the file size * of the executable. Output of various header values and offsets * is in hex and decimal to save a trip to the calculator. * * It then opens a temporary file in . and carves the file out * of the image based on the offset of MZ and * the size. * * Code is ugly but commented, probably not enough error checking, * but if fseek fails, you have bigger problems than I. * * Written for SANS network forensics puzzle contest #6 * Copyright 2010 Candice Quates, license GPL. */ #include #include #include int main(int argc, char *argv[]) { long mzoffset; long peoffset; long filesize; unsigned int sections; FILE *source; FILE *dest; unsigned int i,j,k,l; int destfd; char tmpname[14] = "./pefileXXXXX"; if (argc==2) { printf("filename: %s\n",argv[1]); } else { fprintf(stderr, "usage: %s filename", argv[0]); exit (1); } // open file source=fopen(argv[1],"r"); if (source == NULL) { fprintf(stderr,"error: %s, %s\n", argv[0],strerror(errno)); exit(1); } // search for MZ j=0; while (j!=EOF) { k=j; j=fgetc(source); if (j=='Z' && k=='M') { mzoffset=ftell(source); mzoffset=mzoffset-2; break; } } if (j==EOF) { fprintf(stderr,"I cannot find an executable file here.\n"); exit(1); } fprintf(stdout,"MZ located %d %x\n",mzoffset,mzoffset); // fseek(source,0x3c,SEEK_CUR); // offset to PEoffset // I should be chasing offsets here. but this is easier. // search for PE while (j!=EOF) { k=j; j=fgetc(source); if (j=='E' && k=='P') { peoffset=ftell(source); peoffset=peoffset-2; break; } } if (j==EOF) { fprintf(stderr,"I cannot find an executable file here.\n"); exit(1); } fprintf(stdout,"PE located %d %x\n",peoffset,peoffset); // the section count is a few bytes further. +2, but need +2 for 00 fseek(source,4,SEEK_CUR); sections=fgetc(source); fprintf(stdout,"Number of sections %d %x\n",sections,sections); // optional header size fseek(source,13,SEEK_CUR); i=fgetc(source); fprintf(stdout,"Opt header size %d %x\n",i,i); // 2 more bytes in coff header, plus size of optional, should // put us in the section table. fseek(source,i+3,SEEK_CUR); // go down N sections. fseek(source,40*(sections-1),SEEK_CUR); // size of last section fseek(source,16,SEEK_CUR); j=getw(source); fprintf(stdout,"Last section raw size %d %x\n",j,j); l=getw(source); fprintf(stdout,"Last section raw offset %d %x\n",l,l); // add together. voila. filesize=l+j; fprintf(stdout,"Size of file from MZ, %d %x\n",filesize,filesize); // now, to carve it, open new temp file destfd=mkstemp(tmpname); if (destfd==-1) { fprintf(stderr,"Error creating temp file %s: %s\n", tmpname, strerror(errno)); exit(1); } fprintf(stdout,"Output file: %s\n",tmpname); dest=fdopen(destfd,"w"); // go back up to MZ fseek(source,mzoffset,SEEK_SET); // this is ugly. if ((filesize % 2) != 0) filesize--; for (i=0; i