static void print_exports(PE_FILE *pe) { QWORD va; IMAGE_EXPORT_DIRECTORY exp; DWORD rva, aux, faddr = 0; va = pe->directories_ptr[IMAGE_DIRECTORY_ENTRY_EXPORT] ? pe->directories_ptr[IMAGE_DIRECTORY_ENTRY_EXPORT]->VirtualAddress : 0; if (!va) { fprintf(stderr, "export directory not found\n"); return; } if (fseek(pe->handle, rva2ofs(pe, va), SEEK_SET)) EXIT_ERROR("unable to seek until export directory"); if (!fread(&exp, sizeof(exp), 1, pe->handle)) EXIT_ERROR("unable to read export directory"); if (fseek(pe->handle, rva2ofs(pe, exp.AddressOfNames), SEEK_SET)) EXIT_ERROR("unable to seek"); if (!fread(&rva, sizeof(rva), 1, pe->handle)) EXIT_ERROR("unable to read"); if (fseek(pe->handle, rva2ofs(pe, rva), SEEK_SET)) EXIT_ERROR("unable to seek"); output("Exported functions", NULL); for (unsigned i=0; i<exp.NumberOfNames; i++) { char c=1, addr[30], fun[300]; aux = ftell(pe->handle); fseek(pe->handle, exp.AddressOfFunctions + sizeof(DWORD) * i, SEEK_SET); fread(&faddr, sizeof(faddr), 1, pe->handle); fseek(pe->handle, aux, SEEK_SET); memset(&fun, 0, sizeof(fun)); memset(&addr, 0, sizeof(addr)); snprintf(addr, 30, "%#x", faddr); for (unsigned j=0; c; j++) { fread(&c, sizeof(c), 1, pe->handle); fun[j] = c; } output(addr, fun); } }
int main(int argc, char *argv[]) { PE_FILE pe; FILE *fp = NULL; unsigned long rva = 0; parse_options(argc, argv); // opcoes if (argc != 3) { usage(); exit(1); } if ((fp = fopen(argv[2], "rb")) == NULL) EXIT_ERROR("file not found or unreadable"); rva = (unsigned long) strtol(argv[1], NULL, 0); if (!rva) EXIT_ERROR("invalid RVA"); pe_init(&pe, fp); // inicializa o struct pe if (!ispe(&pe)) EXIT_ERROR("not a valid PE file"); printf("%#"PRIx64"\n", rva2ofs(&pe, rva)); // libera a memoria pe_deinit(&pe); return 1; }
int main(int argc, char *argv[]) { PE_FILE pe; FILE *dbfile = NULL, *fp = NULL; QWORD ep_offset, pesize; char value[MAX_MSG]; unsigned char *pe_data; if (argc < 2) { usage(); exit(1); } memset(&config, 0, sizeof(config)); 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 (!ispe(&pe)) EXIT_ERROR("invalid PE file"); if (!pe_get_optional(&pe)) EXIT_ERROR("unable to read optional header"); if (!(ep_offset = rva2ofs(&pe, pe.entrypoint))) EXIT_ERROR("unable to get entrypoint offset"); pesize = pe_get_size(&pe); pe_data = (unsigned char *) xmalloc(pesize); //if (fseek(pe.handle, ep, SEEK_SET)) //EXIT_ERROR("unable to seek to entrypoint offset"); if (!fread(pe_data, pesize, 1, pe.handle)) EXIT_ERROR("unable to read entrypoint data"); if (!loaddb(&dbfile)) fprintf(stderr, "warning: without valid database file, %s will search in generic mode only\n", PROGRAM); // packer by signature if (compare_signature(pe_data, ep_offset, dbfile, value)); // generic detection else if (generic_packer(&pe, ep_offset)) snprintf(value, MAX_MSG, "generic"); else snprintf(value, MAX_MSG, "no packer found"); free(pe_data); output("packer", value); if (dbfile) fclose(dbfile); pe_deinit(&pe); return 0; }
int main(int argc, char *argv[]) { PE_FILE pe; FILE *fp = NULL; DWORD ep, stub_offset; int callbacks; double entropy; // unsigned int num_sections; 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"); // File entropy entropy = calculate_entropy_file(&pe); if(entropy < 7.0) snprintf(value, MAX_MSG, "normal (%f)", entropy); else snprintf(value, MAX_MSG, "packed (%f)", entropy); output("file entropy", value); memset(&value, 0, sizeof(value)); if (!pe_get_optional(&pe)) return 1; ep = (pe.optional_ptr->_32 ? pe.optional_ptr->_32->AddressOfEntryPoint : (pe.optional_ptr->_64 ? pe.optional_ptr->_64->AddressOfEntryPoint : 0)); // fake ep if (ep == 0) snprintf(value, MAX_MSG, "null"); else if (pe_check_fake_entrypoint(&pe, &ep)) if (config.verbose) snprintf(value, MAX_MSG, "fake - va: %#x - raw: %#"PRIx64, ep, rva2ofs(&pe, ep)); else snprintf(value, MAX_MSG, "fake"); else if (config.verbose) snprintf(value, MAX_MSG, "normal - va: %#x - raw: %#"PRIx64, ep, rva2ofs(&pe, ep)); else snprintf(value, MAX_MSG, "normal"); output("entrypoint", value); // dos stub memset(&value, 0, sizeof(value)); if (!normal_dos_stub(&pe, &stub_offset)) { if (config.verbose) snprintf(value, MAX_MSG, "suspicious - raw: %#x", stub_offset); else snprintf(value, MAX_MSG, "suspicious"); } else snprintf(value, MAX_MSG, "normal"); output("DOS stub", value); // tls callbacks callbacks = pe_get_tls_callbacks(&pe); if (callbacks == 0) snprintf(value, MAX_MSG, "not found"); else if (callbacks == -1) snprintf(value, MAX_MSG, "found - no functions"); else if (callbacks >0) snprintf(value, MAX_MSG, "found - %d function(s)", callbacks); output("TLS directory", value); memset(&value, 0, sizeof(value)); // section analysis print_strange_sections(&pe); // no imagebase if (!normal_imagebase(&pe)) { if (config.verbose) snprintf(value, MAX_MSG, "suspicious - %#"PRIx64, pe.imagebase); else snprintf(value, MAX_MSG, "suspicious"); } else { if (config.verbose) snprintf(value, MAX_MSG, "normal - %#"PRIx64, pe.imagebase); else snprintf(value, MAX_MSG, "normal"); } output("imagebase", value); // invalid timestamp IMAGE_COFF_HEADER coff; if (!pe_get_coff(&pe, &coff)) EXIT_ERROR("unable to read coff header"); print_timestamp(&coff.TimeDateStamp); pe_deinit(&pe); return 0; }
/* * -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; }
static void print_imports(PE_FILE *pe) { QWORD va; // store temporary addresses long aux; IMAGE_IMPORT_DESCRIPTOR id; char c = 0; char dllname[MAX_DLL_NAME]; unsigned int i; va = pe->directories_ptr[IMAGE_DIRECTORY_ENTRY_IMPORT] ? pe->directories_ptr[IMAGE_DIRECTORY_ENTRY_IMPORT]->VirtualAddress : 0; if (!va) EXIT_ERROR("import directory not found"); if (fseek(pe->handle, rva2ofs(pe, va), SEEK_SET)) EXIT_ERROR("error seeking file"); memset(&id, 0, sizeof(id)); memset(&dllname, 0, sizeof(dllname)); output("Imported functions", NULL); while (1) { if (!fread(&id, sizeof(id), 1, pe->handle)) return; if (!id.u1.OriginalFirstThunk) break; aux = ftell(pe->handle); va = rva2ofs(pe, id.Name); if (!va) return; // shortcut to read DLL name if (fseek(pe->handle, va, SEEK_SET)) return; // print dll name for (i=0; i < MAX_DLL_NAME; i++) { fread(&c, sizeof(c), 1, pe->handle); if (!c) break; dllname[i] = c; } output(dllname, NULL); memset(&dllname, 0, sizeof(dllname)); if (fseek(pe->handle, aux, SEEK_SET)) // restore file pointer return; // search for dll imported functions va = rva2ofs(pe, id.u1.OriginalFirstThunk); if (!va) return; print_imported_functions(pe, va); } }
static void print_imported_functions(PE_FILE *pe, long offset) { QWORD fptr = 0; // pointer to functions long aux2, aux = ftell(pe->handle); WORD hint = 0; // function number char c; char fname[MAX_FUNCTION_NAME]; char hintstr[16]; unsigned int i; if (fseek(pe->handle, offset, SEEK_SET)) return; memset(&fname, 0, sizeof(fname)); memset(&hintstr, 0, sizeof(hintstr)); while (1) { if (!fread(&fptr, (pe->architecture == PE64) ? sizeof(QWORD) : sizeof(DWORD), 1, pe->handle)) return; if (!fptr) break; // function without name (test msb) if (fptr & ((pe->architecture == PE64) ? IMAGE_ORDINAL_FLAG64 : IMAGE_ORDINAL_FLAG32)) snprintf(hintstr, 15, "%"PRIu64, fptr & 0x0fffffff); else { // save file pointer in functions array aux2 = ftell(pe->handle); if (fseek(pe->handle, rva2ofs(pe, fptr), SEEK_SET)) return; // follow function pointer if (!fread(&hint, sizeof(hint), 1, pe->handle)) return; for (i=0; i<MAX_FUNCTION_NAME; i++) { if (!fread(&c, sizeof(c), 1, pe->handle)) return; if (!isprint((int)c)) // 0 and non-printable break; fname[i] = c; } snprintf(hintstr, 15, "%d", hint); // restore file pointer to functions array if (fseek(pe->handle, aux2, SEEK_SET)) return; } // print things output(hintstr, fname); memset(&fname, 0, sizeof(fname)); memset(&hintstr, 0, sizeof(hintstr)); } fseek(pe->handle, aux, SEEK_SET); }