bool find_section(PE_FILE *pe, IMAGE_SECTION_HEADER *sec, bool executable) { rewind(pe->handle); if (!pe_get_sections(pe)) return false; if (fseek(pe->handle, pe->addr_sections, SEEK_SET)) return false; for (unsigned int i=0; i < pe->num_sections; i++) { fread(sec, sizeof(*sec), 1, pe->handle); if (executable && (sec->Characteristics & 0x20)) return true; } return false; }
static void print_strange_sections(PE_FILE *pe) { bool aux = false; if (!pe_get_sections(pe) || !pe->num_sections) return; if (pe->num_sections <= 2) snprintf(value, MAX_MSG, "%d (low)", pe->num_sections); else if (pe->num_sections > 8) snprintf(value, MAX_MSG, "%d (high)", pe->num_sections); else snprintf(value, MAX_MSG, "%d", pe->num_sections); output("section count", value); for (unsigned i=0; i < pe->num_sections && i <= 65535; i++, aux=false) { memset(&value, 0, sizeof(value)); if (!strisprint((const char *)pe->sections_ptr[i]->Name)) stradd(value, "suspicious name", &aux); if (!pe->sections_ptr[i]->SizeOfRawData) stradd(value, "zero length", &aux); else if (pe->sections_ptr[i]->SizeOfRawData <= 512) stradd(value, "small length", &aux); // rwx or writable + executable code if (pe->sections_ptr[i]->Characteristics & 0x80000000 && (pe->sections_ptr[i]->Characteristics & 0x20 || pe->sections_ptr[i]->Characteristics & 0x20000000)) stradd(value, "self-modifying", &aux); if (!aux) strncpy(value, "normal", 7); output((char *)pe->sections_ptr[i]->Name, value); } }
static IMAGE_SECTION_HEADER *pe_check_fake_entrypoint(PE_FILE *pe, DWORD *ep) { IMAGE_SECTION_HEADER *epsec = NULL; if (!pe->optional_ptr) pe_get_optional(pe); if (!pe->num_sections || !pe->sections_ptr) pe_get_sections(pe); if (!pe->num_sections) return NULL; epsec = pe_rva2section(pe, *ep); if (!epsec) return NULL; if (!(epsec->Characteristics & 0x20)) return epsec; return NULL; }
/* * -1 - fake tls callbacks detected * 0 - no tls directory * >0 - number of callbacks functions found */ static int pe_get_tls_callbacks(PE_FILE *pe) { QWORD tls_addr = 0; int ret = 0; if (!pe) return 0; tls_addr = pe_get_tls_directory(pe); if (!tls_addr || !pe_get_sections(pe)) return 0; // search for tls in all sections for (unsigned int i=0, j=0; i < pe->num_sections; i++) { if (tls_addr >= pe->sections_ptr[i]->VirtualAddress && tls_addr < (pe->sections_ptr[i]->VirtualAddress + pe->sections_ptr[i]->SizeOfRawData)) { unsigned int funcaddr = 0; if (fseek(pe->handle, tls_addr - pe->sections_ptr[i]->VirtualAddress + pe->sections_ptr[i]->PointerToRawData, SEEK_SET)) return 0; if (pe->architecture == PE32) { IMAGE_TLS_DIRECTORY32 tlsdir32; if (!fread(&tlsdir32, sizeof(tlsdir32), 1, pe->handle)) return 0; if (! (tlsdir32.AddressOfCallBacks & pe->optional_ptr->_32->ImageBase)) break; if (fseek(pe->handle, rva2ofs(pe, tlsdir32.AddressOfCallBacks - pe->optional_ptr->_32->ImageBase), SEEK_SET)) return 0; } else if (pe->architecture == PE64) { IMAGE_TLS_DIRECTORY64 tlsdir64; if (!fread(&tlsdir64, sizeof(tlsdir64), 1, pe->handle)) return 0; if (! (tlsdir64.AddressOfCallBacks & pe->optional_ptr->_64->ImageBase)) break; if (fseek(pe->handle, rva2ofs(pe, tlsdir64.AddressOfCallBacks - pe->optional_ptr->_64->ImageBase), SEEK_SET)) return 0; } else return 0; ret = -1; // tls directory and section exists do { fread(&funcaddr, sizeof(int), 1, pe->handle); if (funcaddr) { char value[MAX_MSG]; ret = ++j; // function found if (config.verbose) { snprintf(value, MAX_MSG, "%#x", funcaddr); output("TLS callback function", value); } } } while (funcaddr); return ret; } } return 0; }
int main(int argc, char *argv[]) { PE_FILE pe; FILE *fp = NULL; if (argc < 2) { usage(); exit(1); } parse_options(argc, argv); // opcoes if ((fp = fopen(argv[argc-1], "rb")) == NULL) EXIT_ERROR("file not found or unreadable"); pe_init(&pe, fp); // inicializa o struct pe if (!is_pe(&pe)) EXIT_ERROR("not a valid PE file"); // dos header if (config.dos || config.all_headers || config.all) { IMAGE_DOS_HEADER dos; if (pe_get_dos(&pe, &dos)) print_dos_header(&dos); else { EXIT_ERROR("unable to read DOS header"); } } // coff/file header if (config.coff || config.all_headers || config.all) { IMAGE_COFF_HEADER coff; if (pe_get_coff(&pe, &coff)) print_coff_header(&coff); else { EXIT_ERROR("unable to read COFF file header"); } } // optional header if (config.opt || config.all_headers || config.all) { if (pe_get_optional(&pe)) print_optional_header(&pe); else { EXIT_ERROR("unable to read Optional (Image) file header"); } } // directories if (config.dirs || config.all) { if (pe_get_directories(&pe)) print_directories(&pe); else { EXIT_ERROR("unable to read the Directories entry from Optional header"); } } // imports if (config.imports || config.all) { if (pe_get_directories(&pe)) print_imports(&pe); else { EXIT_ERROR("unable to read the Directories entry from Optional header"); } } // exports if (config.exports || config.all) { if (pe_get_directories(&pe)) print_exports(&pe); else { EXIT_ERROR("unable to read directories from optional header"); } } // sections if (config.all_sections || config.all) { if (pe_get_sections(&pe)) print_sections(&pe); else { EXIT_ERROR("unable to read sections"); } } // free pe_deinit(&pe); return 0; }