mirror of
https://github.com/QuasarApp/pe-parse.git
synced 2025-04-26 12:24:32 +00:00
Merge branch 'master' into cqtdeployer
This commit is contained in:
commit
d56534b061
@ -2,7 +2,6 @@ AlignEscapedNewlinesLeft: true
|
||||
AllowShortFunctionsOnASingleLine: false
|
||||
BinPackArguments: false
|
||||
BinPackParameters: false
|
||||
BreakBeforeBraces: Attach
|
||||
ColumnLimit: 80
|
||||
IndentCaseLabels: true
|
||||
IndentWidth: 2
|
||||
|
134
.github/workflows/ci.yml
vendored
Normal file
134
.github/workflows/ci.yml
vendored
Normal file
@ -0,0 +1,134 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
schedule:
|
||||
# run CI every day even if no PRs/merges occur
|
||||
- cron: '0 12 * * *'
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: deps
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y clang-format-9
|
||||
|
||||
- name: lint
|
||||
run: |
|
||||
mkdir build && cd build
|
||||
cmake ..
|
||||
cmake --build . --target peparse_format
|
||||
cd .. && git diff --exit-code
|
||||
|
||||
pe-parse:
|
||||
strategy:
|
||||
matrix:
|
||||
platform: ["ubuntu-latest", "macos-latest"]
|
||||
build-type: ["Debug", "Release"]
|
||||
build-shared: ["0", "1"]
|
||||
compiler:
|
||||
- { CC: "clang", CXX: "clang++" }
|
||||
- { CC: "gcc", CXX: "g++" }
|
||||
exclude:
|
||||
- platform: macos-latest
|
||||
compiler: { CC: "gcc", CXX: "g++" }
|
||||
runs-on: ${{ matrix.platform }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: build
|
||||
env:
|
||||
CC: ${{ matrix.compiler.CC }}
|
||||
CXX: ${{ matrix.compiler.CXX }}
|
||||
run: |
|
||||
mkdir build
|
||||
cd build
|
||||
cmake \
|
||||
-DCMAKE_BUILD_TYPE=${{ matrix.build-type }} \
|
||||
-DBUILD_SHARED_LIBS=${{ matrix.build-shared }} \
|
||||
..
|
||||
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: |
|
||||
python3 setup.py build
|
||||
- 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-arch: ["x64", "Win32"]
|
||||
build-type: ["Debug", "Release"]
|
||||
build-shared: ["0", "1"]
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: build
|
||||
run: |
|
||||
mkdir build
|
||||
cd build
|
||||
cmake `
|
||||
-G "Visual Studio 16 2019" `
|
||||
-A ${{ matrix.build-arch }} `
|
||||
-DBUILD_SHARED_LIBS=${{ matrix.build-shared }} `
|
||||
..
|
||||
cmake --build . --config ${{ matrix.build-type }}
|
||||
- name: install
|
||||
run: |
|
||||
cd build
|
||||
cmake --build . --target install
|
||||
- name: test
|
||||
run: |
|
||||
.\build\bin\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
|
34
.github/workflows/release.yml
vendored
Normal file
34
.github/workflows/release.yml
vendored
Normal file
@ -0,0 +1,34 @@
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v*'
|
||||
|
||||
name: release
|
||||
|
||||
jobs:
|
||||
pypi:
|
||||
name: upload release to PyPI
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-python@v1
|
||||
with:
|
||||
python-version: 3.8
|
||||
- name: create release
|
||||
id: create_release
|
||||
uses: actions/create-release@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
tag_name: ${{ github.ref }}
|
||||
release_name: Release ${{ github.ref }}
|
||||
draft: false
|
||||
prerelease: ${{ contains(github.ref, 'pre') || contains(github.ref, 'rc') }}
|
||||
- name: sdist
|
||||
run: python3 setup.py sdist
|
||||
- name: publish
|
||||
uses: pypa/gh-action-pypi-publish@master
|
||||
with:
|
||||
user: __token__
|
||||
password: ${{ secrets.PYPI_TOKEN }}
|
||||
|
10
.gitignore
vendored
10
.gitignore
vendored
@ -1,8 +1,8 @@
|
||||
*Makefile*
|
||||
Makefile
|
||||
cmake_install.cmake
|
||||
dump-prog/dump-prog
|
||||
*.swp
|
||||
python/build
|
||||
build/
|
||||
.idea
|
||||
cmake-build-debug
|
||||
cmake-build-release
|
||||
@ -11,8 +11,10 @@ CMakeSettings.json
|
||||
.vs
|
||||
.vscode
|
||||
examples_build
|
||||
|
||||
|
||||
.DS_Store
|
||||
dist/
|
||||
MANIFEST
|
||||
*.egg-info/
|
||||
*.stash
|
||||
|
||||
*.o
|
||||
|
32
.travis.yml
32
.travis.yml
@ -1,32 +0,0 @@
|
||||
language: cpp
|
||||
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
|
||||
compiler:
|
||||
- clang
|
||||
- gcc
|
||||
|
||||
before_install:
|
||||
- ./travis.sh "$TRAVIS_OS_NAME" initialize
|
||||
script:
|
||||
- ./travis.sh "$TRAVIS_OS_NAME" build
|
||||
|
||||
matrix:
|
||||
exclude:
|
||||
- compiler: gcc
|
||||
os: osx
|
||||
|
||||
env:
|
||||
global:
|
||||
- secure: "O+BGqz4ugoVIJbQTh0dJjKRrsSVzkCYSe0WpRzEWK3l8Mw7hqX300g81TxRwTzN2zfUsROMzaeGaXWfGzYakgW59K1WIioaczxtv2MzzUQTbqzJPa+qQoP9bk/b2wJ5jcOL965/rudRju4UiIwuIgzDAMN3nAfIEJgV/2zANLIg="
|
||||
|
||||
addons:
|
||||
coverity_scan:
|
||||
project:
|
||||
name: "trailofbits/pe-parse"
|
||||
description: "Principled, lightweight C/C++ PE parser"
|
||||
notification_email: dan@trailofbits.com
|
||||
build_command: "./travis.sh linux build"
|
||||
branch_pattern: master
|
@ -1,11 +1,13 @@
|
||||
cmake_minimum_required(VERSION 3.7)
|
||||
cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
|
||||
project(pe-parse)
|
||||
|
||||
# NOTE(ww): CMake has bad defaults for install prefixes.
|
||||
# Instead of fussing over them, install everything to the build directory by default
|
||||
# and let the user set CMAKE_INSTALL_PREFIX explicitly for their own needs.
|
||||
if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
|
||||
set(CMAKE_INSTALL_PREFIX "/usr" CACHE PATH "Default install directory" FORCE)
|
||||
set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}" CACHE PATH "Default install directory" FORCE)
|
||||
endif ()
|
||||
|
||||
set(CMAKE_VERBOSE_MAKEFILE True)
|
||||
if (NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE "RelWithDebInfo")
|
||||
endif ()
|
||||
@ -13,19 +15,45 @@ endif ()
|
||||
include(cmake/compilation_flags.cmake)
|
||||
list(APPEND GLOBAL_CXXFLAGS ${DEFAULT_CXX_FLAGS})
|
||||
|
||||
option(BUILD_SHARED_LIBS "Build Shared Libraries" OFF)
|
||||
option(BUILD_SHARED_LIBS "Build Shared Libraries" ON)
|
||||
option(BUILD_COMMAND_LINE_TOOLS "Build Command Line Tools" ON)
|
||||
option(PEPARSE_LIBRARY_WARNINGS "Log pe-parse library warnings to stderr" OFF)
|
||||
|
||||
|
||||
if (MSVC)
|
||||
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
|
||||
endif ()
|
||||
|
||||
file(READ "${PROJECT_SOURCE_DIR}/VERSION" PEPARSE_VERSION)
|
||||
string(STRIP "${PEPARSE_VERSION}" PEPARSE_VERSION)
|
||||
add_compile_definitions(PEPARSE_VERSION="${PEPARSE_VERSION}")
|
||||
|
||||
add_subdirectory(pe-parser-library)
|
||||
|
||||
if (BUILD_COMMAND_LINE_TOOLS)
|
||||
add_subdirectory(dump-pe)
|
||||
endif ()
|
||||
|
||||
# `peparse_format` target.
|
||||
file(
|
||||
GLOB_RECURSE
|
||||
PEPARSE_ALL_SOURCES
|
||||
pe-parser-library/*.cpp
|
||||
pe-parser-library/*.h
|
||||
pepy/*.cpp
|
||||
pepy/*.h
|
||||
dump-pe/*.cpp
|
||||
examples/*.cpp
|
||||
examples/*.h
|
||||
)
|
||||
add_custom_target(
|
||||
peparse_format
|
||||
COMMAND clang-format -i -style=file ${PEPARSE_ALL_SOURCES}
|
||||
WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}"
|
||||
COMMENT "Auto-format the codebase with clang-format"
|
||||
VERBATIM
|
||||
)
|
||||
|
||||
message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
|
||||
message(STATUS "Build Shared: ${BUILD_SHARED_LIBS} ${BUILD_SHARED_LIBS_MESSAGE}")
|
||||
message(STATUS "Build Command Line Tools: ${BUILD_COMMAND_LINE_TOOLS}")
|
||||
|
26
CONTRIBUTING.md
Normal file
26
CONTRIBUTING.md
Normal file
@ -0,0 +1,26 @@
|
||||
Contributing to pe-parse
|
||||
========================
|
||||
|
||||
Hello, and welcome to the contributing guidelines for pe-parse!
|
||||
|
||||
For general building instructions, see the [README](README.md).
|
||||
|
||||
For licensing information, see the [LICENSE](LICENSE.txt) file. pe-parse includes a CLA; you will be
|
||||
automatically prompted to sign it during your first PR.
|
||||
|
||||
## General contribution guidelines
|
||||
|
||||
* Your changes should be valid C++11
|
||||
* Your changes should work across all major compiler vendors (GCC, Clang, MSVC) and all
|
||||
major operating systems (Linux, macOS, Windows)
|
||||
* Your changes should be auto-formatted with `clang-format -style=file`
|
||||
* Your changes should not introduce *mandatory* third-party dependencies
|
||||
|
||||
## Adding features
|
||||
|
||||
Feature additions to either the parsing library or `dump-pe` are welcome!
|
||||
|
||||
Check out the following issue labels for some contribution ideas:
|
||||
|
||||
* [Enhancements](https://github.com/trailofbits/pe-parse/issues?q=is%3Aissue+is%3Aopen+label%3Aenhancement)
|
||||
* [Hacktoberfest](https://github.com/trailofbits/pe-parse/issues?q=is%3Aissue+is%3Aopen+label%3Ahacktoberfest)
|
22
Dockerfile
Normal file
22
Dockerfile
Normal file
@ -0,0 +1,22 @@
|
||||
FROM alpine:latest
|
||||
ARG BUILD_TYPE=Release
|
||||
|
||||
LABEL name "pe-parse"
|
||||
LABEL src "https://github.com/trailofbits/pe-parse"
|
||||
LABEL creator "Trail of Bits"
|
||||
LABEL dockerfile_maintenance "William Woodruff <william@trailofbits>"
|
||||
LABEL desc "Principled, lightweight C/C++ PE parser"
|
||||
|
||||
RUN apk add --no-cache cmake icu-dev clang build-base
|
||||
|
||||
COPY . /app/pe-parse
|
||||
WORKDIR /app/pe-parse
|
||||
ENV CC=clang CXX=clang++
|
||||
RUN mkdir build && \
|
||||
cd build && \
|
||||
cmake -DCMAKE_BUILD_TYPE="${BUILD_TYPE}" .. && \
|
||||
cmake --build . && \
|
||||
cmake --build . --target install
|
||||
|
||||
ENTRYPOINT [ "/usr/bin/dump-pe" ]
|
||||
CMD ["--help"]
|
3
MANIFEST.in
Normal file
3
MANIFEST.in
Normal file
@ -0,0 +1,3 @@
|
||||
include VERSION
|
||||
include pepy/README.md
|
||||
include pe-parser-library/include/pe-parse/*.h
|
83
README.md
83
README.md
@ -1,10 +1,15 @@
|
||||
pe-parse
|
||||
=========================================
|
||||
========
|
||||
|
||||
[](https://travis-ci.org/trailofbits/pe-parse)
|
||||
[](https://scan.coverity.com/projects/3671)
|
||||
[](https://github.com/trailofbits/pe-parse/actions?query=workflow%3ACI)
|
||||
[](https://lgtm.com/projects/g/trailofbits/pe-parse/alerts/)
|
||||
|
||||
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
|
||||
@ -16,21 +21,44 @@ 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.
|
||||
|
||||
## Installation
|
||||
|
||||
pe-parse can be installed via [vcpkg](https://github.com/microsoft/vcpkg):
|
||||
|
||||
```bash
|
||||
$ vcpkg install pe-parse
|
||||
```
|
||||
|
||||
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
|
||||
cd pe-parse
|
||||
@ -39,37 +67,40 @@ 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
|
||||
```
|
||||
|
||||
### Notes about Windows
|
||||
### Windows-specific
|
||||
|
||||
If you are building on Windows with Visual Studio, the generator option can be used to select the compiler version and the output architecture:
|
||||
VS 2017 and VS 2019 are supported.
|
||||
|
||||
```
|
||||
# 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 ..
|
||||
# Or, with VS 2019, use the -A flag for architecture
|
||||
cmake -G "Visual Studio 16 2019" -A Win64 ..
|
||||
|
||||
# Pass the build type at build time
|
||||
cmake --build . --config Release
|
||||
```
|
||||
|
||||
Using the library
|
||||
=======
|
||||
## Using the library
|
||||
|
||||
Once the library is installed, linking to it is easy! Add the following lines in your CMake project:
|
||||
|
||||
```
|
||||
find_package(peparse REQUIRED)
|
||||
find_package(pe-parse REQUIRED)
|
||||
|
||||
target_link_libraries(your_target_name ${PEPARSE_LIBRARIES})
|
||||
target_include_directories(your_target_name PRIVATE ${PEPARSE_INCLUDE_DIRS})
|
||||
target_link_libraries(your_target_name PRIVATE pe-parse::pe-parse)
|
||||
```
|
||||
|
||||
You can see a full example in the examples/peaddrconv folder.
|
||||
You can see a full example in the [examples/peaddrconv](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).
|
||||
|
@ -11,6 +11,7 @@ if (MSVC)
|
||||
|
||||
else ()
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
|
||||
if (NOT MINGW)
|
||||
@ -31,10 +32,8 @@ else ()
|
||||
endif ()
|
||||
|
||||
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
message(STATUS "This is a debug build; enabling -Weverything...")
|
||||
|
||||
list(APPEND DEFAULT_CXX_FLAGS
|
||||
-Weverything -Wno-c++98-compat -Wno-missing-prototypes
|
||||
-Wno-c++98-compat -Wno-missing-prototypes
|
||||
-Wno-missing-variable-declarations -Wno-global-constructors
|
||||
-Wno-exit-time-destructors -Wno-padded -Wno-error
|
||||
)
|
||||
|
@ -1,8 +1,8 @@
|
||||
cmake_minimum_required(VERSION 3.7)
|
||||
cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
|
||||
project(dump-pe)
|
||||
|
||||
add_executable(${PROJECT_NAME} main.cpp)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE pe-parser-library)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE pe-parse)
|
||||
target_compile_options(${PROJECT_NAME} PRIVATE ${GLOBAL_CXXFLAGS})
|
||||
|
||||
install(TARGETS ${PROJECT_NAME} DESTINATION "bin")
|
||||
install(TARGETS ${PROJECT_NAME} RUNTIME DESTINATION "bin")
|
||||
|
298
dump-pe/main.cpp
298
dump-pe/main.cpp
@ -22,16 +22,21 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <cstring>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
#include <parser-library/parse.h>
|
||||
#include <pe-parse/parse.h>
|
||||
|
||||
#include "vendor/argh.h"
|
||||
|
||||
using namespace peparse;
|
||||
|
||||
int printExps(void *N, VA funcAddr, std::string &mod, std::string &func) {
|
||||
int printExps(void *N,
|
||||
const VA &funcAddr,
|
||||
const std::string &mod,
|
||||
const std::string &func) {
|
||||
static_cast<void>(N);
|
||||
|
||||
auto address = static_cast<std::uint32_t>(funcAddr);
|
||||
@ -47,7 +52,7 @@ int printExps(void *N, VA funcAddr, std::string &mod, std::string &func) {
|
||||
}
|
||||
|
||||
int printImports(void *N,
|
||||
VA impAddr,
|
||||
const VA &impAddr,
|
||||
const std::string &modName,
|
||||
const std::string &symName) {
|
||||
static_cast<void>(N);
|
||||
@ -59,33 +64,33 @@ int printImports(void *N,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int printRelocs(void *N, VA relocAddr, reloc_type type) {
|
||||
int printRelocs(void *N, const VA &relocAddr, const reloc_type &type) {
|
||||
static_cast<void>(N);
|
||||
|
||||
std::cout << "TYPE: ";
|
||||
switch (type) {
|
||||
case ABSOLUTE:
|
||||
case RELOC_ABSOLUTE:
|
||||
std::cout << "ABSOLUTE";
|
||||
break;
|
||||
case HIGH:
|
||||
case RELOC_HIGH:
|
||||
std::cout << "HIGH";
|
||||
break;
|
||||
case LOW:
|
||||
case RELOC_LOW:
|
||||
std::cout << "LOW";
|
||||
break;
|
||||
case HIGHLOW:
|
||||
case RELOC_HIGHLOW:
|
||||
std::cout << "HIGHLOW";
|
||||
break;
|
||||
case HIGHADJ:
|
||||
case RELOC_HIGHADJ:
|
||||
std::cout << "HIGHADJ";
|
||||
break;
|
||||
case MIPS_JMPADDR:
|
||||
case RELOC_MIPS_JMPADDR:
|
||||
std::cout << "MIPS_JMPADDR";
|
||||
break;
|
||||
case MIPS_JMPADDR16:
|
||||
case RELOC_MIPS_JMPADDR16:
|
||||
std::cout << "MIPS_JMPADD16";
|
||||
break;
|
||||
case DIR64:
|
||||
case RELOC_DIR64:
|
||||
std::cout << "DIR64";
|
||||
break;
|
||||
default:
|
||||
@ -99,12 +104,12 @@ int printRelocs(void *N, VA relocAddr, reloc_type type) {
|
||||
}
|
||||
|
||||
int printSymbols(void *N,
|
||||
std::string &strName,
|
||||
uint32_t &value,
|
||||
int16_t §ionNumber,
|
||||
uint16_t &type,
|
||||
uint8_t &storageClass,
|
||||
uint8_t &numberOfAuxSymbols) {
|
||||
const std::string &strName,
|
||||
const uint32_t &value,
|
||||
const int16_t §ionNumber,
|
||||
const uint16_t &type,
|
||||
const uint8_t &storageClass,
|
||||
const uint8_t &numberOfAuxSymbols) {
|
||||
static_cast<void>(N);
|
||||
|
||||
std::cout << "Symbol Name: " << strName << "\n";
|
||||
@ -227,7 +232,19 @@ int printSymbols(void *N,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int printRsrc(void *N, resource r) {
|
||||
int printRich(void *N, const rich_entry &r) {
|
||||
static_cast<void>(N);
|
||||
std::cout << std::dec;
|
||||
std::cout << std::setw(10) << "ProdId:" << std::setw(7) << r.ProductId;
|
||||
std::cout << std::setw(10) << "Build:" << std::setw(7) << r.BuildNumber;
|
||||
std::cout << std::setw(10) << "Name:" << std::setw(40)
|
||||
<< GetRichProductName(r.BuildNumber) << " "
|
||||
<< GetRichObjectType(r.ProductId);
|
||||
std::cout << std::setw(10) << "Count:" << std::setw(7) << r.Count << "\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
int printRsrc(void *N, const resource &r) {
|
||||
static_cast<void>(N);
|
||||
|
||||
if (r.type_str.length())
|
||||
@ -252,10 +269,10 @@ int printRsrc(void *N, resource r) {
|
||||
}
|
||||
|
||||
int printSecs(void *N,
|
||||
VA secBase,
|
||||
std::string &secName,
|
||||
image_section_header s,
|
||||
bounded_buffer *data) {
|
||||
const VA &secBase,
|
||||
const std::string &secName,
|
||||
const image_section_header &s,
|
||||
const bounded_buffer *data) {
|
||||
static_cast<void>(N);
|
||||
static_cast<void>(s);
|
||||
|
||||
@ -264,114 +281,173 @@ int printSecs(void *N,
|
||||
if (data)
|
||||
std::cout << "Sec Size: " << std::dec << data->bufLen << "\n";
|
||||
else
|
||||
std::cout << "Sec Size: 0" << "\n";
|
||||
std::cout << "Sec Size: 0"
|
||||
<< "\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define DUMP_FIELD(x) \
|
||||
std::cout << "" #x << ": 0x"; \
|
||||
std::cout << std::hex << static_cast<std::uint64_t>(p->peHeader.nt.x) \
|
||||
<< "\n";
|
||||
#define DUMP_DEC_FIELD(x) \
|
||||
std::cout << "" #x << ": "; \
|
||||
std::cout << std::dec << static_cast<std::uint64_t>(p->peHeader.nt.x) \
|
||||
<< "\n";
|
||||
#define DUMP_FIELD(x) \
|
||||
std::cout << "" #x << ": 0x"; \
|
||||
std::cout << std::hex << static_cast<std::uint64_t>(p->peHeader.x) << "\n";
|
||||
#define DUMP_DEC_FIELD(x) \
|
||||
std::cout << "" #x << ": "; \
|
||||
std::cout << std::dec << static_cast<std::uint64_t>(p->peHeader.x) << "\n";
|
||||
#define DUMP_BOOL_FIELD(x) \
|
||||
std::cout << "" #x << ": "; \
|
||||
std::cout << std::boolalpha << static_cast<bool>(p->peHeader.x) << "\n";
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
if (argc != 2 || (argc == 2 && std::strcmp(argv[1], "--help") == 0)) {
|
||||
|
||||
argh::parser cmdl(argv);
|
||||
|
||||
if (cmdl[{"-h", "--help"}] || argc <= 1) {
|
||||
std::cout << "dump-pe utility from Trail of Bits\n";
|
||||
std::cout << "Repository: https://github.com/trailofbits/pe-parse\n\n";
|
||||
std::cout << "Usage:\n\tdump-pe /path/to/executable.exe\n";
|
||||
return 0;
|
||||
} else if (cmdl[{"-v", "--version"}]) {
|
||||
std::cout << "dump-pe (pe-parse) version " << PEPARSE_VERSION << "\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
parsed_pe *p = ParsePEFromFile(cmdl[1].c_str());
|
||||
|
||||
if (p == nullptr) {
|
||||
std::cout << "Error: " << GetPEErr() << " (" << GetPEErrString() << ")"
|
||||
<< "\n";
|
||||
std::cout << "Location: " << GetPEErrLoc() << "\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
parsed_pe *p = ParsePEFromFile(argv[1]);
|
||||
|
||||
if (p != NULL) {
|
||||
// Print DOS header
|
||||
DUMP_FIELD(dos.e_magic);
|
||||
DUMP_FIELD(dos.e_cp);
|
||||
DUMP_FIELD(dos.e_crlc);
|
||||
DUMP_FIELD(dos.e_cparhdr);
|
||||
DUMP_FIELD(dos.e_minalloc);
|
||||
DUMP_FIELD(dos.e_maxalloc);
|
||||
DUMP_FIELD(dos.e_ss);
|
||||
DUMP_FIELD(dos.e_sp);
|
||||
DUMP_FIELD(dos.e_csum);
|
||||
DUMP_FIELD(dos.e_ip);
|
||||
DUMP_FIELD(dos.e_cs);
|
||||
DUMP_FIELD(dos.e_lfarlc);
|
||||
DUMP_FIELD(dos.e_ovno);
|
||||
DUMP_FIELD(dos.e_res[0]);
|
||||
DUMP_FIELD(dos.e_res[1]);
|
||||
DUMP_FIELD(dos.e_res[2]);
|
||||
DUMP_FIELD(dos.e_res[3]);
|
||||
DUMP_FIELD(dos.e_oemid);
|
||||
DUMP_FIELD(dos.e_oeminfo);
|
||||
DUMP_FIELD(dos.e_res2[0]);
|
||||
DUMP_FIELD(dos.e_res2[1]);
|
||||
DUMP_FIELD(dos.e_res2[2]);
|
||||
DUMP_FIELD(dos.e_res2[3]);
|
||||
DUMP_FIELD(dos.e_res2[4]);
|
||||
DUMP_FIELD(dos.e_res2[5]);
|
||||
DUMP_FIELD(dos.e_res2[6]);
|
||||
DUMP_FIELD(dos.e_res2[7]);
|
||||
DUMP_FIELD(dos.e_res2[8]);
|
||||
DUMP_FIELD(dos.e_res2[9]);
|
||||
DUMP_FIELD(dos.e_lfanew);
|
||||
// Print Rich header info
|
||||
DUMP_BOOL_FIELD(rich.isPresent);
|
||||
if (p->peHeader.rich.isPresent) {
|
||||
DUMP_FIELD(rich.DecryptionKey);
|
||||
DUMP_FIELD(rich.Checksum);
|
||||
DUMP_BOOL_FIELD(rich.isValid);
|
||||
IterRich(p, printRich, NULL);
|
||||
}
|
||||
// print out some things
|
||||
DUMP_FIELD(Signature);
|
||||
DUMP_FIELD(FileHeader.Machine);
|
||||
DUMP_FIELD(FileHeader.NumberOfSections);
|
||||
DUMP_DEC_FIELD(FileHeader.TimeDateStamp);
|
||||
DUMP_FIELD(FileHeader.PointerToSymbolTable);
|
||||
DUMP_DEC_FIELD(FileHeader.NumberOfSymbols);
|
||||
DUMP_FIELD(FileHeader.SizeOfOptionalHeader);
|
||||
DUMP_FIELD(FileHeader.Characteristics);
|
||||
DUMP_FIELD(nt.Signature);
|
||||
DUMP_FIELD(nt.FileHeader.Machine);
|
||||
DUMP_FIELD(nt.FileHeader.NumberOfSections);
|
||||
DUMP_DEC_FIELD(nt.FileHeader.TimeDateStamp);
|
||||
DUMP_FIELD(nt.FileHeader.PointerToSymbolTable);
|
||||
DUMP_DEC_FIELD(nt.FileHeader.NumberOfSymbols);
|
||||
DUMP_FIELD(nt.FileHeader.SizeOfOptionalHeader);
|
||||
DUMP_FIELD(nt.FileHeader.Characteristics);
|
||||
if (p->peHeader.nt.OptionalMagic == NT_OPTIONAL_32_MAGIC) {
|
||||
DUMP_FIELD(OptionalHeader.Magic);
|
||||
DUMP_DEC_FIELD(OptionalHeader.MajorLinkerVersion);
|
||||
DUMP_DEC_FIELD(OptionalHeader.MinorLinkerVersion);
|
||||
DUMP_FIELD(OptionalHeader.SizeOfCode);
|
||||
DUMP_FIELD(OptionalHeader.SizeOfInitializedData);
|
||||
DUMP_FIELD(OptionalHeader.SizeOfUninitializedData);
|
||||
DUMP_FIELD(OptionalHeader.AddressOfEntryPoint);
|
||||
DUMP_FIELD(OptionalHeader.BaseOfCode);
|
||||
DUMP_FIELD(OptionalHeader.BaseOfData);
|
||||
DUMP_FIELD(OptionalHeader.ImageBase);
|
||||
DUMP_FIELD(OptionalHeader.SectionAlignment);
|
||||
DUMP_FIELD(OptionalHeader.FileAlignment);
|
||||
DUMP_DEC_FIELD(OptionalHeader.MajorOperatingSystemVersion);
|
||||
DUMP_DEC_FIELD(OptionalHeader.MinorOperatingSystemVersion);
|
||||
DUMP_DEC_FIELD(OptionalHeader.Win32VersionValue);
|
||||
DUMP_FIELD(OptionalHeader.SizeOfImage);
|
||||
DUMP_FIELD(OptionalHeader.SizeOfHeaders);
|
||||
DUMP_FIELD(OptionalHeader.CheckSum);
|
||||
DUMP_FIELD(OptionalHeader.Subsystem);
|
||||
DUMP_FIELD(OptionalHeader.DllCharacteristics);
|
||||
DUMP_FIELD(OptionalHeader.SizeOfStackReserve);
|
||||
DUMP_FIELD(OptionalHeader.SizeOfStackCommit);
|
||||
DUMP_FIELD(OptionalHeader.SizeOfHeapReserve);
|
||||
DUMP_FIELD(OptionalHeader.SizeOfHeapCommit);
|
||||
DUMP_FIELD(OptionalHeader.LoaderFlags);
|
||||
DUMP_DEC_FIELD(OptionalHeader.NumberOfRvaAndSizes);
|
||||
DUMP_FIELD(nt.OptionalHeader.Magic);
|
||||
DUMP_DEC_FIELD(nt.OptionalHeader.MajorLinkerVersion);
|
||||
DUMP_DEC_FIELD(nt.OptionalHeader.MinorLinkerVersion);
|
||||
DUMP_FIELD(nt.OptionalHeader.SizeOfCode);
|
||||
DUMP_FIELD(nt.OptionalHeader.SizeOfInitializedData);
|
||||
DUMP_FIELD(nt.OptionalHeader.SizeOfUninitializedData);
|
||||
DUMP_FIELD(nt.OptionalHeader.AddressOfEntryPoint);
|
||||
DUMP_FIELD(nt.OptionalHeader.BaseOfCode);
|
||||
DUMP_FIELD(nt.OptionalHeader.BaseOfData);
|
||||
DUMP_FIELD(nt.OptionalHeader.ImageBase);
|
||||
DUMP_FIELD(nt.OptionalHeader.SectionAlignment);
|
||||
DUMP_FIELD(nt.OptionalHeader.FileAlignment);
|
||||
DUMP_DEC_FIELD(nt.OptionalHeader.MajorOperatingSystemVersion);
|
||||
DUMP_DEC_FIELD(nt.OptionalHeader.MinorOperatingSystemVersion);
|
||||
DUMP_DEC_FIELD(nt.OptionalHeader.Win32VersionValue);
|
||||
DUMP_FIELD(nt.OptionalHeader.SizeOfImage);
|
||||
DUMP_FIELD(nt.OptionalHeader.SizeOfHeaders);
|
||||
DUMP_FIELD(nt.OptionalHeader.CheckSum);
|
||||
DUMP_FIELD(nt.OptionalHeader.Subsystem);
|
||||
DUMP_FIELD(nt.OptionalHeader.DllCharacteristics);
|
||||
DUMP_FIELD(nt.OptionalHeader.SizeOfStackReserve);
|
||||
DUMP_FIELD(nt.OptionalHeader.SizeOfStackCommit);
|
||||
DUMP_FIELD(nt.OptionalHeader.SizeOfHeapReserve);
|
||||
DUMP_FIELD(nt.OptionalHeader.SizeOfHeapCommit);
|
||||
DUMP_FIELD(nt.OptionalHeader.LoaderFlags);
|
||||
DUMP_DEC_FIELD(nt.OptionalHeader.NumberOfRvaAndSizes);
|
||||
} else {
|
||||
DUMP_FIELD(OptionalHeader64.Magic);
|
||||
DUMP_DEC_FIELD(OptionalHeader64.MajorLinkerVersion);
|
||||
DUMP_DEC_FIELD(OptionalHeader64.MinorLinkerVersion);
|
||||
DUMP_FIELD(OptionalHeader64.SizeOfCode);
|
||||
DUMP_FIELD(OptionalHeader64.SizeOfInitializedData);
|
||||
DUMP_FIELD(OptionalHeader64.SizeOfUninitializedData);
|
||||
DUMP_FIELD(OptionalHeader64.AddressOfEntryPoint);
|
||||
DUMP_FIELD(OptionalHeader64.BaseOfCode);
|
||||
DUMP_FIELD(OptionalHeader64.ImageBase);
|
||||
DUMP_FIELD(OptionalHeader64.SectionAlignment);
|
||||
DUMP_FIELD(OptionalHeader64.FileAlignment);
|
||||
DUMP_DEC_FIELD(OptionalHeader64.MajorOperatingSystemVersion);
|
||||
DUMP_DEC_FIELD(OptionalHeader64.MinorOperatingSystemVersion);
|
||||
DUMP_DEC_FIELD(OptionalHeader64.Win32VersionValue);
|
||||
DUMP_FIELD(OptionalHeader64.SizeOfImage);
|
||||
DUMP_FIELD(OptionalHeader64.SizeOfHeaders);
|
||||
DUMP_FIELD(OptionalHeader64.CheckSum);
|
||||
DUMP_FIELD(OptionalHeader64.Subsystem);
|
||||
DUMP_FIELD(OptionalHeader64.DllCharacteristics);
|
||||
DUMP_FIELD(OptionalHeader64.SizeOfStackReserve);
|
||||
DUMP_FIELD(OptionalHeader64.SizeOfStackCommit);
|
||||
DUMP_FIELD(OptionalHeader64.SizeOfHeapReserve);
|
||||
DUMP_FIELD(OptionalHeader64.SizeOfHeapCommit);
|
||||
DUMP_FIELD(OptionalHeader64.LoaderFlags);
|
||||
DUMP_DEC_FIELD(OptionalHeader64.NumberOfRvaAndSizes);
|
||||
DUMP_FIELD(nt.OptionalHeader64.Magic);
|
||||
DUMP_DEC_FIELD(nt.OptionalHeader64.MajorLinkerVersion);
|
||||
DUMP_DEC_FIELD(nt.OptionalHeader64.MinorLinkerVersion);
|
||||
DUMP_FIELD(nt.OptionalHeader64.SizeOfCode);
|
||||
DUMP_FIELD(nt.OptionalHeader64.SizeOfInitializedData);
|
||||
DUMP_FIELD(nt.OptionalHeader64.SizeOfUninitializedData);
|
||||
DUMP_FIELD(nt.OptionalHeader64.AddressOfEntryPoint);
|
||||
DUMP_FIELD(nt.OptionalHeader64.BaseOfCode);
|
||||
DUMP_FIELD(nt.OptionalHeader64.ImageBase);
|
||||
DUMP_FIELD(nt.OptionalHeader64.SectionAlignment);
|
||||
DUMP_FIELD(nt.OptionalHeader64.FileAlignment);
|
||||
DUMP_DEC_FIELD(nt.OptionalHeader64.MajorOperatingSystemVersion);
|
||||
DUMP_DEC_FIELD(nt.OptionalHeader64.MinorOperatingSystemVersion);
|
||||
DUMP_DEC_FIELD(nt.OptionalHeader64.Win32VersionValue);
|
||||
DUMP_FIELD(nt.OptionalHeader64.SizeOfImage);
|
||||
DUMP_FIELD(nt.OptionalHeader64.SizeOfHeaders);
|
||||
DUMP_FIELD(nt.OptionalHeader64.CheckSum);
|
||||
DUMP_FIELD(nt.OptionalHeader64.Subsystem);
|
||||
DUMP_FIELD(nt.OptionalHeader64.DllCharacteristics);
|
||||
DUMP_FIELD(nt.OptionalHeader64.SizeOfStackReserve);
|
||||
DUMP_FIELD(nt.OptionalHeader64.SizeOfStackCommit);
|
||||
DUMP_FIELD(nt.OptionalHeader64.SizeOfHeapReserve);
|
||||
DUMP_FIELD(nt.OptionalHeader64.SizeOfHeapCommit);
|
||||
DUMP_FIELD(nt.OptionalHeader64.LoaderFlags);
|
||||
DUMP_DEC_FIELD(nt.OptionalHeader64.NumberOfRvaAndSizes);
|
||||
}
|
||||
|
||||
#undef DUMP_FIELD
|
||||
#undef DUMP_DEC_FIELD
|
||||
|
||||
std::cout << "Imports: " << "\n";
|
||||
std::cout << "Imports: "
|
||||
<< "\n";
|
||||
IterImpVAString(p, printImports, NULL);
|
||||
std::cout << "Relocations: " << "\n";
|
||||
std::cout << "Relocations: "
|
||||
<< "\n";
|
||||
IterRelocs(p, printRelocs, NULL);
|
||||
std::cout << "Symbols (symbol table): " << "\n";
|
||||
std::cout << "Symbols (symbol table): "
|
||||
<< "\n";
|
||||
IterSymbols(p, printSymbols, NULL);
|
||||
std::cout << "Sections: " << "\n";
|
||||
std::cout << "Sections: "
|
||||
<< "\n";
|
||||
IterSec(p, printSecs, NULL);
|
||||
std::cout << "Exports: " << "\n";
|
||||
std::cout << "Exports: "
|
||||
<< "\n";
|
||||
IterExpVA(p, printExps, NULL);
|
||||
|
||||
// read the first 8 bytes from the entry point and print them
|
||||
VA entryPoint;
|
||||
if (GetEntryPoint(p, entryPoint)) {
|
||||
std::cout << "First 8 bytes from entry point (0x";
|
||||
|
||||
std::cout << std::hex << entryPoint << "):" << "\n";
|
||||
std::cout << std::hex << entryPoint << "):"
|
||||
<< "\n";
|
||||
for (std::size_t i = 0; i < 8; i++) {
|
||||
std::uint8_t b;
|
||||
if (!ReadByteAtVA(p, i + entryPoint, b)) {
|
||||
@ -384,14 +460,12 @@ int main(int argc, char *argv[]) {
|
||||
std::cout << "\n";
|
||||
}
|
||||
|
||||
std::cout << "Resources: " << "\n";
|
||||
IterRsrc(p, printRsrc, NULL);
|
||||
DestructParsedPE(p);
|
||||
} else {
|
||||
std::cout << "Error: " << GetPEErr() << " (" << GetPEErrString() << ")"
|
||||
std::cout << "Resources: "
|
||||
<< "\n";
|
||||
std::cout << "Location: " << GetPEErrLoc() << "\n";
|
||||
}
|
||||
IterRsrc(p, printRsrc, NULL);
|
||||
|
||||
return 0;
|
||||
DestructParsedPE(p);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
463
dump-pe/vendor/argh.h
vendored
Normal file
463
dump-pe/vendor/argh.h
vendored
Normal file
@ -0,0 +1,463 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Adi Shavit
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of nor the names of its contributors may be used to
|
||||
* endorse or promote products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include <cassert>
|
||||
|
||||
namespace argh
|
||||
{
|
||||
// Terminology:
|
||||
// A command line is composed of 2 types of args:
|
||||
// 1. Positional args, i.e. free standing values
|
||||
// 2. Options: args beginning with '-'. We identify two kinds:
|
||||
// 2.1: Flags: boolean options => (exist ? true : false)
|
||||
// 2.2: Parameters: a name followed by a non-option value
|
||||
|
||||
#if !defined(__GNUC__) || (__GNUC__ >= 5)
|
||||
using string_stream = std::istringstream;
|
||||
#else
|
||||
// Until GCC 5, istringstream did not have a move constructor.
|
||||
// stringstream_proxy is used instead, as a workaround.
|
||||
class stringstream_proxy
|
||||
{
|
||||
public:
|
||||
stringstream_proxy() = default;
|
||||
|
||||
// Construct with a value.
|
||||
stringstream_proxy(std::string const& value) :
|
||||
stream_(value)
|
||||
{}
|
||||
|
||||
// Copy constructor.
|
||||
stringstream_proxy(const stringstream_proxy& other) :
|
||||
stream_(other.stream_.str())
|
||||
{
|
||||
stream_.setstate(other.stream_.rdstate());
|
||||
}
|
||||
|
||||
void setstate(std::ios_base::iostate state) { stream_.setstate(state); }
|
||||
|
||||
// Stream out the value of the parameter.
|
||||
// If the conversion was not possible, the stream will enter the fail state,
|
||||
// and operator bool will return false.
|
||||
template<typename T>
|
||||
stringstream_proxy& operator >> (T& thing)
|
||||
{
|
||||
stream_ >> thing;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
// Get the string value.
|
||||
std::string str() const { return stream_.str(); }
|
||||
|
||||
std::stringbuf* rdbuf() const { return stream_.rdbuf(); }
|
||||
|
||||
// Check the state of the stream.
|
||||
// False when the most recent stream operation failed
|
||||
explicit operator bool() const { return !!stream_; }
|
||||
|
||||
~stringstream_proxy() = default;
|
||||
private:
|
||||
std::istringstream stream_;
|
||||
};
|
||||
using string_stream = stringstream_proxy;
|
||||
#endif
|
||||
|
||||
class parser
|
||||
{
|
||||
public:
|
||||
enum Mode { PREFER_FLAG_FOR_UNREG_OPTION = 1 << 0,
|
||||
PREFER_PARAM_FOR_UNREG_OPTION = 1 << 1,
|
||||
NO_SPLIT_ON_EQUALSIGN = 1 << 2,
|
||||
SINGLE_DASH_IS_MULTIFLAG = 1 << 3,
|
||||
};
|
||||
|
||||
parser() = default;
|
||||
|
||||
parser(std::initializer_list<char const* const> pre_reg_names)
|
||||
{ add_params(pre_reg_names); }
|
||||
|
||||
parser(const char* const argv[], int mode = PREFER_FLAG_FOR_UNREG_OPTION)
|
||||
{ parse(argv, mode); }
|
||||
|
||||
parser(int argc, const char* const argv[], int mode = PREFER_FLAG_FOR_UNREG_OPTION)
|
||||
{ parse(argc, argv, mode); }
|
||||
|
||||
void add_param(std::string const& name);
|
||||
void add_params(std::initializer_list<char const* const> init_list);
|
||||
|
||||
void parse(const char* const argv[], int mode = PREFER_FLAG_FOR_UNREG_OPTION);
|
||||
void parse(int argc, const char* const argv[], int mode = PREFER_FLAG_FOR_UNREG_OPTION);
|
||||
|
||||
std::multiset<std::string> const& flags() const { return flags_; }
|
||||
std::map<std::string, std::string> const& params() const { return params_; }
|
||||
std::vector<std::string> const& pos_args() const { return pos_args_; }
|
||||
|
||||
// begin() and end() for using range-for over positional args.
|
||||
std::vector<std::string>::const_iterator begin() const { return pos_args_.cbegin(); }
|
||||
std::vector<std::string>::const_iterator end() const { return pos_args_.cend(); }
|
||||
size_t size() const { return pos_args_.size(); }
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Accessors
|
||||
|
||||
// flag (boolean) accessors: return true if the flag appeared, otherwise false.
|
||||
bool operator[](std::string const& name) const;
|
||||
|
||||
// multiple flag (boolean) accessors: return true if at least one of the flag appeared, otherwise false.
|
||||
bool operator[](std::initializer_list<char const* const> init_list) const;
|
||||
|
||||
// returns positional arg string by order. Like argv[] but without the options
|
||||
std::string const& operator[](size_t ind) const;
|
||||
|
||||
// returns a std::istream that can be used to convert a positional arg to a typed value.
|
||||
string_stream operator()(size_t ind) const;
|
||||
|
||||
// same as above, but with a default value in case the arg is missing (index out of range).
|
||||
template<typename T>
|
||||
string_stream operator()(size_t ind, T&& def_val) const;
|
||||
|
||||
// parameter accessors, give a name get an std::istream that can be used to convert to a typed value.
|
||||
// call .str() on result to get as string
|
||||
string_stream operator()(std::string const& name) const;
|
||||
|
||||
// accessor for a parameter with multiple names, give a list of names, get an std::istream that can be used to convert to a typed value.
|
||||
// call .str() on result to get as string
|
||||
// returns the first value in the list to be found.
|
||||
string_stream operator()(std::initializer_list<char const* const> init_list) const;
|
||||
|
||||
// same as above, but with a default value in case the param was missing.
|
||||
// Non-string def_val types must have an operator<<() (output stream operator)
|
||||
// If T only has an input stream operator, pass the string version of the type as in "3" instead of 3.
|
||||
template<typename T>
|
||||
string_stream operator()(std::string const& name, T&& def_val) const;
|
||||
|
||||
// same as above but for a list of names. returns the first value to be found.
|
||||
template<typename T>
|
||||
string_stream operator()(std::initializer_list<char const* const> init_list, T&& def_val) const;
|
||||
|
||||
private:
|
||||
string_stream bad_stream() const;
|
||||
std::string trim_leading_dashes(std::string const& name) const;
|
||||
bool is_number(std::string const& arg) const;
|
||||
bool is_option(std::string const& arg) const;
|
||||
bool got_flag(std::string const& name) const;
|
||||
bool is_param(std::string const& name) const;
|
||||
|
||||
private:
|
||||
std::vector<std::string> args_;
|
||||
std::map<std::string, std::string> params_;
|
||||
std::vector<std::string> pos_args_;
|
||||
std::multiset<std::string> flags_;
|
||||
std::set<std::string> registeredParams_;
|
||||
std::string empty_;
|
||||
};
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline void parser::parse(const char * const argv[], int mode)
|
||||
{
|
||||
int argc = 0;
|
||||
for (auto argvp = argv; *argvp; ++argc, ++argvp);
|
||||
parse(argc, argv, mode);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline void parser::parse(int argc, const char* const argv[], int mode /*= PREFER_FLAG_FOR_UNREG_OPTION*/)
|
||||
{
|
||||
// convert to strings
|
||||
args_.resize(static_cast<decltype(args_)::size_type>(argc));
|
||||
std::transform(argv, argv + argc, args_.begin(), [](const char* const arg) { return arg; });
|
||||
|
||||
// parse line
|
||||
for (auto i = 0u; i < args_.size(); ++i)
|
||||
{
|
||||
if (!is_option(args_[i]))
|
||||
{
|
||||
pos_args_.emplace_back(args_[i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
auto name = trim_leading_dashes(args_[i]);
|
||||
|
||||
if (!(mode & NO_SPLIT_ON_EQUALSIGN))
|
||||
{
|
||||
auto equalPos = name.find('=');
|
||||
if (equalPos != std::string::npos)
|
||||
{
|
||||
params_.insert({ name.substr(0, equalPos), name.substr(equalPos + 1) });
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// if the option is unregistered and should be a multi-flag
|
||||
if (1 == (args_[i].size() - name.size()) && // single dash
|
||||
argh::parser::SINGLE_DASH_IS_MULTIFLAG & mode && // multi-flag mode
|
||||
!is_param(name)) // unregistered
|
||||
{
|
||||
std::string keep_param;
|
||||
|
||||
if (!name.empty() && is_param(std::string(1ul, name.back()))) // last char is param
|
||||
{
|
||||
keep_param += name.back();
|
||||
name.resize(name.size() - 1);
|
||||
}
|
||||
|
||||
for (auto const& c : name)
|
||||
{
|
||||
flags_.emplace(std::string{ c });
|
||||
}
|
||||
|
||||
if (!keep_param.empty())
|
||||
{
|
||||
name = keep_param;
|
||||
}
|
||||
else
|
||||
{
|
||||
continue; // do not consider other options for this arg
|
||||
}
|
||||
}
|
||||
|
||||
// any potential option will get as its value the next arg, unless that arg is an option too
|
||||
// in that case it will be determined a flag.
|
||||
if (i == args_.size() - 1 || is_option(args_[i + 1]))
|
||||
{
|
||||
flags_.emplace(name);
|
||||
continue;
|
||||
}
|
||||
|
||||
// if 'name' is a pre-registered option, then the next arg cannot be a free parameter to it is skipped
|
||||
// otherwise we have 2 modes:
|
||||
// PREFER_FLAG_FOR_UNREG_OPTION: a non-registered 'name' is determined a flag.
|
||||
// The following value (the next arg) will be a free parameter.
|
||||
//
|
||||
// PREFER_PARAM_FOR_UNREG_OPTION: a non-registered 'name' is determined a parameter, the next arg
|
||||
// will be the value of that option.
|
||||
|
||||
assert(!(mode & argh::parser::PREFER_FLAG_FOR_UNREG_OPTION)
|
||||
|| !(mode & argh::parser::PREFER_PARAM_FOR_UNREG_OPTION));
|
||||
|
||||
bool preferParam = mode & argh::parser::PREFER_PARAM_FOR_UNREG_OPTION;
|
||||
|
||||
if (is_param(name) || preferParam)
|
||||
{
|
||||
params_.insert({ name, args_[i + 1] });
|
||||
++i; // skip next value, it is not a free parameter
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
flags_.emplace(name);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline string_stream parser::bad_stream() const
|
||||
{
|
||||
string_stream bad;
|
||||
bad.setstate(std::ios_base::failbit);
|
||||
return bad;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline bool parser::is_number(std::string const& arg) const
|
||||
{
|
||||
// inefficient but simple way to determine if a string is a number (which can start with a '-')
|
||||
std::istringstream istr(arg);
|
||||
double number;
|
||||
istr >> number;
|
||||
return !(istr.fail() || istr.bad());
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline bool parser::is_option(std::string const& arg) const
|
||||
{
|
||||
assert(0 != arg.size());
|
||||
if (is_number(arg))
|
||||
return false;
|
||||
return '-' == arg[0];
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline std::string parser::trim_leading_dashes(std::string const& name) const
|
||||
{
|
||||
auto pos = name.find_first_not_of('-');
|
||||
return std::string::npos != pos ? name.substr(pos) : name;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline bool argh::parser::got_flag(std::string const& name) const
|
||||
{
|
||||
return flags_.end() != flags_.find(trim_leading_dashes(name));
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline bool argh::parser::is_param(std::string const& name) const
|
||||
{
|
||||
return registeredParams_.count(name);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline bool parser::operator[](std::string const& name) const
|
||||
{
|
||||
return got_flag(name);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline bool parser::operator[](std::initializer_list<char const* const> init_list) const
|
||||
{
|
||||
return std::any_of(init_list.begin(), init_list.end(), [&](char const* const name) { return got_flag(name); });
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline std::string const& parser::operator[](size_t ind) const
|
||||
{
|
||||
if (ind < pos_args_.size())
|
||||
return pos_args_[ind];
|
||||
return empty_;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline string_stream parser::operator()(std::string const& name) const
|
||||
{
|
||||
auto optIt = params_.find(trim_leading_dashes(name));
|
||||
if (params_.end() != optIt)
|
||||
return string_stream(optIt->second);
|
||||
return bad_stream();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline string_stream parser::operator()(std::initializer_list<char const* const> init_list) const
|
||||
{
|
||||
for (auto& name : init_list)
|
||||
{
|
||||
auto optIt = params_.find(trim_leading_dashes(name));
|
||||
if (params_.end() != optIt)
|
||||
return string_stream(optIt->second);
|
||||
}
|
||||
return bad_stream();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<typename T>
|
||||
string_stream parser::operator()(std::string const& name, T&& def_val) const
|
||||
{
|
||||
auto optIt = params_.find(trim_leading_dashes(name));
|
||||
if (params_.end() != optIt)
|
||||
return string_stream(optIt->second);
|
||||
|
||||
std::ostringstream ostr;
|
||||
ostr.precision(std::numeric_limits<long double>::max_digits10);
|
||||
ostr << def_val;
|
||||
return string_stream(ostr.str()); // use default
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// same as above but for a list of names. returns the first value to be found.
|
||||
template<typename T>
|
||||
string_stream parser::operator()(std::initializer_list<char const* const> init_list, T&& def_val) const
|
||||
{
|
||||
for (auto& name : init_list)
|
||||
{
|
||||
auto optIt = params_.find(trim_leading_dashes(name));
|
||||
if (params_.end() != optIt)
|
||||
return string_stream(optIt->second);
|
||||
}
|
||||
std::ostringstream ostr;
|
||||
ostr.precision(std::numeric_limits<long double>::max_digits10);
|
||||
ostr << def_val;
|
||||
return string_stream(ostr.str()); // use default
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline string_stream parser::operator()(size_t ind) const
|
||||
{
|
||||
if (pos_args_.size() <= ind)
|
||||
return bad_stream();
|
||||
|
||||
return string_stream(pos_args_[ind]);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<typename T>
|
||||
string_stream parser::operator()(size_t ind, T&& def_val) const
|
||||
{
|
||||
if (pos_args_.size() <= ind)
|
||||
{
|
||||
std::ostringstream ostr;
|
||||
ostr.precision(std::numeric_limits<long double>::max_digits10);
|
||||
ostr << def_val;
|
||||
return string_stream(ostr.str());
|
||||
}
|
||||
|
||||
return string_stream(pos_args_[ind]);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline void parser::add_param(std::string const& name)
|
||||
{
|
||||
registeredParams_.insert(trim_leading_dashes(name));
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline void parser::add_params(std::initializer_list<char const* const> init_list)
|
||||
{
|
||||
for (auto& name : init_list)
|
||||
registeredParams_.insert(trim_leading_dashes(name));
|
||||
}
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
dump_prog = executable(
|
||||
'dump-prog',
|
||||
'dump.cpp',
|
||||
include_directories : [ incdirs ],
|
||||
install : true,
|
||||
install_dir : join_paths(get_option('datadir'), 'pe-parse/examples'),
|
||||
link_with : pe_parser_library)
|
@ -1,4 +1,4 @@
|
||||
cmake_minimum_required(VERSION 3.1)
|
||||
cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
|
||||
project(peaddrconv)
|
||||
|
||||
if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
|
||||
@ -35,11 +35,10 @@ else ()
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
find_package(peparse REQUIRED)
|
||||
find_package(pe-parse REQUIRED)
|
||||
|
||||
add_executable(${PROJECT_NAME} main.cpp)
|
||||
target_link_libraries(${PROJECT_NAME} ${PEPARSE_LIBRARIES})
|
||||
target_include_directories(${PROJECT_NAME} PRIVATE ${PEPARSE_INCLUDE_DIR})
|
||||
target_link_libraries(${PROJECT_NAME} pe-parse::pe-parse)
|
||||
target_compile_options(${PROJECT_NAME} PRIVATE ${PEADDRCONV_CXXFLAGS})
|
||||
|
||||
install(TARGETS ${PROJECT_NAME} DESTINATION "bin")
|
||||
|
@ -1,12 +1,12 @@
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <algorithm>
|
||||
|
||||
#include <climits>
|
||||
#include <cstring>
|
||||
|
||||
#include <parser-library/parse.h>
|
||||
#include <pe-parse/parse.h>
|
||||
|
||||
using ParsedPeRef =
|
||||
std::unique_ptr<peparse::parsed_pe, void (*)(peparse::parsed_pe *)>;
|
||||
@ -243,7 +243,9 @@ bool convertAddress(ParsedPeRef &pe,
|
||||
result);
|
||||
}
|
||||
|
||||
default: { return false; }
|
||||
default: {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -262,7 +264,8 @@ int main(int argc, char *argv[]) {
|
||||
char *last_parsed_char = nullptr;
|
||||
errno = 0;
|
||||
|
||||
std::uint64_t address = std::strtoull(address_as_string, &last_parsed_char, 16);
|
||||
std::uint64_t address =
|
||||
std::strtoull(address_as_string, &last_parsed_char, 16);
|
||||
if (address == 0U && *last_parsed_char != 0) {
|
||||
std::cout << "Invalid address specified\n";
|
||||
return 1;
|
||||
|
@ -1,8 +0,0 @@
|
||||
project('pe-parse',
|
||||
'cpp',
|
||||
default_options : [ 'cpp_std=c++11' ],
|
||||
license : [ 'MIT' ],
|
||||
)
|
||||
|
||||
subdir('parser-library')
|
||||
subdir('dump-prog')
|
@ -1,11 +0,0 @@
|
||||
incdirs = include_directories('.')
|
||||
parser_source = [
|
||||
'buffer.cpp',
|
||||
'parse.cpp'
|
||||
]
|
||||
|
||||
pe_parser_library = library('pe-parser-library',
|
||||
sources : parser_source,
|
||||
install : true
|
||||
)
|
||||
install_headers('parse.h', subdir : 'pe-parse')
|
@ -1,24 +1,63 @@
|
||||
cmake_minimum_required(VERSION 3.7)
|
||||
project(pe-parser-library)
|
||||
cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
|
||||
project(pe-parse)
|
||||
|
||||
message(STATUS "VERSION file: ${PROJECT_SOURCE_DIR}/../VERSION")
|
||||
|
||||
# List all files explicitly; this will make IDEs happy (i.e. QtCreator, CLion, ...)
|
||||
list(APPEND PEPARSERLIB_SOURCEFILES
|
||||
include/parser-library/parse.h
|
||||
include/parser-library/nt-headers.h
|
||||
include/parser-library/to_string.h
|
||||
include/pe-parse/parse.h
|
||||
include/pe-parse/nt-headers.h
|
||||
include/pe-parse/to_string.h
|
||||
|
||||
src/buffer.cpp
|
||||
src/parse.cpp
|
||||
)
|
||||
|
||||
# NOTE(ww): On Windows we use the Win32 API's built-in UTF16 conversion
|
||||
# routines; on other platforms we use codecvt. codecvt is nominally deprecated
|
||||
# in C++17 and onwards, but will probably be available for quite some time.
|
||||
# Previous versions of pe-parse used ICU when available, but this caused
|
||||
# DLL hell on Windows and wasn't worth the additional dependency.
|
||||
if(MSVC)
|
||||
list(APPEND PEPARSERLIB_SOURCEFILES src/unicode_winapi.cpp)
|
||||
else()
|
||||
list(APPEND PEPARSERLIB_SOURCEFILES src/unicode_codecvt.cpp)
|
||||
endif()
|
||||
|
||||
add_library(${PROJECT_NAME} ${PEPARSERLIB_SOURCEFILES})
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||
|
||||
if(PEPARSE_LIBRARY_WARNINGS)
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE PEPARSE_LIBRARY_WARNINGS=1)
|
||||
endif ()
|
||||
|
||||
target_include_directories(
|
||||
${PROJECT_NAME}
|
||||
PUBLIC
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
|
||||
$<INSTALL_INTERFACE:include>
|
||||
)
|
||||
target_compile_options(${PROJECT_NAME} PRIVATE ${GLOBAL_CXXFLAGS})
|
||||
|
||||
install(TARGETS ${PROJECT_NAME}
|
||||
RUNTIME DESTINATION "bin"
|
||||
LIBRARY DESTINATION "lib"
|
||||
ARCHIVE DESTINATION "lib"
|
||||
install(
|
||||
TARGETS ${PROJECT_NAME}
|
||||
EXPORT pe-parse-config
|
||||
RUNTIME
|
||||
DESTINATION "bin"
|
||||
LIBRARY
|
||||
DESTINATION "lib"
|
||||
ARCHIVE
|
||||
DESTINATION "lib"
|
||||
)
|
||||
install(FILES "cmake/peparse-config.cmake" DESTINATION "lib/cmake/peparse")
|
||||
install(DIRECTORY "include/parser-library" DESTINATION "include")
|
||||
export(
|
||||
TARGETS ${PROJECT_NAME}
|
||||
NAMESPACE pe-parse::
|
||||
FILE "${CMAKE_CURRENT_BINARY_DIR}/pe-parse-config.cmake"
|
||||
)
|
||||
install(
|
||||
EXPORT
|
||||
pe-parse-config
|
||||
DESTINATION "lib/cmake/pe-parse"
|
||||
NAMESPACE pe-parse::
|
||||
EXPORT_LINK_INTERFACE_LIBRARIES
|
||||
)
|
||||
install(DIRECTORY "include/pe-parse" DESTINATION "include")
|
||||
|
5
pe-parser-library/cmake/pe-parse-config.cmake
Normal file
5
pe-parser-library/cmake/pe-parse-config.cmake
Normal file
@ -0,0 +1,5 @@
|
||||
find_path(PEPARSE_INCLUDE_DIR "pe-parse/parse.h")
|
||||
find_library(PEPARSE_LIBRARIES NAMES "libpe-parse" "pe-parse")
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(pe-parse DEFAULT_MSG PEPARSE_INCLUDE_DIR PEPARSE_LIBRARIES)
|
@ -1,5 +0,0 @@
|
||||
find_path(PEPARSE_INCLUDE_DIR $<SHELL_PATH:"parser-library/parse.h">)
|
||||
find_library(PEPARSE_LIBRARIES NAMES "libpe-parser-library" "pe-parser-library")
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(peparse DEFAULT_MSG PEPARSE_INCLUDE_DIR PEPARSE_LIBRARIES)
|
@ -26,16 +26,16 @@ THE SOFTWARE.
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
#define _offset(t, f) \
|
||||
static_cast<std::uint32_t>( \
|
||||
reinterpret_cast<std::ptrdiff_t>(&static_cast<t *>(nullptr)->f))
|
||||
#include <vector>
|
||||
|
||||
// need to pack these structure definitions
|
||||
|
||||
// some constant definitions
|
||||
// clang-format off
|
||||
namespace peparse {
|
||||
constexpr std::uint32_t RICH_MAGIC_END = 0x68636952;
|
||||
constexpr std::uint32_t RICH_MAGIC_START = 0x536e6144;
|
||||
constexpr std::uint32_t RICH_OFFSET = 0x80;
|
||||
constexpr std::uint16_t MZ_MAGIC = 0x5A4D;
|
||||
constexpr std::uint32_t NT_MAGIC = 0x00004550;
|
||||
constexpr std::uint16_t NUM_DIR_ENTRIES = 16;
|
||||
@ -43,22 +43,8 @@ constexpr std::uint16_t NT_OPTIONAL_32_MAGIC = 0x10B;
|
||||
constexpr std::uint16_t NT_OPTIONAL_64_MAGIC = 0x20B;
|
||||
constexpr std::uint16_t NT_SHORT_NAME_LEN = 8;
|
||||
constexpr std::uint16_t SYMTAB_RECORD_LEN = 18;
|
||||
constexpr std::uint16_t DIR_EXPORT = 0;
|
||||
constexpr std::uint16_t DIR_IMPORT = 1;
|
||||
constexpr std::uint16_t DIR_RESOURCE = 2;
|
||||
constexpr std::uint16_t DIR_EXCEPTION = 3;
|
||||
constexpr std::uint16_t DIR_SECURITY = 4;
|
||||
constexpr std::uint16_t DIR_BASERELOC = 5;
|
||||
constexpr std::uint16_t DIR_DEBUG = 6;
|
||||
constexpr std::uint16_t DIR_ARCHITECTURE = 7;
|
||||
constexpr std::uint16_t DIR_GLOBALPTR = 8;
|
||||
constexpr std::uint16_t DIR_TLS = 9;
|
||||
constexpr std::uint16_t DIR_LOAD_CONFIG = 10;
|
||||
constexpr std::uint16_t DIR_BOUND_IMPORT = 11;
|
||||
constexpr std::uint16_t DIR_IAT = 12;
|
||||
constexpr std::uint16_t DIR_DELAY_IMPORT = 13;
|
||||
constexpr std::uint16_t DIR_COM_DESCRIPTOR = 14;
|
||||
|
||||
#ifndef _PEPARSE_WINDOWS_CONFLICTS
|
||||
// Machine Types
|
||||
constexpr std::uint16_t IMAGE_FILE_MACHINE_UNKNOWN = 0x0;
|
||||
constexpr std::uint16_t IMAGE_FILE_MACHINE_ALPHA = 0x1d3; // Alpha_AXP
|
||||
@ -220,6 +206,20 @@ constexpr std::uint8_t IMAGE_SYM_CLASS_FILE = 103;
|
||||
constexpr std::uint8_t IMAGE_SYM_CLASS_SECTION = 104;
|
||||
constexpr std::uint8_t IMAGE_SYM_CLASS_WEAK_EXTERNAL = 105;
|
||||
constexpr std::uint8_t IMAGE_SYM_CLASS_CLR_TOKEN = 107;
|
||||
|
||||
// Optional header DLL characteristics
|
||||
constexpr std::uint16_t IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA = 0x0020;
|
||||
constexpr std::uint16_t IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE = 0x0040;
|
||||
constexpr std::uint16_t IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY = 0x0080;
|
||||
constexpr std::uint16_t IMAGE_DLLCHARACTERISTICS_NX_COMPAT = 0x0100;
|
||||
constexpr std::uint16_t IMAGE_DLLCHARACTERISTICS_NO_ISOLATION = 0x0200;
|
||||
constexpr std::uint16_t IMAGE_DLLCHARACTERISTICS_NO_SEH = 0x0400;
|
||||
constexpr std::uint16_t IMAGE_DLLCHARACTERISTICS_NO_BIND = 0x0800;
|
||||
constexpr std::uint16_t IMAGE_DLLCHARACTERISTICS_APPCONTAINER = 0x1000;
|
||||
constexpr std::uint16_t IMAGE_DLLCHARACTERISTICS_WDM_DRIVER = 0x2000;
|
||||
constexpr std::uint16_t IMAGE_DLLCHARACTERISTICS_GUARD_CF = 0x4000;
|
||||
constexpr std::uint16_t IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE = 0x8000;
|
||||
#endif
|
||||
// clang-format on
|
||||
|
||||
struct dos_header {
|
||||
@ -259,6 +259,25 @@ struct data_directory {
|
||||
std::uint32_t Size;
|
||||
};
|
||||
|
||||
enum data_directory_kind {
|
||||
DIR_EXPORT = 0,
|
||||
DIR_IMPORT = 1,
|
||||
DIR_RESOURCE = 2,
|
||||
DIR_EXCEPTION = 3,
|
||||
DIR_SECURITY = 4,
|
||||
DIR_BASERELOC = 5,
|
||||
DIR_DEBUG = 6,
|
||||
DIR_ARCHITECTURE = 7,
|
||||
DIR_GLOBALPTR = 8,
|
||||
DIR_TLS = 9,
|
||||
DIR_LOAD_CONFIG = 10,
|
||||
DIR_BOUND_IMPORT = 11,
|
||||
DIR_IAT = 12,
|
||||
DIR_DELAY_IMPORT = 13,
|
||||
DIR_COM_DESCRIPTOR = 14,
|
||||
DIR_RESERVED = 15,
|
||||
};
|
||||
|
||||
struct optional_header_32 {
|
||||
std::uint16_t Magic;
|
||||
std::uint8_t MajorLinkerVersion;
|
||||
@ -338,6 +357,22 @@ struct nt_header_32 {
|
||||
std::uint16_t OptionalMagic;
|
||||
};
|
||||
|
||||
struct rich_entry {
|
||||
std::uint16_t ProductId;
|
||||
std::uint16_t BuildNumber;
|
||||
std::uint32_t Count;
|
||||
};
|
||||
|
||||
struct rich_header {
|
||||
std::uint32_t StartSignature;
|
||||
std::vector<rich_entry> Entries;
|
||||
std::uint32_t EndSignature;
|
||||
std::uint32_t DecryptionKey;
|
||||
std::uint32_t Checksum;
|
||||
bool isPresent;
|
||||
bool isValid;
|
||||
};
|
||||
|
||||
/*
|
||||
* This structure is only used to know how far to move the offset
|
||||
* when parsing resources. The data is stored in a resource_dir_entry
|
||||
@ -418,19 +453,116 @@ struct export_dir_table {
|
||||
};
|
||||
|
||||
enum reloc_type {
|
||||
ABSOLUTE = 0,
|
||||
HIGH = 1,
|
||||
LOW = 2,
|
||||
HIGHLOW = 3,
|
||||
HIGHADJ = 4,
|
||||
MIPS_JMPADDR = 5,
|
||||
MIPS_JMPADDR16 = 9,
|
||||
IA64_IMM64 = 9,
|
||||
DIR64 = 10
|
||||
RELOC_ABSOLUTE = 0,
|
||||
RELOC_HIGH = 1,
|
||||
RELOC_LOW = 2,
|
||||
RELOC_HIGHLOW = 3,
|
||||
RELOC_HIGHADJ = 4,
|
||||
RELOC_MIPS_JMPADDR = 5,
|
||||
RELOC_MIPS_JMPADDR16 = 9,
|
||||
RELOC_IA64_IMM64 = 9,
|
||||
RELOC_DIR64 = 10
|
||||
};
|
||||
|
||||
struct reloc_block {
|
||||
std::uint32_t PageRVA;
|
||||
std::uint32_t BlockSize;
|
||||
};
|
||||
|
||||
struct image_load_config_code_integrity {
|
||||
std::uint16_t Flags;
|
||||
std::uint16_t Catalog;
|
||||
std::uint32_t CatalogOffset;
|
||||
std::uint32_t Reserved;
|
||||
};
|
||||
|
||||
struct image_load_config_32 {
|
||||
std::uint32_t Size;
|
||||
std::uint32_t TimeDateStamp;
|
||||
std::uint16_t MajorVersion;
|
||||
std::uint16_t MinorVersion;
|
||||
std::uint32_t GlobalFlagsClear;
|
||||
std::uint32_t GlobalFlagsSet;
|
||||
std::uint32_t CriticalSectionDefaultTimeout;
|
||||
std::uint32_t DeCommitFreeBlockThreshold;
|
||||
std::uint32_t DeCommitTotalFreeThreshold;
|
||||
std::uint32_t LockPrefixTable;
|
||||
std::uint32_t MaximumAllocationSize;
|
||||
std::uint32_t VirtualMemoryThreshold;
|
||||
std::uint32_t ProcessHeapFlags;
|
||||
std::uint32_t ProcessAffinityMask;
|
||||
std::uint16_t CSDVersion;
|
||||
std::uint16_t DependentLoadFlags;
|
||||
std::uint32_t EditList;
|
||||
std::uint32_t SecurityCookie;
|
||||
std::uint32_t SEHandlerTable;
|
||||
std::uint32_t SEHandlerCount;
|
||||
std::uint32_t GuardCFCheckFunctionPointer;
|
||||
std::uint32_t GuardCFDispatchFunctionPointer;
|
||||
std::uint32_t GuardCFFunctionTable;
|
||||
std::uint32_t GuardCFFunctionCount;
|
||||
std::uint32_t GuardFlags;
|
||||
image_load_config_code_integrity CodeIntegrity;
|
||||
std::uint32_t GuardAddressTakenIatEntryTable;
|
||||
std::uint32_t GuardAddressTakenIatEntryCount;
|
||||
std::uint32_t GuardLongJumpTargetTable;
|
||||
std::uint32_t GuardLongJumpTargetCount;
|
||||
std::uint32_t DynamicValueRelocTable;
|
||||
std::uint32_t CHPEMetadataPointer;
|
||||
std::uint32_t GuardRFFailureRoutine;
|
||||
std::uint32_t GuardRFFailureRoutineFunctionPointer;
|
||||
std::uint32_t DynamicValueRelocTableOffset;
|
||||
std::uint16_t DynamicValueRelocTableSection;
|
||||
std::uint16_t Reserved2;
|
||||
std::uint32_t GuardRFVerifyStackPointerFunctionPointer;
|
||||
std::uint32_t HotPatchTableOffset;
|
||||
std::uint32_t Reserved3;
|
||||
std::uint32_t EnclaveConfigurationPointer;
|
||||
std::uint32_t VolatileMetadataPointer;
|
||||
};
|
||||
|
||||
struct image_load_config_64 {
|
||||
std::uint32_t Size;
|
||||
std::uint32_t TimeDateStamp;
|
||||
std::uint16_t MajorVersion;
|
||||
std::uint16_t MinorVersion;
|
||||
std::uint32_t GlobalFlagsClear;
|
||||
std::uint32_t GlobalFlagsSet;
|
||||
std::uint32_t CriticalSectionDefaultTimeout;
|
||||
std::uint64_t DeCommitFreeBlockThreshold;
|
||||
std::uint64_t DeCommitTotalFreeThreshold;
|
||||
std::uint64_t LockPrefixTable;
|
||||
std::uint64_t MaximumAllocationSize;
|
||||
std::uint64_t VirtualMemoryThreshold;
|
||||
std::uint64_t ProcessAffinityMask;
|
||||
std::uint32_t ProcessHeapFlags;
|
||||
std::uint16_t CSDVersion;
|
||||
std::uint16_t DependentLoadFlags;
|
||||
std::uint64_t EditList;
|
||||
std::uint64_t SecurityCookie;
|
||||
std::uint64_t SEHandlerTable;
|
||||
std::uint64_t SEHandlerCount;
|
||||
std::uint64_t GuardCFCheckFunctionPointer;
|
||||
std::uint64_t GuardCFDispatchFunctionPointer;
|
||||
std::uint64_t GuardCFFunctionTable;
|
||||
std::uint64_t GuardCFFunctionCount;
|
||||
std::uint32_t GuardFlags;
|
||||
image_load_config_code_integrity CodeIntegrity;
|
||||
std::uint64_t GuardAddressTakenIatEntryTable;
|
||||
std::uint64_t GuardAddressTakenIatEntryCount;
|
||||
std::uint64_t GuardLongJumpTargetTable;
|
||||
std::uint64_t GuardLongJumpTargetCount;
|
||||
std::uint64_t DynamicValueRelocTable;
|
||||
std::uint64_t CHPEMetadataPointer;
|
||||
std::uint64_t GuardRFFailureRoutine;
|
||||
std::uint64_t GuardRFFailureRoutineFunctionPointer;
|
||||
std::uint32_t DynamicValueRelocTableOffset;
|
||||
std::uint16_t DynamicValueRelocTableSection;
|
||||
std::uint16_t Reserved2;
|
||||
std::uint64_t GuardRFVerifyStackPointerFunctionPointer;
|
||||
std::uint32_t HotPatchTableOffset;
|
||||
std::uint32_t Reserved3;
|
||||
std::uint64_t EnclaveConfigurationPointer;
|
||||
std::uint64_t VolatileMetadataPointer;
|
||||
};
|
||||
} // namespace peparse
|
@ -25,13 +25,14 @@ THE SOFTWARE.
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include "nt-headers.h"
|
||||
#include "to_string.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define __typeof__(x) std::remove_reference < decltype(x) > ::type
|
||||
#define __typeof__(x) std::remove_reference<decltype(x)>::type
|
||||
#endif
|
||||
|
||||
#define PE_ERR(x) \
|
||||
@ -39,28 +40,28 @@ THE SOFTWARE.
|
||||
err_loc.assign(__func__); \
|
||||
err_loc += ":" + to_string<std::uint32_t>(__LINE__, std::dec);
|
||||
|
||||
#define READ_WORD(b, o, inst, member) \
|
||||
if (!readWord(b, o + _offset(__typeof__(inst), member), inst.member)) { \
|
||||
PE_ERR(PEERR_READ); \
|
||||
return false; \
|
||||
}
|
||||
|
||||
#define READ_DWORD(b, o, inst, member) \
|
||||
if (!readDword(b, o + _offset(__typeof__(inst), member), inst.member)) { \
|
||||
#define READ_WORD(b, o, inst, member) \
|
||||
if (!readWord(b, o + offsetof(__typeof__(inst), member), inst.member)) { \
|
||||
PE_ERR(PEERR_READ); \
|
||||
return false; \
|
||||
}
|
||||
|
||||
#define READ_QWORD(b, o, inst, member) \
|
||||
if (!readQword(b, o + _offset(__typeof__(inst), member), inst.member)) { \
|
||||
PE_ERR(PEERR_READ); \
|
||||
return false; \
|
||||
#define READ_DWORD(b, o, inst, member) \
|
||||
if (!readDword(b, o + offsetof(__typeof__(inst), member), inst.member)) { \
|
||||
PE_ERR(PEERR_READ); \
|
||||
return false; \
|
||||
}
|
||||
|
||||
#define READ_BYTE(b, o, inst, member) \
|
||||
if (!readByte(b, o + _offset(__typeof__(inst), member), inst.member)) { \
|
||||
PE_ERR(PEERR_READ); \
|
||||
return false; \
|
||||
#define READ_QWORD(b, o, inst, member) \
|
||||
if (!readQword(b, o + offsetof(__typeof__(inst), member), inst.member)) { \
|
||||
PE_ERR(PEERR_READ); \
|
||||
return false; \
|
||||
}
|
||||
|
||||
#define READ_BYTE(b, o, inst, member) \
|
||||
if (!readByte(b, o + offsetof(__typeof__(inst), member), inst.member)) { \
|
||||
PE_ERR(PEERR_READ); \
|
||||
return false; \
|
||||
}
|
||||
|
||||
#define TEST_MACHINE_CHARACTERISTICS(h, m, ch) \
|
||||
@ -98,6 +99,7 @@ struct resource {
|
||||
bounded_buffer *buf;
|
||||
};
|
||||
|
||||
#ifndef _PEPARSE_WINDOWS_CONFLICTS
|
||||
// http://msdn.microsoft.com/en-us/library/ms648009(v=vs.85).aspx
|
||||
enum resource_type {
|
||||
RT_CURSOR = 1,
|
||||
@ -122,6 +124,7 @@ enum resource_type {
|
||||
RT_HTML = 23,
|
||||
RT_MANIFEST = 24
|
||||
};
|
||||
#endif
|
||||
|
||||
enum pe_err {
|
||||
PEERR_NONE = 0,
|
||||
@ -136,14 +139,17 @@ enum pe_err {
|
||||
PEERR_MAGIC = 9,
|
||||
PEERR_BUFFER = 10,
|
||||
PEERR_ADDRESS = 11,
|
||||
PEERR_SIZE = 12,
|
||||
};
|
||||
|
||||
bool readByte(bounded_buffer *b, std::uint32_t offset, std::uint8_t &out);
|
||||
bool readWord(bounded_buffer *b, std::uint32_t offset, std::uint16_t &out);
|
||||
bool readDword(bounded_buffer *b, std::uint32_t offset, std::uint32_t &out);
|
||||
bool readQword(bounded_buffer *b, std::uint32_t offset, std::uint64_t &out);
|
||||
bool readChar16(bounded_buffer *b, std::uint32_t offset, char16_t &out);
|
||||
|
||||
bounded_buffer *readFileToFileBuffer(const char *filePath);
|
||||
bounded_buffer *makeBufferFromPointer(std::uint8_t *data, std::uint32_t sz);
|
||||
bounded_buffer *
|
||||
splitBuffer(bounded_buffer *b, std::uint32_t from, std::uint32_t to);
|
||||
void deleteBuffer(bounded_buffer *b);
|
||||
@ -152,6 +158,8 @@ uint64_t bufLen(bounded_buffer *b);
|
||||
struct parsed_pe_internal;
|
||||
|
||||
typedef struct _pe_header {
|
||||
dos_header dos;
|
||||
rich_header rich;
|
||||
nt_header_32 nt;
|
||||
} pe_header;
|
||||
|
||||
@ -161,6 +169,12 @@ typedef struct _parsed_pe {
|
||||
pe_header peHeader;
|
||||
} parsed_pe;
|
||||
|
||||
// Resolve a Rich header product id / build number pair to a known
|
||||
// product name
|
||||
typedef std::pair<std::uint16_t, std::uint16_t> ProductKey;
|
||||
const std::string &GetRichObjectType(std::uint16_t prodId);
|
||||
const std::string &GetRichProductName(std::uint16_t buildNum);
|
||||
|
||||
// get parser error status as integer
|
||||
std::uint32_t GetPEErr();
|
||||
|
||||
@ -173,38 +187,54 @@ std::string GetPEErrLoc();
|
||||
// get a PE parse context from a file
|
||||
parsed_pe *ParsePEFromFile(const char *filePath);
|
||||
|
||||
parsed_pe *ParsePEFromPointer(std::uint8_t *buffer, std::uint32_t sz);
|
||||
parsed_pe *ParsePEFromBuffer(bounded_buffer *buffer);
|
||||
|
||||
// destruct a PE context
|
||||
void DestructParsedPE(parsed_pe *p);
|
||||
|
||||
// iterate over Rich header entries
|
||||
typedef int (*iterRich)(void *, const rich_entry &);
|
||||
void IterRich(parsed_pe *pe, iterRich cb, void *cbd);
|
||||
|
||||
// iterate over the resources
|
||||
typedef int (*iterRsrc)(void *, resource);
|
||||
typedef int (*iterRsrc)(void *, const resource &);
|
||||
void IterRsrc(parsed_pe *pe, iterRsrc cb, void *cbd);
|
||||
|
||||
// iterate over the imports by RVA and string
|
||||
typedef int (*iterVAStr)(void *, VA, const std::string &, const std::string &);
|
||||
typedef int (*iterVAStr)(void *,
|
||||
const VA &,
|
||||
const std::string &,
|
||||
const std::string &);
|
||||
void IterImpVAString(parsed_pe *pe, iterVAStr cb, void *cbd);
|
||||
|
||||
// iterate over relocations in the PE file
|
||||
typedef int (*iterReloc)(void *, VA, reloc_type);
|
||||
typedef int (*iterReloc)(void *, const VA &, const reloc_type &);
|
||||
void IterRelocs(parsed_pe *pe, iterReloc cb, void *cbd);
|
||||
|
||||
// Iterate over symbols (symbol table) in the PE file
|
||||
typedef int (*iterSymbol)(void *,
|
||||
std::string &,
|
||||
std::uint32_t &,
|
||||
std::int16_t &,
|
||||
std::uint16_t &,
|
||||
std::uint8_t &,
|
||||
std::uint8_t &);
|
||||
const std::string &,
|
||||
const std::uint32_t &,
|
||||
const std::int16_t &,
|
||||
const std::uint16_t &,
|
||||
const std::uint8_t &,
|
||||
const std::uint8_t &);
|
||||
void IterSymbols(parsed_pe *pe, iterSymbol cb, void *cbd);
|
||||
|
||||
// iterate over the exports
|
||||
typedef int (*iterExp)(void *, VA, std::string &, std::string &);
|
||||
typedef int (*iterExp)(void *,
|
||||
const VA &,
|
||||
const std::string &,
|
||||
const std::string &);
|
||||
void IterExpVA(parsed_pe *pe, iterExp cb, void *cbd);
|
||||
|
||||
// iterate over sections
|
||||
typedef int (*iterSec)(
|
||||
void *, VA secBase, std::string &, image_section_header, bounded_buffer *b);
|
||||
typedef int (*iterSec)(void *,
|
||||
const VA &,
|
||||
const std::string &,
|
||||
const image_section_header &,
|
||||
const bounded_buffer *);
|
||||
void IterSec(parsed_pe *pe, iterSec cb, void *cbd);
|
||||
|
||||
// get byte at VA in PE
|
||||
@ -218,4 +248,9 @@ const char *GetMachineAsString(parsed_pe *pe);
|
||||
|
||||
// get subsystem as human readable string
|
||||
const char *GetSubsystemAsString(parsed_pe *pe);
|
||||
|
||||
// get a table or string by its data directory entry
|
||||
bool GetDataDirectoryEntry(parsed_pe *pe,
|
||||
data_directory_kind dirnum,
|
||||
std::vector<std::uint8_t> &raw_entry);
|
||||
} // namespace peparse
|
@ -1,6 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
typedef std::basic_string<wchar_t> UCharString;
|
||||
#else
|
||||
typedef std::u16string UCharString;
|
||||
#endif
|
||||
|
||||
namespace peparse {
|
||||
template <class T>
|
||||
@ -9,4 +16,6 @@ static std::string to_string(T t, std::ios_base &(*f)(std::ios_base &) ) {
|
||||
oss << f << t;
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string from_utf16(const UCharString &u);
|
||||
} // namespace peparse
|
@ -26,7 +26,7 @@ THE SOFTWARE.
|
||||
#include <fstream>
|
||||
|
||||
// keep this header above "windows.h" because it contains many types
|
||||
#include <parser-library/parse.h>
|
||||
#include <pe-parse/parse.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
@ -164,6 +164,31 @@ bool readQword(bounded_buffer *b, std::uint32_t offset, std::uint64_t &out) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool readChar16(bounded_buffer *b, std::uint32_t offset, char16_t &out) {
|
||||
if (b == nullptr) {
|
||||
PE_ERR(PEERR_BUFFER);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (offset + 1 >= b->bufLen) {
|
||||
PE_ERR(PEERR_ADDRESS);
|
||||
return false;
|
||||
}
|
||||
|
||||
char16_t *tmp = nullptr;
|
||||
if (b->swapBytes) {
|
||||
std::uint8_t tmpBuf[2];
|
||||
tmpBuf[0] = *(b->buf + offset + 1);
|
||||
tmpBuf[1] = *(b->buf + offset);
|
||||
tmp = reinterpret_cast<char16_t *>(tmpBuf);
|
||||
} else {
|
||||
tmp = reinterpret_cast<char16_t *>(b->buf + offset);
|
||||
}
|
||||
out = *tmp;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bounded_buffer *readFileToFileBuffer(const char *filePath) {
|
||||
#ifdef _WIN32
|
||||
HANDLE h = CreateFileA(filePath,
|
||||
@ -273,6 +298,28 @@ bounded_buffer *readFileToFileBuffer(const char *filePath) {
|
||||
return p;
|
||||
}
|
||||
|
||||
bounded_buffer *makeBufferFromPointer(std::uint8_t *data, std::uint32_t sz) {
|
||||
if (data == nullptr) {
|
||||
PE_ERR(PEERR_MEM);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bounded_buffer *p = new (std::nothrow) bounded_buffer();
|
||||
|
||||
if (p == nullptr) {
|
||||
PE_ERR(PEERR_MEM);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
p->copy = true;
|
||||
p->detail = nullptr;
|
||||
p->buf = data;
|
||||
p->bufLen = sz;
|
||||
p->swapBytes = false;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
// split buffer inclusively from from to to by offset
|
||||
bounded_buffer *
|
||||
splitBuffer(bounded_buffer *b, std::uint32_t from, std::uint32_t to) {
|
||||
|
File diff suppressed because it is too large
Load Diff
36
pe-parser-library/src/unicode_codecvt.cpp
Normal file
36
pe-parser-library/src/unicode_codecvt.cpp
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2019 Trail of Bits, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <codecvt>
|
||||
#include <locale>
|
||||
#include <pe-parse/to_string.h>
|
||||
|
||||
namespace peparse {
|
||||
// See
|
||||
// https://stackoverflow.com/questions/38688417/utf-conversion-functions-in-c11
|
||||
std::string from_utf16(const UCharString &u) {
|
||||
std::wstring_convert<std::codecvt_utf8<char16_t>, char16_t> convert;
|
||||
return convert.to_bytes(u);
|
||||
}
|
||||
} // namespace peparse
|
56
pe-parser-library/src/unicode_winapi.cpp
Normal file
56
pe-parser-library/src/unicode_winapi.cpp
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2020 Trail of Bits, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <Windows.h>
|
||||
#include <pe-parse/to_string.h>
|
||||
|
||||
namespace peparse {
|
||||
std::string from_utf16(const UCharString &u) {
|
||||
std::string result;
|
||||
std::size_t size = WideCharToMultiByte(CP_UTF8,
|
||||
0,
|
||||
u.data(),
|
||||
static_cast<int>(u.size()),
|
||||
nullptr,
|
||||
0,
|
||||
nullptr,
|
||||
nullptr);
|
||||
|
||||
if (size <= 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
result.reserve(size);
|
||||
WideCharToMultiByte(CP_UTF8,
|
||||
0,
|
||||
u.data(),
|
||||
static_cast<int>(u.size()),
|
||||
&result[0],
|
||||
static_cast<int>(result.capacity()),
|
||||
nullptr,
|
||||
nullptr);
|
||||
|
||||
return result;
|
||||
}
|
||||
} // namespace peparse
|
204
pepy/README.md
Normal file
204
pepy/README.md
Normal 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).
|
@ -26,31 +26,14 @@
|
||||
*/
|
||||
|
||||
#include <Python.h>
|
||||
#include <parser-library/parse.h>
|
||||
#include <pe-parse/parse.h>
|
||||
#include <structmember.h>
|
||||
|
||||
using namespace peparse;
|
||||
|
||||
#define PEPY_VERSION "0.3"
|
||||
|
||||
/*
|
||||
* Add some definition for compatibility between python2 and python3
|
||||
/* NOTE(ww): These don't necessarily have to be the same, but currently are.
|
||||
*/
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
#define PyString_FromString PyUnicode_FromString
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Some macro only available after python 2.6
|
||||
* Needed for compatibility with python3
|
||||
*/
|
||||
#ifndef PyVarObject_HEAD_INIT
|
||||
#define PyVarObject_HEAD_INIT(type, size) PyObject_HEAD_INIT(type) size,
|
||||
#endif
|
||||
|
||||
#ifndef Py_TYPE
|
||||
#define Py_TYPE(_ob_) (((PyObject *) (_ob_))->ob_type)
|
||||
#endif
|
||||
#define PEPY_VERSION PEPARSE_VERSION
|
||||
|
||||
/* These are used to across multiple objects. */
|
||||
#define PEPY_OBJECT_GET(OBJ, ATTR) \
|
||||
@ -154,9 +137,9 @@ static void pepy_import_dealloc(pepy_import *self) {
|
||||
Py_TYPE(self)->tp_free((PyObject *) self);
|
||||
}
|
||||
|
||||
PEPY_OBJECT_GET(import, name)
|
||||
PEPY_OBJECT_GET(import, sym)
|
||||
PEPY_OBJECT_GET(import, addr)
|
||||
PEPY_OBJECT_GET(import, name);
|
||||
PEPY_OBJECT_GET(import, sym);
|
||||
PEPY_OBJECT_GET(import, addr);
|
||||
|
||||
static PyGetSetDef pepy_import_getseters[] = {
|
||||
OBJECTGETTER(import, name, "Name"),
|
||||
@ -228,9 +211,9 @@ static void pepy_export_dealloc(pepy_export *self) {
|
||||
Py_TYPE(self)->tp_free((PyObject *) self);
|
||||
}
|
||||
|
||||
PEPY_OBJECT_GET(export, mod)
|
||||
PEPY_OBJECT_GET(export, func)
|
||||
PEPY_OBJECT_GET(export, addr)
|
||||
PEPY_OBJECT_GET(export, mod);
|
||||
PEPY_OBJECT_GET(export, func);
|
||||
PEPY_OBJECT_GET(export, addr);
|
||||
|
||||
static PyGetSetDef pepy_export_getseters[] = {
|
||||
OBJECTGETTER(export, mod, "Module"),
|
||||
@ -302,8 +285,8 @@ static void pepy_relocation_dealloc(pepy_relocation *self) {
|
||||
Py_TYPE(self)->tp_free((PyObject *) self);
|
||||
}
|
||||
|
||||
PEPY_OBJECT_GET(relocation, type)
|
||||
PEPY_OBJECT_GET(relocation, addr)
|
||||
PEPY_OBJECT_GET(relocation, type);
|
||||
PEPY_OBJECT_GET(relocation, addr);
|
||||
|
||||
static PyGetSetDef pepy_relocation_getseters[] = {
|
||||
OBJECTGETTER(relocation, type, "Type"),
|
||||
@ -390,15 +373,15 @@ static void pepy_section_dealloc(pepy_section *self) {
|
||||
Py_TYPE(self)->tp_free((PyObject *) self);
|
||||
}
|
||||
|
||||
PEPY_OBJECT_GET(section, name)
|
||||
PEPY_OBJECT_GET(section, base)
|
||||
PEPY_OBJECT_GET(section, length)
|
||||
PEPY_OBJECT_GET(section, virtaddr)
|
||||
PEPY_OBJECT_GET(section, virtsize)
|
||||
PEPY_OBJECT_GET(section, numrelocs)
|
||||
PEPY_OBJECT_GET(section, numlinenums)
|
||||
PEPY_OBJECT_GET(section, characteristics)
|
||||
PEPY_OBJECT_GET(section, data)
|
||||
PEPY_OBJECT_GET(section, name);
|
||||
PEPY_OBJECT_GET(section, base);
|
||||
PEPY_OBJECT_GET(section, length);
|
||||
PEPY_OBJECT_GET(section, virtaddr);
|
||||
PEPY_OBJECT_GET(section, virtsize);
|
||||
PEPY_OBJECT_GET(section, numrelocs);
|
||||
PEPY_OBJECT_GET(section, numlinenums);
|
||||
PEPY_OBJECT_GET(section, characteristics);
|
||||
PEPY_OBJECT_GET(section, data);
|
||||
|
||||
static PyGetSetDef pepy_section_getseters[] = {
|
||||
OBJECTGETTER(section, name, "Name"),
|
||||
@ -495,16 +478,16 @@ static void pepy_resource_dealloc(pepy_resource *self) {
|
||||
Py_TYPE(self)->tp_free((PyObject *) self);
|
||||
}
|
||||
|
||||
PEPY_OBJECT_GET(resource, type_str)
|
||||
PEPY_OBJECT_GET(resource, name_str)
|
||||
PEPY_OBJECT_GET(resource, lang_str)
|
||||
PEPY_OBJECT_GET(resource, type)
|
||||
PEPY_OBJECT_GET(resource, name)
|
||||
PEPY_OBJECT_GET(resource, lang)
|
||||
PEPY_OBJECT_GET(resource, codepage)
|
||||
PEPY_OBJECT_GET(resource, RVA)
|
||||
PEPY_OBJECT_GET(resource, size)
|
||||
PEPY_OBJECT_GET(resource, data)
|
||||
PEPY_OBJECT_GET(resource, type_str);
|
||||
PEPY_OBJECT_GET(resource, name_str);
|
||||
PEPY_OBJECT_GET(resource, lang_str);
|
||||
PEPY_OBJECT_GET(resource, type);
|
||||
PEPY_OBJECT_GET(resource, name);
|
||||
PEPY_OBJECT_GET(resource, lang);
|
||||
PEPY_OBJECT_GET(resource, codepage);
|
||||
PEPY_OBJECT_GET(resource, RVA);
|
||||
PEPY_OBJECT_GET(resource, size);
|
||||
PEPY_OBJECT_GET(resource, data);
|
||||
|
||||
static PyObject *pepy_resource_type_as_str(PyObject *self, PyObject *args) {
|
||||
PyObject *ret;
|
||||
@ -587,7 +570,7 @@ static PyObject *pepy_resource_type_as_str(PyObject *self, PyObject *args) {
|
||||
break;
|
||||
}
|
||||
|
||||
ret = PyString_FromString(str);
|
||||
ret = PyUnicode_FromString(str);
|
||||
if (!ret) {
|
||||
PyErr_SetString(pepy_error, "Unable to create return string.");
|
||||
return NULL;
|
||||
@ -704,7 +687,8 @@ static PyObject *pepy_parsed_get_entry_point(PyObject *self, PyObject *args) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
static PyObject *pepy_parsed_get_machine_as_str(PyObject *self, PyObject *args) {
|
||||
static PyObject *pepy_parsed_get_machine_as_str(PyObject *self,
|
||||
PyObject *args) {
|
||||
PyObject *ret;
|
||||
const char *str;
|
||||
|
||||
@ -712,7 +696,7 @@ static PyObject *pepy_parsed_get_machine_as_str(PyObject *self, PyObject *args)
|
||||
if (!str)
|
||||
Py_RETURN_NONE;
|
||||
|
||||
ret = PyString_FromString(str);
|
||||
ret = PyUnicode_FromString(str);
|
||||
if (!ret) {
|
||||
PyErr_SetString(pepy_error, "Unable to create return string.");
|
||||
return NULL;
|
||||
@ -721,7 +705,8 @@ static PyObject *pepy_parsed_get_machine_as_str(PyObject *self, PyObject *args)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static PyObject *pepy_parsed_get_subsystem_as_str(PyObject *self, PyObject *args) {
|
||||
static PyObject *pepy_parsed_get_subsystem_as_str(PyObject *self,
|
||||
PyObject *args) {
|
||||
PyObject *ret;
|
||||
const char *str;
|
||||
|
||||
@ -729,7 +714,7 @@ static PyObject *pepy_parsed_get_subsystem_as_str(PyObject *self, PyObject *args
|
||||
if (!str)
|
||||
Py_RETURN_NONE;
|
||||
|
||||
ret = PyString_FromString(str);
|
||||
ret = PyUnicode_FromString(str);
|
||||
if (!ret) {
|
||||
PyErr_SetString(pepy_error, "Unable to create return string.");
|
||||
return NULL;
|
||||
@ -802,10 +787,10 @@ static PyObject *pepy_data_converter(bounded_buffer *data) {
|
||||
}
|
||||
|
||||
int section_callback(void *cbd,
|
||||
VA base,
|
||||
std::string &name,
|
||||
image_section_header s,
|
||||
bounded_buffer *data) {
|
||||
const VA &base,
|
||||
const std::string &name,
|
||||
const image_section_header &s,
|
||||
const bounded_buffer *data) {
|
||||
uint32_t buflen;
|
||||
PyObject *sect;
|
||||
PyObject *tuple;
|
||||
@ -876,7 +861,7 @@ static PyObject *pepy_parsed_get_sections(PyObject *self, PyObject *args) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
int resource_callback(void *cbd, resource r) {
|
||||
int resource_callback(void *cbd, const resource &r) {
|
||||
PyObject *rsrc;
|
||||
PyObject *tuple;
|
||||
PyObject *list = (PyObject *) cbd;
|
||||
@ -885,15 +870,6 @@ int resource_callback(void *cbd, resource r) {
|
||||
* The tuple item order is important here. It is passed into the
|
||||
* section type initialization and parsed there.
|
||||
*/
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
tuple = Py_BuildValue("u#u#u#IIIIIIO&",
|
||||
r.type_str.c_str(),
|
||||
r.type_str.length() / 2,
|
||||
r.name_str.c_str(),
|
||||
r.name_str.length() / 2,
|
||||
r.lang_str.c_str(),
|
||||
r.lang_str.length() / 2,
|
||||
#else
|
||||
tuple = Py_BuildValue("s#s#s#IIIIIIO&",
|
||||
r.type_str.c_str(),
|
||||
r.type_str.length(),
|
||||
@ -901,7 +877,6 @@ int resource_callback(void *cbd, resource r) {
|
||||
r.name_str.length(),
|
||||
r.lang_str.c_str(),
|
||||
r.lang_str.length(),
|
||||
#endif
|
||||
r.type,
|
||||
r.name,
|
||||
r.lang,
|
||||
@ -946,7 +921,7 @@ static PyObject *pepy_parsed_get_resources(PyObject *self, PyObject *args) {
|
||||
}
|
||||
|
||||
int import_callback(void *cbd,
|
||||
VA addr,
|
||||
const VA &addr,
|
||||
const std::string &name,
|
||||
const std::string &sym) {
|
||||
PyObject *imp;
|
||||
@ -993,7 +968,10 @@ static PyObject *pepy_parsed_get_imports(PyObject *self, PyObject *args) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
int export_callback(void *cbd, VA addr, std::string &mod, std::string &func) {
|
||||
int export_callback(void *cbd,
|
||||
const VA &addr,
|
||||
const std::string &mod,
|
||||
const std::string &func) {
|
||||
PyObject *exp;
|
||||
PyObject *tuple;
|
||||
PyObject *list = (PyObject *) cbd;
|
||||
@ -1042,7 +1020,7 @@ static PyObject *pepy_parsed_get_exports(PyObject *self, PyObject *args) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
int reloc_callback(void *cbd, VA addr, reloc_type type) {
|
||||
int reloc_callback(void *cbd, const VA &addr, const reloc_type &type) {
|
||||
PyObject *reloc;
|
||||
PyObject *tuple;
|
||||
PyObject *list = (PyObject *) cbd;
|
||||
@ -1089,21 +1067,20 @@ static PyObject *pepy_parsed_get_relocations(PyObject *self, PyObject *args) {
|
||||
|
||||
#define PEPY_PARSED_GET(ATTR, VAL) \
|
||||
static PyObject *pepy_parsed_get_##ATTR(PyObject *self, void *closure) { \
|
||||
PyObject *ret = \
|
||||
PyLong_FromUnsignedLongLong( \
|
||||
((pepy_parsed *) self)->pe->peHeader.nt.VAL); \
|
||||
PyObject *ret = PyLong_FromUnsignedLongLong( \
|
||||
((pepy_parsed *) self)->pe->peHeader.nt.VAL); \
|
||||
if (!ret) \
|
||||
PyErr_SetString(PyExc_AttributeError, "Error getting attribute."); \
|
||||
return ret; \
|
||||
}
|
||||
|
||||
PEPY_PARSED_GET(signature, Signature)
|
||||
PEPY_PARSED_GET(machine, FileHeader.Machine)
|
||||
PEPY_PARSED_GET(numberofsections, FileHeader.NumberOfSections)
|
||||
PEPY_PARSED_GET(timedatestamp, FileHeader.TimeDateStamp)
|
||||
PEPY_PARSED_GET(numberofsymbols, FileHeader.NumberOfSymbols)
|
||||
PEPY_PARSED_GET(characteristics, FileHeader.Characteristics)
|
||||
PEPY_PARSED_GET(magic, OptionalMagic)
|
||||
PEPY_PARSED_GET(signature, Signature);
|
||||
PEPY_PARSED_GET(machine, FileHeader.Machine);
|
||||
PEPY_PARSED_GET(numberofsections, FileHeader.NumberOfSections);
|
||||
PEPY_PARSED_GET(timedatestamp, FileHeader.TimeDateStamp);
|
||||
PEPY_PARSED_GET(numberofsymbols, FileHeader.NumberOfSymbols);
|
||||
PEPY_PARSED_GET(characteristics, FileHeader.Characteristics);
|
||||
PEPY_PARSED_GET(magic, OptionalMagic);
|
||||
|
||||
/*
|
||||
* This is used to get things from the optional header, which can be either
|
||||
@ -1134,8 +1111,8 @@ PEPY_PARSED_GET(magic, OptionalMagic)
|
||||
return ret; \
|
||||
}
|
||||
|
||||
PEPY_PARSED_GET_OPTIONAL(majorlinkerver, MajorLinkerVersion)
|
||||
PEPY_PARSED_GET_OPTIONAL(minorlinkerver, MinorLinkerVersion)
|
||||
PEPY_PARSED_GET_OPTIONAL(majorlinkerver, MajorLinkerVersion);
|
||||
PEPY_PARSED_GET_OPTIONAL(minorlinkerver, MinorLinkerVersion);
|
||||
PEPY_PARSED_GET_OPTIONAL(codesize, SizeOfCode);
|
||||
PEPY_PARSED_GET_OPTIONAL(initdatasize, SizeOfInitializedData);
|
||||
PEPY_PARSED_GET_OPTIONAL(uninitdatasize, SizeOfUninitializedData);
|
||||
@ -1337,7 +1314,7 @@ static PyObject *pepy_parse(PyObject *self, PyObject *args) {
|
||||
static PyMethodDef pepy_methods[] = {
|
||||
{"parse", pepy_parse, METH_VARARGS, "Parse PE from file."}, {NULL}};
|
||||
|
||||
static PyObject *pepi_module_init(void) {
|
||||
PyMODINIT_FUNC PyInit_pepy(void) {
|
||||
PyObject *m;
|
||||
|
||||
if (PyType_Ready(&pepy_parsed_type) < 0 ||
|
||||
@ -1348,7 +1325,6 @@ static PyObject *pepi_module_init(void) {
|
||||
PyType_Ready(&pepy_resource_type) < 0)
|
||||
return NULL;
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
static struct PyModuleDef moduledef = {
|
||||
PyModuleDef_HEAD_INIT,
|
||||
"pepy",
|
||||
@ -1360,13 +1336,8 @@ static PyObject *pepi_module_init(void) {
|
||||
NULL,
|
||||
NULL,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
m = PyModule_Create(&moduledef);
|
||||
#else
|
||||
m = Py_InitModule3("pepy", pepy_methods, "Python interface to pe-parse.");
|
||||
#endif
|
||||
if (!m)
|
||||
return NULL;
|
||||
|
||||
@ -1393,6 +1364,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);
|
||||
@ -1456,13 +1429,3 @@ static PyObject *pepi_module_init(void) {
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
PyMODINIT_FUNC PyInit_pepy(void) {
|
||||
return pepi_module_init();
|
||||
}
|
||||
#else
|
||||
PyMODINIT_FUNC initpepy(void) {
|
||||
pepi_module_init();
|
||||
}
|
||||
#endif
|
217
python/README.md
217
python/README.md
@ -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)
|
@ -1,68 +0,0 @@
|
||||
# Copyright (c) 2013, Wesley Shields <wxs@atarininja.org>. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
#
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
# SUCH DAMAGE.
|
||||
|
||||
from distutils.core import setup, Extension
|
||||
import os
|
||||
import sys
|
||||
import platform
|
||||
|
||||
here = os.path.abspath(os.path.dirname(__file__))
|
||||
|
||||
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'))]
|
||||
|
||||
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')),
|
||||
'C:\\usr\\include']
|
||||
LIBRARY_DIRS = [os.path.abspath(os.path.join(os.path.dirname(sys.executable), 'libs')),
|
||||
'C:\\usr\\lib']
|
||||
COMPILE_ARGS = ["/EHsc"]
|
||||
else:
|
||||
INCLUDE_DIRS = ['/usr/local/include',
|
||||
'/opt/local/include',
|
||||
'/usr/include',
|
||||
os.path.abspath(os.path.join(here, '..', 'pe-parser-library', 'include'))]
|
||||
LIBRARY_DIRS = ['/usr/lib',
|
||||
'/usr/local/lib']
|
||||
COMPILE_ARGS = ["-std=c++11", "-g", "-O0"] # Debug only
|
||||
|
||||
extension_mod = Extension('pepy',
|
||||
sources = SOURCE_FILES,
|
||||
extra_compile_args = COMPILE_ARGS,
|
||||
language='c++',
|
||||
include_dirs = INCLUDE_DIRS,
|
||||
library_dirs = LIBRARY_DIRS)
|
||||
|
||||
|
||||
setup (name = 'pepy',
|
||||
version = '0.1',
|
||||
description = 'python bindings for pe-parse',
|
||||
author = 'Wesley Shields',
|
||||
author_email = 'wxs@atarininja.org',
|
||||
license = 'BSD',
|
||||
long_description = 'Python bindings for pe-parse',
|
||||
ext_modules = [extension_mod])
|
@ -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)
|
101
setup.py
Normal file
101
setup.py
Normal file
@ -0,0 +1,101 @@
|
||||
# Copyright (c) 2013, Wesley Shields <wxs@atarininja.org>. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
#
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
# SUCH DAMAGE.
|
||||
|
||||
from setuptools import setup, Extension
|
||||
import os
|
||||
import sys
|
||||
import platform
|
||||
|
||||
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(pepy, "pepy.cpp"),
|
||||
os.path.join(here, "pe-parser-library", "src", "parse.cpp"),
|
||||
os.path.join(here, "pe-parser-library", "src", "buffer.cpp"),
|
||||
]
|
||||
|
||||
INCLUDE_DIRS = []
|
||||
LIBRARY_DIRS = []
|
||||
|
||||
if platform.system() == "Windows":
|
||||
SOURCE_FILES.append(
|
||||
os.path.join(here, "pe-parser-library", "src", "unicode_winapi.cpp")
|
||||
)
|
||||
INCLUDE_DIRS += [
|
||||
os.path.abspath(os.path.join(os.path.dirname(sys.executable), "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",
|
||||
f'/D"PEPARSE_VERSION=\\"{VERSION}\\""',
|
||||
]
|
||||
else:
|
||||
SOURCE_FILES.append(
|
||||
os.path.join(here, "pe-parser-library", "src", "unicode_codecvt.cpp")
|
||||
)
|
||||
INCLUDE_DIRS += [
|
||||
"/usr/local/include",
|
||||
"/opt/local/include",
|
||||
"/usr/include",
|
||||
os.path.join(here, "pe-parser-library", "include"),
|
||||
]
|
||||
LIBRARY_DIRS += ["/usr/lib", "/usr/local/lib"]
|
||||
COMPILE_ARGS = ["-std=c++11", f'-DPEPARSE_VERSION="{VERSION}"']
|
||||
|
||||
extension_mod = Extension(
|
||||
"pepy",
|
||||
sources=SOURCE_FILES,
|
||||
extra_compile_args=COMPILE_ARGS,
|
||||
language="c++",
|
||||
include_dirs=INCLUDE_DIRS,
|
||||
library_dirs=LIBRARY_DIRS,
|
||||
)
|
||||
|
||||
setup(
|
||||
name="pepy",
|
||||
url="https://github.com/trailofbits/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",
|
||||
ext_modules=[extension_mod],
|
||||
)
|
BIN
test/assets/example.exe
Normal file
BIN
test/assets/example.exe
Normal file
Binary file not shown.
210
travis.sh
210
travis.sh
@ -1,210 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
main() {
|
||||
if [ $# -ne 2 ] ; then
|
||||
printf "Usage:\n\ttravis.sh <linux|osx> <initialize|build>\n"
|
||||
return 1
|
||||
fi
|
||||
|
||||
local platform_name="$1"
|
||||
local operation_type="$2"
|
||||
|
||||
if [[ "${platform_name}" != "osx" && "${platform_name}" != "linux" ]] ; then
|
||||
printf "Invalid platform: ${platform_name}\n"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [[ "${operation_type}" == "initialize" ]] ; then
|
||||
"${platform_name}_initialize"
|
||||
return $?
|
||||
|
||||
elif [[ "$operation_type" == "build" ]] ; then
|
||||
"${platform_name}_build"
|
||||
return $?
|
||||
|
||||
else
|
||||
printf "Invalid operation\n"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
get_processor_count() {
|
||||
which nproc > /dev/null
|
||||
if [ $? -eq 0 ] ; then
|
||||
nproc
|
||||
return 0
|
||||
fi
|
||||
|
||||
which sysctl > /dev/null
|
||||
if [ $? -eq 0 ] ; then
|
||||
sysctl -n hw.ncpu
|
||||
return 0
|
||||
fi
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
linux_initialize() {
|
||||
printf "Initializing platform: linux\n"
|
||||
local log_file=`mktemp`
|
||||
|
||||
printf " > Updating the package database..\n"
|
||||
sudo apt-get -qq update > "${log_file}" 2>&1
|
||||
if [ $? -ne 0 ] ; then
|
||||
printf " x The package database could not be updated\n\n\n"
|
||||
cat "${log_file}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
printf " > Installing the required packages...\n"
|
||||
sudo apt-get install -qqy cmake python2.7 python-dev build-essential realpath > "${log_file}" 2>&1
|
||||
if [ $? -ne 0 ] ; then
|
||||
printf " x Could not install the required dependencies\n\n\n"
|
||||
cat "${log_file}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
printf " > The system has been successfully initialized\n"
|
||||
return 0
|
||||
}
|
||||
|
||||
osx_initialize() {
|
||||
printf "Initializing platform: macOS\n"
|
||||
local log_file=`mktemp`
|
||||
|
||||
printf " > Updating the package database..\n"
|
||||
brew update > "${log_file}" 2>&1
|
||||
if [ $? -ne 0 ] ; then
|
||||
printf " x The package database could not be updated\n\n\n"
|
||||
cat "${log_file}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
printf " > Installing CMake...\n"
|
||||
brew install cmake > "${log_file}" 2>&1
|
||||
if [ $? -ne 0 ] ; then
|
||||
printf " x Failed to install CMake\n\n\n"
|
||||
cat "${log_file}"
|
||||
fi
|
||||
|
||||
printf " > The system has been successfully initialized\n"
|
||||
return 0
|
||||
}
|
||||
|
||||
common_build() {
|
||||
printf "Gathering system information...\n"
|
||||
|
||||
which cmake > /dev/null
|
||||
printf " > CMake version: "
|
||||
if [ $? -eq 0 ] ; then
|
||||
cmake --version | head -n 1
|
||||
else
|
||||
printf "not found\n"
|
||||
fi
|
||||
|
||||
which gcc > /dev/null
|
||||
printf " > GCC version: "
|
||||
if [ $? -eq 0 ] ; then
|
||||
gcc --version | head -n 1
|
||||
else
|
||||
printf "not found\n"
|
||||
fi
|
||||
|
||||
which clang > /dev/null
|
||||
printf " > Clang version: "
|
||||
if [ $? -eq 0 ] ; then
|
||||
clang --version | head -n 1
|
||||
else
|
||||
printf "not found\n"
|
||||
fi
|
||||
|
||||
printf "\n"
|
||||
|
||||
printf "Library\n"
|
||||
if [ ! -d "build" ] ; then
|
||||
printf " > Creating the build directory...\n"
|
||||
mkdir "build"
|
||||
if [ $? -ne 0 ] ; then
|
||||
printf " x Failed to create the build directory\n"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
local log_file=`mktemp`
|
||||
local processor_count=`get_processor_count`
|
||||
|
||||
printf " > Configuring...\n"
|
||||
( cd "build" && cmake .. ) > "$log_file" 2>&1
|
||||
if [ $? -ne 0 ] ; then
|
||||
printf " x Configure failed; CMake returned an error.\n\n\n"
|
||||
cat "$log_file"
|
||||
return 1
|
||||
fi
|
||||
|
||||
printf " > Building...\n"
|
||||
( cd "build" && make -j "${processor_count}" ) > "$log_file" 2>&1
|
||||
if [ $? -ne 0 ] ; then
|
||||
printf " x The build has failed.\n\n\n"
|
||||
cat "$log_file"
|
||||
return 1
|
||||
fi
|
||||
|
||||
printf " > Installing...\n"
|
||||
sudo touch /usr/lib/test_file > /dev/null 2>&1
|
||||
if [ $? -ne 0 ] ; then
|
||||
printf " x Access denied to /usr/lib; the 'install' step will be skipped\n"
|
||||
|
||||
else
|
||||
( cd "build" && sudo make install ) > "$log_file" 2>&1
|
||||
if [ $? -ne 0 ] ; then
|
||||
printf " x Failed to install the library.\n\n\n"
|
||||
cat "$log_file"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
printf "\n"
|
||||
|
||||
printf "pepy\n"
|
||||
|
||||
printf " > Building...\n"
|
||||
( cd python && python2 ./setup.py build ) > "$log_file" 2>&1
|
||||
if [ $? -ne 0 ] ; then
|
||||
printf " x Build failed.\n\n\n"
|
||||
cat "$log_file"
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
linux_build() {
|
||||
printf "Building platform: linux\n"
|
||||
|
||||
source /etc/*-release
|
||||
printf "Distribution: ${DISTRIB_DESCRIPTION}\n\n"
|
||||
|
||||
common_build
|
||||
if [ $? -ne 0 ] ; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
osx_build() {
|
||||
printf "Building platform: macOS\n\n"
|
||||
|
||||
printf "macOS version: "
|
||||
sw_vers -productVersion
|
||||
|
||||
common_build
|
||||
if [ $? -ne 0 ] ; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
main $@
|
||||
exit $?
|
35
util/release
Executable file
35
util/release
Executable file
@ -0,0 +1,35 @@
|
||||
#!/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.
|
||||
installed git || die "Missing dependency: git"
|
||||
|
||||
# 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=v$(<./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}"
|
||||
|
||||
echo OK
|
Loading…
x
Reference in New Issue
Block a user