Skip to content

Commit

Permalink
Merge branch 'master' of github.com:erocarrera/pefile
Browse files Browse the repository at this point in the history
  • Loading branch information
Drewsif committed Dec 27, 2016
2 parents a93f560 + 465b2ee commit ddea082
Show file tree
Hide file tree
Showing 8 changed files with 46 additions and 24 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*.bak
.coverage
tests/test_files/*
venv*

# Back-up files
*~
Expand Down
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ python:
- '2.7'
- '3.5'
before_install:
- openssl aes-256-cbc -K $encrypted_5f282b249fcf_key -iv $encrypted_5f282b249fcf_iv
- openssl aes-256-cbc -K $encrypted_83afbfb26b22_key -iv $encrypted_83afbfb26b22_iv
-in tests/test_data.tar.bz2.enc -out tests/test_data.tar.bz2 -d
- tar jxf tests/test_data.tar.bz2 -C tests
install:
Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ Prompted by the move to GitHub, the need to support Python 3 in addition to reso

## Projects and products using _pefile_

* [Exe Dump Utility](http://utilitymill.com/utility/Exe_Dump_Utility) a web-based _pefile_
* [MAEC](http://maec.mitre.org) MAEC is a standardized language for encoding and communicating high-fidelity information about malware based upon attributes such as behaviors, artifacts, and attack patterns. MAEC [converts](https://github.com/MAECProject/pefile-to-maec) _pefile_'s output into their XML format.
* [Qiew](https://github.com/mtivadar/qiew) Qiew - Hex/File format viewer.
* [VirusTotal](http://www.virustotal.com/)
* [bbfreeze](http://pypi.python.org/pypi/bbfreeze)
* **pyemu**: [download](https://www.openrce.org/repositories/browse/codypierce), [whitepaper](https://www.blackhat.com/presentations/bh-usa-07/Pierce/Whitepaper/bh-usa-07-pierce-WP.pdf)
Expand All @@ -61,6 +62,7 @@ PDFs of posters depicting the PE file format:
The following links provide detailed information about the PE format and its structures.

* [corkami's wiki page about the PE format](https://code.google.com/p/corkami/wiki/PE) has grown to be one of the most in-depth repositories of information about the PE format
* [corkami's treasure trove of PE weirdness](https://github.com/corkami/pocs/tree/master/PE)
* [An In-Depth Look into the Win32 Portable Executable File Format](http://msdn.microsoft.com/msdnmag/issues/02/02/PE/default.aspx)
* [An In-Depth Look into the Win32 Portable Executable File Format, Part 2](http://msdn.microsoft.com/msdnmag/issues/02/03/PE2/default.aspx)
* [The Portable Executable File Format](http://www.csn.ul.ie/~caolan/publink/winresdump/winresdump/doc/pefile.html)
Expand Down
35 changes: 29 additions & 6 deletions pefile.py
Original file line number Diff line number Diff line change
Expand Up @@ -981,7 +981,7 @@ def dump_dict(self):
for key in keys:

val = getattr(self, key)
if isinstance(val, int) or isinstance(val, int):
if isinstance(val, (int, long)):
if key == 'TimeDateStamp' or key == 'dwTimeStamp':
try:
val = '0x%-8X [%s UTC]' % (val, time.asctime(time.gmtime(val)))
Expand Down Expand Up @@ -1772,6 +1772,7 @@ def close(self):
((isinstance(mmap.mmap, type) and isinstance(self.__data__, mmap.mmap)) or
'mmap.mmap' in repr(type(self.__data__))) ):
self.__data__.close()
del self.__data__


def __unpack_data__(self, format, data, file_offset):
Expand Down Expand Up @@ -1829,6 +1830,19 @@ def __parse__(self, fname, data, fast_load):
self.__data__ = data
self.__from_file = False

for byte, byte_count in Counter(bytearray(self.__data__)).items():
# Only report the cases where a byte makes up for more than 50% (if
# zero) or 15% (if non-zero) of the file's contents. There are
# legitimate PEs where 0x00 bytes are close to 50% of the whole
# file's contents.
if (byte == 0 and 1.0 * byte_count / len(self.__data__) > 0.5) or (
byte != 0 and 1.0 * byte_count / len(self.__data__) > 0.15):
self.__warnings.append(
("Byte 0x{0:02x} makes up {1:.4f}% of the file's contents."
" This may indicate truncation / malformation.").format(
byte, 100.0 * byte_count / len(self.__data__)))


dos_header_data = self.__data__[:64]
if len(dos_header_data) != 64:
raise PEFormatError('Unable to read the DOS Header, possibly a truncated file.')
Expand Down Expand Up @@ -2133,12 +2147,20 @@ def parse_rich_header(self):
DANS = 0x536E6144 # 'DanS' as dword
RICH = 0x68636952 # 'Rich' as dword

rich_index = self.__data__.find(
b'Rich', 0x80, self.OPTIONAL_HEADER.get_file_offset())
if rich_index == -1:
return None

# Read a block of data
try:
rich_data = self.get_data(0x80, 0x80)
if len(rich_data) != 0x80:
# The end of the structure is 8 bytes after the start of the Rich
# string.
rich_data = self.get_data(0x80, rich_index + 8)
data = list(struct.unpack(
'<{0}I'.format(int(len(rich_data)/4)), rich_data))
if b'RICH' not in data:
return None
data = list(struct.unpack("<32I", rich_data))
except PEFormatError:
return None

Expand Down Expand Up @@ -3761,7 +3783,8 @@ def parse_import_directory(self, rva, size, dllnames_only=False):
try:
# If the RVA is invalid all would blow up. Some EXEs seem to be
# specially nasty and have an invalid RVA.
data = self.get_data(rva, Structure(self.__IMAGE_IMPORT_DESCRIPTOR_format__).sizeof() )
data = self.get_data(rva, Structure(
self.__IMAGE_IMPORT_DESCRIPTOR_format__).sizeof() )
except PEFormatError as e:
self.__warnings.append(
'Error parsing the import directory at RVA: 0x%x' % ( rva ) )
Expand Down Expand Up @@ -5317,7 +5340,7 @@ def generate_checksum(self):

# Get the offset to the CheckSum field in the OptionalHeader
# (The offset is the same in PE32 and PE32+)
checksum_offset = self.OPTIONAL_HEADER.__file_offset__ + 0x40 # 64
checksum_offset = self.OPTIONAL_HEADER.get_file_offset() + 0x40 # 64

checksum = 0
# Verify the data is dword-aligned. Add padding if needed
Expand Down
2 changes: 1 addition & 1 deletion peutils.py
Original file line number Diff line number Diff line change
Expand Up @@ -426,7 +426,7 @@ def __load(self, filename=None, data=None):
# Helper function to parse the signature bytes
#
def to_byte(value) :
if value == '??' or value == '?0' :
if '?' in value::
return value
return int (value, 16)

Expand Down
22 changes: 7 additions & 15 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,6 @@ def initialize_options(self):
def finalize_options(self):
pass


# build_msi does not support the 1.2.10-139 versioning schema
# (or 1.2.10.139), hence the revision number is stripped.
pefile_version = _read_attr('__version__')
if 'bdist_msi' in sys.argv:
pefile_version, _, _ = pefile_version.partition('-')


class TestCommand(Command):
"""Run tests."""
user_options = []
Expand All @@ -76,7 +68,7 @@ def run(self):


setup(name = 'pefile',
version = pefile_version,
version = _read_attr('__version__'),
description = 'Python PE parsing module',
author = _read_attr('__author__'),
author_email = _read_attr('__contact__'),
Expand All @@ -85,12 +77,12 @@ def run(self):
keywords = ['pe', 'exe', 'dll', 'pefile', 'pecoff'],
classifiers = [
'Development Status :: 5 - Production/Stable',
'Intended Audience :: Developers',
'Intended Audience :: Science/Research',
'Natural Language :: English',
'Operating System :: OS Independent',
'Programming Language :: Python',
'Topic :: Software Development :: Libraries :: Python Modules'],
'Intended Audience :: Developers',
'Intended Audience :: Science/Research',
'Natural Language :: English',
'Operating System :: OS Independent',
'Programming Language :: Python',
'Topic :: Software Development :: Libraries :: Python Modules'],
long_description = "\n".join(_read_doc().split('\n')),
cmdclass={"test": TestCommand},
py_modules = ['pefile', 'peutils'],
Expand Down
4 changes: 4 additions & 0 deletions tests/pefile_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,9 @@ def test_selective_loading_integrity(self):
# Verify both methods obtained the same results.
self.assertEqual(pe_full.dump_info(), pe.dump_info())

pe.close()
pe_full.close()


def test_imphash(self):
"""Test imphash values."""
Expand Down Expand Up @@ -213,6 +216,7 @@ def test_write_header_fields(self):
#
self.assertEqual(''.join(differences).encode('utf-8', 'backslashreplace'), str1+str2+str3)

pe.close()

def test_nt_headers_exception(self):
"""pefile should fail parsing invalid data (missing NT headers)"""
Expand Down
Binary file modified tests/test_data.tar.bz2.enc
Binary file not shown.

0 comments on commit ddea082

Please sign in to comment.