From 399689252359a008066bea0a9361cf717baa9555 Mon Sep 17 00:00:00 2001
From: Nickie S <DCNick3@users.noreply.github.com>
Date: Thu, 6 Aug 2020 19:23:32 +0300
Subject: [PATCH] Add ability to parse PE file without backing file (#136)

* Add ability to parse PE file without backing file

* Add size check

* Fix formatting

* Change buffer size type
---
 .../include/parser-library/parse.h            |  4 +++
 pe-parser-library/src/buffer.cpp              | 22 +++++++++++++
 pe-parser-library/src/parse.cpp               | 32 ++++++++++++++-----
 3 files changed, 50 insertions(+), 8 deletions(-)

diff --git a/pe-parser-library/include/parser-library/parse.h b/pe-parser-library/include/parser-library/parse.h
index 5cb4616..ab9065e 100644
--- a/pe-parser-library/include/parser-library/parse.h
+++ b/pe-parser-library/include/parser-library/parse.h
@@ -149,6 +149,7 @@ bool readQword(bounded_buffer *b, std::uint32_t offset, std::uint64_t &out);
 bool readChar16(bounded_buffer *b, std::uint32_t offset, char16_t &out);
 
 bounded_buffer *readFileToFileBuffer(const char *filePath);
+bounded_buffer *makeBufferFromPointer(std::uint8_t *data, std::uint32_t sz);
 bounded_buffer *
 splitBuffer(bounded_buffer *b, std::uint32_t from, std::uint32_t to);
 void deleteBuffer(bounded_buffer *b);
@@ -186,6 +187,9 @@ std::string GetPEErrLoc();
 // get a PE parse context from a file
 parsed_pe *ParsePEFromFile(const char *filePath);
 
+parsed_pe *ParsePEFromPointer(std::uint8_t *buffer, std::uint32_t sz);
+parsed_pe *ParsePEFromBuffer(bounded_buffer *buffer);
+
 // destruct a PE context
 void DestructParsedPE(parsed_pe *p);
 
diff --git a/pe-parser-library/src/buffer.cpp b/pe-parser-library/src/buffer.cpp
index 3cba9bc..c56864d 100644
--- a/pe-parser-library/src/buffer.cpp
+++ b/pe-parser-library/src/buffer.cpp
@@ -298,6 +298,28 @@ bounded_buffer *readFileToFileBuffer(const char *filePath) {
   return p;
 }
 
+bounded_buffer *makeBufferFromPointer(std::uint8_t *data, std::uint32_t sz) {
+  if (data == nullptr) {
+    PE_ERR(PEERR_MEM);
+    return nullptr;
+  }
+
+  bounded_buffer *p = new (std::nothrow) bounded_buffer();
+
+  if (p == nullptr) {
+    PE_ERR(PEERR_MEM);
+    return nullptr;
+  }
+
+  p->copy = true;
+  p->detail = nullptr;
+  p->buf = data;
+  p->bufLen = sz;
+  p->swapBytes = false;
+
+  return p;
+}
+
 // split buffer inclusively from from to to by offset
 bounded_buffer *
 splitBuffer(bounded_buffer *b, std::uint32_t from, std::uint32_t to) {
diff --git a/pe-parser-library/src/parse.cpp b/pe-parser-library/src/parse.cpp
index 6e12cce..b0beb5c 100644
--- a/pe-parser-library/src/parse.cpp
+++ b/pe-parser-library/src/parse.cpp
@@ -2337,7 +2337,7 @@ bool getSymbolTable(parsed_pe *p) {
   return true;
 }
 
-parsed_pe *ParsePEFromFile(const char *filePath) {
+parsed_pe *ParsePEFromBuffer(bounded_buffer *buffer) {
   // First, create a new parsed_pe structure
   // We pass std::nothrow parameter to new so in case of failure it returns
   // nullptr instead of throwing exception std::bad_alloc.
@@ -2349,13 +2349,7 @@ parsed_pe *ParsePEFromFile(const char *filePath) {
   }
 
   // Make a new buffer object to hold just our file data
-  p->fileBuffer = readFileToFileBuffer(filePath);
-
-  if (p->fileBuffer == nullptr) {
-    delete p;
-    // err is set by readFileToFileBuffer
-    return nullptr;
-  }
+  p->fileBuffer = buffer;
 
   p->internal = new (std::nothrow) parsed_pe_internal();
 
@@ -2431,6 +2425,28 @@ parsed_pe *ParsePEFromFile(const char *filePath) {
   return p;
 }
 
+parsed_pe *ParsePEFromFile(const char *filePath) {
+  auto buffer = readFileToFileBuffer(filePath);
+
+  if (buffer == nullptr) {
+    // err is set by readFileToFileBuffer
+    return nullptr;
+  }
+
+  return ParsePEFromBuffer(buffer);
+}
+
+parsed_pe *ParsePEFromPointer(std::uint8_t *ptr, std::uint32_t sz) {
+  auto buffer = makeBufferFromPointer(ptr, sz);
+
+  if (buffer == nullptr) {
+    // err is set by makeBufferFromPointer
+    return nullptr;
+  }
+
+  return ParsePEFromBuffer(buffer);
+}
+
 void DestructParsedPE(parsed_pe *p) {
   if (p == nullptr) {
     return;