Directory entry retrieval (#90)

* pe-parser-library: Directory entry extraction

Also runs clang-format on all library files.

* dump-pe: Refactor, clang-format

* pe-parser-library: Use enum for directory kinds

* travis: Refactor

* travis: Fixup stages

* travis: Fix matrix

* examples, pe-parser-library, pepy: clang-format

* travis: Use minimal for lint

* travis: Use find

* clang-format: Remove old option

* travis: More experimentation

* travis: Move addons

* travis: Remove coverity

* travis: Hackery

* travis: Move addons up

* .travis: clang-format-8

* examples: clang-format

* travis: Fix homebrew

* CONTRIBUTING: Add contrib guidelines

* travis: Build python ext, reenable coverity

Remove old build files.

* travis: Re-add coverity secret

* travis: Build with coverity in a separate dir
This commit is contained in:
William Woodruff 2019-10-21 09:00:54 -04:00 committed by GitHub
parent 1544c61c38
commit 2c775e5d6a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 441 additions and 456 deletions

View File

@ -2,7 +2,6 @@ AlignEscapedNewlinesLeft: true
AllowShortFunctionsOnASingleLine: false
BinPackArguments: false
BinPackParameters: false
BreakBeforeBraces: Attach
ColumnLimit: 80
IndentCaseLabels: true
IndentWidth: 2

View File

@ -1,32 +1,56 @@
language: cpp
__build_stage_script: &__build_stage_script
stage: build
language: cpp
script:
- mkdir build && cd build
- cmake ..
- make
- cd ../python
- python2 setup.py build
- python3 setup.py build
addons:
apt:
packages:
- cmake
- python2.7
- python-dev
- build-essential
- realpath
- libicu-dev
homebrew:
packages:
- cmake
coverity_scan:
project:
name: "trailofbits/pe-parse"
description: "Principled, lightweight C/C++ PE parser"
notification_email: dan@trailofbits.com
build_command_prepend: mkdir cov_build && cd cov_build && cmake ..
build_command: make
branch_pattern: master
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
jobs:
include:
- stage: lint
language: minimal
dist: bionic
addons:
apt:
packages:
- clang-format-8
script:
- find . \( -name '*.h' \) -or \( -name '*.cpp' \) | xargs clang-format -i -style=file
- git diff --exit-code
- <<: *__build_stage_script
os: linux
compiler: clang
- <<: *__build_stage_script
os: linux
compiler: gcc
- <<: *__build_stage_script
os: osx
compiler: clang
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

26
CONTRIBUTING.md Normal file
View 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)

View File

