diff --git a/.clang-format b/.clang-format index 02e245f..207911d 100644 --- a/.clang-format +++ b/.clang-format @@ -2,7 +2,6 @@ AlignEscapedNewlinesLeft: true AllowShortFunctionsOnASingleLine: false BinPackArguments: false BinPackParameters: false -BreakBeforeBraces: Attach ColumnLimit: 80 IndentCaseLabels: true IndentWidth: 2 diff --git a/.travis.yml b/.travis.yml index ff11b28..a9230be 100644 --- a/.travis.yml +++ b/.travis.yml @@ -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 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..c08017d --- /dev/null +++ b/CONTRIBUTING.md @@ -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) diff --git a/dump-pe/main.cpp b/dump-pe/main.cpp index e1c8c3e..53d252f 100644 --- a/dump-pe/main.cpp +++ b/dump-pe/main.cpp @@ -22,10 +22,10 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#include -#include -#include #include +#include +#include +#include #include @@ -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(p->peHeader.nt.x) \ - << "\n"; -#define DUMP_DEC_FIELD(x) \ - std::cout << "" #x << ": "; \ - std::cout << std::dec << static_cast(p->peHeader.nt.x) \ - << "\n"; +#define DUMP_FIELD(x) \ + std::cout << "" #x << ": 0x"; \ + std::cout << std::hex << static_cast(p->peHeader.nt.x) << "\n"; +#define DUMP_DEC_FIELD(x) \ + std::cout << "" #x << ": "; \ + std::cout << std::dec << static_cast(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(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(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; } diff --git a/dump-prog/meson.build b/dump-prog/meson.build deleted file mode 100644 index 2625ea7..0000000 --- a/dump-prog/meson.build +++ /dev/null @@ -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) diff --git a/examples/peaddrconv/main.cpp b/examples/peaddrconv/main.cpp index f671110..3bb0741 100644 --- a/examples/peaddrconv/main.cpp +++ b/examples/peaddrconv/main.cpp @@ -1,7 +1,7 @@ +#include #include #include #include -#include #include #include @@ -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; diff --git a/meson.build b/meson.build deleted file mode 100644 index 3a5f4a1..0000000 --- a/meson.build +++ /dev/null @@ -1,8 +0,0 @@ -project('pe-parse', - 'cpp', - default_options : [ 'cpp_std=c++11' ], - license : [ 'MIT' ], - ) - -subdir('parser-library') -subdir('dump-prog') diff --git a/parser-library/meson.build b/parser-library/meson.build deleted file mode 100644 index 451bc9b..0000000 --- a/parser-library/meson.build +++ /dev/null @@ -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') diff --git a/pe-parser-library/include/parser-library/nt-headers.h b/pe-parser-library/include/parser-library/nt-headers.h index 2c714ab..c64bfda 100644 --- a/pe-parser-library/include/parser-library/nt-headers.h +++ b/pe-parser-library/include/parser-library/nt-headers.h @@ -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 diff --git a/pe-parser-library/include/parser-library/parse.h b/pe-parser-library/include/parser-library/parse.h index 55f45b8..3e4281b 100644 --- a/pe-parser-library/include/parser-library/parse.h +++ b/pe-parser-library/include/parser-library/parse.h @@ -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 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 diff --git a/pe-parser-library/include/parser-library/to_string.h b/pe-parser-library/include/parser-library/to_string.h index a47caff..a5fc1d2 100644 --- a/pe-parser-library/include/parser-library/to_string.h +++ b/pe-parser-library/include/parser-library/to_string.h @@ -1,7 +1,7 @@ #pragma once -#include #include +#include #ifdef USE_ICU4C #include diff --git a/pe-parser-library/src/parse.cpp b/pe-parser-library/src/parse.cpp index 125de84..901c6e5 100644 --- a/pe-parser-library/src/parse.cpp +++ b/pe-parser-library/src/parse.cpp @@ -23,10 +23,11 @@ THE SOFTWARE. */ #include +#include #include #include -#include #include +#include #include #include @@ -125,14 +126,14 @@ struct parsed_pe_internal { // The mapping of Rich header product id / build number pairs // to strings static const std::map ProductMap = { - {std::make_pair(1, 0), "Imported Functions"} -}; + {std::make_pair(1, 0), "Imported Functions"}}; static const std::string kUnknownProduct = ""; // 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(oval, std::dec); + std::string symName = "ORDINAL_" + modName + "_" + + to_string(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(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(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 rawEntry(sec.sectionData->buf + off, + sec.sectionData->buf + off + dir.Size); + + return rawEntry.data(); +} + } // namespace peparse diff --git a/pe-parser-library/src/unicode_codecvt.cpp b/pe-parser-library/src/unicode_codecvt.cpp index c76c3c7..f297408 100644 --- a/pe-parser-library/src/unicode_codecvt.cpp +++ b/pe-parser-library/src/unicode_codecvt.cpp @@ -22,17 +22,18 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#include -#include #include +#include +#include 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, 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, 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::int16_t> convert; auto p = reinterpret_cast(u.data()); return convert.to_bytes(p, p + u.size()); diff --git a/pe-parser-library/src/unicode_icu.cpp b/pe-parser-library/src/unicode_icu.cpp index 365cb1f..ef1bd9e 100644 --- a/pe-parser-library/src/unicode_icu.cpp +++ b/pe-parser-library/src/unicode_icu.cpp @@ -26,8 +26,7 @@ THE SOFTWARE. #include 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); diff --git a/python/pepy.cpp b/python/pepy.cpp index 64b71e8..d9396e9 100644 --- a/python/pepy.cpp +++ b/python/pepy.cpp @@ -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; \ diff --git a/travis.sh b/travis.sh deleted file mode 100755 index 6cd3e68..0000000 --- a/travis.sh +++ /dev/null @@ -1,210 +0,0 @@ -#!/usr/bin/env bash - -main() { - if [ $# -ne 2 ] ; then - printf "Usage:\n\ttravis.sh \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 $?