├── lotus_parser ├── file_util.h ├── lotus_print.h ├── CMakeLists.txt ├── main.cpp ├── README.md ├── lotus_headers.h ├── file_util.cpp ├── lotus_headers.cpp └── lotus_print.cpp ├── iced_id_parser ├── iceid_parser.h ├── util.h ├── iceid_to_pe.h ├── CMakeLists.txt ├── iceid_header.h ├── README.md ├── main.cpp ├── iceid_parser.cpp ├── util.cpp └── iceid_to_pe.cpp ├── CMakeLists.txt ├── isfb_parser ├── isfb_parser.h ├── util.h ├── README.md ├── isfb_to_pe.h ├── CMakeLists.txt ├── main.cpp ├── isfb_header.h ├── isfb_parser.cpp ├── util.cpp └── isfb_to_pe.cpp ├── README.md └── .appveyor.yml /lotus_parser/file_util.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | BYTE* load_file(const char *filename, OUT size_t &read_size); 6 | -------------------------------------------------------------------------------- /lotus_parser/lotus_print.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "lotus_headers.h" 4 | 5 | namespace lotus { 6 | bool print_headers(BYTE *content, size_t content_size); 7 | }; 8 | -------------------------------------------------------------------------------- /iced_id_parser/iceid_parser.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "iceid_header.h" 3 | 4 | namespace icedid 5 | { 6 | void print_header(const iced_module_hdr &hdr); 7 | 8 | void print_sections(const ICED_SECTION &hdr); 9 | }; 10 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 2.8) 2 | project (funky_malware_parsers) 3 | # Add sub-directories 4 | # 5 | add_subdirectory( lotus_parser ) 6 | add_subdirectory( isfb_parser ) 7 | add_subdirectory( iced_id_parser ) 8 | -------------------------------------------------------------------------------- /isfb_parser/isfb_parser.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "isfb_header.h" 3 | 4 | namespace isfb 5 | { 6 | void print_header(const isfb_hdr &hdr); 7 | 8 | void print_data_dir(const ISFB_DDIR &hdr); 9 | 10 | void print_sections(const ISFB_SECTION &hdr); 11 | }; 12 | -------------------------------------------------------------------------------- /iced_id_parser/util.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | BYTE* load_file(const char *filename, OUT size_t &read_size); 6 | bool dump_to_file(char *filename, BYTE* buffer, size_t buffer_size); 7 | bool validate_ptr(IN const void* buffer_bgn, IN SIZE_T buffer_size, IN const void* field_bgn, IN SIZE_T field_size); 8 | -------------------------------------------------------------------------------- /isfb_parser/util.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | BYTE* load_file(const char *filename, OUT size_t &read_size); 6 | bool dump_to_file(char *filename, BYTE* buffer, size_t buffer_size); 7 | bool validate_ptr(IN const void* buffer_bgn, IN SIZE_T buffer_size, IN const void* field_bgn, IN SIZE_T field_size); 8 | -------------------------------------------------------------------------------- /isfb_parser/README.md: -------------------------------------------------------------------------------- 1 | # isfb_parser 2 | 3 | Parses (and optionaly converts to PE) the custom executable format (PX) used by ISFB (Gozi v3) malware. 4 | 5 | Samples: 6 | + [7bc4fecb37420387df535dae7fbd8b0aa66baf4eba2e5799063676a52aa4a16d](https://www.virustotal.com/#/file/7bc4fecb37420387df535dae7fbd8b0aa66baf4eba2e5799063676a52aa4a16d/detection) 7 | -------------------------------------------------------------------------------- /iced_id_parser/iceid_to_pe.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include "iceid_header.h" 6 | 7 | namespace icedid 8 | { 9 | BYTE* alloc_pe(IN const iced_module_hdr &hdr, OUT size_t &out_size); 10 | 11 | size_t copy_sections(IN const iced_module_hdr &hdr, IN OUT BYTE* buf, IN const size_t buf_size); 12 | 13 | bool convert_to_pe(const iced_module_hdr& hdr, char* filename); 14 | }; 15 | 16 | -------------------------------------------------------------------------------- /isfb_parser/isfb_to_pe.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "isfb_parser.h" 3 | 4 | BYTE* alloc_pe(IN const isfb_hdr &hdr, OUT size_t &out_size); 5 | 6 | size_t copy_sections(IN const isfb_hdr &hdr, IN OUT BYTE* buf, IN const size_t buf_size); 7 | 8 | size_t copy_headers(IN const isfb_hdr &hdr, IN OUT BYTE* buf, IN const size_t buf_size); 9 | 10 | size_t copy_ddirs(IN const isfb_hdr &hdr, IN OUT BYTE* buf, IN const size_t buf_size); 11 | 12 | bool isfb_to_pe(const isfb_hdr& hdr, char* filename); 13 | -------------------------------------------------------------------------------- /isfb_parser/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 2.8) 2 | 3 | project ( isfb_parser ) 4 | 5 | set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT") 6 | 7 | set (srcs 8 | util.cpp 9 | isfb_parser.cpp 10 | isfb_to_pe.cpp 11 | ) 12 | 13 | set (hdrs 14 | util.h 15 | isfb_header.h 16 | isfb_parser.h 17 | isfb_to_pe.h 18 | ) 19 | 20 | set (rsrc 21 | ) 22 | 23 | add_executable ( ${PROJECT_NAME} ${hdrs} ${srcs} ${rsrc} main.cpp ) 24 | 25 | #install 26 | INSTALL( TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_PREFIX} COMPONENT ${PROJECT_NAME} ) 27 | -------------------------------------------------------------------------------- /lotus_parser/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 2.8) 2 | 3 | project ( lotus_parser ) 4 | 5 | set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT") 6 | 7 | set (srcs 8 | file_util.cpp 9 | lotus_headers.cpp 10 | lotus_print.cpp 11 | ) 12 | 13 | set (hdrs 14 | file_util.h 15 | lotus_headers.h 16 | lotus_print.h 17 | ) 18 | 19 | set (rsrc 20 | ) 21 | 22 | add_executable ( ${PROJECT_NAME} ${hdrs} ${srcs} ${rsrc} main.cpp ) 23 | 24 | #install 25 | INSTALL( TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_PREFIX} COMPONENT ${PROJECT_NAME} ) 26 | 27 | -------------------------------------------------------------------------------- /iced_id_parser/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 2.8) 2 | 3 | project ( iced_id_parser ) 4 | 5 | set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT") 6 | 7 | set (srcs 8 | util.cpp 9 | iceid_parser.cpp 10 | iceid_to_pe.cpp 11 | ) 12 | 13 | set (hdrs 14 | util.h 15 | iceid_header.h 16 | iceid_parser.h 17 | iceid_to_pe.h 18 | ) 19 | 20 | set (rsrc 21 | ) 22 | 23 | add_executable ( ${PROJECT_NAME} ${hdrs} ${srcs} ${rsrc} main.cpp ) 24 | 25 | #install 26 | INSTALL( TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_PREFIX} COMPONENT ${PROJECT_NAME} ) 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # funky_malware_parsers 2 | 3 | [![Build status](https://ci.appveyor.com/api/projects/status/0orp7tfkimmn7c2m?svg=true)](https://ci.appveyor.com/project/hasherezade/funky-malware-formats) 4 | 5 | Parsers for custom malware formats (["Funky malware formats"](https://speakerdeck.com/hshrzd/funky-malware-formats)) 6 | 7 | Contains: 8 | - 9 | + **lotus_parser**: parser for Ocean Lotus custom executable format 10 | + **isfb_parser**: parser (and converter) for ISFB (Gozi v3) scrambled PE 11 | + **bee_parser**: parser for HiddenBee custom executable format - available [here](https://github.com/hasherezade/bee_parser) 12 | + **iced_id_parser**: parser (and converter) for IcedID scrambled PE 13 | -------------------------------------------------------------------------------- /iced_id_parser/iceid_header.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | //#define OLD_ICE_FORMAT 5 | 6 | #define NEXT_OFFSET 0x10 7 | 8 | #pragma pack(push) 9 | #pragma pack(1) 10 | struct ICED_SECTION { 11 | uint32_t virtual_offset; 12 | uint32_t virtual_size; 13 | uint32_t raw_offset; 14 | uint32_t raw_size; 15 | uint8_t characteristics; 16 | }; 17 | 18 | struct iced_module_hdr { 19 | uint64_t image_base; 20 | uint32_t image_size; 21 | uint32_t entry_point_va; 22 | #ifdef OLD_ICE_FORMAT 23 | uint32_t unknown; 24 | #endif 25 | uint32_t import_dir_va; 26 | uint32_t reloc_dir_va; 27 | uint32_t reloc_dir_size; 28 | 29 | uint32_t sections_count; 30 | ICED_SECTION sections[1]; // sections[sections_count] 31 | }; 32 | #pragma pack(pop) 33 | -------------------------------------------------------------------------------- /iced_id_parser/README.md: -------------------------------------------------------------------------------- 1 | # iced_id_parser 2 | 3 | Parses (and optionaly converts to PE) the custom executable format used by IcedID malware. Samples: 4 | + [080de02d9c7ead7bda5ed10bf825876d9509284296799f97f7b1a150a03a96c8](https://www.virustotal.com/gui/file/080de02d9c7ead7bda5ed10bf825876d9509284296799f97f7b1a150a03a96c8/detection) - Main Bot 5 | + [142cb03fd35a980801cc3ce53f57edaaaef1eb9d25a6da4d3d4a3647afb8e731](https://www.virustotal.com/gui/file/142cb03fd35a980801cc3ce53f57edaaaef1eb9d25a6da4d3d4a3647afb8e731/detection) - "HelpDesk" module (backdoor) 6 | 7 | ### More details 8 | + [New version of IcedID Trojan uses steganographic payloads ](https://blog.malwarebytes.com/threat-analysis/2019/12/new-version-of-icedid-trojan-uses-steganographic-payloads/) 9 | -------------------------------------------------------------------------------- /lotus_parser/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "file_util.h" 5 | #include "lotus_print.h" 6 | 7 | 8 | int main(int argc, char *argv[]) 9 | { 10 | if (argc < 2) { 11 | std::cout << "Parser for a executable BLOB format used by Ocean Lotus\n"; 12 | std::cout << "Args: " << std::endl; 13 | system("pause"); 14 | return -1; 15 | } 16 | size_t content_size = 0; 17 | BYTE *content = load_file(argv[1], content_size); 18 | if (!content) { 19 | std::cerr << "Failed to load: " << argv[1] << std::endl; 20 | return -1; 21 | } 22 | std::cout << "Loaded: " << argv[1] << "\nLoaded size: " << std::hex << content_size << std::endl; 23 | lotus::print_headers(content, content_size); 24 | 25 | return 0; 26 | } 27 | -------------------------------------------------------------------------------- /iced_id_parser/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "iceid_parser.h" 4 | #include "util.h" 5 | #include "iceid_to_pe.h" 6 | 7 | int main(int argc, char *argv[]) 8 | { 9 | if (argc < 2) { 10 | std::cout << "Parser and converter for the custom format used by IcedID malware\n"; 11 | std::cout << "Args: [out: PE file]" << std::endl; 12 | system("pause"); 13 | return -1; 14 | } 15 | size_t buffer_size = 0; 16 | BYTE* buffer = load_file(argv[1], buffer_size); 17 | if (!buffer) { 18 | std::cerr << "[!] Couldn't load the file: " << argv[1] << "\n"; 19 | return -2; 20 | } 21 | iced_module_hdr* hdr = (iced_module_hdr*) buffer; 22 | 23 | icedid::print_header(*hdr); 24 | if (argc > 2) { 25 | if (icedid::convert_to_pe(*hdr, argv[2])) { 26 | std::cout << "Saved as a PE: " << argv[2] << std::endl; 27 | } 28 | else { 29 | std::cerr << "Failed converting into PE" << std::endl; 30 | return -4; 31 | } 32 | } 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /.appveyor.yml: -------------------------------------------------------------------------------- 1 | os: 2 | - Visual Studio 2015 3 | 4 | platform: x64 5 | - x64 6 | 7 | branches: 8 | only: 9 | - master 10 | 11 | install: 12 | - git submodule update --init --recursive 13 | - set PATH=C:\Program Files\CMake\bin;%PATH% 14 | 15 | build: 16 | verbosity: detailed 17 | 18 | configuration: 19 | - Release 20 | 21 | environment: 22 | artifactName: $(APPVEYOR_PROJECT_NAME)-$(APPVEYOR_REPO_COMMIT)-$(CONFIGURATION) 23 | matrix: 24 | - env_arch: "x64" 25 | - env_arch: "x86" 26 | 27 | before_build: 28 | - mkdir build 29 | - cd build 30 | - if [%env_arch%]==[x64] ( 31 | cmake .. -A x64 ) 32 | - if [%env_arch%]==[x86] ( 33 | cmake .. ) 34 | 35 | build_script: 36 | - cmake -DCMAKE_INSTALL_PREFIX:PATH=bin .. 37 | - cmake --build . --config %CONFIGURATION% --target install 38 | 39 | after_build: 40 | - mkdir %artifactName% 41 | - cp -r bin/* %artifactName% 42 | 43 | artifacts: 44 | - path: build\%artifactName% 45 | 46 | -------------------------------------------------------------------------------- /isfb_parser/main.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include "isfb_parser.h" 4 | #include "util.h" 5 | #include "isfb_to_pe.h" 6 | 7 | int main(int argc, char *argv[]) 8 | { 9 | if (argc < 2) { 10 | std::cout << "PX to PE:\nparser and converter for the custom format used by ISFB malware\n"; 11 | std::cout << "Args: [out: PE file]" << std::endl; 12 | system("pause"); 13 | return -1; 14 | } 15 | size_t buffer_size = 0; 16 | BYTE* buffer = load_file(argv[1], buffer_size); 17 | if (!buffer) { 18 | std::cerr << "[!] Couldn't load the file: " << argv[1] << "\n"; 19 | return -2; 20 | } 21 | isfb_hdr* hdr = (isfb_hdr*) buffer; 22 | if (hdr->magic != ISFB_MAGIC) { 23 | std::cerr << "[!] This is not the ISFB magic!\n"; 24 | return -3; 25 | } 26 | isfb::print_header(*hdr); 27 | if (argc > 2) { 28 | if (isfb_to_pe(*hdr, argv[2])) { 29 | std::cout << "Saved as a PE: " << argv[2] << std::endl; 30 | } 31 | else { 32 | std::cerr << "Failed converting into PE" << std::endl; 33 | return -4; 34 | } 35 | } 36 | return 0; 37 | } 38 | -------------------------------------------------------------------------------- /isfb_parser/isfb_header.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | #define ISFB_MAGIC 0x00005850 5 | 6 | enum ISFB_DDIR_ID { 7 | ISFB_DDIR_IMPORT = 0, //loaded 8 | ISFB_DDIR_EXPORT = 1, //exports retrieved and copied 9 | ISFB_DDIR_IAT = 2, //copied 10 | ISFB_DDIR_SECURITY = 3, //copied 11 | ISFB_DDIR_EXCEPTION = 4, //copied 12 | ISFB_DDIR_RELOCS = 5, //loaded 13 | ISFB_DDIR_COUNT 14 | }; 15 | 16 | struct ISFB_DDIR { 17 | DWORD original_rva; //RVA in the PE 18 | DWORD size; 19 | DWORD offset; //offset in the custom header 20 | }; 21 | 22 | struct ISFB_SECTION { 23 | DWORD virtual_offset; 24 | DWORD virtual_size; 25 | DWORD raw_offset; 26 | DWORD raw_size; 27 | DWORD characteristics; 28 | }; 29 | 30 | struct isfb_hdr { 31 | DWORD magic; 32 | DWORD checksum; 33 | DWORD size; 34 | 35 | DWORD nt_hdr_offset; 36 | DWORD image_size; 37 | DWORD nt_hdr_size; 38 | 39 | ISFB_DDIR data_dir[ISFB_DDIR_COUNT]; 40 | 41 | WORD machine_id; //from: FileHeader -> Machine 42 | WORD sections_count; 43 | DWORD entry_point; 44 | 45 | ISFB_SECTION sections[1]; // sections[sections_count] 46 | }; 47 | -------------------------------------------------------------------------------- /lotus_parser/README.md: -------------------------------------------------------------------------------- 1 | # lotus_parser 2 | 3 | Parses a custom executable format used by the Ocean Lotus APT: 4 | Samples: 5 | + [cd7e75930194fff08a05bbb1c412c1f4a8e709ac0a8b0d3ba44d36915bc02edc](https://www.virustotal.com/#/file/cd7e75930194fff08a05bbb1c412c1f4a8e709ac0a8b0d3ba44d36915bc02edc/detection) - SPORDER.cab (set #1) 6 | + [3e341783eca3139fdec2e1b3143b206f925ab0f1a47de372035e5a64eef76d8f](https://www.virustotal.com/#/file/3e341783eca3139fdec2e1b3143b206f925ab0f1a47de372035e5a64eef76d8f/detection) - SPORDER.blob (set #1) 7 | + [d93500629000e01013073f3db06f6a659557503dbf42a92c312c16aaf4030298](https://www.virustotal.com/#/file/d93500629000e01013073f3db06f6a659557503dbf42a92c312c16aaf4030298/detection) - SPORDER.cab (set #2) 8 | + [90ab82a7f777bedd0703e1e7eb8e68766b5c86d95b65f56a016f8bdb3544a8f4](https://www.virustotal.com/#/file/90ab82a7f777bedd0703e1e7eb8e68766b5c86d95b65f56a016f8bdb3544a8f4/detection) - SPORDER.blob (set #2) 9 | 10 | ### More details 11 | + [“Funky malware format” found in Ocean Lotus sample](https://blog.malwarebytes.com/threat-analysis/2019/04/funky-malware-format-found-in-ocean-lotus-sample/) 12 | -------------------------------------------------------------------------------- /lotus_parser/lotus_headers.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace lotus { 5 | 6 | typedef struct 7 | { 8 | DWORD checksum; 9 | DWORD xor_val2; 10 | DWORD xor_val1; 11 | DWORD code_size; 12 | //BYTE code[1]; //code[code_size] 13 | } header1_t; 14 | 15 | typedef struct 16 | { 17 | DWORD dll_main; 18 | DWORD iat_size; 19 | //DWORD records[1]; 20 | } header2_t; 21 | 22 | typedef enum { 23 | RTYPE_NONE = 0, 24 | RTYPE_RELOC = 1, 25 | RTYPE_EXPORT = 2, 26 | RTYPE_IMPORT = 3 27 | } record_type_t; 28 | 29 | typedef enum { 30 | ITYPE_ORDINAL = 1, 31 | ITYPE_NAME = 2, 32 | ITYPE_ERASE_FUNC = 3, 33 | ITYPE_ERASE_DLL = 4 34 | } import_type_t; 35 | 36 | typedef struct 37 | { 38 | DWORD counter; //TODO: check what it really is 39 | DWORD dll_rva; 40 | DWORD func_rva; 41 | DWORD iat_rva; 42 | } import_t; 43 | 44 | typedef struct { 45 | DWORD reloc_field; 46 | } reloc_t; 47 | 48 | typedef struct { 49 | DWORD count; 50 | DWORD entry_rva; 51 | DWORD name_rva; //export name 52 | } export_t; 53 | 54 | bool decode_file(IN OUT BYTE* content, IN size_t content_size); 55 | DWORD calc_checksum(IN const BYTE* content, IN const size_t content_size); 56 | 57 | header1_t* get_hdr1(IN BYTE* content, IN size_t content_size); 58 | header2_t* get_hdr2(IN BYTE* content, IN size_t content_size); 59 | 60 | BYTE* get_code(IN BYTE* content, IN size_t content_size, OUT size_t &code_size); 61 | DWORD* get_records(IN BYTE* content, IN size_t content_size); 62 | 63 | }; //namespace lotus 64 | 65 | -------------------------------------------------------------------------------- /lotus_parser/file_util.cpp: -------------------------------------------------------------------------------- 1 | #include "file_util.h" 2 | 3 | #ifdef _DEBUG 4 | #include 5 | #endif 6 | 7 | BYTE* load_file(const char *filename, OUT size_t &read_size) 8 | { 9 | HANDLE file = CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); 10 | if (file == INVALID_HANDLE_VALUE) { 11 | #ifdef _DEBUG 12 | std::cerr << "Could not open file!" << std::endl; 13 | #endif 14 | return nullptr; 15 | } 16 | HANDLE mapping = CreateFileMapping(file, 0, PAGE_READONLY, 0, 0, 0); 17 | if (!mapping) { 18 | #ifdef _DEBUG 19 | std::cerr << "Could not create mapping!" << std::endl; 20 | #endif 21 | CloseHandle(file); 22 | return nullptr; 23 | } 24 | BYTE *dllRawData = (BYTE*)MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0); 25 | if (dllRawData == nullptr) { 26 | #ifdef _DEBUG 27 | std::cerr << "Could not map view of file" << std::endl; 28 | #endif 29 | CloseHandle(mapping); 30 | CloseHandle(file); 31 | return nullptr; 32 | } 33 | size_t r_size = GetFileSize(file, 0); 34 | if (read_size != 0 && read_size <= r_size) { 35 | r_size = read_size; 36 | } 37 | BYTE* localCopyAddress = (BYTE*)calloc(r_size, 1); 38 | if (localCopyAddress != nullptr) { 39 | memcpy(localCopyAddress, dllRawData, r_size); 40 | read_size = r_size; 41 | } 42 | else { 43 | read_size = 0; 44 | #ifdef _DEBUG 45 | std::cerr << "Could not allocate memory in the current process" << std::endl; 46 | #endif 47 | } 48 | UnmapViewOfFile(dllRawData); 49 | CloseHandle(mapping); 50 | CloseHandle(file); 51 | return localCopyAddress; 52 | } 53 | -------------------------------------------------------------------------------- /iced_id_parser/iceid_parser.cpp: -------------------------------------------------------------------------------- 1 | #include "iceid_parser.h" 2 | 3 | #include 4 | 5 | void icedid::print_sections(const ICED_SECTION &hdr) 6 | { 7 | std::cout << "virtual_offset: " << std::hex << hdr.virtual_offset << "\n"; 8 | std::cout << "virtual_size: " << std::hex << hdr.virtual_size << "\n"; 9 | std::cout << "raw_offset: " << std::hex << hdr.raw_offset << "\n"; 10 | std::cout << "raw_size: " << std::hex << hdr.raw_size << "\n"; 11 | std::cout << "characteristics: " << std::hex << (int)hdr.characteristics << "\n"; 12 | } 13 | 14 | void icedid::print_header(const iced_module_hdr &hdr) 15 | { 16 | std::cout << "IceId header:\n"; 17 | std::cout << "Image Base: " << std::hex << hdr.image_base << "\n"; 18 | std::cout << "Image Size: " << std::hex << hdr.image_size << "\n"; 19 | std::cout << "Entry Pint: " << std::hex << hdr.entry_point_va << "\n"; 20 | std::cout << "\n"; 21 | std::cout << "Data Directories:\n"; 22 | std::cout << "Imports Va: " << std::hex << hdr.import_dir_va << "\n"; 23 | #ifdef OLD_ICE_FORMAT 24 | std::cout << "Unknown: " << std::hex << hdr.unknown << "\n"; 25 | #endif 26 | std::cout << "Relocations VA: " << std::hex << hdr.reloc_dir_va << "\n"; 27 | std::cout << "Relocations Size: " << std::hex << hdr.reloc_dir_size << "\n"; 28 | std::cout << "Sections Count: " << std::hex << hdr.sections_count << "\n"; 29 | 30 | std::cout << "Sections:\n"; 31 | for (size_t i = 0; i < hdr.sections_count; i++) { 32 | std::cout << "---\n#" << i << "\n"; 33 | print_sections(hdr.sections[i]); 34 | } 35 | }; 36 | 37 | -------------------------------------------------------------------------------- /isfb_parser/isfb_parser.cpp: -------------------------------------------------------------------------------- 1 | #include "isfb_parser.h" 2 | 3 | #include 4 | 5 | void isfb::print_data_dir(const ISFB_DDIR &hdr) 6 | { 7 | std::cout << "original_rva: " << std::hex << hdr.original_rva << "\n"; 8 | std::cout << "size: " << std::hex << hdr.size << "\n"; 9 | std::cout << "offset: " << std::hex << hdr.offset << "\n"; 10 | } 11 | 12 | void isfb::print_sections(const ISFB_SECTION &hdr) 13 | { 14 | std::cout << "virtual_offset: " << std::hex << hdr.virtual_offset << "\n"; 15 | std::cout << "virtual_size: " << std::hex << hdr.virtual_size << "\n"; 16 | std::cout << "raw_offset: " << std::hex << hdr.raw_offset << "\n"; 17 | std::cout << "raw_size: " << std::hex << hdr.raw_size << "\n"; 18 | std::cout << "characteristics: " << std::hex << hdr.characteristics << "\n"; 19 | } 20 | 21 | void isfb::print_header(const isfb_hdr &hdr) 22 | { 23 | std::cout << "ISFB header:\n"; 24 | std::cout << "magic: " << std::hex << hdr.magic << "\n"; 25 | std::cout << "checksum: " << std::hex << hdr.checksum << "\n"; 26 | std::cout << "size: " << std::hex << hdr.size << "\n"; 27 | std::cout << "\n"; 28 | std::cout << "nt_hdr_offset: " << std::hex << hdr.nt_hdr_offset << "\n"; 29 | std::cout << "image_size: " << std::hex << hdr.image_size << "\n"; 30 | std::cout << "nt_hdr_size: " << std::hex << hdr.nt_hdr_size << "\n"; 31 | std::cout << "\n"; 32 | std::cout << "Data Directories:\n"; 33 | for (size_t i = 0; i < ISFB_DDIR_COUNT; i++) { 34 | std::cout << "---\n#" << i << "\n"; 35 | print_data_dir(hdr.data_dir[i]); 36 | } 37 | std::cout << "\n"; 38 | std::cout << "machine_id:\t" << std::hex << hdr.machine_id << "\n"; 39 | std::cout << "sections_count:\t" << std::hex << hdr.sections_count << "\n"; 40 | std::cout << "entry_point:\t" << std::hex << hdr.entry_point << "\n"; 41 | std::cout << "\n"; 42 | std::cout << "Sections:\n"; 43 | for (size_t i = 0; i < hdr.sections_count; i++) { 44 | std::cout << "---\n#" << i << "\n"; 45 | print_sections(hdr.sections[i]); 46 | } 47 | }; 48 | 49 | -------------------------------------------------------------------------------- /isfb_parser/util.cpp: -------------------------------------------------------------------------------- 1 | #include "util.h" 2 | 3 | #include 4 | 5 | BYTE* load_file(const char *filename, OUT size_t &read_size) 6 | { 7 | HANDLE file = CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); 8 | if (file == INVALID_HANDLE_VALUE) { 9 | #ifdef _DEBUG 10 | std::cerr << "Could not open file!" << std::endl; 11 | #endif 12 | return nullptr; 13 | } 14 | HANDLE mapping = CreateFileMapping(file, 0, PAGE_READONLY, 0, 0, 0); 15 | if (!mapping) { 16 | #ifdef _DEBUG 17 | std::cerr << "Could not create mapping!" << std::endl; 18 | #endif 19 | CloseHandle(file); 20 | return nullptr; 21 | } 22 | BYTE *dllRawData = (BYTE*)MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0); 23 | if (dllRawData == nullptr) { 24 | #ifdef _DEBUG 25 | std::cerr << "Could not map view of file" << std::endl; 26 | #endif 27 | CloseHandle(mapping); 28 | CloseHandle(file); 29 | return nullptr; 30 | } 31 | size_t r_size = GetFileSize(file, 0); 32 | if (read_size != 0 && read_size <= r_size) { 33 | r_size = read_size; 34 | } 35 | BYTE* localCopyAddress = (BYTE*)calloc(r_size, 1); 36 | if (localCopyAddress != nullptr) { 37 | memcpy(localCopyAddress, dllRawData, r_size); 38 | read_size = r_size; 39 | } 40 | else { 41 | read_size = 0; 42 | #ifdef _DEBUG 43 | std::cerr << "Could not allocate memory in the current process" << std::endl; 44 | #endif 45 | } 46 | UnmapViewOfFile(dllRawData); 47 | CloseHandle(mapping); 48 | CloseHandle(file); 49 | return localCopyAddress; 50 | } 51 | 52 | bool dump_to_file(char *filename, BYTE* buffer, size_t buffer_size) 53 | { 54 | FILE *fp = fopen(filename, "wb"); 55 | if (!fp) return false; 56 | 57 | fwrite(buffer, 1, buffer_size, fp); 58 | fclose(fp); 59 | return true; 60 | } 61 | 62 | 63 | bool validate_ptr(IN const void* buffer_bgn, IN SIZE_T buffer_size, IN const void* field_bgn, IN SIZE_T field_size) 64 | { 65 | if (buffer_bgn == nullptr || field_bgn == nullptr) { 66 | return false; 67 | } 68 | ULONGLONG start = (ULONGLONG)buffer_bgn; 69 | ULONGLONG end = start + buffer_size; 70 | 71 | ULONGLONG field_end = (ULONGLONG)field_bgn + field_size; 72 | 73 | if ((ULONGLONG)field_bgn < start) { 74 | return false; 75 | } 76 | if (field_end > end) { 77 | return false; 78 | } 79 | return true; 80 | } 81 | -------------------------------------------------------------------------------- /iced_id_parser/util.cpp: -------------------------------------------------------------------------------- 1 | #include "util.h" 2 | 3 | #include 4 | 5 | BYTE* load_file(const char *filename, OUT size_t &read_size) 6 | { 7 | HANDLE file = CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); 8 | if (file == INVALID_HANDLE_VALUE) { 9 | #ifdef _DEBUG 10 | std::cerr << "Could not open file!" << std::endl; 11 | #endif 12 | return nullptr; 13 | } 14 | HANDLE mapping = CreateFileMapping(file, 0, PAGE_READONLY, 0, 0, 0); 15 | if (!mapping) { 16 | #ifdef _DEBUG 17 | std::cerr << "Could not create mapping!" << std::endl; 18 | #endif 19 | CloseHandle(file); 20 | return nullptr; 21 | } 22 | BYTE *dllRawData = (BYTE*)MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0); 23 | if (dllRawData == nullptr) { 24 | #ifdef _DEBUG 25 | std::cerr << "Could not map view of file" << std::endl; 26 | #endif 27 | CloseHandle(mapping); 28 | CloseHandle(file); 29 | return nullptr; 30 | } 31 | size_t r_size = GetFileSize(file, 0); 32 | if (read_size != 0 && read_size <= r_size) { 33 | r_size = read_size; 34 | } 35 | BYTE* localCopyAddress = (BYTE*)calloc(r_size, 1); 36 | if (localCopyAddress != nullptr) { 37 | memcpy(localCopyAddress, dllRawData, r_size); 38 | read_size = r_size; 39 | } 40 | else { 41 | read_size = 0; 42 | #ifdef _DEBUG 43 | std::cerr << "Could not allocate memory in the current process" << std::endl; 44 | #endif 45 | } 46 | UnmapViewOfFile(dllRawData); 47 | CloseHandle(mapping); 48 | CloseHandle(file); 49 | return localCopyAddress; 50 | } 51 | 52 | bool dump_to_file(char *filename, BYTE* buffer, size_t buffer_size) 53 | { 54 | FILE *fp = fopen(filename, "wb"); 55 | if (!fp) return false; 56 | 57 | fwrite(buffer, 1, buffer_size, fp); 58 | fclose(fp); 59 | return true; 60 | } 61 | 62 | 63 | bool validate_ptr(IN const void* buffer_bgn, IN SIZE_T buffer_size, IN const void* field_bgn, IN SIZE_T field_size) 64 | { 65 | if (buffer_bgn == nullptr || field_bgn == nullptr) { 66 | return false; 67 | } 68 | ULONGLONG start = (ULONGLONG)buffer_bgn; 69 | ULONGLONG end = start + buffer_size; 70 | 71 | ULONGLONG field_end = (ULONGLONG)field_bgn + field_size; 72 | 73 | if ((ULONGLONG)field_bgn < start) { 74 | return false; 75 | } 76 | if (field_end > end) { 77 | return false; 78 | } 79 | return true; 80 | } 81 | -------------------------------------------------------------------------------- /lotus_parser/lotus_headers.cpp: -------------------------------------------------------------------------------- 1 | #include "lotus_headers.h" 2 | #include 3 | 4 | bool lotus::decode_file(IN OUT BYTE* content, IN size_t content_size) 5 | { 6 | lotus::header1_t* hdr1 = lotus::get_hdr1(content, content_size); 7 | if (!hdr1) return false; 8 | 9 | DWORD xor_val[2] = { 0 }; 10 | xor_val[0] = hdr1->xor_val1; 11 | xor_val[1] = hdr1->xor_val2; 12 | if (xor_val[0] == 0 && xor_val[1] == 0) return true; // already decoded 13 | 14 | DWORD* dwcontent_ptr = (DWORD*)content; 15 | const size_t dwcontent_size = content_size / sizeof(DWORD); 16 | for (size_t i = 3; i < dwcontent_size; i++) { 17 | dwcontent_ptr[i] ^= xor_val[i%2]; 18 | } 19 | return true; 20 | } 21 | 22 | DWORD lotus::calc_checksum(IN const BYTE* content, IN const size_t content_size) 23 | { 24 | const DWORD* file_buf = (const DWORD*)(content); 25 | DWORD checksum = 0; 26 | DWORD val1 = 0; 27 | DWORD val2 = 0; 28 | 29 | size_t size_dw = (content_size >> 2) - 3; 30 | if (!size_dw) { 31 | return 0; 32 | } 33 | 34 | size_t indx2 = 0; 35 | DWORD next_val = 0; 36 | do { 37 | next_val = file_buf[indx2 + 3]; 38 | if (indx2 % 3) { 39 | if (indx2 % 3 == 1) { 40 | val1 = 4 * next_val; 41 | val2 = 0x3FF57F3; 42 | } 43 | else { 44 | val1 = 15 * next_val; 45 | val2 = 0x82393F; 46 | } 47 | } 48 | else { 49 | val1 = 7 * next_val; 50 | val2 = 0x90335F; 51 | } 52 | 53 | checksum = (val1 % val2 + checksum) & 0xFFFFFFF; 54 | indx2++; 55 | 56 | } while (indx2 < size_dw); 57 | 58 | return checksum; 59 | } 60 | 61 | lotus::header1_t* lotus::get_hdr1(IN BYTE* content, IN size_t content_size) 62 | { 63 | if (content_size < sizeof(lotus::header1_t)) { 64 | return nullptr; 65 | } 66 | return (lotus::header1_t*)content; 67 | } 68 | 69 | BYTE* lotus::get_code(IN BYTE* content, IN size_t content_size, OUT size_t &code_size) 70 | { 71 | lotus::header1_t *hdr = get_hdr1(content, content_size); 72 | if (!hdr) return nullptr; 73 | if (hdr->code_size + sizeof(lotus::header1_t) > content_size) { 74 | return nullptr; 75 | } 76 | BYTE *ptr = (BYTE*)hdr + sizeof(lotus::header1_t); 77 | code_size = hdr->code_size; 78 | return ptr; 79 | } 80 | 81 | lotus::header2_t* lotus::get_hdr2(IN BYTE* content, IN size_t content_size) 82 | { 83 | lotus::header1_t* hdr1 = get_hdr1(content, content_size); 84 | if (!hdr1) { 85 | return nullptr; 86 | } 87 | size_t offset = hdr1->code_size + sizeof(lotus::header1_t); 88 | if (offset + sizeof(lotus::header2_t) > content_size) { 89 | return nullptr; 90 | } 91 | BYTE *ptr = content + offset; 92 | return (lotus::header2_t*)ptr; 93 | } 94 | 95 | DWORD* lotus::get_records(IN BYTE* content, IN size_t content_size) 96 | { 97 | lotus::header2_t *part2 = get_hdr2(content, content_size); 98 | if (!part2) return nullptr; 99 | 100 | BYTE *ptr = (BYTE*)part2 + sizeof(lotus::header2_t); 101 | return (DWORD*)ptr; 102 | } 103 | -------------------------------------------------------------------------------- /lotus_parser/lotus_print.cpp: -------------------------------------------------------------------------------- 1 | #include "lotus_print.h" 2 | #include 3 | #include 4 | #include // std::stringstream 5 | 6 | DWORD* print_dwords(DWORD *buf, size_t num) 7 | { 8 | for (size_t i = 0; i < num; i++) { 9 | std::cout << " : " << std::hex << buf[i]; 10 | } 11 | std::cout << std::endl; 12 | return buf + num; 13 | } 14 | 15 | std::string type_to_string(lotus::record_type_t &type) 16 | { 17 | switch (type) { 18 | case lotus::RTYPE_EXPORT: 19 | return "[Export]"; 20 | case lotus::RTYPE_IMPORT: 21 | return "[Import]"; 22 | case lotus::RTYPE_RELOC: 23 | return "[Reloc]"; 24 | } 25 | return ""; 26 | } 27 | 28 | std::string counter_to_string(DWORD cntr) 29 | { 30 | switch (cntr) { 31 | case lotus::ITYPE_ORDINAL: 32 | return "[import by Ordinal]"; 33 | case lotus::ITYPE_NAME: 34 | return "[import by Name]"; 35 | case lotus::ITYPE_ERASE_FUNC: 36 | return "[erase function name]"; 37 | case lotus::ITYPE_ERASE_DLL: 38 | return "[erase DLL name]"; 39 | } 40 | return ""; 41 | } 42 | 43 | void print_export(BYTE *part1, lotus::export_t* ep) 44 | { 45 | std::cout << "Export: " << std::hex << ep->entry_rva << " : "; 46 | if (ep->name_rva == 0) { 47 | std::cout << ep->name_rva << " (unnamed)\n"; 48 | } 49 | else { 50 | char* name_ptr = (char*)(part1 + ep->name_rva); 51 | std::cout << std::hex << ep->name_rva << " " << name_ptr << std::endl; 52 | } 53 | } 54 | 55 | void print_imports(BYTE *part1, lotus::import_t* imp) 56 | { 57 | if (!imp || !part1) return; 58 | 59 | std::cout << imp->counter << " : " << counter_to_string(imp->counter) << "\n"; 60 | 61 | char* dll_ptr = (char*)(part1 + imp->dll_rva); 62 | //TODO: check the pointers 63 | std::cout << std::hex << imp->dll_rva << " : " << dll_ptr << std::endl; 64 | 65 | if (imp->counter != lotus::ITYPE_ORDINAL) { 66 | char* imp_ptr = (char*)(part1 + imp->func_rva); 67 | std::cout << std::hex << imp->func_rva << " : " << imp_ptr; 68 | } 69 | else { 70 | std::cout << std::hex << imp->func_rva; 71 | } 72 | std::cout << std::endl; 73 | } 74 | 75 | void print_table(BYTE *content, size_t content_size, size_t module_size) 76 | { 77 | BYTE *code_part = content + sizeof(lotus::header1_t); 78 | size_t code_size = content_size - sizeof(lotus::header1_t); 79 | 80 | DWORD *table = lotus::get_records(content, content_size); 81 | size_t i = 0; 82 | 83 | size_t args_by_type[4]; 84 | args_by_type[lotus::RTYPE_NONE] = 0; 85 | args_by_type[lotus::RTYPE_RELOC] = 1; 86 | args_by_type[lotus::RTYPE_EXPORT] = 3; 87 | args_by_type[lotus::RTYPE_IMPORT] = 4; 88 | 89 | while (true) { 90 | lotus::record_type_t type = (lotus::record_type_t) table[i++]; 91 | if (type == lotus::RTYPE_NONE) break; 92 | 93 | std::cout << "type: " << std::hex << type << " " << type_to_string(type); 94 | size_t arg_num = args_by_type[type]; 95 | print_dwords(&table[i], arg_num); 96 | 97 | switch (type) { 98 | case lotus::RTYPE_RELOC: 99 | break; 100 | case lotus::RTYPE_EXPORT: 101 | print_export(code_part, (lotus::export_t*) &table[i]); 102 | break; 103 | case lotus::RTYPE_IMPORT: 104 | print_imports(code_part, (lotus::import_t*) &table[i]); 105 | break; 106 | } 107 | table += arg_num; 108 | } 109 | } 110 | 111 | bool lotus::print_headers(BYTE *content, size_t content_size) 112 | { 113 | if (!lotus::decode_file(content, content_size)) { 114 | std::cerr << "Decoding failed!" << std::endl; 115 | return false; 116 | } 117 | lotus::header1_t *hdr1 = lotus::get_hdr1(content, content_size); 118 | if (!hdr1) { 119 | return false; 120 | } 121 | DWORD calculated_checks = lotus::calc_checksum(content, content_size); 122 | std::cout << "\nHDR1: \nchecksum: " << std::hex << hdr1->checksum; 123 | if (calculated_checks == hdr1->checksum) { 124 | std::cout << " [VALID]"; 125 | } 126 | else { 127 | std::cout << " [INVALID]"; 128 | } 129 | std::cout << "\ncode size: " << std::hex << hdr1->code_size 130 | << "\n---" << std::endl; 131 | 132 | lotus::header2_t *hdr2 = lotus::get_hdr2(content, content_size); 133 | if (!hdr2) { 134 | return false; 135 | } 136 | std::cout << "HDR2: \nDllMain: " << std::hex << hdr2->dll_main 137 | << "\nIAT size: " << std::hex << hdr2->iat_size 138 | << "\n---\n" << std::endl; 139 | 140 | print_table(content, content_size, hdr1->code_size); 141 | std::cout << std::endl; 142 | return true; 143 | } 144 | -------------------------------------------------------------------------------- /iced_id_parser/iceid_to_pe.cpp: -------------------------------------------------------------------------------- 1 | #include "iceid_to_pe.h" 2 | #include "util.h" 3 | 4 | #include 5 | 6 | #ifndef PAGE_SIZE 7 | #define PAGE_SIZE 0x1000 8 | #endif 9 | 10 | BYTE* icedid::alloc_pe(IN const iced_module_hdr &hdr, OUT size_t &out_size) 11 | { 12 | out_size = 0; 13 | BYTE* allocated = (BYTE*)VirtualAlloc(0, hdr.image_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); 14 | if (allocated) { 15 | out_size = hdr.image_size; 16 | } 17 | return allocated; 18 | } 19 | 20 | size_t icedid::copy_sections(IN const iced_module_hdr &hdr, IN OUT BYTE* buf, IN const size_t buf_size) 21 | { 22 | size_t copied_cntr = 0; 23 | for (size_t i = 0; i < hdr.sections_count; i++) { 24 | if (hdr.sections[i].virtual_size == 0) continue; 25 | 26 | const size_t copy_size = hdr.sections[i].raw_size; 27 | 28 | BYTE* vptr = buf + hdr.sections[i].virtual_offset; 29 | if (!validate_ptr(buf, buf_size, vptr, copy_size)) continue; 30 | 31 | BYTE* rptr = (BYTE*)&hdr + hdr.sections[i].raw_offset; 32 | if (!validate_ptr((BYTE*)&hdr, hdr.image_size, rptr, copy_size)) continue; 33 | 34 | memcpy(vptr, rptr, copy_size); 35 | copied_cntr++; 36 | } 37 | return copied_cntr; 38 | } 39 | 40 | void sort_sections(IN const iced_module_hdr &hdr, std::map §ions_sorted) 41 | { 42 | for (size_t i = 0; i < hdr.sections_count; i++) { 43 | DWORD offset = hdr.sections[i].virtual_offset; 44 | sections_sorted[offset] = i; 45 | } 46 | 47 | std::map::iterator itr; 48 | for (itr = sections_sorted.begin(); itr != sections_sorted.end(); itr++) { 49 | size_t index = itr->second; 50 | const ICED_SECTION& iceid_sec = hdr.sections[index]; 51 | } 52 | } 53 | 54 | DWORD translate_protect(DWORD charact) 55 | { 56 | switch (charact) { 57 | case PAGE_EXECUTE_READWRITE: 58 | return IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE; 59 | case PAGE_EXECUTE_READ: 60 | return IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ; 61 | case PAGE_READWRITE: 62 | return IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_READ; 63 | case PAGE_READONLY: 64 | return IMAGE_SCN_MEM_READ; 65 | } 66 | return 0; 67 | } 68 | 69 | bool copy_sec_hdrs(IN const iced_module_hdr &hdr, IN OUT BYTE* buf, IN const size_t buf_size, size_t sec_hdr_offset) 70 | { 71 | std::map sections_sorted; 72 | sort_sections(hdr, sections_sorted); 73 | 74 | BYTE* buffer = buf + sec_hdr_offset; 75 | std::map::iterator itr; 76 | size_t i = 0; 77 | for (itr = sections_sorted.begin(); itr != sections_sorted.end(); itr++, i++) { 78 | IMAGE_SECTION_HEADER* sections = (IMAGE_SECTION_HEADER*)((ULONG_PTR)buffer + sizeof(IMAGE_SECTION_HEADER) * i); 79 | if (!validate_ptr(buf, buf_size, sections, sizeof(IMAGE_SECTION_HEADER)) ) break; 80 | 81 | size_t index = itr->second; 82 | const ICED_SECTION& iceid_sec = hdr.sections[index]; 83 | 84 | sections->VirtualAddress = iceid_sec.virtual_offset; 85 | sections->PointerToRawData = iceid_sec.virtual_offset; 86 | sections->SizeOfRawData = iceid_sec.raw_size; 87 | sections->Misc.VirtualSize = iceid_sec.virtual_size; 88 | sections->Characteristics = translate_protect(iceid_sec.characteristics); 89 | } 90 | 91 | std::cout << "[*] Copied section headers\n"; 92 | return true; 93 | } 94 | 95 | template 96 | void copy_headers(IN const iced_module_hdr &hdr, IN OUT BYTE* buf, IN const size_t buf_size, WORD machine) 97 | { 98 | 99 | IMAGE_DOS_HEADER dos_hdr = { 0 }; 100 | dos_hdr.e_magic = IMAGE_DOS_SIGNATURE; 101 | dos_hdr.e_lfanew = sizeof(IMAGE_DOS_HEADER); 102 | memcpy(buf, &dos_hdr, sizeof(IMAGE_DOS_HEADER)); 103 | 104 | BYTE *vptr = buf + sizeof(IMAGE_DOS_HEADER); 105 | 106 | IMAGE_NT_HEADERS_T nt_hdr = { 0 }; 107 | nt_hdr.Signature = IMAGE_NT_SIGNATURE; 108 | nt_hdr.FileHeader.NumberOfSections = hdr.sections_count; 109 | nt_hdr.FileHeader.SizeOfOptionalHeader = sizeof(nt_hdr.OptionalHeader); 110 | nt_hdr.FileHeader.Machine = machine; 111 | 112 | if (machine == IMAGE_FILE_MACHINE_I386) { 113 | nt_hdr.OptionalHeader.Magic = IMAGE_NT_OPTIONAL_HDR32_MAGIC; 114 | } 115 | else { 116 | nt_hdr.OptionalHeader.Magic = IMAGE_NT_OPTIONAL_HDR64_MAGIC; 117 | } 118 | nt_hdr.OptionalHeader.AddressOfEntryPoint = hdr.entry_point_va; 119 | nt_hdr.OptionalHeader.SizeOfImage = hdr.image_size; 120 | nt_hdr.OptionalHeader.FileAlignment = PAGE_SIZE; 121 | nt_hdr.OptionalHeader.SectionAlignment = PAGE_SIZE; 122 | nt_hdr.OptionalHeader.ImageBase = hdr.image_base; 123 | nt_hdr.OptionalHeader.SizeOfHeaders = sizeof(IMAGE_DOS_HEADER) + sizeof(IMAGE_NT_HEADERS_T); 124 | nt_hdr.OptionalHeader.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_GUI; 125 | 126 | nt_hdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = hdr.import_dir_va; 127 | nt_hdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = hdr.reloc_dir_va; 128 | nt_hdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = hdr.reloc_dir_size; 129 | 130 | memcpy(vptr, &nt_hdr, sizeof(IMAGE_NT_HEADERS_T)); 131 | 132 | size_t sec_hdr_offset = sizeof(IMAGE_DOS_HEADER) + sizeof(IMAGE_NT_HEADERS_T); 133 | copy_sec_hdrs(hdr, buf, buf_size, sec_hdr_offset); 134 | } 135 | 136 | 137 | bool icedid::convert_to_pe(const iced_module_hdr& hdr, char* filename) 138 | { 139 | size_t buf_size = 0; 140 | BYTE* buf = alloc_pe(hdr, buf_size); 141 | if (!buf) return false; 142 | 143 | copy_sections(hdr, buf, buf_size); 144 | bool is32bit = true; 145 | 146 | if ((DWORD(hdr.image_base)) < hdr.image_base) { 147 | is32bit = false; 148 | } 149 | if (is32bit) { 150 | std::cout << "[*] 32bit module\n"; 151 | copy_headers(hdr, buf, buf_size, IMAGE_FILE_MACHINE_I386); 152 | } 153 | else { 154 | std::cout << "[*] 64bit module\n"; 155 | copy_headers(hdr, buf, buf_size, IMAGE_FILE_MACHINE_AMD64); 156 | } 157 | 158 | std::cout << "[*] Saving buffer!\n"; 159 | dump_to_file(filename, buf, buf_size); 160 | return true; 161 | } 162 | -------------------------------------------------------------------------------- /isfb_parser/isfb_to_pe.cpp: -------------------------------------------------------------------------------- 1 | #include "isfb_to_pe.h" 2 | #include "util.h" 3 | 4 | #include 5 | 6 | #ifndef PAGE_SIZE 7 | #define PAGE_SIZE 0x1000 8 | #endif 9 | 10 | 11 | BYTE* alloc_pe(IN const isfb_hdr &hdr, OUT size_t &out_size) 12 | { 13 | out_size = 0; 14 | BYTE* allocated = (BYTE*)VirtualAlloc(0, hdr.image_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); 15 | if (allocated) { 16 | out_size = hdr.image_size; 17 | } 18 | return allocated; 19 | } 20 | 21 | size_t copy_sections(IN const isfb_hdr &hdr, IN OUT BYTE* buf, IN const size_t buf_size) 22 | { 23 | size_t copied_cntr = 0; 24 | for (size_t i = 0; i < hdr.sections_count; i++) { 25 | if (hdr.sections[i].virtual_size == 0) continue; 26 | 27 | BYTE* vptr = buf + hdr.sections[i].virtual_offset; 28 | if (!validate_ptr(buf, buf_size, vptr, hdr.sections[i].raw_size)) continue; 29 | 30 | BYTE* rptr = (BYTE*)&hdr + hdr.sections[i].raw_offset; 31 | if (!validate_ptr((BYTE*)&hdr, hdr.size, rptr, hdr.sections[i].raw_size)) continue; 32 | 33 | memcpy(vptr, rptr, hdr.sections[i].raw_size); 34 | copied_cntr++; 35 | } 36 | return copied_cntr; 37 | } 38 | 39 | size_t copy_ddirs(IN const isfb_hdr &hdr, IN OUT BYTE* buf, IN const size_t buf_size) 40 | { 41 | size_t copied_cntr = 0; 42 | for (size_t i = 0; i < ISFB_DDIR_COUNT; i++) { 43 | const ISFB_DDIR &ddir = hdr.data_dir[i]; 44 | 45 | if (ddir.size == 0) continue; 46 | 47 | BYTE* vptr = buf + ddir.original_rva; 48 | if (!validate_ptr(buf, buf_size, vptr, ddir.size)) continue; 49 | 50 | BYTE* rptr = (BYTE*)&hdr + ddir.offset; 51 | if (!validate_ptr((BYTE*)&hdr, hdr.size, rptr, ddir.size)) continue; 52 | memcpy(vptr, rptr, ddir.size); 53 | copied_cntr++; 54 | } 55 | return copied_cntr; 56 | } 57 | 58 | template 59 | size_t fill_nt_hdr(IN const isfb_hdr &hdr, IN OUT IMAGE_NT_HEADERS_T* nt_hdrs, bool is64) 60 | { 61 | if (!nt_hdrs) return 0; 62 | 63 | nt_hdrs->OptionalHeader.AddressOfEntryPoint = hdr.entry_point; 64 | nt_hdrs->OptionalHeader.SizeOfImage = hdr.image_size; 65 | nt_hdrs->FileHeader.NumberOfSections = hdr.sections_count; 66 | nt_hdrs->FileHeader.Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_DLL; 67 | nt_hdrs->OptionalHeader.SectionAlignment = PAGE_SIZE; 68 | 69 | if (is64) { 70 | nt_hdrs->FileHeader.Machine = IMAGE_FILE_MACHINE_AMD64; 71 | nt_hdrs->OptionalHeader.Magic = IMAGE_NT_OPTIONAL_HDR64_MAGIC; 72 | nt_hdrs->FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_NT_HEADERS64); 73 | } 74 | else { 75 | nt_hdrs->FileHeader.Machine = IMAGE_FILE_MACHINE_I386; 76 | nt_hdrs->OptionalHeader.Magic = IMAGE_NT_OPTIONAL_HDR32_MAGIC; 77 | nt_hdrs->FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_NT_HEADERS32); 78 | } 79 | //fill data dir: 80 | size_t dir_entries[] = { 81 | IMAGE_DIRECTORY_ENTRY_IMPORT, 82 | IMAGE_DIRECTORY_ENTRY_EXPORT, 83 | IMAGE_DIRECTORY_ENTRY_IAT, 84 | IMAGE_DIRECTORY_ENTRY_SECURITY, 85 | IMAGE_DIRECTORY_ENTRY_EXCEPTION, 86 | IMAGE_DIRECTORY_ENTRY_BASERELOC 87 | }; 88 | for (size_t i = 0; i < ISFB_DDIR_COUNT; i++) { 89 | size_t entry_id = dir_entries[i]; 90 | if (hdr.data_dir[i].original_rva == 0) { 91 | // do not overwrite if empty 92 | continue; 93 | } 94 | nt_hdrs->OptionalHeader.DataDirectory[entry_id].VirtualAddress = hdr.data_dir[i].original_rva; 95 | nt_hdrs->OptionalHeader.DataDirectory[entry_id].Size = hdr.data_dir[i].size; 96 | } 97 | return sizeof(IMAGE_NT_HEADERS_T); 98 | } 99 | 100 | template 101 | size_t realign_sections(IN const isfb_hdr &hdr, IN OUT IMAGE_NT_HEADERS_T* nt_hdr, IN OUT BYTE* buf, IN const size_t buf_size) 102 | { 103 | if (!nt_hdr) return 0; 104 | 105 | IMAGE_SECTION_HEADER* sec_ptr = (IMAGE_SECTION_HEADER*)((BYTE*)&nt_hdr->OptionalHeader + nt_hdr->FileHeader.SizeOfOptionalHeader); 106 | 107 | for (size_t i = 0; i < hdr.sections_count; i++) { 108 | //std::cout << "section: " << std::hex << sec_ptr[i].PointerToRawData << "\n"; 109 | if (!validate_ptr(buf, buf_size, &sec_ptr[i], sizeof(IMAGE_SECTION_HEADER))) { 110 | break; 111 | } 112 | sec_ptr[i].VirtualAddress = hdr.sections[i].virtual_offset; 113 | sec_ptr[i].PointerToRawData = hdr.sections[i].virtual_offset; 114 | sec_ptr[i].Misc.VirtualSize = hdr.sections[i].virtual_size; 115 | sec_ptr[i].SizeOfRawData = hdr.sections[i].raw_size; 116 | sec_ptr[i].Characteristics = hdr.sections[i].characteristics; 117 | } 118 | nt_hdr->OptionalHeader.FileAlignment = nt_hdr->OptionalHeader.SectionAlignment; 119 | return hdr.sections_count; 120 | } 121 | 122 | size_t copy_headers(IN const isfb_hdr &hdr, IN OUT BYTE* buf, IN const size_t buf_size) 123 | { 124 | BYTE* rptr = (BYTE*)&hdr + hdr.nt_hdr_offset; 125 | if (!validate_ptr((BYTE*)&hdr, hdr.size, rptr, hdr.nt_hdr_size)) return 0; 126 | 127 | BYTE* vptr = buf + sizeof(IMAGE_DOS_HEADER); 128 | if (!validate_ptr(buf, buf_size, vptr, hdr.nt_hdr_size)) return 0; 129 | 130 | memcpy(vptr, rptr, hdr.nt_hdr_size); 131 | DWORD arch = hdr.machine_id; 132 | 133 | IMAGE_DOS_HEADER dos_hdr = { 0 }; 134 | dos_hdr.e_magic = IMAGE_DOS_SIGNATURE; 135 | dos_hdr.e_lfanew = sizeof(IMAGE_DOS_HEADER); 136 | memcpy(buf, &dos_hdr, sizeof(IMAGE_DOS_HEADER)); 137 | 138 | DWORD nt_sign = IMAGE_NT_SIGNATURE; 139 | memcpy(vptr, &nt_sign, sizeof(IMAGE_NT_SIGNATURE)); 140 | 141 | if (arch == IMAGE_FILE_MACHINE_I386) { 142 | IMAGE_NT_HEADERS32* nt_hdr = (IMAGE_NT_HEADERS32*)vptr; 143 | fill_nt_hdr(hdr, nt_hdr, false); 144 | realign_sections(hdr, nt_hdr, buf, buf_size); 145 | } 146 | else { 147 | IMAGE_NT_HEADERS64* nt_hdr = (IMAGE_NT_HEADERS64*)vptr; 148 | fill_nt_hdr(hdr, nt_hdr, true); 149 | realign_sections(hdr, nt_hdr, buf, buf_size); 150 | } 151 | return hdr.nt_hdr_size; 152 | } 153 | 154 | bool isfb_to_pe(const isfb_hdr& hdr, char* filename) 155 | { 156 | size_t buf_size = 0; 157 | BYTE* buf = alloc_pe(hdr, buf_size); 158 | if (!buf) return false; 159 | std::cout << "Copying sections to PE...\n"; 160 | copy_sections(hdr, buf, buf_size); 161 | std::cout << "Copying headers to PE...\n"; 162 | copy_headers(hdr, buf, buf_size); 163 | std::cout << "Copying data dirs to PE...\n"; 164 | copy_ddirs(hdr, buf, buf_size); 165 | dump_to_file(filename, buf, buf_size); 166 | return true; 167 | } 168 | --------------------------------------------------------------------------------