@ -22,10 +22,10 @@ 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>
@ -232,8 +232,8 @@ int printRich(void *N, rich_entry r) {
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(20) << GetRichProductName(r.ProductId, r.BuildNumber);
std::cout << std::setw(10) << "Name:" << std::setw(20)
<< GetRichProductName(r.ProductId, r.BuildNumber);
std::cout << std::setw(10) << "Count:" << std::setw(7) << r.Count << "\n";
return 0;
}
@ -275,18 +275,17 @@ 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.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";
int main(int argc, char *argv[]) {
if (argc != 2 || (argc == 2 && std::strcmp(argv[1], "--help") == 0)) {
@ -297,119 +296,127 @@ int main(int argc, char *argv[]) {
}
parsed_pe *p = ParsePEFromFile(argv[1]);
if (p == nullptr) {
std::cout << "Error: " << GetPEErr() << " (" << GetPEErrString() << ")"
<< "\n";
std::cout << "Location: " << GetPEErrLoc() << "\n";
return 1;
}
if (p != NULL) {
// Print Rich header info
if(p->peHeader.rich.isPresent) {
std::cout << "Rich header: present\n";
IterRich(p, printRich, NULL);
} else {
std::cout << "Rich header: not present\n";
}
// 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);
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);
} 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);
}
// Print Rich header info
if (p->peHeader.rich.isPresent) {
std::cout << "Rich header: present\n";
IterRich(p, printRich, NULL);
} else {
std::cout << "Rich header: not present\n";
}
// 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);
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);
} 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);
}
#undef DUMP_FIELD
#undef DUMP_DEC_FIELD
std::cout << "Imports: " << "\n";
IterImpVAString(p, printImports, NULL);
std::cout << "Relocations: " << "\n";
IterRelocs(p, printRelocs, NULL);
std::cout << "Symbols (symbol table): " << "\n";
IterSymbols(p, printSymbols, NULL);
std::cout << "Sections: " << "\n";
IterSec(p, printSecs, NULL);
std::cout << "Exports: " << "\n";
IterExpVA(p, printExps, NULL);
std::cout << "Imports: "
<< "\n";
IterImpVAString(p, printImports, NULL);
std::cout << "Relocations: "
<< "\n";
IterRelocs(p, printRelocs, NULL);
std::cout << "Symbols (symbol table): "
<< "\n";
IterSymbols(p, printSymbols, NULL);
std::cout << "Sections: "
<< "\n";
IterSec(p, printSecs, NULL);
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";
// 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";
for (std::size_t i = 0; i < 8; i++) {
std::uint8_t b;
if (!ReadByteAtVA(p, i + entryPoint, b)) {
std::cout << " ERR";
} else {
std::cout << " 0x" << std::hex << static_cast<int>(b);
}
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)) {
std::cout << " ERR";
} else {
std::cout << " 0x" << std::hex << static_cast<int>(b);
}
std::cout << "\n";
}
std::cout << "Resources: " << "\n";
IterRsrc(p, printRsrc, NULL);
DestructParsedPE(p);
} else {
std::cout << "Error: " << GetPEErr() << " (" << GetPEErrString() << ")"
<< "\n";
std::cout << "Location: " << GetPEErrLoc() << "\n";
std::cout << "\n";
}
std::cout << "Resources: "
<< "\n";
IterRsrc(p, printRsrc, NULL);
DestructParsedPE(p);
return 0;
}

View File

@ -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)

View File

@ -1,7 +1,7 @@
#include <algorithm>
#include <iostream>
#include <limits>
#include <memory>
#include <algorithm>
#include <climits>
#include <cstring>
@ -262,7 +262,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;

View File

@ -1,8 +0,0 @@
project('pe-parse',
'cpp',
default_options : [ 'cpp_std=c++11' ],
license : [ 'MIT' ],
)
subdir('parser-library')
subdir('dump-prog')

View File

@ -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')

View File

@ -47,21 +47,6 @@ 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;
// Machine Types
constexpr std::uint16_t IMAGE_FILE_MACHINE_UNKNOWN = 0x0;
@ -263,6 +248,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;
@ -451,4 +455,101 @@ 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

View File

@ -32,7 +32,7 @@ THE SOFTWARE.
#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) \
@ -137,6 +137,7 @@ 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);
@ -167,7 +168,8 @@ typedef struct _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& GetRichProductName(std::uint16_t prodId, std::uint16_t buildNum);
const std::string &GetRichProductName(std::uint16_t prodId,
std::uint16_t buildNum);
// get parser error status as integer
std::uint32_t GetPEErr();
@ -230,4 +232,7 @@ 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
const void *GetDataDirectoryEntry(parsed_pe *pe, data_directory_kind dirnum);
} // namespace peparse

View File

@ -1,7 +1,7 @@
#pragma once
#include <string>
#include <sstream>
#include <string>
#ifdef USE_ICU4C
#include <unicode/unistr.h>

View File

