Release 1.0 prep work (#113)

Co-authored-by: Eric Kilmer <eric.d.kilmer@gmail.com>
This commit is contained in:
William Woodruff 2020-03-17 13:38:56 -04:00 committed by GitHub
parent c5e9a09087
commit 1dc2c53566
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 411 additions and 372 deletions

View File

@ -10,10 +10,11 @@ on:
- cron: '0 12 * * *'
jobs:
test:
pe-parse:
strategy:
matrix:
platform: ["ubuntu-latest", "macos-latest"]
build-type: ["Debug", "Release"]
compiler:
- { CC: "clang", CXX: "clang++" }
- { CC: "gcc", CXX: "g++" }
@ -23,27 +24,80 @@ jobs:
runs-on: ${{ matrix.platform }}
steps:
- uses: actions/checkout@v2
- name: Build C
- name: build
env:
CC: ${{ matrix.compiler.CC }}
CXX: ${{ matrix.compiler.CXX }}
run: |
mkdir build
cd build
cmake ..
make
- name: Build Python
cmake -DCMAKE_BUILD_TYPE=${{ matrix.build-type }} ..
cmake --build .
- name: test
run: |
./build/dump-pe/dump-pe ./test/assets/example.exe
pepy:
strategy:
matrix:
platform: ["ubuntu-latest", "macos-latest"]
python:
- "3.6"
- "3.7"
- "3.8"
runs-on: ${{ matrix.platform }}
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v1
with:
python-version: ${{ matrix.python }}
- name: build
run: |
cd python
python2 setup.py build
python3 setup.py build
test-windows:
- name: sdist and install
run: |
python3 setup.py sdist
python3 -m pip install --user dist/*.tar.gz
- name: test
run: |
python3 test/test_pepy.py test/assets/example.exe
pe-parse-windows:
strategy:
matrix:
build-type: ["Debug", "Release"]
runs-on: windows-latest
steps:
- uses: actions/checkout@v2
- name: Build C
- name: build
run: |
mkdir build
cd build
cmake -G "Visual Studio 16 2019" -A x64 ..
cmake --build .
cmake --build . --config ${{ matrix.build-type }}
- name: test
run: |
.\build\dump-pe\${{ matrix.build-type }}\dump-pe.exe .\test\assets\example.exe
pepy-windows:
strategy:
matrix:
python:
- "3.6"
- "3.7"
- "3.8"
runs-on: windows-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v1
with:
python-version: ${{ matrix.python }}
- name: build
run: |
python setup.py build
- name: install
run: |
python -m pip install --user .
- name: test
run: |
python test/test_pepy.py test/assets/example.exe

7
.gitignore vendored
View File

@ -2,7 +2,7 @@ Makefile
cmake_install.cmake
dump-prog/dump-prog
*.swp
python/build
build/
.idea
cmake-build-debug
cmake-build-release
@ -11,4 +11,7 @@ CMakeSettings.json
.vs
.vscode
examples_build
.DS_Store
dist/
MANIFEST
*.egg-info/

3
MANIFEST.in Normal file
View File

@ -0,0 +1,3 @@
include VERSION
include pepy/README.md
include pe-parser-library/include/parser-library/*.h

View File

@ -1,9 +1,14 @@
pe-parse
=========================================
========
[![Build Status](https://img.shields.io/github/workflow/status/trailofbits/pe-parse/CI/master)](https://github.com/trailofbits/pe-parse/actions?query=workflow%3ACI)
pe-parse is a principled, lightweight parser for windows portable executable files. It was created to assist in compiled program analysis, potentially of programs of unknown origins. This means that it should be resistant to malformed or maliciously crafted PE files, and it should support questions that analysis software would ask of an executable program container. For example, listing relocations, describing imports and exports, and supporting byte reads from virtual addresses as well as file offsets.
pe-parse is a principled, lightweight parser for windows portable executable files.
It was created to assist in compiled program analysis, potentially of programs of unknown origins.
This means that it should be resistant to malformed or maliciously crafted PE files, and it should
support questions that analysis software would ask of an executable program container.
For example, listing relocations, describing imports and exports, and supporting byte reads from
virtual addresses as well as file offsets.
pe-parse supports these use cases via a minimal API that provides methods for
* Opening and closing a PE file
@ -15,20 +20,34 @@ pe-parse supports these use cases via a minimal API that provides methods for
* Reading bytes from specified virtual addresses
* Retrieving the program entry point
The interface is defined in `parser-library/parse.h`. The program in `dump-prog/dump.cpp` is an example of using the parser-library API to dump information about a PE file.
The interface is defined in `parser-library/parse.h`.
Internally, the parser-library uses a bounded buffer abstraction to access information stored in the PE file. This should help in constructing a sane parser that allows for detection of the use of bogus values in the PE that would result in out of bounds accesses of the input buffer. Once data is read from the file it is sanitized and placed in C++ STL containers of internal types.
The program in `dump-prog/dump.cpp` is an example of using the parser-library API to dump
information about a PE file.
Internally, the parser-library uses a bounded buffer abstraction to access information stored in
the PE file. This should help in constructing a sane parser that allows for detection of the use
of bogus values in the PE that would result in out of bounds accesses of the input buffer.
Once data is read from the file it is sanitized and placed in C++ STL containers of internal types.
pe-parse includes Python bindings via `pepy`, which can be installed via `pip`:
```bash
$ pip3 install pepy
```
More information about `pepy` can be found in its [README](./pepy/README.md).
## Dependencies
Dependencies
========
### CMake
* Debian/Ubuntu: `sudo apt-get install cmake`
* RedHat/Fedora: `sudo yum install cmake`
* OSX: `brew install cmake`
* Windows: Download the installer from the [CMake page](https://cmake.org/download/)
Building
========
## Building
### Generic instructions
```
git clone https://github.com/trailofbits/pe-parse.git
@ -38,37 +57,48 @@ mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=Release ..
cmake --build . --config Release
cmake --build .
# optional
cmake --build . --config Release --target install
cmake --build . --target install
```
PE files that have a Resource section with strings for the Type are encoded in UTF-16, but that `std::string` expects UTF-8. Some cross-platform solution
is desired. You can let cmake choose one it finds in your build environment or you can choose one from the following options yourself and specify it with
the `-DUNICODE_LIBRARY` argument when generating the project files with cmake:
* `icu` (preferred) - "[ICU](http://site.icu-project.org/) is a mature, widely used set of C/C++ and Java libraries providing Unicode and Globalization support for software applications"
* `codecvt` - A C++ library header file ([now deprecated](http://open-std.org/JTC1/SC22/WG21/docs/papers/2017/p0618r0.html)) supported by some C++ runtimes
PE files that have a Resource section with strings for the Type are encoded in UTF-16, but that
`std::string` expects UTF-8. Some cross-platform solution is desired.
You can let `cmake` choose one it finds in your build environment or you can choose one from the
following options yourself and specify it with the `-DUNICODE_LIBRARY` argument when generating the
project files with `cmake`:
* `icu` (preferred) - "[ICU](http://site.icu-project.org/) is a mature, widely used set of C/C++
and Java libraries providing Unicode and Globalization support for software applications"
* `codecvt` - A C++ library header file
([now deprecated](http://open-std.org/JTC1/SC22/WG21/docs/papers/2017/p0618r0.html)) supported
by some C++ runtimes
### Notes about Windows
If you are building on Windows with Visual Studio, the generator option can be used to select the compiler version and the output architecture:
If you are building on Windows with Visual Studio, the generator option can be used to select the
compiler version and the output architecture:
```
# Compile 64-bit binaries with Visual Studio 2017
cmake -G "Visual Studio 15 2017 Win64" -DCMAKE_BUILD_TYPE=Release ..
cmake -G "Visual Studio 15 2017 Win64" ..
# Compile 32-bit binaries with Visual Studio 2017
cmake -G "Visual Studio 15 2017" -DCMAKE_BUILD_TYPE=Release ..
cmake -G "Visual Studio 15 2017" ..
```
Visual Studio 2015 or higher is required to use codecvt, but you also have the option of using [ICU](http://site.icu-project.org/). The easiest way to
get started with ICU in Windows is with [vcpkg](https://vcpkg.readthedocs.io/): `vcpkg install icu`. Then add the
`-DCMAKE_TOOLCHAIN_FILE=C:\src\vcpkg\scripts\buildsystems\vcpkg.cmake` argument when generating the project files with cmake to add the appropriate
library and include directories to the project.
Visual Studio 2015 or higher is required to use codecvt, but you also have the option of using
[ICU](http://site.icu-project.org/). The easiest way to get started with ICU in Windows is with
[vcpkg](https://vcpkg.readthedocs.io/): `vcpkg install icu`.
Then, add the `-DCMAKE_TOOLCHAIN_FILE=C:\src\vcpkg\scripts\buildsystems\vcpkg.cmake` argument when
generating the project files with cmake to add the appropriate library and include directories to
the project.
## Using the library
Using the library
=======
Once the library is installed, linking to it is easy! Add the following lines in your CMake project:
```
@ -80,6 +110,7 @@ target_include_directories(your_target_name PRIVATE ${PEPARSE_INCLUDE_DIRS})
You can see a full example in the examples/peaddrconv folder.
Authors
=======
pe-parse was designed and implemented by Andrew Ruef (andrew@trailofbits.com), with significant contributions from [Wesley Shields](https://github.com/wxsBSD).
## Authors
pe-parse was designed and implemented by Andrew Ruef (andrew@trailofbits.com), with significant
contributions from [Wesley Shields](https://github.com/wxsBSD).

1
VERSION Normal file
View File

@ -0,0 +1 @@
1.0.0-rc.2

View File

@ -1,6 +1,12 @@
cmake_minimum_required(VERSION 3.7)
project(pe-parser-library)
message(STATUS "VERSION file: ${CMAKE_SOURCE_DIR}/VERSION")
file(READ "${CMAKE_SOURCE_DIR}/VERSION" PEPARSE_VERSION)
string(STRIP "${PEPARSE_VERSION}" PEPARSE_VERSION)
add_compile_definitions(PEPARSE_VERSION="${PEPARSE_VERSION}")
set(UNICODE_LIBRARY "any" CACHE STRING "Select a unicode library")
set_property(CACHE UNICODE_LIBRARY PROPERTY STRINGS "any" "icu" "codecvt")

204
pepy/README.md Normal file
View File

@ -0,0 +1,204 @@
pepy
====
pepy (pronounced p-pie) is a python binding to the pe-parse parser.
pepy supports Python versions 3.6 and above.
The easiest way to use pepy is to install it via pip:
```bash
$ pip3 install pepy
```
## Building
If you can build pe-parse and have a working python environment (headers and
libraries) you can build pepy.
1. Build pepy:
* `python3 setup.py build`
2. Install pepy:
* `python3 setup.py install`
**Building on Windows:** Python 3.x is typically installed as _python.exe_,
**NOT** _python3.exe_.
## Using
### Parsed object
There are a number of objects involved in pepy. The main one is the **parsed**
object. This object is returned by the *parse* method.
```python
import pepy
p = pepy.parse("/path/to/exe")
```
The **parsed** object has a number of methods:
* `get_entry_point`: Return the entry point address
* `get_machine_as_str`: Return the machine as a human readable string
* `get_subsystem_as_str`: Return the subsystem as a human readable string
* `get_bytes`: Return the first N bytes at a given address
* `get_sections`: Return a list of section objects
* `get_imports`: Return a list of import objects
* `get_exports`: Return a list of export objects
* `get_relocations`: Return a list of relocation objects
* `get_resources`: Return a list of resource objects
The **parsed** object has a number of attributes:
* `signature`
* `machine`
* `numberofsections`
* `timedatestamp`
* `numberofsymbols`
* `characteristics`
* `magic`
* `majorlinkerver`
* `minorlinkerver`
* `codesize`
* `initdatasize`
* `uninitdatasize`
* `entrypointaddr`
* `baseofcode`
* `baseofdata`
* `imagebase`
* `sectionalignement`
* `filealignment`
* `majorosver`
* `minorosver`
* `win32ver`
* `imagesize`
* `headersize`
* `checksum`
* `subsystem`
* `dllcharacteristics`
* `stackreservesize`
* `stackcommitsize`
* `heapreservesize`
* `heapcommitsize`
* `loaderflags`
* `rvasandsize`
Example:
```python
import time
import pepy
p = pepy.parse("/path/to/exe")
print("Timedatestamp: %s" % time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(p.timedatestamp)))
ep = p.get_entry_point()
print("Entry point: 0x%x" % ep)
```
The `get_sections`, `get_imports`, `get_exports`, `get_relocations` and
`get_resources` methods each return a list of objects. The type of object
depends upon the method called. `get_sections` returns a list of `section`
objects, `get_imports` returns a list of `import` objects, etc.
### Section Object
The `section` object has the following attributes:
* `base`
* `length`
* `virtaddr`
* `virtsize`
* `numrelocs`
* `numlinenums`
* `characteristics`
* `data`
### Import Object
The `import` object has the following attributes:
* `sym`
* `name`
* `addr`
### Export Object
The `export` object has the following attributes:
* `mod`
* `func`
* `addr`
### Relocation Object
The `relocation` object has the following attributes:
* `type`
* `addr`
### Resource Object
The `resource` object has the following attributes:
* `type_str`
* `name_str`
* `lang_str`
* `type`
* `name`
* `lang`
* `codepage`
* `RVA`
* `size`
* `data`
The `resource` object has the following methods:
* `type_as_str`
Resources are stored in a directory structure. The first three levels of the
are called `type`, `name` and `lang`. Each of these levels can have
either a pre-defined value or a custom string. The pre-defined values are
stored in the `type`, `name` and `lang` attributes. If a custom string is
found it will be stored in the `type_str`, `name_str` and `lang_str`
attributes. The `type_as_str` method can be used to convert a pre-defined
type value to a string representation.
The following code shows how to iterate through resources:
```python
import pepy
from hashlib import md5
import sys
p = pepy.parse(sys.argv[1])
resources = p.get_resources()
print("Resources: (%i)" % len(resources))
for resource in resources:
print("[+] MD5: (%i) %s" % (len(resource.data), md5(resource.data).hexdigest()))
if resource.type_str:
print("\tType string: %s" % resource.type_str)
else:
print("\tType: %s (%s)" % (hex(resource.type), resource.type_as_str()))
if resource.name_str:
print("\tName string: %s" % resource.name_str)
else:
print("\tName: %s" % hex(resource.name))
if resource.lang_str:
print("\tLang string: %s" % resource.lang_str)
else:
print("\tLang: %s" % hex(resource.lang))
print("\tCodepage: %s" % hex(resource.codepage))
print("\tRVA: %s" % hex(resource.RVA))
print("\tSize: %s" % hex(resource.size))
```
Note that some binaries (particularly packed) may have corrupt resource entries.
In these cases you may find that `len(resource.data)` is 0 but `resource.size` is
greater than 0. The `size` attribute is the size of the data as declared by the
resource data entry.
## Authors
pe-parse was designed and implemented by Andrew Ruef (andrew@trailofbits.com).
pepy was written by Wesley Shields (wxs@atarininja.org).

View File

@ -31,7 +31,9 @@
using namespace peparse;
#define PEPY_VERSION "0.3"
/* NOTE(ww): These don't necessarily have to be the same, but currently are.
*/
#define PEPY_VERSION PEPARSE_VERSION
/*
* Add some definition for compatibility between python2 and python3
@ -1384,6 +1386,8 @@ static PyObject *pepi_module_init(void) {
PyModule_AddObject(m, "pepy_resource", (PyObject *) &pepy_resource_type);
PyModule_AddStringMacro(m, PEPY_VERSION);
PyModule_AddStringMacro(m, PEPARSE_VERSION);
PyModule_AddStringConstant(m, "__version__", PEPY_VERSION);
PyModule_AddIntMacro(m, MZ_MAGIC);
PyModule_AddIntMacro(m, NT_MAGIC);

View File

@ -1,217 +0,0 @@
pepy
====
pepy (pronounced p-pie) is a python binding to the pe-parse parser.
Building
========
If you can build pe-parse and have a working python environment (headers and
libraries) you can build pepy.
Python 2.7
----------
1. Build pepy:
* python setup.py build
2. Install pepy:
* python setup.py install
**Building on Windows:** If you get a build error of 'Unable to find
vcvarsall.bat', you must set the `VS90COMNTOOLS` environment variable prior
to the appropriate path as per
[this SO article](http://stackoverflow.com/questions/2817869/error-unable-to-find-vcvarsall-bat):
> While running setup.py for package installations, Python 2.7 searches for an
> installed Visual Studio 2008. You can trick Python to use a newer Visual
> Studio by setting the correct path in VS90COMNTOOLS environment variable
> before calling setup.py.
>
> Execute the following command based on the version of Visual Studio installed:
> * Visual Studio 2010 (VS10): `SET VS90COMNTOOLS=%VS100COMNTOOLS%`
> * Visual Studio 2012 (VS11): `SET VS90COMNTOOLS=%VS110COMNTOOLS%`
> * Visual Studio 2013 (VS12): `SET VS90COMNTOOLS=%VS120COMNTOOLS%`
> * Visual Studio 2015/2017 (VS14): `SET VS90COMNTOOLS=%VS140COMNTOOLS%`
Python 3.x
----------
1. Build pepy:
* python3 setup.py build
2. Install pepy:
* python3 setup.py install
**Building on Windows:** Python 3.x is typically installed as _python.exe_
**NOT** _python3.exe_.
Using
=====
Parsed object
-------------
There are a number of objects involved in pepy. The main one is the **parsed**
object. This object is returned by the *parse* method.
```
import pepy
p = pepy.parse("/path/to/exe")
```
The **parsed** object has a number of methods:
* get_entry_point: Return the entry point address
* get_machine_as_str: Return the machine as a human readable string
* get_subsystem_as_str: Return the subsystem as a human readable string
* get_bytes: Return the first N bytes at a given address
* get_sections: Return a list of section objects
* get_imports: Return a list of import objects
* get_exports: Return a list of export objects
* get_relocations: Return a list of relocation objects
* get_resources: Return a list of resource objects
The **parsed** object has a number of attributes:
* signature
* machine
* numberofsections
* timedatestamp
* numberofsymbols
* characteristics
* magic
* majorlinkerver
* minorlinkerver
* codesize
* initdatasize
* uninitdatasize
* entrypointaddr
* baseofcode
* baseofdata
* imagebase
* sectionalignement
* filealignment
* majorosver
* minorosver
* win32ver
* imagesize
* headersize
* checksum
* subsystem
* dllcharacteristics
* stackreservesize
* stackcommitsize
* heapreservesize
* heapcommitsize
* loaderflags
* rvasandsize
Example:
```
import time
import pepy
p = pepy.parse("/path/to/exe")
print "Timedatestamp: %s" % time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(p.timedatestamp))
ep = p.get_entry_point()
print "Entry point: 0x%x" % ep
```
The *get_sections*, *get_imports*, *get_exports*, *get_relocations* and
*get_resources* methods each return a list of objects. The type of object
depends upon the method called. *get_sections* returns a list of **section**
objects, *get_imports* returns a list of **import** objects, etc.
Section Object
--------------
The **section** object has the following attributes:
* base
* length
* virtaddr
* virtsize
* numrelocs
* numlinenums
* characteristics
* data
Import Object
-------------
The **import** object has the following attributes:
* sym
* name
* addr
Export Object
-------------
The **export** object has the following attributes:
* mod
* func
* addr
Relocation Object
-----------------
The **relocation** object has the following attributes:
* type
* addr
Resource Object
---------------
The **resource** object has the following attributes:
* type_str
* name_str
* lang_str
* type
* name
* lang
* codepage
* RVA
* size
* data
The **resource** object has the following methods:
* type_as_str
Resources are stored in a directory structure. The first three levels of the
are called **type**, **name** and **lang**. Each of these levels can have
either a pre-defined value or a custom string. The pre-defined values are
stored in the *type*, *name* and *lang* attributes. If a custom string is
found it will be stored in the *type_str*, *name_str* and *lang_str*
attributes. The *type_as_str* method can be used to convert a pre-defined
type value to a string representation.
The following code shows how to iterate through resources:
```
import pepy
from hashlib import md5
p = pepy.parse(sys.argv[1])
resources = p.get_resources()
print "Resources: (%i)" % len(resources)
for resource in resources:
print "[+] MD5: (%i) %s" % (len(resource.data), md5(resource.data).hexdigest())
if resource.type_str:
print "\tType string: %s" % resource.type_str
else:
print "\tType: %s (%s)" % (hex(resource.type), resource.type_as_str())
if resource.name_str:
print "\tName string: %s" % resource.name_str
else:
print "\tName: %s" % hex(resource.name)
if resource.lang_str:
print "\tLang string: %s" % resource.lang_str
else:
print "\tLang: %s" % hex(resource.lang)
print "\tCodepage: %s" % hex(resource.codepage)
print "\tRVA: %s" % hex(resource.RVA)
print "\tSize: %s" % hex(resource.size)
```
Note that some binaries (particularly packed) may have corrupt resource entries.
In these cases you may find that len(resource.data) is 0 but resource.size is
greater than 0. The *size* attribute is the size of the data as declared by the
resource data entry.
Authors
=======
pe-parse was designed and implemented by Andrew Ruef (andrew@trailofbits.com)
pepy was written by Wesley Shields (wxs@atarininja.org)

View File

@ -1,99 +0,0 @@
#!/usr/bin/env python
import sys
import time
import pepy
import binascii
from hashlib import md5
try:
p = pepy.parse(sys.argv[1])
except pepy.error as e:
print e
sys.exit(1)
print "Magic: %s" % hex(p.magic)
print "Signature: %s" % hex(p.signature)
print "Machine: %s (%s)" % (hex(p.machine), p.get_machine_as_str())
print "Number of sections: %s" % p.numberofsections
print "Number of symbols: %s" % p.numberofsymbols
print "Characteristics: %s" % hex(p.characteristics)
print "Timedatestamp: %s" % time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(p.timedatestamp))
print "Major linker version: %s" % hex(p.majorlinkerver)
print "Minor linker version: %s" % hex(p.minorlinkerver)
print "Size of code: %s" % hex(p.codesize)
print "Size of initialized data: %s" % hex(p.initdatasize)
print "Size of uninitialized data: %s" % hex(p.uninitdatasize)
print "Address of entry point: %s" % hex(p.entrypointaddr)
print "Base address of code: %s" % hex(p.baseofcode)
try:
print "Base address of data: %s" % hex(p.baseofdata)
except:
# Not available on PE32+, ignore it.
pass
print "Image base address: %s" % hex(p.imagebase)
print "Section alignment: %s" % hex(p.sectionalignement)
print "File alignment: %s" % hex(p.filealignment)
print "Major OS version: %s" % hex(p.majorosver)
print "Minor OS version: %s" % hex(p.minorosver)
print "Win32 version: %s" % hex(p.win32ver)
print "Size of image: %s" % hex(p.imagesize)
print "Size of headers: %s" % hex(p.headersize)
print "Checksum: %s" % hex(p.checksum)
print "Subsystem: %s (%s)" % (hex(p.subsystem), p.get_subsystem_as_str())
print "DLL characteristics: %s" % hex(p.dllcharacteristics)
print "Size of stack reserve: %s" % hex(p.stackreservesize)
print "Size of stack commit: %s" % hex(p.stackcommitsize)
print "Size of heap reserve: %s" % hex(p.heapreservesize)
print "Size of heap commit: %s" % hex(p.heapcommitsize)
print "Loader flags: %s" % hex(p.loaderflags)
print "Number of RVA and sizes: %s" % hex(p.rvasandsize)
ep = p.get_entry_point()
byts = p.get_bytes(ep, 8)
print "Bytes at %s: %s" % (hex(ep), ' '.join(['0x' + binascii.hexlify(b) for b in str(byts)]))
sections = p.get_sections()
print "Sections: (%i)" % len(sections)
for sect in sections:
print "[+] %s" % sect.name
print "\tBase: %s" % hex(sect.base)
print "\tLength: %s" % sect.length
print "\tVirtual address: %s" % hex(sect.virtaddr)
print "\tVirtual size: %i" % sect.virtsize
print "\tNumber of Relocations: %i" % sect.numrelocs
print "\tNumber of Line Numbers: %i" % sect.numlinenums
print "\tCharacteristics: %s" % hex(sect.characteristics)
if sect.length:
print "\tFirst 10 bytes: 0x%s" % binascii.hexlify(sect.data[:10])
print "\tMD5: %s" % md5(sect.data).hexdigest()
imports = p.get_imports()
print "Imports: (%i)" % len(imports)
for imp in imports:
print "[+] Symbol: %s (%s %s)" % (imp.sym, imp.name, hex(imp.addr))
exports = p.get_exports()
print "Exports: (%i)" % len(exports)
for exp in exports:
print "[+] Module: %s (%s %s)" % (exp.mod, exp.func, hex(exp.addr))
relocations = p.get_relocations()
print "Relocations: (%i)" % len(relocations)
for reloc in relocations:
print "[+] Type: %s (%s)" % (reloc.type, hex(reloc.addr))
resources = p.get_resources()
print "Resources: (%i)" % len(resources)
for resource in resources:
print "[+] MD5: (%i) %s" % (len(resource.data), md5(resource.data).hexdigest())
if resource.type_str:
print "\tType string: %s" % resource.type_str
else:
print "\tType: %s (%s)" % (hex(resource.type), resource.type_as_str())
if resource.name_str:
print "\tName string: %s" % resource.name_str
else:
print "\tName: %s" % hex(resource.name)
if resource.lang_str:
print "\tLang string: %s" % resource.lang_str
else:
print "\tLang: %s" % hex(resource.lang)
print "\tCodepage: %s" % hex(resource.codepage)
print "\tRVA: %s" % hex(resource.RVA)
print "\tSize: %s" % hex(resource.size)

View File

@ -23,42 +23,47 @@
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
from distutils.core import setup, Extension
from setuptools import setup, Extension
import os
import sys
import platform
here = os.path.abspath(os.path.dirname(__file__))
here = os.path.dirname(__file__)
pepy = os.path.join(here, "pepy")
with open(os.path.join(pepy, "README.md")) as f:
README = f.read()
with open(os.path.join(here, "VERSION")) as f:
VERSION = f.read().strip()
SOURCE_FILES = [
os.path.join(here, "pepy.cpp"),
os.path.abspath(os.path.join(here, "..", "pe-parser-library", "src", "parse.cpp")),
os.path.abspath(os.path.join(here, "..", "pe-parser-library", "src", "buffer.cpp")),
os.path.abspath(
os.path.join(here, "..", "pe-parser-library", "src", "unicode_codecvt.cpp")
),
os.path.join(pepy, "pepy.cpp"),
os.path.join(here, "pe-parser-library", "src", "parse.cpp"),
os.path.join(here, "pe-parser-library", "src", "buffer.cpp"),
os.path.join(here, "pe-parser-library", "src", "unicode_codecvt.cpp"),
]
if platform.system() == "Windows":
INCLUDE_DIRS = [
os.path.abspath(os.path.join(os.path.dirname(sys.executable), "include")),
os.path.abspath(os.path.join(here, "..", "pe-parser-library", "include")),
os.path.join(here, "pe-parser-library", "include"),
"C:\\usr\\include",
]
LIBRARY_DIRS = [
os.path.abspath(os.path.join(os.path.dirname(sys.executable), "libs")),
"C:\\usr\\lib",
]
COMPILE_ARGS = ["/EHsc"]
COMPILE_ARGS = ["/EHsc", f'/D"PEPARSE_VERSION=\\"{VERSION}\\""']
else:
INCLUDE_DIRS = [
"/usr/local/include",
"/opt/local/include",
"/usr/include",
os.path.abspath(os.path.join(here, "..", "pe-parser-library", "include")),
os.path.join(here, "pe-parser-library", "include"),
]
LIBRARY_DIRS = ["/usr/lib", "/usr/local/lib"]
COMPILE_ARGS = ["-std=c++11", "-g", "-O0"] # Debug only
COMPILE_ARGS = ["-std=c++11", f'-DPEPARSE_VERSION="{VERSION}"']
extension_mod = Extension(
"pepy",
@ -69,14 +74,15 @@ extension_mod = Extension(
library_dirs=LIBRARY_DIRS,
)
setup(
name="pepy",
version="0.1",
description="python bindings for pe-parse",
python_requires=">= 3.6",
version=VERSION,
description="Python bindings for pe-parse",
long_description=README,
long_description_content_type="text/markdown",
author="Wesley Shields",
author_email="wxs@atarininja.org",
license="BSD",
long_description="Python bindings for pe-parse",
ext_modules=[extension_mod],
)

BIN
test/assets/example.exe Normal file

Binary file not shown.

43
util/release Executable file
View File

@ -0,0 +1,43 @@
#!/usr/bin/env bash
# release: perform the chore work required for a pe-parse/pepy release
set -eo pipefail
function installed {
cmd=$(command -v "${1}")
[[ -n "${cmd}" ]] && [[ -f "${cmd}" ]]
return ${?}
}
function die {
>&2 echo "Barf: ${*}"
exit 1
}
# Fail early if we don't have the expected tools.
for tool in git python3 twine; do
installed "${tool}" || die "Missing dependency: ${tool}"
done
# Fail early if `git status` reports any untracked changes.
[[ -n $(git status -s) ]] && die "Untracked changes in repo"
# Next, check the VERSION in version and make sure it doesn't already have a git tag.
[[ -f ./VERSION ]] || die "Missing VERSION file; wrong directory?"
version=$(<./VERSION)
[[ -n $(git tag -l "${version}") ]] && die "git tag for ${version} already exists!"
# Next, craft a tag for the current HEAD. Push both the current commit and the tag.
git tag "${version}"
git push
git push origin "${version}"
# Finally, build pepy and publish it to PyPI.
# Nuke the dist/ directory before, to avoid old sdists.
rm -rf dist/
python3 setup.py sdist
twine upload dist/*
echo OK