├── .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 |
--------------------------------------------------------------------------------