Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
cmake-build-debug/
build/
.vs
.idea
.idea
test_output
4 changes: 2 additions & 2 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
[submodule "include/keystone"]
path = include/keystone
url = https://github.com/keystone-engine/keystone.git
path = include/keystone
url = https://github.com/keystone-engine/keystone.git
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ addons:
packages:
- gcc-6
- g++-6
- libboost-all-dev
notifications:
email:
on_success: never
Expand Down
19 changes: 12 additions & 7 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
cmake_minimum_required(VERSION 3.6)
project(pe_ep_intercept)

set(KEYSTONE_BUILD_STATIC_RUNTIME on)
include_directories(include include/keystone/include)
add_subdirectory(include/keystone)
add_subdirectory(src)
cmake_minimum_required(VERSION 3.6)
project(pe_ep_intercept)
# Keystone
set(KEYSTONE_BUILD_STATIC_RUNTIME on)
include_directories(include include/keystone/include)

file(GLOB COMMON_SOURCE_FILES common/*.hpp common/*.cpp)

# Sources
add_subdirectory(include/keystone)
add_subdirectory(src)
add_subdirectory(tests)
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Writes a new entry point for a target executable using Keystone as the assembler
### Table of Contents
* **[Why does this exist](#Why-does-this-exist)**
* **[Details](#Details)**
* **[How to compile](#How-to-compile)**
* **[How to msvc_cmd](#How-to-msvc_cmd)**

### Why does this exist
I found it difficult to find a portable executable patcher that handles a random base address and doesn't use inline assembly for the copied instructions. It was also difficult to find a patcher that does not store compiled x86 or x86-64 machine code in the source.
Expand All @@ -22,7 +22,7 @@ Two approaches for ASLR base address:

The newly added section's code jumps to the original oep allowing normal execution of the program.

### How to compile
### How to msvc_cmd

1. Ensure that you have Cmake installed.
2. Execute `run_build.sh`.
Expand Down
14 changes: 5 additions & 9 deletions src/PePatch.cpp → common/Assembler.cpp
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
#include <keystone/include/keystone/keystone.h>
#include "PePatch.hpp"
#include "Assembler.hpp"

namespace PeEpIntercept {
PePatch::PePatch(std::string &path) : PeFile(path) {

}

std::vector<char> PePatch::Assemble(const std::string &assembly) {
namespace Interceptor {
std::vector<char> Assembler::assemble(MachineType type, const std::string &assembly) {
std::vector<char> instructions;

if (assembly.empty()) {
Expand All @@ -29,10 +25,10 @@ namespace PeEpIntercept {
ks_mode instruct_mode;

switch (type) {
case PeArch::x86:
case MachineType::x86:
instruct_mode = KS_MODE_32;
break;
case PeArch::x64:
case MachineType::x64:
instruct_mode = KS_MODE_64;
break;
default:
Expand Down
15 changes: 15 additions & 0 deletions common/Assembler.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#ifndef PE_EP_INTERCEPT_PEASSEMBLER_HPP
#define PE_EP_INTERCEPT_PEASSEMBLER_HPP

#include "PeFile.hpp"

namespace Interceptor {
class Assembler {
protected:
public:
std::vector<char> assemble(MachineType type, const std::string &assembly);
};
}


#endif //PE_EP_INTERCEPT_PEASSEMBLER_HPP
10 changes: 5 additions & 5 deletions src/PeAssembly.cpp → common/Assembly.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#include "PeAssembly.hpp"
#include "Assembly.hpp"

namespace PeEpIntercept {
std::string EntryRedirectAssemblyX64(uint32_t oep) {
namespace Interceptor {
std::string entryRedirectAssemblyX64(uint32_t oep) {
std::string address = std::to_string(oep);

return "push rbp;"
Expand Down Expand Up @@ -44,7 +44,7 @@ namespace PeEpIntercept {
"ret;";
}

std::string EntryRedirectAssemblyX86(uint32_t oep) {
std::string entryRedirectAssemblyX86(uint32_t oep) {
std::string address = std::to_string(oep);

return "push ebp;"
Expand Down Expand Up @@ -86,4 +86,4 @@ namespace PeEpIntercept {
// patch in ExitProcess
"ret;";
}
} // namespace PeEpIntercept
} // namespace Interceptor
8 changes: 4 additions & 4 deletions src/PeAssembly.hpp → common/Assembly.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,16 @@

#include <string>

namespace PeEpIntercept {
enum class PeArch {
namespace Interceptor {
enum class MachineType {
x86,
x64,
unknown
};

std::string EntryRedirectAssemblyX64(uint32_t oep);
std::string entryRedirectAssemblyX64(uint32_t oep);

std::string EntryRedirectAssemblyX86(uint32_t oep);
std::string entryRedirectAssemblyX86(uint32_t oep);
}


Expand Down
63 changes: 63 additions & 0 deletions common/Editor.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#include <iostream>
#include "Editor.hpp"
#include "Assembly.hpp"
#include "Assembler.hpp"
#include "PePatchX64.hpp"

namespace Interceptor {
bool Editor::edit(std::string file_path, const std::string &section) {
std::unique_ptr<Interceptor::PePatchX64> patcher;

std::fstream file_stream;
file_stream.exceptions(std::ifstream::failbit | std::ifstream::badbit);
file_stream.open(
file_path,
std::ios::binary |
std::ifstream::ate |
std::fstream::in |
std::fstream::out
);

std::streamsize size = file_stream.tellg();
file_stream.seekg(0, std::ios::beg);

if (size <= 0) {
throw std::runtime_error("could not get file size");
}

std::vector<char> file_contents(size);

if (!file_stream.read(file_contents.data(), size)) {
throw std::runtime_error("could not read file");
}

std::string instruct;
uint32_t oep = 0;

Assembler assembler;
PeFile file(file_contents);
MachineType machine_type = file.getMachineType();

switch (machine_type) {
case Interceptor::MachineType::x64:
patcher = std::make_unique<Interceptor::PePatchX64>(assembler, file);
oep = file.getEntryPoint();
instruct = Interceptor::entryRedirectAssemblyX64(oep);
break;
default:
std::cout << "Unsupported executable architecture." << std::endl;
return false;
}

if (file.hasSection(section)) {
std::cout << "The exectuable already has a section called \"" << section << "\"." << std::endl;
return false;
}

file_contents = patcher->patch();
file_stream.seekp(0);
file_stream.write(file_contents.data(), file_contents.size());

return true;
}
}
12 changes: 12 additions & 0 deletions common/Editor.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#ifndef PE_EP_INTERCEPT_EDITOR_HPP
#define PE_EP_INTERCEPT_EDITOR_HPP

namespace Interceptor {
class Editor {
public:
static bool edit(std::string file_path, const std::string &section);
};
}


#endif //PE_EP_INTERCEPT_EDITOR_HPP
Loading