├── .gitignore ├── project_template ├── main.def ├── include │ └── api.h ├── dll_main.cpp ├── LICENSE ├── CMakeLists.txt └── main.cpp ├── .gitmodules ├── .appveyor.yml ├── CMakeLists.txt └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | *.bak 2 | 3 | -------------------------------------------------------------------------------- /project_template/main.def: -------------------------------------------------------------------------------- 1 | EXPORTS demo_export 2 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "libpeconv"] 2 | path = libpeconv 3 | url = https://github.com/hasherezade/libpeconv.git 4 | -------------------------------------------------------------------------------- /project_template/include/api.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #ifdef PECONV_PROJECT_EXPORTS 6 | #define PECONV_PROJECT_API __declspec(dllexport) 7 | #else 8 | #define PECONV_PROJECT_API __declspec(dllimport) 9 | #endif 10 | 11 | extern "C" { 12 | //replace by your own function: 13 | void PECONV_PROJECT_API __stdcall demo_export(void); 14 | }; 15 | -------------------------------------------------------------------------------- /.appveyor.yml: -------------------------------------------------------------------------------- 1 | os: 2 | - Visual Studio 2015 3 | 4 | platform: x64 5 | - x64 6 | 7 | branches: 8 | only: 9 | - master 10 | 11 | install: 12 | - git submodule update --init --recursive 13 | - set PATH=C:\Program Files\CMake\bin;%PATH% 14 | 15 | build: 16 | verbosity: detailed 17 | 18 | configuration: 19 | - Debug 20 | 21 | environment: 22 | matrix: 23 | - env_arch: "x64" 24 | - env_arch: "x86" 25 | 26 | build_script: 27 | - mkdir build 28 | - cd build 29 | - if [%env_arch%]==[x64] ( 30 | cmake .. -A x64 ) 31 | - if [%env_arch%]==[x86] ( 32 | cmake .. ) 33 | - cmake --build . 34 | - cd .. 35 | 36 | -------------------------------------------------------------------------------- /project_template/dll_main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define PECONV_PROJECT_EXPORTS 4 | #include "api.h" 5 | 6 | //replace by your own DLL name, update "main.def" 7 | #define LIB_NAME "TemplateDLL" 8 | 9 | //replace by your own function, update "api.h" and "main.def" 10 | void __stdcall demo_export(void) 11 | { 12 | MessageBox(NULL, "PEconv Project", LIB_NAME, MB_ICONINFORMATION); 13 | } 14 | 15 | BOOL WINAPI DllMain (HANDLE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) 16 | { 17 | switch (fdwReason) 18 | { 19 | case DLL_PROCESS_ATTACH: 20 | case DLL_THREAD_ATTACH: 21 | case DLL_THREAD_DETACH: 22 | case DLL_PROCESS_DETACH: 23 | break; 24 | } 25 | return TRUE; 26 | } 27 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required ( VERSION 3.0 ) 2 | 3 | # replace "peconv_project" by your own project name: 4 | project ( peconv_project ) 5 | 6 | # libs 7 | # modules: 8 | set ( M_PARSER "libpeconv/libpeconv" ) 9 | 10 | option(PECONV_UNICODE "Enable Unicode" OFF) 11 | 12 | # enable unicode support 13 | if(PECONV_UNICODE) 14 | add_definitions (-DUNICODE -D_UNICODE) 15 | endif() 16 | 17 | # modules paths: 18 | set (PECONV_DIR "${CMAKE_SOURCE_DIR}/${M_PARSER}" CACHE PATH "PEConv main path") 19 | add_subdirectory ( ${PECONV_DIR} ) 20 | set ( PECONV_LIB $ CACHE PATH "PEConvLib library path" ) 21 | 22 | # Add sub-directories 23 | # 24 | add_subdirectory ( project_template ) 25 | 26 | -------------------------------------------------------------------------------- /project_template/LICENSE: -------------------------------------------------------------------------------- 1 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 2 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 3 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 4 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 5 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 6 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 7 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 8 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 9 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 10 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # libPeConv project template 2 | [![Build status](https://ci.appveyor.com/api/projects/status/ehmf01f38h5ce8ri?svg=true)](https://ci.appveyor.com/project/hasherezade/libpeconv-tpl) 3 | [![Last Commit](https://img.shields.io/github/last-commit/hasherezade/libpeconv_tpl/master)](https://github.com/hasherezade/libpeconv_tpl/commits) 4 | 5 | A ready-made template for a project based on [libpeconv](https://github.com/hasherezade/libpeconv). 6 | 7 | Clone & build 8 | - 9 | 10 | 1. Use [Git](https://git-scm.com/download/) to make a **recursive** clone of this repo, containing all the required submodules: 11 | 12 | ```console 13 | git clone --recursive https://github.com/hasherezade/libpeconv_tpl.git 14 | ``` 15 | 16 | 2. With the help of [CMake](https://cmake.org/), generate a Visual Studio project, analogously to described [here](https://github.com/hasherezade/libpeconv/wiki/Building-the-library). 17 | -------------------------------------------------------------------------------- /project_template/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 3.0) 2 | 3 | # replace "project_template" by your own project name: 4 | project ( project_template ) 5 | 6 | # This option allows you to choose if you want to build a DLL or EXE: 7 | option(BUILD_AS_DLL "Build the project as a DLL" OFF) 8 | 9 | set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT") 10 | 11 | # include libpeconv headers: 12 | include_directories ( ${PECONV_DIR}/include ) 13 | 14 | set (srcs 15 | #put your sources here 16 | ) 17 | 18 | # general headers - they will be used for both EXE and DLL: 19 | set (hdrs 20 | #put your headers here 21 | ) 22 | 23 | set (rsrc 24 | #put your resources here 25 | ) 26 | 27 | 28 | # DLL-specific headers - they will be included only in the DLL build: 29 | set (dll_hdrs 30 | #put your headers here 31 | ) 32 | 33 | # Choose to build the DLL or EXE 34 | 35 | if(BUILD_AS_DLL) 36 | include_directories ( 37 | include 38 | ) 39 | set (dll_hdrs 40 | ${hdrs} 41 | include/api.h 42 | ) 43 | add_library ( ${PROJECT_NAME} SHARED ${dll_hdrs} ${srcs} ${rsrc} dll_main.cpp main.def) 44 | else() 45 | add_executable ( ${PROJECT_NAME} ${hdrs} ${srcs} ${rsrc} main.cpp ) 46 | endif() 47 | 48 | # link with libpeconv.lib 49 | target_link_libraries ( ${PROJECT_NAME} ${PECONV_LIB} ) 50 | 51 | #dependencies: 52 | add_dependencies( ${PROJECT_NAME} libpeconv ) 53 | 54 | INSTALL( TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_PREFIX} COMPONENT ${PROJECT_NAME} ) 55 | -------------------------------------------------------------------------------- /project_template/main.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | A demo of a basic manual PE loader - you can use it as a starting point for your own project, 3 | or delete it and start from scratch 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include // include libPeConv header 11 | 12 | BYTE* g_Payload = nullptr; 13 | size_t g_PayloadSize = 0; 14 | 15 | // manually load the PE file using libPeConv 16 | bool load_payload(LPCTSTR pe_path) 17 | { 18 | if (g_Payload) { 19 | // already loaded 20 | std::cerr << "[!] The payload is already loaded!\n"; 21 | return false; 22 | } 23 | #ifdef LOAD_FROM_PATH 24 | //if the PE is dropped on the disk, you can load it from the file: 25 | g_Payload = peconv::load_pe_executable(pe_path, g_PayloadSize); 26 | #else // load from memory buffer 27 | /* 28 | in this example the memory buffer is first loaded from the disk, 29 | but it can as well be fetch from resources, or a hardcoded buffer 30 | */ 31 | size_t bufsize = 0; 32 | BYTE* buf = peconv::load_file(pe_path, bufsize); 33 | if (!buf) { 34 | return false; 35 | } 36 | // if the file is NOT dropped on the disk, you can load it directly from a memory buffer: 37 | g_Payload = peconv::load_pe_executable(buf, bufsize, g_PayloadSize); 38 | 39 | // at this point we can free the buffer with the raw payload: 40 | peconv::free_file(buf); buf = nullptr; 41 | 42 | #endif 43 | if (!g_Payload) { 44 | return false; 45 | } 46 | 47 | // if the loaded PE needs to access resources, you may need to connect it to the PEB: 48 | peconv::set_main_module_in_peb((HMODULE)g_Payload); 49 | 50 | // load delayed imports (if present): 51 | const ULONGLONG loadBase = (ULONGLONG)g_Payload; 52 | peconv::load_delayed_imports(g_Payload, loadBase); 53 | 54 | return true; 55 | } 56 | 57 | int run_payload() 58 | { 59 | if (!g_Payload) { 60 | std::cerr << "[!] The payload is not loaded!\n"; 61 | return -1; 62 | } 63 | 64 | // if needed, you can run TLS callbacks before the Entry Point: 65 | peconv::run_tls_callbacks(g_Payload, g_PayloadSize); 66 | 67 | //calculate the Entry Point of the manually loaded module 68 | DWORD ep_rva = peconv::get_entry_point_rva(g_Payload); 69 | if (!ep_rva) { 70 | std::cerr << "[!] Cannot fetch EP!\n"; 71 | return -2; 72 | } 73 | const ULONG_PTR ep_va = ep_rva + (ULONG_PTR)g_Payload; 74 | 75 | // run appropriate version of payload's main: 76 | int ret = 0; 77 | if (peconv::is_module_dll(g_Payload)) { 78 | //the prototype of the DllMain fuction: 79 | BOOL WINAPI _DllMain( 80 | HINSTANCE hinstDLL, // handle to DLL module 81 | DWORD fdwReason, // reason for calling function 82 | LPVOID lpvReserved); // reserved 83 | auto new_main = reinterpret_cast(ep_va); 84 | 85 | // call the Entry Point of the manually loaded PE : 86 | ret = new_main((HINSTANCE)g_Payload, DLL_PROCESS_ATTACH, 0); 87 | } 88 | else { 89 | //the simplest prototype of the main fuction: 90 | int basic_main(void); 91 | auto new_main = reinterpret_cast(ep_va); 92 | 93 | //call the Entry Point of the manually loaded PE: 94 | ret = new_main(); 95 | } 96 | return ret; 97 | } 98 | 99 | int _tmain(int argc, LPTSTR argv[]) 100 | { 101 | if (argc < 2) { 102 | std::cout << "Args: " << std::endl; 103 | return 0; 104 | } 105 | const LPTSTR pe_path = argv[1]; 106 | if (!load_payload(pe_path)) { 107 | return -1; 108 | } 109 | std::cout << "Payload loaded!\n"; 110 | return run_payload(); 111 | } 112 | --------------------------------------------------------------------------------