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 AllowShortFunctionsOnASingleLine: false
BinPackArguments: false BinPackArguments: false
BinPackParameters: false BinPackParameters: false
BreakBeforeBraces: Attach
ColumnLimit: 80 ColumnLimit: 80
IndentCaseLabels: true IndentCaseLabels: true
IndentWidth: 2 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: jobs:
- linux include:
- osx - stage: lint
language: minimal
compiler: dist: bionic
- clang addons:
- gcc apt:
packages:
before_install: - clang-format-8
- ./travis.sh "$TRAVIS_OS_NAME" initialize script:
script: - find . \( -name '*.h' \) -or \( -name '*.cpp' \) | xargs clang-format -i -style=file
- ./travis.sh "$TRAVIS_OS_NAME" build - git diff --exit-code
- <<: *__build_stage_script
matrix: os: linux
exclude: compiler: clang
- compiler: gcc - <<: *__build_stage_script
os: osx os: linux
compiler: gcc
- <<: *__build_stage_script
os: osx
compiler: clang
env: env:
global: global:
- secure: "O+BGqz4ugoVIJbQTh0dJjKRrsSVzkCYSe0WpRzEWK3l8Mw7hqX300g81TxRwTzN2zfUsROMzaeGaXWfGzYakgW59K1WIioaczxtv2MzzUQTbqzJPa+qQoP9bk/b2wJ5jcOL965/rudRju4UiIwuIgzDAMN3nAfIEJgV/2zANLIg=" - 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. THE SOFTWARE.
*/ */
#include <iostream>
#include <iomanip>
#include <sstream>
#include <cstring> #include <cstring>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <parser-library/parse.h> #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) << "ProdId:" << std::setw(7) << r.ProductId;
std::cout << std::setw(10) << "Build:" << std::setw(7) << r.BuildNumber; std::cout << std::setw(10) << "Build:" << std::setw(7) << r.BuildNumber;
std::cout << std::setw(10) << "Name:" std::cout << std::setw(10) << "Name:" << std::setw(20)
<< std::setw(20) << GetRichProductName(r.ProductId, r.BuildNumber); << GetRichProductName(r.ProductId, r.BuildNumber);
std::cout << std::setw(10) << "Count:" << std::setw(7) << r.Count << "\n"; std::cout << std::setw(10) << "Count:" << std::setw(7) << r.Count << "\n";
return 0; return 0;
} }
@ -275,18 +275,17 @@ int printSecs(void *N,
if (data) if (data)
std::cout << "Sec Size: " << std::dec << data->bufLen << "\n"; std::cout << "Sec Size: " << std::dec << data->bufLen << "\n";
else else
std::cout << "Sec Size: 0" << "\n"; std::cout << "Sec Size: 0"
<< "\n";
return 0; return 0;
} }
#define DUMP_FIELD(x) \ #define DUMP_FIELD(x) \
std::cout << "" #x << ": 0x"; \ std::cout << "" #x << ": 0x"; \
std::cout << std::hex << static_cast<std::uint64_t>(p->peHeader.nt.x) \ std::cout << std::hex << static_cast<std::uint64_t>(p->peHeader.nt.x) << "\n";
<< "\n"; #define DUMP_DEC_FIELD(x) \
#define DUMP_DEC_FIELD(x) \ std::cout << "" #x << ": "; \
std::cout << "" #x << ": "; \ std::cout << std::dec << static_cast<std::uint64_t>(p->peHeader.nt.x) << "\n";
std::cout << std::dec << static_cast<std::uint64_t>(p->peHeader.nt.x) \
<< "\n";
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
if (argc != 2 || (argc == 2 && std::strcmp(argv[1], "--help") == 0)) { 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]); 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
// Print Rich header info if (p->peHeader.rich.isPresent) {
if(p->peHeader.rich.isPresent) { std::cout << "Rich header: present\n";
std::cout << "Rich header: present\n"; IterRich(p, printRich, NULL);
IterRich(p, printRich, NULL); } else {
} else { std::cout << "Rich header: not present\n";
std::cout << "Rich header: not present\n"; }
} // print out some things
// print out some things DUMP_FIELD(Signature);
DUMP_FIELD(Signature); DUMP_FIELD(FileHeader.Machine);
DUMP_FIELD(FileHeader.Machine); DUMP_FIELD(FileHeader.NumberOfSections);
DUMP_FIELD(FileHeader.NumberOfSections); DUMP_DEC_FIELD(FileHeader.TimeDateStamp);
DUMP_DEC_FIELD(FileHeader.TimeDateStamp); DUMP_FIELD(FileHeader.PointerToSymbolTable);
DUMP_FIELD(FileHeader.PointerToSymbolTable); DUMP_DEC_FIELD(FileHeader.NumberOfSymbols);
DUMP_DEC_FIELD(FileHeader.NumberOfSymbols); DUMP_FIELD(FileHeader.SizeOfOptionalHeader);
DUMP_FIELD(FileHeader.SizeOfOptionalHeader); DUMP_FIELD(FileHeader.Characteristics);
DUMP_FIELD(FileHeader.Characteristics); if (p->peHeader.nt.OptionalMagic == NT_OPTIONAL_32_MAGIC) {
if (p->peHeader.nt.OptionalMagic == NT_OPTIONAL_32_MAGIC) { DUMP_FIELD(OptionalHeader.Magic);
DUMP_FIELD(OptionalHeader.Magic); DUMP_DEC_FIELD(OptionalHeader.MajorLinkerVersion);
DUMP_DEC_FIELD(OptionalHeader.MajorLinkerVersion); DUMP_DEC_FIELD(OptionalHeader.MinorLinkerVersion);
DUMP_DEC_FIELD(OptionalHeader.MinorLinkerVersion); DUMP_FIELD(OptionalHeader.SizeOfCode);
DUMP_FIELD(OptionalHeader.SizeOfCode); DUMP_FIELD(OptionalHeader.SizeOfInitializedData);
DUMP_FIELD(OptionalHeader.SizeOfInitializedData); DUMP_FIELD(OptionalHeader.SizeOfUninitializedData);
DUMP_FIELD(OptionalHeader.SizeOfUninitializedData); DUMP_FIELD(OptionalHeader.AddressOfEntryPoint);
DUMP_FIELD(OptionalHeader.AddressOfEntryPoint); DUMP_FIELD(OptionalHeader.BaseOfCode);
DUMP_FIELD(OptionalHeader.BaseOfCode); DUMP_FIELD(OptionalHeader.BaseOfData);
DUMP_FIELD(OptionalHeader.BaseOfData); DUMP_FIELD(OptionalHeader.ImageBase);
DUMP_FIELD(OptionalHeader.ImageBase); DUMP_FIELD(OptionalHeader.SectionAlignment);
DUMP_FIELD(OptionalHeader.SectionAlignment); DUMP_FIELD(OptionalHeader.FileAlignment);
DUMP_FIELD(OptionalHeader.FileAlignment); DUMP_DEC_FIELD(OptionalHeader.MajorOperatingSystemVersion);
DUMP_DEC_FIELD(OptionalHeader.MajorOperatingSystemVersion); DUMP_DEC_FIELD(OptionalHeader.MinorOperatingSystemVersion);
DUMP_DEC_FIELD(OptionalHeader.MinorOperatingSystemVersion); DUMP_DEC_FIELD(OptionalHeader.Win32VersionValue);
DUMP_DEC_FIELD(OptionalHeader.Win32VersionValue); DUMP_FIELD(OptionalHeader.SizeOfImage);
DUMP_FIELD(OptionalHeader.SizeOfImage); DUMP_FIELD(OptionalHeader.SizeOfHeaders);
DUMP_FIELD(OptionalHeader.SizeOfHeaders); DUMP_FIELD(OptionalHeader.CheckSum);
DUMP_FIELD(OptionalHeader.CheckSum); DUMP_FIELD(OptionalHeader.Subsystem);
DUMP_FIELD(OptionalHeader.Subsystem); DUMP_FIELD(OptionalHeader.DllCharacteristics);
DUMP_FIELD(OptionalHeader.DllCharacteristics); DUMP_FIELD(OptionalHeader.SizeOfStackReserve);
DUMP_FIELD(OptionalHeader.SizeOfStackReserve); DUMP_FIELD(OptionalHeader.SizeOfStackCommit);
DUMP_FIELD(OptionalHeader.SizeOfStackCommit); DUMP_FIELD(OptionalHeader.SizeOfHeapReserve);
DUMP_FIELD(OptionalHeader.SizeOfHeapReserve); DUMP_FIELD(OptionalHeader.SizeOfHeapCommit);
DUMP_FIELD(OptionalHeader.SizeOfHeapCommit); DUMP_FIELD(OptionalHeader.LoaderFlags);
DUMP_FIELD(OptionalHeader.LoaderFlags); DUMP_DEC_FIELD(OptionalHeader.NumberOfRvaAndSizes);
DUMP_DEC_FIELD(OptionalHeader.NumberOfRvaAndSizes); } else {
} else { DUMP_FIELD(OptionalHeader64.Magic);
DUMP_FIELD(OptionalHeader64.Magic); DUMP_DEC_FIELD(OptionalHeader64.MajorLinkerVersion);
DUMP_DEC_FIELD(OptionalHeader64.MajorLinkerVersion); DUMP_DEC_FIELD(OptionalHeader64.MinorLinkerVersion);
DUMP_DEC_FIELD(OptionalHeader64.MinorLinkerVersion); DUMP_FIELD(OptionalHeader64.SizeOfCode);
DUMP_FIELD(OptionalHeader64.SizeOfCode); DUMP_FIELD(OptionalHeader64.SizeOfInitializedData);
DUMP_FIELD(OptionalHeader64.SizeOfInitializedData); DUMP_FIELD(OptionalHeader64.SizeOfUninitializedData);
DUMP_FIELD(OptionalHeader64.SizeOfUninitializedData); DUMP_FIELD(OptionalHeader64.AddressOfEntryPoint);
DUMP_FIELD(OptionalHeader64.AddressOfEntryPoint); DUMP_FIELD(OptionalHeader64.BaseOfCode);
DUMP_FIELD(OptionalHeader64.BaseOfCode); DUMP_FIELD(OptionalHeader64.ImageBase);
DUMP_FIELD(OptionalHeader64.ImageBase); DUMP_FIELD(OptionalHeader64.SectionAlignment);
DUMP_FIELD(OptionalHeader64.SectionAlignment); DUMP_FIELD(OptionalHeader64.FileAlignment);
DUMP_FIELD(OptionalHeader64.FileAlignment); DUMP_DEC_FIELD(OptionalHeader64.MajorOperatingSystemVersion);
DUMP_DEC_FIELD(OptionalHeader64.MajorOperatingSystemVersion); DUMP_DEC_FIELD(OptionalHeader64.MinorOperatingSystemVersion);
DUMP_DEC_FIELD(OptionalHeader64.MinorOperatingSystemVersion); DUMP_DEC_FIELD(OptionalHeader64.Win32VersionValue);
DUMP_DEC_FIELD(OptionalHeader64.Win32VersionValue); DUMP_FIELD(OptionalHeader64.SizeOfImage);
DUMP_FIELD(OptionalHeader64.SizeOfImage); DUMP_FIELD(OptionalHeader64.SizeOfHeaders);
DUMP_FIELD(OptionalHeader64.SizeOfHeaders); DUMP_FIELD(OptionalHeader64.CheckSum);
DUMP_FIELD(OptionalHeader64.CheckSum); DUMP_FIELD(OptionalHeader64.Subsystem);
DUMP_FIELD(OptionalHeader64.Subsystem); DUMP_FIELD(OptionalHeader64.DllCharacteristics);
DUMP_FIELD(OptionalHeader64.DllCharacteristics); DUMP_FIELD(OptionalHeader64.SizeOfStackReserve);
DUMP_FIELD(OptionalHeader64.SizeOfStackReserve); DUMP_FIELD(OptionalHeader64.SizeOfStackCommit);
DUMP_FIELD(OptionalHeader64.SizeOfStackCommit); DUMP_FIELD(OptionalHeader64.SizeOfHeapReserve);
DUMP_FIELD(OptionalHeader64.SizeOfHeapReserve); DUMP_FIELD(OptionalHeader64.SizeOfHeapCommit);
DUMP_FIELD(OptionalHeader64.SizeOfHeapCommit); DUMP_FIELD(OptionalHeader64.LoaderFlags);
DUMP_FIELD(OptionalHeader64.LoaderFlags); DUMP_DEC_FIELD(OptionalHeader64.NumberOfRvaAndSizes);
DUMP_DEC_FIELD(OptionalHeader64.NumberOfRvaAndSizes); }
}
#undef DUMP_FIELD #undef DUMP_FIELD
#undef DUMP_DEC_FIELD #undef DUMP_DEC_FIELD
std::cout << "Imports: " << "\n"; std::cout << "Imports: "
IterImpVAString(p, printImports, NULL); << "\n";
std::cout << "Relocations: " << "\n"; IterImpVAString(p, printImports, NULL);
IterRelocs(p, printRelocs, NULL); std::cout << "Relocations: "
std::cout << "Symbols (symbol table): " << "\n"; << "\n";
IterSymbols(p, printSymbols, NULL); IterRelocs(p, printRelocs, NULL);
std::cout << "Sections: " << "\n"; std::cout << "Symbols (symbol table): "
IterSec(p, printSecs, NULL); << "\n";
std::cout << "Exports: " << "\n"; IterSymbols(p, printSymbols, NULL);
IterExpVA(p, printExps, 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 // read the first 8 bytes from the entry point and print them
VA entryPoint; VA entryPoint;
if (GetEntryPoint(p, entryPoint)) { if (GetEntryPoint(p, entryPoint)) {
std::cout << "First 8 bytes from entry point (0x"; std::cout << "First 8 bytes from entry point (0x";
std::cout << std::hex << entryPoint << "):" << "\n"; std::cout << std::hex << entryPoint << "):"
for (std::size_t i = 0; i < 8; i++) { << "\n";
std::uint8_t b; for (std::size_t i = 0; i < 8; i++) {
if (!ReadByteAtVA(p, i + entryPoint, b)) { std::uint8_t b;
std::cout << " ERR"; if (!ReadByteAtVA(p, i + entryPoint, b)) {
} else { std::cout << " ERR";
std::cout << " 0x" << std::hex << static_cast<int>(b); } else {
} std::cout << " 0x" << std::hex << static_cast<int>(b);
} }
std::cout << "\n";
} }
std::cout << "Resources: " << "\n"; std::cout << "\n";
IterRsrc(p, printRsrc, NULL);
DestructParsedPE(p);
} else {
std::cout << "Error: " << GetPEErr() << " (" << GetPEErrString() << ")"
<< "\n";
std::cout << "Location: " << GetPEErrLoc() << "\n";
} }
std::cout << "Resources: "
<< "\n";
IterRsrc(p, printRsrc, NULL);
DestructParsedPE(p);
return 0; 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 <iostream>
#include <limits> #include <limits>
#include <memory> #include <memory>
#include <algorithm>
#include <climits> #include <climits>
#include <cstring> #include <cstring>
@ -262,7 +262,8 @@ int main(int argc, char *argv[]) {
char *last_parsed_char = nullptr; char *last_parsed_char = nullptr;
errno = 0; 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) { if (address == 0U && *last_parsed_char != 0) {
std::cout << "Invalid address specified\n"; std::cout << "Invalid address specified\n";
return 1; 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_OPTIONAL_64_MAGIC = 0x20B;
constexpr std::uint16_t NT_SHORT_NAME_LEN = 8; constexpr std::uint16_t NT_SHORT_NAME_LEN = 8;
constexpr std::uint16_t SYMTAB_RECORD_LEN = 18; 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 // Machine Types
constexpr std::uint16_t IMAGE_FILE_MACHINE_UNKNOWN = 0x0; constexpr std::uint16_t IMAGE_FILE_MACHINE_UNKNOWN = 0x0;
@ -263,6 +248,25 @@ struct data_directory {
std::uint32_t Size; 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 { struct optional_header_32 {
std::uint16_t Magic; std::uint16_t Magic;
std::uint8_t MajorLinkerVersion; std::uint8_t MajorLinkerVersion;
@ -451,4 +455,101 @@ struct reloc_block {
std::uint32_t PageRVA; std::uint32_t PageRVA;
std::uint32_t BlockSize; 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 } // namespace peparse

View File

@ -32,7 +32,7 @@ THE SOFTWARE.
#include "to_string.h" #include "to_string.h"
#ifdef _MSC_VER #ifdef _MSC_VER
#define __typeof__(x) std::remove_reference < decltype(x) > ::type #define __typeof__(x) std::remove_reference < decltype(x)> ::type
#endif #endif
#define PE_ERR(x) \ #define PE_ERR(x) \
@ -137,6 +137,7 @@ enum pe_err {
PEERR_MAGIC = 9, PEERR_MAGIC = 9,
PEERR_BUFFER = 10, PEERR_BUFFER = 10,
PEERR_ADDRESS = 11, PEERR_ADDRESS = 11,
PEERR_SIZE = 12,
}; };
bool readByte(bounded_buffer *b, std::uint32_t offset, std::uint8_t &out); 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 // Resolve a Rich header product id / build number pair to a known
// product name // product name
typedef std::pair<std::uint16_t, std::uint16_t> ProductKey; 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 // get parser error status as integer
std::uint32_t GetPEErr(); std::uint32_t GetPEErr();
@ -230,4 +232,7 @@ const char *GetMachineAsString(parsed_pe *pe);
// get subsystem as human readable string // get subsystem as human readable string
const char *GetSubsystemAsString(parsed_pe *pe); 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 } // namespace peparse

View File

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

View File

@ -23,10 +23,11 @@ THE SOFTWARE.
*/ */
#include <algorithm> #include <algorithm>
#include <array>
#include <cstring> #include <cstring>
#include <iostream> #include <iostream>
#include <vector>
#include <stdexcept> #include <stdexcept>
#include <vector>
#include <parser-library/nt-headers.h> #include <parser-library/nt-headers.h>
#include <parser-library/parse.h> #include <parser-library/parse.h>
@ -125,14 +126,14 @@ struct parsed_pe_internal {
// The mapping of Rich header product id / build number pairs // The mapping of Rich header product id / build number pairs
// to strings // to strings
static const std::map<ProductKey, const std::string> ProductMap = { 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>"; static const std::string kUnknownProduct = "<unknown>";
// Resolve a Rich header product id / build number pair to a known // Resolve a Rich header product id / build number pair to a known
// product name // 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)); auto it = ProductMap.find(std::make_pair(prodId, buildNum));
if (it != ProductMap.end()) { if (it != ProductMap.end()) {
return it->second; 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::uint32_t err = 0;
std::string err_loc; std::string err_loc;
static const char *pe_err_str[] = {"None", static const char *pe_err_str[] = {
"Out of memory", "None",
"Invalid header", "Out of memory",
"Invalid section", "Invalid header",
"Invalid resource", "Invalid section",
"Unable to get section for VA", "Invalid resource",
"Unable to read data", "Unable to get section for VA",
"Unable to open", "Unable to read data",
"Unable to stat", "Unable to open",
"Bad magic", "Unable to stat",
"Invalid buffer", "Bad magic",
"Invalid address",}; "Invalid buffer",
"Invalid address",
"Invalid size",
};
std::uint32_t GetPEErr() { std::uint32_t GetPEErr() {
return err; return err;
@ -230,8 +234,9 @@ const char *GetSymbolTableStorageClassName(std::uint8_t id) {
} }
} }
static bool static bool readCString(const bounded_buffer &buffer,
readCString(const bounded_buffer &buffer, std::uint32_t off, std::string &result) { std::uint32_t off,
std::string &result) {
if (off < buffer.bufLen) { if (off < buffer.bufLen) {
std::uint8_t *p = buffer.buf; std::uint8_t *p = buffer.buf;
std::uint32_t n = buffer.bufLen; std::uint32_t n = buffer.bufLen;
@ -282,7 +287,9 @@ void IterRsrc(parsed_pe *pe, iterRsrc cb, void *cbd) {
return; 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; std::uint16_t len;
if (!readWord(data, id, len)) { if (!readWord(data, id, len)) {
return false; return false;
@ -388,9 +395,10 @@ bool parse_resource_table(bounded_buffer *sectionData,
} }
} }
} else { } else {
/* .rsrc can accomodate up to 2**31 levels, but Windows only uses 3 by convention. /* .rsrc can accomodate up to 2**31 levels, but Windows only uses 3 by
* As such, any depth above 3 indicates potentially unchecked recusion. * convention. As such, any depth above 3 indicates potentially unchecked
* See: https://docs.microsoft.com/en-us/windows/desktop/debug/pe-format#the-rsrc-section * recusion. See:
* https://docs.microsoft.com/en-us/windows/desktop/debug/pe-format#the-rsrc-section
*/ */
PE_ERR(PEERR_RESC); 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 // now we have the section header information, so fill in a section
// object appropriately // object appropriately
section thisSec; 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]; std::uint8_t c = curSec.Name[charIndex];
if (c == 0) { if (c == 0) {
break; break;
@ -825,7 +834,9 @@ bool readNtHeader(bounded_buffer *b, nt_header_32 &header) {
return true; 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) { if (rich_buf == nullptr) {
return false; 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 // The first decrypted DWORD value of the rich header
// at offset 0 should be 0x536e6144 aka the "DanS" signature // at offset 0 should be 0x536e6144 aka the "DanS" signature
if (!readDword(rich_buf, 0, encrypted_dword)) { if (!readDword(rich_buf, 0, encrypted_dword)) {
PE_ERR(PEERR_READ); PE_ERR(PEERR_READ);
return false; return false;
} }
decrypted_dword = encrypted_dword ^ key; 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 // a DWORD is 4 bytes. Loop is incrementing 8 bytes, however
// we are reading two DWORDS at a time, which is the size // we are reading two DWORDS at a time, which is the size
// of one rich header entry. // 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; rich_entry entry;
// Read first DWORD of entry and decrypt it // Read first DWORD of entry and decrypt it
if (!readDword(rich_buf, i, encrypted_dword)) { 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); entry.BuildNumber = (decrypted_dword & 0xFFFF);
// The second DWORD represents the use count // 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); PE_ERR(PEERR_READ);
return false; return false;
} }
@ -883,13 +894,12 @@ bool readRichHeader(bounded_buffer *rich_buf, std::uint32_t key, rich_header &ri
// Preserve the individual entry // Preserve the individual entry
rich_hdr.Entries.push_back(entry); rich_hdr.Entries.push_back(entry);
} }
// Preserve the end signature aka "Rich" magic // Preserve the end signature aka "Rich" magic
if (!readDword(rich_buf, rich_buf->bufLen-4, rich_hdr.EndSignature)) { if (!readDword(rich_buf, rich_buf->bufLen - 4, rich_hdr.EndSignature)) {
PE_ERR(PEERR_READ); PE_ERR(PEERR_READ);
return false; return false;
}; };
if (rich_hdr.EndSignature != RICH_MAGIC_END) { if (rich_hdr.EndSignature != RICH_MAGIC_END) {
PE_ERR(PEERR_MAGIC); 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 // Preserve the decryption key
rich_hdr.DecryptionKey = key; rich_hdr.DecryptionKey = key;
return true; 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 // 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) { if (richBuf == nullptr) {
return false; return false;
} }
@ -992,12 +1003,12 @@ bool getHeader(bounded_buffer *file, pe_header &p, bounded_buffer *&rem) {
std::uint32_t rem_size; std::uint32_t rem_size;
if (p.nt.OptionalMagic == NT_OPTIONAL_32_MAGIC) { if (p.nt.OptionalMagic == NT_OPTIONAL_32_MAGIC) {
// signature + file_header + optional_header_32 // signature + file_header + optional_header_32
rem_size = rem_size = sizeof(std::uint32_t) + sizeof(file_header) +
sizeof(std::uint32_t) + sizeof(file_header) + sizeof(optional_header_32); sizeof(optional_header_32);
} else if (p.nt.OptionalMagic == NT_OPTIONAL_64_MAGIC) { } else if (p.nt.OptionalMagic == NT_OPTIONAL_64_MAGIC) {
// signature + file_header + optional_header_64 // signature + file_header + optional_header_64
rem_size = rem_size = sizeof(std::uint32_t) + sizeof(file_header) +
sizeof(std::uint32_t) + sizeof(file_header) + sizeof(optional_header_64); sizeof(optional_header_64);
} else { } else {
PE_ERR(PEERR_MAGIC); PE_ERR(PEERR_MAGIC);
deleteBuffer(ntBuf); deleteBuffer(ntBuf);
@ -1529,8 +1540,8 @@ bool getImports(parsed_pe *p) {
ent.moduleName = modName; ent.moduleName = modName;
p->internal->imports.push_back(ent); p->internal->imports.push_back(ent);
} else { } else {
std::string symName = std::string symName = "ORDINAL_" + modName + "_" +
"ORDINAL_" + modName + "_" + to_string<std::uint32_t>(oval, std::dec); to_string<std::uint32_t>(oval, std::dec);
importent ent; importent ent;
@ -1579,7 +1590,8 @@ bool getSymbolTable(parsed_pe *p) {
std::uint32_t offset = p->peHeader.nt.FileHeader.PointerToSymbolTable; 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; symbol sym;
// Read name // Read name
@ -1607,7 +1619,8 @@ bool getSymbolTable(parsed_pe *p) {
strOffset += sizeof(std::uint8_t); strOffset += sizeof(std::uint8_t);
} }
} else { } 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++) { n++) {
sym.strName.push_back(static_cast<char>(sym.name.shortName[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 } // 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. THE SOFTWARE.
*/ */
#include <parser-library/to_string.h>
#include <locale>
#include <codecvt> #include <codecvt>
#include <locale>
#include <parser-library/to_string.h>
namespace peparse { namespace peparse {
// See https://stackoverflow.com/questions/38688417/utf-conversion-functions-in-c11 // See
std::string from_utf16(const UCharString &u) // https://stackoverflow.com/questions/38688417/utf-conversion-functions-in-c11
{ std::string from_utf16(const UCharString &u) {
#if defined(_MSC_VER) #if defined(_MSC_VER)
// std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>convert; // Doesn't compile with Visual Studio. // std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>convert;
// See https://stackoverflow.com/questions/32055357/visual-studio-c-2015-stdcodecvt-with-char16-t-or-char32-t // // 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; std::wstring_convert<std::codecvt_utf8<std::int16_t>, std::int16_t> convert;
auto p = reinterpret_cast<const std::int16_t *>(u.data()); auto p = reinterpret_cast<const std::int16_t *>(u.data());
return convert.to_bytes(p, p + u.size()); return convert.to_bytes(p, p + u.size());

View File

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

View File

@ -704,7 +704,8 @@ static PyObject *pepy_parsed_get_entry_point(PyObject *self, PyObject *args) {
return ret; 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; PyObject *ret;
const char *str; const char *str;
@ -721,7 +722,8 @@ static PyObject *pepy_parsed_get_machine_as_str(PyObject *self, PyObject *args)
return ret; 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; PyObject *ret;
const char *str; const char *str;
@ -1079,9 +1081,8 @@ static PyObject *pepy_parsed_get_relocations(PyObject *self, PyObject *args) {
#define PEPY_PARSED_GET(ATTR, VAL) \ #define PEPY_PARSED_GET(ATTR, VAL) \
static PyObject *pepy_parsed_get_##ATTR(PyObject *self, void *closure) { \ static PyObject *pepy_parsed_get_##ATTR(PyObject *self, void *closure) { \
PyObject *ret = \ PyObject *ret = PyLong_FromUnsignedLongLong( \
PyLong_FromUnsignedLongLong( \ ((pepy_parsed *) self)->pe->peHeader.nt.VAL); \
((pepy_parsed *) self)->pe->peHeader.nt.VAL); \
if (!ret) \ if (!ret) \
PyErr_SetString(PyExc_AttributeError, "Error getting attribute."); \ PyErr_SetString(PyExc_AttributeError, "Error getting attribute."); \
return ret; \ 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 $?