├── .gitignore ├── COPYING ├── LICENSE.txt ├── README.rst ├── pefile_to_maec.py ├── pefile_to_maec ├── LICENSE.txt ├── __init__.py ├── mappings │ ├── __init__.py │ ├── file_object.py │ ├── image_data_directory.py │ ├── image_dos_header.py │ ├── image_export_directory.py │ ├── image_file_header.py │ ├── image_imports.py │ ├── image_nt_headers.py │ ├── image_optional_header.py │ ├── image_resources.py │ └── image_sections.py └── pefile_parser.py └── setup.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | *.py[co] 3 | build/ 4 | dist/ 5 | *.egg-info 6 | .settings/ 7 | .project 8 | .pydevproject 9 | .vagrant/ 10 | 11 | docs/_build 12 | .DS_Store 13 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | ************** 2 | pefile-to-maec 3 | ************** 4 | 5 | Copyright (c) 2015, The MITRE Corporation All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | 2. Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | 3. The name of the author may not be used to endorse or promote products 18 | derived from this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 21 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 22 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 23 | EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 24 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 25 | OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 28 | IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 29 | OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015, The MITRE Corporation 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | * Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | * Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | * Neither the name of The MITRE Corporation nor the 12 | names of its contributors may be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 19 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | pefile-to-maec 2 | ============== 3 | v1.0.0-beta1 4 | 5 | A Python library for converting output from Ero Carrera's `pefile `_ utility to Malware Attribute Enumeration and Characterization (MAEC™) XML content. It is currently in the BETA phase. 6 | 7 | pefile-to-maec uses the pefile package: "pefile is a multi-platform Python module to read and work with Portable Executable (aka PE) files. Most of the information in the PE Header is accessible, as well as all the sections, section's information and data."[1] 8 | 9 | This package consists of a module that captures the pefile output for binary files in MAEC format (``/pefile_to_maec``), and a script that uses that module (``pefile_to_maec.py``). 10 | 11 | :Source: https://github.com/MAECProject/pefile-to-maec 12 | :MAEC: https://maecproject.github.io/ 13 | 14 | Dependencies 15 | ------------ 16 | The pefile-to-maec script depends on the presence of certain packages/libraries 17 | to function. Please refer to their installation documentation for installation 18 | instructions. 19 | 20 | - `python-maec >=4.1.0.9 and < 4.1.0.13 `_ 21 | - `python-cybox >=2.1.0.8 and < 2.1.0.13. `_ 22 | - `pefile >=1.2.10 `_ 23 | 24 | Usage 25 | ----- 26 | 27 | The script can be called with: 28 | 29 | ``python pefile_to_maec.py infile outfile`` 30 | 31 | Where ``infile`` refers to the input PE binary file and ``outfile`` the name of 32 | the MAEC XML file to which the output will be written. 33 | 34 | The module exposes the following functions: 35 | 36 | - ``generate_package_from_binary_filepath`` - given an filepath, return 37 | a python-maec Package object with the PEFile output. 38 | 39 | To use these module functions, the module must first be installed with setuptools: 40 | 41 | ``python setup.py install`` 42 | 43 | At which point it can be used as a library: 44 | 45 | ``import pefile_to_maec`` 46 | 47 | Compatibility 48 | ------------- 49 | 50 | The pefile-to-maec library is tested and written against python ``2.7.x``. Compatibility with other python versions is neither guaranteed nor implied. 51 | 52 | Supported Features 53 | ------------------ 54 | The following features are mapped from the PEFile output and captured in MAEC: 55 | 56 | - Metadata 57 | - File name (on disk) 58 | - File path 59 | - File size (in bytes) 60 | - Hashes (MD5, SHA1) 61 | - DOS header 62 | - File header 63 | - Optional header 64 | - Exports 65 | - Imports 66 | - Resource directories 67 | 68 | Feedback 69 | -------- 70 | 71 | Bug reports and feature requests are welcome and encouraged. Pull requests are 72 | especially appreciated. Feel free to use the issue tracker on GitHub, join the `MAEC Community Email Discussion List `_, or send an 73 | email directly to maec@mitre.org. 74 | -------------------------------------------------------------------------------- /pefile_to_maec.py: -------------------------------------------------------------------------------- 1 | # -*- coding: Latin-1 -*- 2 | # Copyright (c) 2015, The MITRE Corporation. All rights reserved. 3 | # For more information, please refer to the LICENSE.txt file. 4 | 5 | import argparse 6 | import os 7 | from pefile_to_maec import __version__, generate_package_from_binary_filepath 8 | from maec.misc.options import ScriptOptions 9 | 10 | def create_maec(inputfile, outpath, options_dict): 11 | package = generate_package_from_binary_filepath(inputfile) 12 | package.to_xml_file(outpath, custom_header=options_dict) 13 | 14 | if __name__ == '__main__': 15 | 16 | # Setup the argument parser 17 | parser = argparse.ArgumentParser(description="Ero Carrera's Pefile module to MITRE MAEC Translator v" + __version__) 18 | parser.add_argument("infile", help="the name of the input portable executable (PE) file to capture the pefile output for.") 19 | parser.add_argument("outfile", help="the name of the MAEC XML file to which the output will be written.") 20 | args = parser.parse_args() 21 | 22 | options_dict = {"Created by":"PEFile to MAEC (http://github.com/MAECProject/pefile-to-maec)"} 23 | 24 | # Test if the input is a directory or file 25 | if os.path.isfile(args.infile): 26 | outfilename = args.outfile 27 | # Test if the output is a directory 28 | # If so, concatenate "_maec.xml" to the input filename 29 | # and use this as the output filename 30 | if os.path.isdir(args.outfile): 31 | outfilename = os.path.join(args.outfile, str(os.path.basename(args.infile))[:-4] + "_maec.xml") 32 | # If we're dealing with a single file, just call create_maec() 33 | create_maec(args.infile, outfilename, options_dict) 34 | # If a directory was specified, perform the corresponding conversion 35 | elif os.path.isdir(args.infile): 36 | # Iterate and try to parse/convert each file in the directory 37 | for filename in os.listdir(args.infile): 38 | # Only handle PE files 39 | if str(filename).lower()[-3:] not in ["exe", "dll", "sys"]: 40 | print str("Error: {0} does not appear to be an PE file. Skipping.\n").format(filename) 41 | continue 42 | outfilename = str(filename)[:-4] + "pefile_maec.xml" 43 | create_maec(os.path.join(args.infile, filename), os.path.join(args.outfile, outfilename), options_dict) 44 | else: 45 | print "Input file " + args.infile + " does not exist" 46 | -------------------------------------------------------------------------------- /pefile_to_maec/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015, The MITRE Corporation 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | * Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | * Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | * Neither the name of The MITRE Corporation nor the 12 | names of its contributors may be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 19 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | -------------------------------------------------------------------------------- /pefile_to_maec/__init__.py: -------------------------------------------------------------------------------- 1 | import pefile_to_maec 2 | import pefile_parser 3 | 4 | __version__ = '1.0.0-beta1' 5 | 6 | def generate_package_from_binary_filepath(input_path): 7 | "Accept a filepath to a PE file and return a MAEC Package object" 8 | # Instantiate the pefile parser and parse the pefile object 9 | parser = pefile_parser.PefileParser(input_path) 10 | # Instantiate the MAEC translator and perform the translation 11 | maec_translator = pefile_parser.PefileToMAEC(parser) 12 | package = maec_translator.package 13 | package.__input_namespaces__["http://code.google.com/p/pefile/"] = "pefile" 14 | # return the MAEC Package object 15 | return package 16 | -------------------------------------------------------------------------------- /pefile_to_maec/mappings/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MAECProject/pefile-to-maec/dfd0f5ddf58d4c09b7c0acdff49639e9fb071c2b/pefile_to_maec/mappings/__init__.py -------------------------------------------------------------------------------- /pefile_to_maec/mappings/file_object.py: -------------------------------------------------------------------------------- 1 | # -*- coding: Latin-1 -*- 2 | # Copyright (c) 2015, The MITRE Corporation. All rights reserved. 3 | # See License.txt for complete terms. 4 | 5 | # file object -> CybOX File Object mappings 6 | file_object_mappings = {'file_format': 'file_format', 7 | 'type': 'type', 8 | 'file_name': 'file_name', 9 | 'file_path': 'file_path', 10 | 'size': 'size_in_bytes', 11 | 'magic_number': 'magic_number', 12 | 'file_extension': 'file_extension', 13 | 'entropy': 'peak_entropy'} 14 | 15 | -------------------------------------------------------------------------------- /pefile_to_maec/mappings/image_data_directory.py: -------------------------------------------------------------------------------- 1 | # -*- coding: Latin-1 -*- 2 | # Copyright (c) 2015, The MITRE Corporation. All rights reserved. 3 | # See License.txt for complete terms. 4 | 5 | # IMAGE_DATA_DIRECTORY_ -> CybOX Windows Executable File Object Data Directory DataDirectoryStruct mappings 6 | """Represents an array of data directory structures containing the RVA and size of the actual object. 7 | 8 | pe_struct: _IMAGE_DATA_DIRECTORY 9 | 10 | DWORD VirtualAddress; 11 | DWORD Size; 12 | 13 | pefile_struct: __IMAGE_DATA_DIRECTORY_format__ 14 | cybox_struct: DataDirectoryStructType 15 | 16 | """ 17 | IMAGE_DATA_DIRECTORY_MAPPINGS = {'VirtualAddress':'headers/optional_header/data_directory/virtual_address', 18 | 'Size':'headers/optional_header/data_directory/size'} 19 | 20 | # __IMAGE_DATA_DIRECTORY_ENTRY_format__ -> CybOX Windows Executable File Object Data Directory mappings 21 | """Each IMAGE_DATA_DIRECTORY_ENTRY is of IMAGE_DATA_DIRECTORY type. 22 | 23 | // Directory Entries 24 | 25 | #define IMAGE_DIRECTORY_ENTRY_EXPORT 0 // Export Directory 26 | #define IMAGE_DIRECTORY_ENTRY_IMPORT 1 // Import Directory 27 | #define IMAGE_DIRECTORY_ENTRY_RESOURCE 2 // Resource Directory 28 | #define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 // Exception Directory 29 | #define IMAGE_DIRECTORY_ENTRY_SECURITY 4 // Security Directory 30 | #define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 // Base Relocation Table 31 | #define IMAGE_DIRECTORY_ENTRY_DEBUG 6 // Debug Directory 32 | // IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7 // (X86 usage) 33 | #define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE 7 // Architecture Specific Data 34 | #define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 // RVA of GP 35 | #define IMAGE_DIRECTORY_ENTRY_TLS 9 // TLS Directory 36 | #define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 // Load Configuration Directory 37 | #define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 11 // Bound Import Directory in headers 38 | #define IMAGE_DIRECTORY_ENTRY_IAT 12 // Import Address Table 39 | #define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 13 // Delay Load Import Descriptors 40 | #define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14 // COM Runtime descriptor 41 | 42 | """ 43 | IMAGE_DATA_DIRECTORY_ENTRY_MAPPINGS = {'IMAGE_DIRECTORY_ENTRY_EXPORT':'headers/optional_header/data_directory/export_table', 44 | 'IMAGE_DIRECTORY_ENTRY_IMPORT':'headers/optional_header/data_directory/import_table', 45 | 'IMAGE_DIRECTORY_ENTRY_RESOURCE':'headers/optional_header/data_directory/resource_table', 46 | 'IMAGE_DIRECTORY_ENTRY_EXCEPTION':'headers/optional_header/data_directory/exception_table', 47 | 'IMAGE_DIRECTORY_ENTRY_SECURITY':'headers/optional_header/data_directory/certificate_table', 48 | 'IMAGE_DIRECTORY_ENTRY_BASERELOC':'headers/optional_header/data_directory/base_relocation_table', 49 | 'IMAGE_DIRECTORY_ENTRY_DEBUG':'headers/optional_header/data_directory/debug', 50 | 'IMAGE_DIRECTORY_ENTRY_COPYRIGHT':'headers/optional_header/data_directory/architecture', 51 | 'IMAGE_DIRECTORY_ENTRY_GLOBALPTR':'headers/optional_header/data_directory/global_ptr', 52 | 'IMAGE_DIRECTORY_ENTRY_TLS':'headers/optional_header/data_directory/tls_table', 53 | 'IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG':'headers/optional_header/data_directory/load_config', 54 | 'IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT':'headers/optional_header/data_directory/bound_import', 55 | 'IMAGE_DIRECTORY_ENTRY_IAT':'headers/optional_header/data_directory/import_address_table', 56 | 'IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT':'headers/optional_header/data_directory/delay_import_descriptor', 57 | 'IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR':'headers/optional_header/data_directory/clr_runtime_header', 58 | 'IMAGE_DIRECTORY_ENTRY_RESERVED':'headers/optional_header/data_directory/reserved'} 59 | 60 | # __IMAGE_DIRECTORY_ENTRY_EXPORT_format__ -> CybOX Windows Executable File Object Data Directory Export Table mappings 61 | IMAGE_DIRECTORY_ENTRY_EXPORT_MAPPINGS = {'VirtualAddress':'headers/optional_header/data_directory/export_table/virtual_address', 62 | 'Size':'headers/optional_header/data_directory/export_table/size'} 63 | 64 | # __IMAGE_DIRECTORY_ENTRY_IMPORT_format__ -> CybOX Windows Executable File Object Data Directory Import Table mappings 65 | IMAGE_DIRECTORY_ENTRY_IMPORT_MAPPINGS = {'VirtualAddress':'headers/optional_header/data_directory/import_table/virtual_address', 66 | 'Size':'headers/optional_header/data_directory/import_table/size'} 67 | 68 | # __IMAGE_DIRECTORY_ENTRY_RESOURCE_format__ -> CybOX Windows Executable File Object Data Directory Resource Table mappings 69 | IMAGE_DIRECTORY_ENTRY_RESOURCE_MAPPINGS = {'VirtualAddress':'headers/optional_header/data_directory/resource_table/virtual_address', 70 | 'Size':'headers/optional_header/data_directory/resource_table/size'} 71 | 72 | # IMAGE_DIRECTORY_ENTRY_EXCEPTION -> CybOX Windows Executable File Object Data Directory Exception Table mappings 73 | IMAGE_DIRECTORY_ENTRY_EXCEPTION_MAPPINGS = {'VirtualAddress':'headers/optional_header/data_directory/exception_table/virtual_address', 74 | 'Size':'headers/optional_header/data_directory/exception_table/size'} 75 | 76 | # IMAGE_DIRECTORY_ENTRY_SECURITY -> CybOX Windows Executable File Object Data Directory Certificate Table mappings 77 | IMAGE_DIRECTORY_ENTRY_SECURITY_MAPPINGS = {'VirtualAddress':'headers/optional_header/data_directory/certificate_table/virtual_address', 78 | 'Size':'headers/optional_header/data_directory/certificate_table/size'} 79 | 80 | # IMAGE_DIRECTORY_ENTRY_BASERELOC -> CybOX Windows Executable File Object Data Directory Base Relocation Table mappings 81 | IMAGE_DIRECTORY_ENTRY_BASERELOC_MAPPINGS = {'VirtualAddress':'headers/optional_header/data_directory/base_relocation_table/virtual_address', 82 | 'Size':'headers/optional_header/data_directory/base_relocation_table/size'} 83 | 84 | # IMAGE_DIRECTORY_ENTRY_DEBUG -> CybOX Windows Executable File Object Data Directory Debug mappings 85 | IMAGE_DIRECTORY_ENTRY_DEBUG_MAPPINGS = {'VirtualAddress':'headers/optional_header/data_directory/debug/virtual_address', 86 | 'Size':'headers/optional_header/data_directory/debug/size'} 87 | 88 | # IMAGE_DIRECTORY_ENTRY_COPYRIGHT -> CybOX Windows Executable File Object Data Directory Copyright mappings 89 | IMAGE_DIRECTORY_ENTRY_COPYRIGHT_MAPPINGS = {'VirtualAddress':'No_Mapping', 90 | 'Size':'No_Mapping'} 91 | 92 | # IMAGE_DIRECTORY_ENTRY_ARCHITECTURE -> CybOX Windows Executable File Object Data Directory Architecture mappings 93 | IMAGE_DIRECTORY_ENTRY_ARCHITECTURE_MAPPINGS = {'VirtualAddress':'headers/optional_header/data_directory/architecture/virtual_address', 94 | 'Size':'headers/optional_header/data_directory/architecture/size'} 95 | 96 | # IMAGE_DIRECTORY_ENTRY_GLOBALPTR -> CybOX Windows Executable File Object Data Directory Global Pointer mappings 97 | IMAGE_DIRECTORY_ENTRY_GLOBALPTR_MAPPINGS = {'VirtualAddress':'headers/optional_header/data_directory/global_ptr/virtual_address', 98 | 'Size':'headers/optional_header/data_directory/global_ptr/size'} 99 | 100 | # IMAGE_DIRECTORY_ENTRY_TLS -> CybOX Windows Executable File Object Data Directory Thread Local Storage Table mappings 101 | IMAGE_DIRECTORY_ENTRY_TLS_MAPPINGS = {'VirtualAddress':'headers/optional_header/data_directory/tls_table/virtual_address', 102 | 'Size':'headers/optional_header/data_directory/tls_table/size'} 103 | 104 | # IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG -> CybOX Windows Executable File Object Data Directory Load Config Table mappings 105 | IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG_MAPPINGS = {'VirtualAddress':'headers/optional_header/data_directory/load_config_table/virtual_address', 106 | 'Size':'headers/optional_header/data_directory/load_config_table/size'} 107 | 108 | # __IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT_format__ -> CybOX Windows Executable File Object Data Directory Bound Imports mappings 109 | IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT = {'VirtualAddress':'headers/optional_header/data_directory/bound_import/virtual_address', 110 | 'Size':'headers/optional_header/data_directory/bound_import/size'} 111 | 112 | # __IMAGE_DIRECTORY_ENTRY_IAT_format__ -> CybOX Windows Executable File Object Data Directory Import Address Table mappings 113 | IMAGE_DIRECTORY_ENTRY_IAT_MAPPINGS = {'VirtualAddress':'headers/optional_header/data_directory/import_address_table/virtual_address', 114 | 'Size':'headers/optional_header/data_directory/import_address_table/size'} 115 | 116 | # IMAGE_DIRECTORY_DELAY_IMPORT -> CybOX Windows Executable File Object Data Directory Delay Import Descriptor mappings 117 | IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT_MAPPINGS = {'VirtualAddress':'headers/optional_header/data_directory/delay_import_descriptor/virtual_address', 118 | 'Size':'headers/optional_header/data_directory/delay_import_descriptor/size'} 119 | 120 | # IMAGE_DIRECTORY_COM_DESCRIPTOR -> CybOX Windows Executable File Object Data Directory CLR Runtime Header mappings 121 | IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR_MAPPINGS = {'VirtualAddress':'headers/optional_header/data_directory/clr_runtime_header/virtual_address', 122 | 'Size':'headers/optional_header/data_directory/clr_runtime_header/size'} 123 | 124 | # IMAGE_DIRECTORY_RESERVED -> CybOX Windows Executable File Object Data Directory Reserved mappings 125 | IMAGE_DIRECTORY_ENTRY_RESERVED_MAPPINGS = {'VirtualAddress':'headers/optional_header/data_directory/reserved/virtual_address', 126 | 'Size':'headers/optional_header/data_directory/reserved/size'} 127 | 128 | -------------------------------------------------------------------------------- /pefile_to_maec/mappings/image_dos_header.py: -------------------------------------------------------------------------------- 1 | # -*- coding: Latin-1 -*- 2 | # Copyright (c) 2015, The MITRE Corporation. All rights reserved. 3 | # See License.txt for complete terms. 4 | 5 | # IMAGE_DOS_HEADER -> CybOX Windows Executable File Object DOSHeaderType mappings 6 | """Holds DOS Header information. 7 | 8 | pe_struct: _IMAGE_DOS_HEADER 9 | 10 | WORD e_magic; // Magic number 11 | WORD e_cblp; // Bytes on last page of file 12 | WORD e_cp; // Pages in file 13 | WORD e_crlc; // Relocations 14 | WORD e_cparhdr; // Size of header in paragraphs 15 | WORD e_minalloc; // Minimum extra paragraphs needed 16 | WORD e_maxalloc; // Maximum extra paragraphs needed 17 | WORD e_ss; // Initial (relative) SS value 18 | WORD e_sp; // Initial SP value 19 | WORD e_csum; // Checksum 20 | WORD e_ip; // Initial IP value 21 | WORD e_cs; // Initial (relative) CS value 22 | WORD e_lfarlc; // File address of relocation table 23 | WORD e_ovno; // Overlay number 24 | WORD e_res[4]; // Reserved words 25 | WORD e_oemid; // OEM identifier (for e_oeminfo) 26 | WORD e_oeminfo; // OEM information; e_oemid specific 27 | WORD e_res2[10]; // Reserved words 28 | LONG e_lfanew; // File address of new exe header 29 | 30 | pefile_struct: __IMAGE_DOS_HEADER_format__ 31 | cybox_struct: DOSHeaderType 32 | 33 | """ 34 | IMAGE_DOS_HEADER_MAPPINGS = {'e_magic':'e_magic', 35 | 'e_cblp':'e_cblp', 36 | 'e_cp':'e_cp', 37 | 'e_crlc':'e_crlc', 38 | 'e_cparhdr':'e_cparhdr', 39 | 'e_minalloc':'e_minalloc', 40 | 'e_maxalloc':'e_maxalloc', 41 | 'e_ss':'e_ss', 42 | 'e_sp':'e_sp', 43 | 'e_csum':'e_csum', 44 | 'e_ip':'e_ip', 45 | 'e_cs':'e_cs', 46 | 'e_lfarlc':'e_lfarlc', 47 | 'e_ovno':'e_ovro', 48 | 'e_res':'e_res', 49 | 'e_oemid':'e_oemid', 50 | 'e_oeminfo':'e_oeminfo', 51 | 'e_res2':'reserved2', 52 | 'e_lfanew':'e_lfanew'} 53 | 54 | -------------------------------------------------------------------------------- /pefile_to_maec/mappings/image_export_directory.py: -------------------------------------------------------------------------------- 1 | # -*- coding: Latin-1 -*- 2 | # Copyright (c) 2015, The MITRE Corporation. All rights reserved. 3 | # See License.txt for complete terms. 4 | 5 | # __IMAGE_EXPORT_DIRECTORY_format__ -> CybOX Windows Executable File Object Exports mappings 6 | IMAGE_EXPORT_DIRECTORY_MAPPINGS = {'Characteristics':'No_Mapping', 7 | 'TimeDateStamp':'exports/exports_time_stamp', 8 | 'MajorVersion':'No_Mapping', 9 | 'MinorVersion':'No_Mapping', 10 | 'Name':'exports/name', 11 | 'Base':'headers/optional_header/image_base', 12 | 'NumberOfFunctions':'exports/number_of_functions', 13 | 'NumberOfNames':'exports/number_of_names', 14 | 'AddressOfFunctions':'No_Mapping', # RVA from base of image 15 | 'AddressOfNames':'No_Mapping', # RVA from base of image 16 | 'AddressOfNameOrdinals':'No_Mapping'} # RVA from base of image 17 | -------------------------------------------------------------------------------- /pefile_to_maec/mappings/image_file_header.py: -------------------------------------------------------------------------------- 1 | # -*- coding: Latin-1 -*- 2 | # Copyright (c) 2015, The MITRE Corporation. All rights reserved. 3 | # See License.txt for complete terms. 4 | 5 | # IMAGE_FILE_HEADER -> CybOX Windows Executable File Object PEFileHeaderType mappings 6 | """Holds PE File Header information. 7 | 8 | pe_struct: _IMAGE_FILE_HEADER 9 | 10 | WORD Machine; 11 | WORD NumberOfSections; 12 | DWORD TimeDateStamp; 13 | DWORD PointerToSymbolTable; 14 | DWORD NumberOfSymbols; 15 | WORD SizeOfOptionalHeader; 16 | WORD Characteristics; 17 | 18 | pefile_struct: __IMAGE_FILE_HEADER_format__ 19 | cybox_struct: PEFileHeaderType 20 | 21 | """ 22 | IMAGE_FILE_HEADER_MAPPINGS = {'Machine':'machine', 23 | 'NumberOfSections':'number_of_sections', 24 | 'TimeDateStamp':'time_date_stamp', 25 | 'PointerToSymbolTable':'pointer_to_symbol_table', 26 | 'NumberOfSymbols':'number_of_symbols', 27 | 'SizeOfOptionalHeader':'size_of_optional_header', 28 | 'Characteristics':'characteristics'} 29 | 30 | -------------------------------------------------------------------------------- /pefile_to_maec/mappings/image_imports.py: -------------------------------------------------------------------------------- 1 | # -*- coding: Latin-1 -*- 2 | # Copyright (c) 2015, The MITRE Corporation. All rights reserved. 3 | # See License.txt for complete terms. 4 | 5 | # __IMAGE_IMPORT_DESCRIPTOR__format__ -> CybOX Windows Executable File Object Imports mappings 6 | IMAGE_IMPORT_DESCRIPTOR_MAPPINGS = {'OriginalFirstThunk':'No_Mapping', 7 | 'TimeDateStamp':'No_Mapping', 8 | 'ForwarderChain':'No_Mapping', 9 | 'Name':'imports/file_name', 10 | 'FirstThunk':'imports/virtual_address'} 11 | 12 | # __IMAGE_THUNK_DATA_format__ -> CybOX Windows Executable File Object Imports mappings 13 | IMAGE_THUNK_DATA32_MAPPINGS = {'ForwarderString':'No_Mapping', 14 | 'Function':'imports/imported_functions/virtual_address', 15 | 'Ordinal':'imports/imported_functions/ordinal', 16 | 'AddressOfData':'No_Mapping'} 17 | 18 | # __IMAGE_THUNK_DATA64_format__ -> CybOX Windows Executable File Object Imports mappings 19 | IMAGE_THUNK_DATA64_MAPPINGS = {'ForwarderString':'No_Mapping', 20 | 'Function':'imports/imported_functions/virtual_address', 21 | 'Ordinal':'imports/imported_functions/ordinal', 22 | 'AddressOfData':'No_Mapping'} 23 | 24 | # IMAGE_IMPORT_BY_NAME -> CybOX Windows Executable File Object Imports mappings 25 | IMAGE_IMPORT_BY_NAME_MAPPINGS = {'Hint':'imports/imported_functions/hint', 26 | 'Name':'imports/imported_functions/function_name'} 27 | 28 | # __IMAGE_BOUND_IMPORT_DESCRIPTOR_format__ -> CybOX Windows Executable File Object Bound Imports mappings 29 | IMAGE_BOUND_IMPORT_DESCRIPTOR_MAPPINGS = {'TimeDateStamp':'No_Mapping', 30 | 'OffsetModuleName':'No_Mapping', 31 | 'NumberOfModuleForwarderRefs':'No_Mapping'} 32 | 33 | # __IMAGE_BOUND_IMPORT_FORWARDER_REF -> CybOX Windows Executable File Object Bound Imports mappings 34 | IMAGE_BOUND_IMPORT_FORWARDER_REF_MAPPINGS = {'TimeDateStamp':'No_Mapping', 35 | 'OffsetModuleName':'No_Mapping', 36 | 'Reserved':'No_Mapping'} 37 | 38 | -------------------------------------------------------------------------------- /pefile_to_maec/mappings/image_nt_headers.py: -------------------------------------------------------------------------------- 1 | # -*- coding: Latin-1 -*- 2 | # Copyright (c) 2015, The MITRE Corporation. All rights reserved. 3 | # See License.txt for complete terms. 4 | 5 | # IMAGE_NT_HEADERS -> CybOX Windows Executable File Object PEHeadersType mappings 6 | """Holds NT Headers information. 7 | 8 | pe_struct: _IMAGE_NT_HEADERS 9 | 10 | DWORD Signature; 11 | IMAGE_FILE_HEADER FileHeader; 12 | IMAGE_OPTIONAL_HEADER64 OptionalHeader; 13 | 14 | pefile_struct: __IMAGE_NT_HEADERS_format__ 15 | cybox_struct: PEHeadersType 16 | 17 | """ 18 | IMAGE_NT_HEADERS_MAPPINGS = {'Signature':'headers/signature'} 19 | IMAGE_NT_HEADERS64_MAPPINGS = {'Signature':'headers/signature'} 20 | 21 | -------------------------------------------------------------------------------- /pefile_to_maec/mappings/image_optional_header.py: -------------------------------------------------------------------------------- 1 | # -*- coding: Latin-1 -*- 2 | # Copyright (c) 2015, The MITRE Corporation. All rights reserved. 3 | # See License.txt for complete terms. 4 | 5 | # IMAGE_OPTIONAL_HEADERS -> CybOX Windows Executable File Object PEOptionalHeaderType mappings 6 | """Holds Optional Header information. 7 | 8 | pe_struct: _IMAGE_OPTIONAL_HEADERS 9 | // 10 | // Standard fields. 11 | // 12 | 13 | WORD Magic; 14 | BYTE MajorLinkerVersion; 15 | BYTE MinorLinkerVersion; 16 | DWORD SizeOfCode; 17 | DWORD SizeOfInitializedData; 18 | DWORD SizeOfUninitializedData; 19 | DWORD AddressOfEntryPoint; 20 | DWORD BaseOfCode; 21 | DWORD BaseOfData; 22 | 23 | // 24 | // NT additional fields. 25 | // 26 | 27 | DWORD ImageBase; 28 | DWORD SectionAlignment; 29 | DWORD FileAlignment; 30 | WORD MajorOperatingSystemVersion; 31 | WORD MinorOperatingSystemVersion; 32 | WORD MajorImageVersion; 33 | WORD MinorImageVersion; 34 | WORD MajorSubsystemVersion; 35 | WORD MinorSubsystemVersion; 36 | DWORD Win32VersionValue; 37 | DWORD SizeOfImage; 38 | DWORD SizeOfHeaders; 39 | DWORD CheckSum; 40 | WORD Subsystem; 41 | WORD DllCharacteristics; 42 | DWORD SizeOfStackReserve; 43 | DWORD SizeOfStackCommit; 44 | DWORD SizeOfHeapReserve; 45 | DWORD SizeOfHeapCommit; 46 | DWORD LoaderFlags; 47 | DWORD NumberOfRvaAndSizes; 48 | IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; 49 | 50 | pefile_struct: __IMAGE_OPTIONAL_HEADERS_format__ 51 | cybox_struct: PEOptionalHeader 52 | 53 | """ 54 | IMAGE_OPTIONAL_HEADER32_MAPPINGS = {'Magic':'magic', 55 | 'MajorLinkerVersion':'major_linker_version', 56 | 'MinorLinkerVersion':'minor_linker_version', 57 | 'SizeOfCode':'size_of_code', 58 | 'SizeOfInitializedData':'size_of_initialized_data', 59 | 'SizeOfUninitializedData':'size_of_unintialized_data', 60 | 'AddressOfEntryPoint':'address_of_entry_point', 61 | 'BaseOfCode':'base_of_code', 62 | 'BaseOfData':'base_of_data', 63 | 'ImageBase':'image_base', 64 | 'SectionAlignment':'section_alignment', 65 | 'FileAlignment':'file_alignment', 66 | 'MajorOperatingSystemVersion':'major_os_version', 67 | 'MinorOperatingSystemVersion':'minor_os_version', 68 | 'MajorImageVersion':'major_image_version', 69 | 'MinorImageVersion':'minor_image_version', 70 | 'MajorSubsystemVersion':'major_subsystem_version', 71 | 'MinorSubsystemVersion':'minor_subsystem_version', 72 | 'Reserved1':'win32_version_value', 73 | 'SizeOfImage':'size_of_image', 74 | 'SizeOfHeaders':'size_of_headers', 75 | 'CheckSum':'checksum', 76 | 'Subsystem':'subsystem', 77 | 'DllCharacteristics':'dll_characteristics', 78 | 'SizeOfStackReserve':'size_of_stack_reserve', 79 | 'SizeOfStackCommit':'size_of_stack_commit', 80 | 'SizeOfHeapReserve':'size_of_heap_reserve', 81 | 'SizeOfHeapCommit':'size_of_heap_commit', 82 | 'LoaderFlags':'loader_flags', 83 | 'NumberOfRvaAndSizes':'number_of_rva_and_sizes', 84 | '_IMAGE_DATA_DIRECTORY':'data_directory'} 85 | 86 | IMAGE_OPTIONAL_HEADER64_MAPPINGS = {'Magic':'magic', 87 | 'MajorLinkerVersion':'major_linker_version', 88 | 'MinorLinkerVersion':'minor_linker_version', 89 | 'SizeOfCode':'size_of_code', 90 | 'SizeOfInitializedData':'size_of_initialized_data', 91 | 'SizeOfUninitializedData':'size_of_unintialized_data', 92 | 'AddressOfEntryPoint':'address_of_entry_point', 93 | 'BaseOfCode':'base_of_code', 94 | 'BaseOfData':'base_of_data', 95 | 'ImageBase':'image_base', 96 | 'SectionAlignment':'section_alignment', 97 | 'FileAlignment':'file_alignment', 98 | 'MajorOperatingSystemVersion':'major_os_version', 99 | 'MinorOperatingSystemVersion':'minor_os_version', 100 | 'MajorImageVersion':'major_image_version', 101 | 'MinorImageVersion':'minor_image_version', 102 | 'MajorSubsystemVersion':'major_subsystem_version', 103 | 'MinorSubsystemVersion':'minor_subsystem_version', 104 | 'Reserved1':'win32_version_value', 105 | 'SizeOfImage':'size_of_image', 106 | 'SizeOfHeaders':'size_of_headers', 107 | 'CheckSum':'checksum', 108 | 'Subsystem':'subsystem', 109 | 'DllCharacteristics':'dll_characteristics', 110 | 'SizeOfStackReserve':'size_of_stack_reserve', 111 | 'SizeOfStackCommit':'size_of_stack_commit', 112 | 'SizeOfHeapReserve':'size_of_heap_reserve', 113 | 'SizeOfHeapCommit':'size_of_heap_commit', 114 | 'LoaderFlags':'loader_flags', 115 | 'NumberOfRvaAndSizes':'number_of_rva_and_sizes', 116 | '_IMAGE_DATA_DIRECTORY':'data_directory'} 117 | 118 | -------------------------------------------------------------------------------- /pefile_to_maec/mappings/image_resources.py: -------------------------------------------------------------------------------- 1 | # -*- coding: Latin-1 -*- 2 | # Copyright (c) 2015, The MITRE Corporation. All rights reserved. 3 | # See License.txt for complete terms. 4 | 5 | # __IMAGE_RESOURCE_DIRECTORY_format__ -> CybOX Windows Executable File Object Resource Table mappings 6 | IMAGE_RESOURCE_DIRECTORY_MAPPINGS = {'Characteristics':'No_Mapping', 7 | 'TimeDateStamp':'No_Mapping', 8 | 'MajorVersion':'No_Mapping', 9 | 'MinorVersion':'No_Mapping', 10 | 'NumberOfNamedEntries':'No_Mapping', 11 | 'NumberOfIdEntries':'No_Mapping'} 12 | 13 | # __IMAGE_RESOURCE_DIRECTORY_ENTRY_format__ -> CybOX Windows Executable File Object Resource Entry mappings 14 | IMAGE_RESOURCE_DIRECTORY_ENTRY_MAPPINGS = {'Name':'resources/name', 15 | 'OffsetToData':'resources/virtual_address'} 16 | 17 | # __IMAGE_RESOURCE_DATA_ENTRY_format__ -> CybOX Windows Executable File Object Resource Table mappings 18 | IMAGE_RESOURCE_DATA_ENTRY_MAPPINGS = {'OffsetToData':'resources/virtual_address', 19 | 'Size':'resources/size', 20 | 'CodePage':'No_Mapping', 21 | 'Reserved':'No_Mapping'} 22 | 23 | -------------------------------------------------------------------------------- /pefile_to_maec/mappings/image_sections.py: -------------------------------------------------------------------------------- 1 | # -*- coding: Latin-1 -*- 2 | # Copyright (c) 2015, The MITRE Corporation. All rights reserved. 3 | # See License.txt for complete terms. 4 | 5 | # IMAGE_SECTION_HEADER -> CybOX Windows Executable File Object Section Header Struct mappings 6 | IMAGE_SECTION_HEADER_MAPPINGS = {'Name':'section_header/name', 7 | 'Misc_VirtualSize':'section_header/virtual_size', 8 | 'VirtualAddress':'section_header/virtual_address', 9 | 'SizeOfRawData':'section_header/size_of_raw_data', 10 | 'PointerToRawData':'section_header/pointer_to_raw_data', 11 | 'PointerToRelocations':'section_header/pointer_to_relocations', 12 | 'PointerToLinenumbers':'section_header/pointer_to_linenumbers', 13 | 'NumberOfRelocations':'section_header/number_of_relocations', 14 | 'NumberOfLinenumbers':'section_header/number_of_linenumbers', 15 | 'Characteristics':'section_header/characteristics'} 16 | -------------------------------------------------------------------------------- /pefile_to_maec/pefile_parser.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os 3 | try: 4 | import pefile 5 | except ImportError: 6 | print 'Unable to import pefile' 7 | try: 8 | sys.path.append(os.path.join(os.path.dirname(__file__), '..')) 9 | import pefile 10 | except Exception as err: 11 | print 'Unable to import pefile.\n' 12 | print 'Please download pefile and place the folder in your PYTHONPATH or install pefile with a package manager.\n' 13 | print 'ERROR MSG => %s' % err.message 14 | sys.exit(-1) 15 | from copy import deepcopy 16 | from mappings.image_dos_header import IMAGE_DOS_HEADER_MAPPINGS 17 | from mappings.image_file_header import IMAGE_FILE_HEADER_MAPPINGS 18 | from mappings.image_optional_header import IMAGE_OPTIONAL_HEADER32_MAPPINGS 19 | from mappings.image_sections import IMAGE_SECTION_HEADER_MAPPINGS 20 | from mappings.image_dos_header import IMAGE_DOS_HEADER_MAPPINGS 21 | from mappings.image_file_header import IMAGE_FILE_HEADER_MAPPINGS 22 | from mappings.image_optional_header import IMAGE_OPTIONAL_HEADER32_MAPPINGS 23 | from mappings.image_sections import IMAGE_SECTION_HEADER_MAPPINGS 24 | import maec.utils 25 | from maec.bundle.bundle import Bundle 26 | from maec.bundle.bundle_reference import BundleReference 27 | from maec.package.analysis import Analysis 28 | from maec.package.malware_subject import MalwareSubject 29 | from maec.package.package import Package 30 | from cybox.core import Object 31 | from cybox.common.tools import ToolInformation 32 | from cybox.utils import Namespace 33 | import hashlib 34 | 35 | class PefileToMAEC(object): 36 | def __init__(self, pefile_parser): 37 | self.pefile_parser = pefile_parser 38 | NS = Namespace("http://code.google.com/p/pefile/", "pefile") 39 | maec.utils.set_id_namespace(NS) 40 | self.package = Package() 41 | self.generate_maec() 42 | 43 | def create_object_dict(self, properties_dict): 44 | object_dict = {'id': maec.utils.idgen.create_id(prefix="object"), 'properties': properties_dict} 45 | return object_dict 46 | 47 | def populate(self, entry_dict, static_bundle, malware_subject=None): 48 | if 'file' in entry_dict and len(entry_dict['file'].keys()) > 1: 49 | file_dict = self.create_object_dict(entry_dict['file']) 50 | if malware_subject: 51 | malware_subject.malware_instance_object_attributes = Object.from_dict(file_dict) 52 | # Add the hashes for the Malware Instance Object Attributes 53 | data = open(self.pefile_parser.infile, 'rb').read() 54 | if data: 55 | md5_hash = hashlib.md5(data).hexdigest() 56 | sha1_hash = hashlib.sha1(data).hexdigest() 57 | malware_subject.malware_instance_object_attributes.properties.add_hash(md5_hash) 58 | malware_subject.malware_instance_object_attributes.properties.add_hash(sha1_hash) 59 | else: 60 | static_bundle.add_object(Object.from_dict(file_dict)) 61 | if 'pe' in entry_dict and len(entry_dict['pe'].keys()) > 1: 62 | pe_dict = self.create_object_dict(entry_dict['pe']) 63 | static_bundle.add_object(Object.from_dict(pe_dict)) 64 | 65 | def generate_analysis(self, static_bundle): 66 | analysis = Analysis() 67 | analysis.type = 'triage' 68 | analysis.method = 'static' 69 | analysis.add_tool(ToolInformation.from_dict({'id': maec.utils.idgen.create_id(prefix="tool"), 70 | 'vendor': 'Ero Carrera', 71 | 'name': 'pefile'})) 72 | findings_bundle_reference = [] 73 | if self.bundle_has_content(static_bundle): 74 | findings_bundle_reference.append(BundleReference.from_dict({'bundle_idref':static_bundle.id_})) 75 | analysis.findings_bundle_reference = findings_bundle_reference 76 | return analysis 77 | 78 | def bundle_has_content(self, bundle): 79 | if bundle.actions and len(bundle.actions) > 0: 80 | return True 81 | if bundle.objects and len(bundle.objects) > 0: 82 | return True 83 | if bundle.behaviors and len(bundle.behaviors) > 0: 84 | return True 85 | return False 86 | 87 | def generate_malware_subjects(self): 88 | entry_dict = self.pefile_parser.entry_dict 89 | malware_subject = MalwareSubject() 90 | entry_dict['id'] = malware_subject 91 | static_bundle = Bundle(None, False, '4.1', 'static analysis tool output') 92 | self.populate(entry_dict, static_bundle, malware_subject) 93 | malware_subject.add_analysis(self.generate_analysis(static_bundle)) 94 | if self.bundle_has_content(static_bundle): 95 | malware_subject.add_findings_bundle(static_bundle) 96 | self.package.add_malware_subject(malware_subject) 97 | 98 | def generate_maec(self): 99 | self.generate_malware_subjects() 100 | 101 | class PefileParser(object): 102 | def __init__(self, infile): 103 | self.infile = infile 104 | self.root_entry = None 105 | self.entry_dict = {} 106 | self.process_entry() 107 | 108 | # Build a nested dictionary from a list 109 | # Set it to a value 110 | def build_nested_dictionary(self, child_list, value): 111 | nested_dict = {} 112 | if len(child_list) == 1: 113 | nested_dict[child_list[0]] = value 114 | return nested_dict 115 | 116 | for list_item in child_list: 117 | next_index = child_list.index(list_item) + 1 118 | nested_dict[list_item] = self.build_nested_dictionary(child_list[next_index:], value) 119 | break 120 | 121 | return nested_dict 122 | 123 | # Function for merging multiple dictionaries 124 | def dict_merge(self, target, *args): 125 | # Merge multiple dicts 126 | if len(args) > 1: 127 | for obj in args: 128 | self.dict_merge(target, obj) 129 | return target 130 | 131 | # Recursively merge dicts and set non-dict values 132 | obj = args[0] 133 | if not isinstance(obj, dict): 134 | return obj 135 | for k, v in obj.iteritems(): 136 | if k in target and isinstance(target[k], dict): 137 | self.dict_merge(target[k], v) 138 | else: 139 | target[k] = deepcopy(v) 140 | return target 141 | 142 | def set_dictionary_value(self, dictionary, key, value): 143 | if '/' in key: 144 | split_names = key.split('/') 145 | if split_names[0] not in dictionary: 146 | dictionary[split_names[0]] = self.build_nested_dictionary(split_names[1:], value) 147 | else: 148 | self.dict_merge(dictionary[split_names[0]], self.build_nested_dictionary(split_names[1:], value)) 149 | else: 150 | dictionary[key] = value 151 | 152 | def perform_mapping(self, struct_dict, element_mapping_dict): 153 | output_dict = {} 154 | for key, value in struct_dict.items(): 155 | if key in element_mapping_dict: 156 | if isinstance(value, str): 157 | self.set_dictionary_value(output_dict, element_mapping_dict[key], value) 158 | elif isinstance(value, dict): 159 | for k,v in value.items(): 160 | if k == 'Value': 161 | self.set_dictionary_value(output_dict, 162 | element_mapping_dict[key], value[k]) 163 | elif isinstance(value, list): 164 | for entry in value: 165 | for k,v in entry.items(): 166 | if k == 'Value': 167 | self.set_dictionary_value(output_dict, 168 | element_mapping_dict[key], entry[k]) 169 | 170 | return output_dict 171 | 172 | def perform_mappings(self, element_list, element_mapping_dict): 173 | output_dict = {} 174 | for element in element_list: 175 | print element 176 | def handle_input_file(self): 177 | try: 178 | self.root_entry = pefile.PE(self.infile, fast_load=True) 179 | except pefile.PEFormatError: 180 | return None 181 | 182 | def handle_file_object(self): 183 | file_dictionary = {} 184 | file_dictionary['xsi:type'] = 'FileObjectType' 185 | file_dictionary['file_name'] = os.path.basename(self.infile) 186 | file_dictionary['file_path'] = os.path.abspath(self.infile) 187 | file_dictionary['size_in_bytes'] = os.path.getsize(self.infile) 188 | 189 | return file_dictionary 190 | 191 | def parse_headers(self): 192 | headers_dictionary = {} 193 | headers_dictionary['dos_header'] = self.perform_mapping( 194 | self.root_entry.DOS_HEADER.dump_dict(), 195 | IMAGE_DOS_HEADER_MAPPINGS) 196 | headers_dictionary['file_header'] = self.perform_mapping( 197 | self.root_entry.FILE_HEADER.dump_dict(), 198 | IMAGE_FILE_HEADER_MAPPINGS) 199 | headers_dictionary['optional_header'] = self.perform_mapping( 200 | self.root_entry.OPTIONAL_HEADER.dump_dict(), 201 | IMAGE_OPTIONAL_HEADER32_MAPPINGS) 202 | 203 | return headers_dictionary 204 | 205 | def get_hash_list(self, item): 206 | hash_list = [] 207 | hash_methods = [ 208 | item.get_hash_md5(), 209 | item.get_hash_sha1(), 210 | item.get_hash_sha256(), 211 | item.get_hash_sha512()] 212 | for hash_method in hash_methods: 213 | hash_list.append(hash_method) 214 | 215 | return hash_list 216 | 217 | def get_entropy(self, item): 218 | entropy_dict = {} 219 | entropy_dict['value'] = item.get_entropy() 220 | 221 | return entropy_dict 222 | 223 | def parse_sections(self): 224 | sections_list = [] 225 | for section in self.root_entry.sections: 226 | section_dict = {} 227 | section_dict = self.perform_mapping(section.dump_dict(), 228 | IMAGE_SECTION_HEADER_MAPPINGS) 229 | section_dict['data_hashes'] = self.get_hash_list(section) 230 | section_dict['entropy'] = self.get_entropy(section) 231 | sections_list.append(section_dict) 232 | 233 | return sections_list 234 | 235 | def load_data_directories(self): 236 | self.root_entry.parse_data_directories( directories=[ 237 | pefile.DIRECTORY_ENTRY['IMAGE_DIRECTORY_ENTRY_IMPORT'], 238 | pefile.DIRECTORY_ENTRY['IMAGE_DIRECTORY_ENTRY_EXPORT'], 239 | pefile.DIRECTORY_ENTRY['IMAGE_DIRECTORY_ENTRY_RESOURCE'], 240 | pefile.DIRECTORY_ENTRY['IMAGE_DIRECTORY_ENTRY_DEBUG'], 241 | pefile.DIRECTORY_ENTRY['IMAGE_DIRECTORY_ENTRY_TLS'], 242 | pefile.DIRECTORY_ENTRY['IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT'], 243 | pefile.DIRECTORY_ENTRY['IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT'] ] ) 244 | 245 | def parse_import_directory(self): 246 | imports_list = [] 247 | 248 | for entry in self.root_entry.DIRECTORY_ENTRY_IMPORT: 249 | library_dictionary = {} 250 | api_list = [] 251 | library_dictionary['file_name'] = entry.dll 252 | library_dictionary['imported_functions'] = api_list 253 | for imp in entry.imports: 254 | api_list.append({'function_name': imp.name}) 255 | imports_list.append(library_dictionary) 256 | 257 | return imports_list 258 | 259 | def parse_export_directory(self): 260 | exports_list = [] 261 | 262 | for entry in self.root_entry.DIRECTORY_ENTRY_EXPORT.symbols: 263 | library_dictionary = {} 264 | api_list = [] 265 | library_dictionary['file_name'] = entry.name 266 | exports_list.append(library_dictionary) 267 | 268 | return exports_list 269 | 270 | def handle_resources(self): 271 | resource_list = [] 272 | 273 | for entry in self.root_entry.DIRECTORY_ENTRY_RESOURCE.entries: 274 | entry_dict = {} 275 | if hasattr(entry, 'name') and entry.name: 276 | entry_dict['name'] = str(entry.name) 277 | if hasattr(entry, 'directory'): 278 | if hasattr(entry.directory, 'entries'): 279 | for child_entry in entry.directory.entries: 280 | if hasattr(child_entry, 'directory'): 281 | if hasattr(child_entry.directory, 'entries'): 282 | for grandchild in child_entry.directory.entries: 283 | if hasattr(grandchild, 'data'): 284 | entry_dict['language'] = pefile.LANG[grandchild.data.lang] 285 | entry_dict['sub_language'] = pefile.SUBLANG[grandchild.data.sublang][0] 286 | entry_dict['size'] = grandchild.data.struct.Size 287 | elif hasattr(entry, 'id') and entry.id: 288 | entry_dict['type'] = pefile.RESOURCE_TYPE[entry.id] 289 | if hasattr(entry, 'directory'): 290 | if hasattr(entry.directory, 'entries'): 291 | for child_entry in entry.directory.entries: 292 | if hasattr(child_entry, 'name') and child_entry.name: 293 | entry_dict['name'] = str(child_entry.name) 294 | if hasattr(child_entry, 'directory'): 295 | if hasattr(child_entry.directory, 'entries'): 296 | for grandchild in child_entry.directory.entries: 297 | if hasattr(grandchild, 'data'): 298 | entry_dict['language'] = pefile.LANG[grandchild.data.lang] 299 | entry_dict['sub_language'] = pefile.SUBLANG[grandchild.data.sublang][0] 300 | entry_dict['size'] = grandchild.data.struct.Size 301 | 302 | resource_list.append(entry_dict) 303 | 304 | return resource_list 305 | 306 | 307 | def handle_pe_object(self): 308 | pe_dictionary = {'xsi:type': 'WindowsExecutableFileObjectType'} 309 | pe_dictionary['headers'] = self.parse_headers() 310 | pe_dictionary['sections'] = self.parse_sections() 311 | 312 | self.load_data_directories() 313 | if hasattr(self.root_entry, 'DIRECTORY_ENTRY_IMPORT'): 314 | pe_dictionary['imports'] = self.parse_import_directory() 315 | 316 | if hasattr(self.root_entry, 'DIRECTORY_ENTRY_EXPORT'): 317 | pe_dictionary['exports'] = self.parse_export_directory() 318 | 319 | if hasattr(self.root_entry, 'DIRECTORY_ENTRY_RESOURCE'): 320 | pe_dictionary['resources'] = self.handle_resources() 321 | 322 | return pe_dictionary 323 | 324 | def process_entry(self): 325 | self.handle_input_file() 326 | 327 | if self.root_entry: 328 | self.entry_dict['file'] = self.handle_file_object() 329 | self.entry_dict['pe'] = self.handle_pe_object() 330 | else: 331 | print 'Error: Not a valid PE file.' 332 | sys.exit(-1) 333 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2015, The MITRE Corporation. All rights reserved. 2 | # See LICENSE.txt for complete terms. 3 | 4 | from os.path import abspath, dirname, join 5 | from setuptools import setup, find_packages 6 | 7 | INIT_FILE = join(dirname(abspath(__file__)), 'pefile_to_maec', '__init__.py') 8 | 9 | def get_version(): 10 | with open(INIT_FILE) as f: 11 | for line in f.readlines(): 12 | if line.startswith("__version__"): 13 | version = line.split()[-1].strip('"') 14 | return version 15 | raise AttributeError("Package does not have a __version__") 16 | 17 | with open('README.rst') as f: 18 | readme = f.read() 19 | 20 | setup( 21 | name="pefile_to_maec", 22 | version=get_version(), 23 | author="MAEC Project", 24 | author_email="maec@mitre.org", 25 | description="An package for generating MAEC documents from pefile analysis.", 26 | long_description=readme, 27 | url="http://maec.mitre.org", 28 | packages=find_packages(), 29 | install_requires=['maec>=4.1.0.9,<4.1.1.0', 'cybox>=2.1.0.8,<2.1.1.0', 'pefile>=1.2.10'], 30 | classifiers=[ 31 | "Programming Language :: Python", 32 | "Development Status :: 4 - Beta", 33 | "Intended Audience :: Developers", 34 | "License :: OSI Approved :: BSD License", 35 | "Operating System :: OS Independent", 36 | ] 37 | ) 38 | --------------------------------------------------------------------------------