@ -23,10 +23,11 @@ THE SOFTWARE.
*/
#include <algorithm>
#include <array>
#include <cstring>
#include <iostream>
#include <vector>
#include <stdexcept>
#include <vector>
#include <parser-library/nt-headers.h>
#include <parser-library/parse.h>
@ -125,14 +126,14 @@ struct parsed_pe_internal {
// The mapping of Rich header product id / build number pairs
// to strings
static const std::map<ProductKey, const std::string> ProductMap = {
{std::make_pair(1, 0), "Imported Functions"}
};
{std::make_pair(1, 0), "Imported Functions"}};
static const std::string kUnknownProduct = "<unknown>";
// Resolve a Rich header product id / build number pair to a known
// product name
const std::string& GetRichProductName(std::uint16_t prodId, std::uint16_t buildNum) {
const std::string &GetRichProductName(std::uint16_t prodId,
std::uint16_t buildNum) {
auto it = ProductMap.find(std::make_pair(prodId, buildNum));
if (it != ProductMap.end()) {
return it->second;
@ -144,18 +145,21 @@ const std::string& GetRichProductName(std::uint16_t prodId, std::uint16_t buildN
std::uint32_t err = 0;
std::string err_loc;
static const char *pe_err_str[] = {"None",
"Out of memory",
"Invalid header",
"Invalid section",
"Invalid resource",
"Unable to get section for VA",
"Unable to read data",
"Unable to open",
"Unable to stat",
"Bad magic",
"Invalid buffer",
"Invalid address",};
static const char *pe_err_str[] = {
"None",
"Out of memory",
"Invalid header",
"Invalid section",
"Invalid resource",
"Unable to get section for VA",
"Unable to read data",
"Unable to open",
"Unable to stat",
"Bad magic",
"Invalid buffer",
"Invalid address",
"Invalid size",
};
std::uint32_t GetPEErr() {
return err;
@ -230,8 +234,9 @@ const char *GetSymbolTableStorageClassName(std::uint8_t id) {
}
}
static bool
readCString(const bounded_buffer &buffer, std::uint32_t off, std::string &result) {
static bool readCString(const bounded_buffer &buffer,
std::uint32_t off,
std::string &result) {
if (off < buffer.bufLen) {
std::uint8_t *p = buffer.buf;
std::uint32_t n = buffer.bufLen;
@ -282,7 +287,9 @@ void IterRsrc(parsed_pe *pe, iterRsrc cb, void *cbd) {
return;
}
bool parse_resource_id(bounded_buffer *data, std::uint32_t id, std::string &result) {
bool parse_resource_id(bounded_buffer *data,
std::uint32_t id,
std::string &result) {
std::uint16_t len;
if (!readWord(data, id, len)) {
return false;
@ -388,9 +395,10 @@ bool parse_resource_table(bounded_buffer *sectionData,
}
}
} else {
/* .rsrc can accomodate up to 2**31 levels, but Windows only uses 3 by convention.
* As such, any depth above 3 indicates potentially unchecked recusion.
* See: https://docs.microsoft.com/en-us/windows/desktop/debug/pe-format#the-rsrc-section
/* .rsrc can accomodate up to 2**31 levels, but Windows only uses 3 by
* convention. As such, any depth above 3 indicates potentially unchecked
* recusion. See:
* https://docs.microsoft.com/en-us/windows/desktop/debug/pe-format#the-rsrc-section
*/
PE_ERR(PEERR_RESC);
@ -575,7 +583,8 @@ bool getSections(bounded_buffer *b,
// now we have the section header information, so fill in a section
// object appropriately
section thisSec;
for (std::uint32_t charIndex = 0; charIndex < NT_SHORT_NAME_LEN; charIndex++) {
for (std::uint32_t charIndex = 0; charIndex < NT_SHORT_NAME_LEN;
charIndex++) {
std::uint8_t c = curSec.Name[charIndex];
if (c == 0) {
break;
@ -825,7 +834,9 @@ bool readNtHeader(bounded_buffer *b, nt_header_32 &header) {
return true;
}
bool readRichHeader(bounded_buffer *rich_buf, std::uint32_t key, rich_header &rich_hdr) {
bool readRichHeader(bounded_buffer *rich_buf,
std::uint32_t key,
rich_header &rich_hdr) {
if (rich_buf == nullptr) {
return false;
}
@ -837,8 +848,8 @@ bool readRichHeader(bounded_buffer *rich_buf, std::uint32_t key, rich_header &ri
// The first decrypted DWORD value of the rich header
// at offset 0 should be 0x536e6144 aka the "DanS" signature
if (!readDword(rich_buf, 0, encrypted_dword)) {
PE_ERR(PEERR_READ);
return false;
PE_ERR(PEERR_READ);
return false;
}
decrypted_dword = encrypted_dword ^ key;
@ -859,7 +870,7 @@ bool readRichHeader(bounded_buffer *rich_buf, std::uint32_t key, rich_header &ri
// a DWORD is 4 bytes. Loop is incrementing 8 bytes, however
// we are reading two DWORDS at a time, which is the size
// of one rich header entry.
for (std::uint32_t i = 16; i < rich_buf->bufLen-8; i += 8) {
for (std::uint32_t i = 16; i < rich_buf->bufLen - 8; i += 8) {
rich_entry entry;
// Read first DWORD of entry and decrypt it
if (!readDword(rich_buf, i, encrypted_dword)) {
@ -873,7 +884,7 @@ bool readRichHeader(bounded_buffer *rich_buf, std::uint32_t key, rich_header &ri
entry.BuildNumber = (decrypted_dword & 0xFFFF);
// The second DWORD represents the use count
if (!readDword(rich_buf, i+4, encrypted_dword)) {
if (!readDword(rich_buf, i + 4, encrypted_dword)) {
PE_ERR(PEERR_READ);
return false;
}
@ -883,13 +894,12 @@ bool readRichHeader(bounded_buffer *rich_buf, std::uint32_t key, rich_header &ri
// Preserve the individual entry
rich_hdr.Entries.push_back(entry);
}
// Preserve the end signature aka "Rich" magic
if (!readDword(rich_buf, rich_buf->bufLen-4, rich_hdr.EndSignature)) {
PE_ERR(PEERR_READ);
return false;
if (!readDword(rich_buf, rich_buf->bufLen - 4, rich_hdr.EndSignature)) {
PE_ERR(PEERR_READ);
return false;
};
if (rich_hdr.EndSignature != RICH_MAGIC_END) {
PE_ERR(PEERR_MAGIC);
@ -897,7 +907,7 @@ bool readRichHeader(bounded_buffer *rich_buf, std::uint32_t key, rich_header &ri
}
// Preserve the decryption key
rich_hdr.DecryptionKey = key;
rich_hdr.DecryptionKey = key;
return true;
}
@ -960,7 +970,8 @@ bool getHeader(bounded_buffer *file, pe_header &p, bounded_buffer *&rem) {
}
// Split the Rich header out into its own buffer
bounded_buffer *richBuf = splitBuffer(file, 0x80, rich_end_signature_offset + 4);
bounded_buffer *richBuf =
splitBuffer(file, 0x80, rich_end_signature_offset + 4);
if (richBuf == nullptr) {
return false;
}
@ -992,12 +1003,12 @@ bool getHeader(bounded_buffer *file, pe_header &p, bounded_buffer *&rem) {
std::uint32_t rem_size;
if (p.nt.OptionalMagic == NT_OPTIONAL_32_MAGIC) {
// signature + file_header + optional_header_32
rem_size =
sizeof(std::uint32_t) + sizeof(file_header) + sizeof(optional_header_32);
rem_size = sizeof(std::uint32_t) + sizeof(file_header) +
sizeof(optional_header_32);
} else if (p.nt.OptionalMagic == NT_OPTIONAL_64_MAGIC) {
// signature + file_header + optional_header_64
rem_size =
sizeof(std::uint32_t) + sizeof(file_header) + sizeof(optional_header_64);
rem_size = sizeof(std::uint32_t) + sizeof(file_header) +
sizeof(optional_header_64);
} else {
PE_ERR(PEERR_MAGIC);
deleteBuffer(ntBuf);
@ -1529,8 +1540,8 @@ bool getImports(parsed_pe *p) {
ent.moduleName = modName;
p->internal->imports.push_back(ent);
} else {
std::string symName =
"ORDINAL_" + modName + "_" + to_string<std::uint32_t>(oval, std::dec);
std::string symName = "ORDINAL_" + modName + "_" +
to_string<std::uint32_t>(oval, std::dec);
importent ent;
@ -1579,7 +1590,8 @@ bool getSymbolTable(parsed_pe *p) {
std::uint32_t offset = p->peHeader.nt.FileHeader.PointerToSymbolTable;
for (std::uint32_t i = 0; i < p->peHeader.nt.FileHeader.NumberOfSymbols; i++) {
for (std::uint32_t i = 0; i < p->peHeader.nt.FileHeader.NumberOfSymbols;
i++) {
symbol sym;
// Read name
@ -1607,7 +1619,8 @@ bool getSymbolTable(parsed_pe *p) {
strOffset += sizeof(std::uint8_t);
}
} else {
for (std::uint8_t n = 0; n < NT_SHORT_NAME_LEN && sym.name.shortName[n] != 0;
for (std::uint8_t n = 0;
n < NT_SHORT_NAME_LEN && sym.name.shortName[n] != 0;
n++) {
sym.strName.push_back(static_cast<char>(sym.name.shortName[n]));
}
@ -2192,4 +2205,48 @@ const char *GetSubsystemAsString(parsed_pe *pe) {
}
}
const void *GetDataDirectoryEntry(parsed_pe *pe, data_directory_kind dirnum) {
if (pe == nullptr) {
PE_ERR(PEERR_NONE);
return nullptr;
}
data_directory dir;
VA addr;
if (pe->peHeader.nt.OptionalMagic == NT_OPTIONAL_32_MAGIC) {
dir = pe->peHeader.nt.OptionalHeader.DataDirectory[dirnum];
addr = dir.VirtualAddress + pe->peHeader.nt.OptionalHeader.ImageBase;
} else if (pe->peHeader.nt.OptionalMagic == NT_OPTIONAL_64_MAGIC) {
dir = pe->peHeader.nt.OptionalHeader64.DataDirectory[dirnum];
addr = dir.VirtualAddress + pe->peHeader.nt.OptionalHeader64.ImageBase;
} else {
PE_ERR(PEERR_MAGIC);
return nullptr;
}
if (dir.Size <= 0) {
PE_ERR(PEERR_SIZE);
return nullptr;
}
section sec;
if (!getSecForVA(pe->internal->secs, addr, sec)) {
PE_ERR(PEERR_SECTVA);
return nullptr;
}
auto off = static_cast<std::uint32_t>(addr - sec.sectionBase);
if (off + dir.Size >= sec.sectionData->bufLen) {
PE_ERR(PEERR_SIZE);
return nullptr;
}
std::cerr << "off: 0x" << std::hex << off << std::endl;
std::vector<uint8_t> rawEntry(sec.sectionData->buf + off,
sec.sectionData->buf + off + dir.Size);
return rawEntry.data();
}
} // namespace peparse

View File

@ -22,17 +22,18 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include <parser-library/to_string.h>
#include <locale>
#include <codecvt>
#include <locale>
#include <parser-library/to_string.h>
namespace peparse {
// See https://stackoverflow.com/questions/38688417/utf-conversion-functions-in-c11
std::string from_utf16(const UCharString &u)
{
// See
// https://stackoverflow.com/questions/38688417/utf-conversion-functions-in-c11
std::string from_utf16(const UCharString &u) {
#if defined(_MSC_VER)
// std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>convert; // Doesn't compile with Visual Studio.
// See https://stackoverflow.com/questions/32055357/visual-studio-c-2015-stdcodecvt-with-char16-t-or-char32-t
// std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>convert;
// // Doesn't compile with Visual Studio. See
// https://stackoverflow.com/questions/32055357/visual-studio-c-2015-stdcodecvt-with-char16-t-or-char32-t
std::wstring_convert<std::codecvt_utf8<std::int16_t>, std::int16_t> convert;
auto p = reinterpret_cast<const std::int16_t *>(u.data());
return convert.to_bytes(p, p + u.size());

View File

@ -26,8 +26,7 @@ THE SOFTWARE.
#include <unicode/unistr.h>
namespace peparse {
std::string from_utf16(const UCharString &u)
{
std::string from_utf16(const UCharString &u) {
icu::UnicodeString utf16_string = icu::UnicodeString(u.data(), u.length());
std::string result;
utf16_string.toUTF8String(result);

View File

@ -704,7 +704,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;
@ -721,7 +722,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;
@ -1079,9 +1081,8 @@ 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; \

210
travis.sh
View File

@ -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 libicu-dev > "${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 $?