reman3/third_party/coffi-1.1/examples/writer/writer.cpp

201 lines
8.9 KiB
C++

/* This example shows how to create a PE program file for Windows
*
* Instructions:
* 1. Compile and link this file with the COFFI library
* g++ writer.cpp -o writer_obj.exe
* 2. Execute the result file writer.exe
* writer.exe
* It will produce hello.exe
* 3. Run the result file:
* hello.exe
* It should open a "Hello World!" message box
*/
//! [ex_writer_open]
#include <coffi/coffi.hpp>
using namespace COFFI;
// clang-format off
void write_the_file( const std::string &filename )
{
coffi writer;
// You can't proceed without this function call!
writer.create(COFFI_ARCHITECTURE_PE);
//! [ex_writer_open]
//! [ex_writer_optional]
// Create the optional header (required for images *.exe, *.dll)
writer.create_optional_header();
//! [ex_writer_optional]
//! [ex_writer_code]
// Create code section
section* text_sec = writer.add_section( ".text" );
char text[] = {
'\x6A', '\x00', // push 0
'\x68', '\x00', '\x20', '\x40', '\x00', // push offset 0x00402000 (string in the .rdata section)
'\x68', '\x00', '\x20', '\x40', '\x00', // push offset 0x00402000 (string in the .rdata section)
'\x6A', '\x00', // push 0
'\xE8', '\x0E', '\x00', '\x00', '\x00', // call 0x401021
'\x6A', '\x00', // push 0
'\xE8', '\x01', '\x00', '\x00', '\x00', // call 0x40101b
'\xF4', // hlt
'\xFF', '\x25', '\x4C', '\x30', '\x40', '\x00', // 0x40101b: jmp *0x40304C (ExitProcess)
'\xFF', '\x25', '\x54', '\x30', '\x40', '\x00' // 0x401021: jmp *0x403054 (MessageBoxA)
};
text_sec->set_data( text, sizeof( text ) );
text_sec->set_virtual_address(0x1000);
text_sec->set_virtual_size(sizeof(text));
text_sec->set_flags(IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_CODE | IMAGE_SCN_ALIGN_4BYTES);
//! [ex_writer_code]
//! [ex_writer_rdata]
// Create a .rdata section, with the string
section* rdata_sec = writer.add_section( ".rdata" );
char rdata[] = "Hello World!\0";
rdata_sec->set_data( rdata, sizeof( rdata ) );
rdata_sec->set_virtual_address(0x2000);
rdata_sec->set_virtual_size(sizeof(rdata));
rdata_sec->set_flags(IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_ALIGN_4BYTES);
//! [ex_writer_rdata]
//! [ex_writer_idata]
// Create a .idata section
section* idata_sec = writer.add_section( ".idata" );
uint8_t idata[] = {
// RVA = 0x3000
// Import table (array of IMAGE_IMPORT_DESCRIPTOR structures)
0x3C, 0x30, 0x00, 0x00, // OriginalFirstThunk: offset of the import lookup table
0x00, 0x00, 0x00, 0x00, // TimeDateStamp
0x00, 0x00, 0x00, 0x00, // ForwarderChain
0x5C, 0x30, 0x00, 0x00, // Name: Offset of "KERNEL32.dll"
0x4C, 0x30, 0x00, 0x00, // FirstThunk: offset of import address table
// Import table (array of IMAGE_IMPORT_DESCRIPTOR structures)
0x44, 0x30, 0x00, 0x00, // OriginalFirstThunk: offset of the import lookup table
0x00, 0x00, 0x00, 0x00, // TimeDateStamp
0x00, 0x00, 0x00, 0x00, // ForwarderChain
0x6C, 0x30, 0x00, 0x00, // Name: Offset of "USER32.dll"
0x54, 0x30, 0x00, 0x00, // FirstThunk: offset of import address table
// Empty IMAGE_IMPORT_DESCRIPTOR structure (signaling the end of the IMAGE_IMPORT_DESCRIPTOR array)
0x00, 0x00, 0x00, 0x00, // OriginalFirstThunk
0x00, 0x00, 0x00, 0x00, // TimeDateStamp
0x00, 0x00, 0x00, 0x00, // ForwarderChain
0x00, 0x00, 0x00, 0x00, // Name
0x00, 0x00, 0x00, 0x00, // FirstThunk
// Import lookup table (array of IMAGE_THUNK_DATA structures)
// RVA = 0x303C
0x7C, 0x30, 0x00, 0x00, // Import function by name
0x00, 0x00, 0x00, 0x00, //
// RVA = 0x3044
0x8C, 0x30, 0x00, 0x00, // Import function by name
0x00, 0x00, 0x00, 0x00, //
// Import address table (array of IMAGE_THUNK_DATA structures)
// RVA = 0x304C
0x7C, 0x30, 0x00, 0x00, // Import function by name
0x00, 0x00, 0x00, 0x00, //
// RVA = 0x3054
0x8C, 0x30, 0x00, 0x00, // Import function by name
0x00, 0x00, 0x00, 0x00, //
// Names
// RVA = 0x305C
'K', 'E', 'R', 'N', 'E', 'L', '3', '2', '.', 'd', 'l', 'l', 0, 0, 0, 0,
// RVA = 0x306C
'U', 'S', 'E', 'R', '3', '2', '.', 'd', 'l', 'l', 0, 0, 0, 0, 0, 0,
// Hint/Name Table
// RVA = 0x307C
0x5E, 0x01, 'E', 'x', 'i', 't', 'P', 'r', 'o', 'c', 'e', 's', 's', 0, 0, 0,
// RVA = 0x308C
0x7F, 0x02, 'M', 'e', 's', 's', 'a', 'g', 'e', 'B', 'o', 'x', 'A', 0, 0, 0,
};
idata_sec->set_data( (char*)idata, sizeof( idata ) );
idata_sec->set_virtual_address(0x3000);
idata_sec->set_virtual_size(sizeof(idata));
idata_sec->set_flags(IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_ALIGN_4BYTES);
//! [ex_writer_idata]
//! [ex_writer_reloc]
// Create a .reloc section
section* reloc_sec = writer.add_section( ".reloc" );
uint16_t reloc[] = {
0x1000, 0x0000, // RVA of relocation block
0x0010, 0x0000, // Size of the relocation block
0x3003, // Relocation HIGHLOW at address 0x1003
0x3008, // Relocation HIGHLOW at address 0x1008
0x301D, // Relocation HIGHLOW at address 0x101D
0x3023, // Relocation HIGHLOW at address 0x1023
};
reloc_sec->set_data( (char*)reloc, sizeof( reloc ) );
reloc_sec->set_virtual_address(0x4000);
reloc_sec->set_virtual_size(sizeof(reloc));
reloc_sec->set_flags(IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_ALIGN_4BYTES);
//! [ex_writer_reloc]
//! [ex_writer_header]
// Set headers properties
writer.get_header()->set_flags(IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_32BIT_MACHINE);
writer.get_optional_header()->set_code_size(0x200);
writer.get_optional_header()->set_initialized_data_size(0x400);
writer.get_optional_header()->set_entry_point_address(0x00001000);
writer.get_optional_header()->set_code_base(0x00001000);
writer.get_optional_header()->set_data_base(0x00002000);
writer.get_win_header()->set_image_base(0x00400000);
writer.get_win_header()->set_section_alignment(0x1000);
writer.get_win_header()->set_major_os_version(4);
writer.get_win_header()->set_major_image_version(1);
writer.get_win_header()->set_major_subsystem_version(4);
writer.get_win_header()->set_image_size(0x5000);
writer.get_win_header()->set_headers_size(0x200);
writer.get_win_header()->set_subsystem(3); // Windows CUI
writer.get_win_header()->set_stack_reserve_size(0x00100000);
writer.get_win_header()->set_stack_commit_size(0x1000);
writer.get_win_header()->set_heap_reserve_size(0x100000);
writer.get_win_header()->set_heap_commit_size(0x1000);
//! [ex_writer_header]
//! [ex_writer_directories]
// Add directories (required for images *.exe, *.dll)
writer.add_directory(image_data_directory{0, 0}); // Export Directory [.edata (or where ever we found it)]
writer.add_directory(image_data_directory{idata_sec->get_virtual_address(), idata_sec->get_virtual_size()}); // Import Directory [parts of .idata]
writer.add_directory(image_data_directory{0, 0}); // Resource Directory [.rsrc]
writer.add_directory(image_data_directory{0, 0}); // Exception Directory [.pdata]
writer.add_directory(image_data_directory{0, 0}); // Security Directory
writer.add_directory(image_data_directory{reloc_sec->get_virtual_address(), reloc_sec->get_virtual_size()}); // Base Relocation Directory [.reloc]
writer.add_directory(image_data_directory{0, 0}); // Debug Directory
writer.add_directory(image_data_directory{0, 0}); // Description Directory
writer.add_directory(image_data_directory{0, 0}); // Special Directory
writer.add_directory(image_data_directory{0, 0}); // Thread Storage Directory [.tls]
writer.add_directory(image_data_directory{0, 0}); // Load Configuration Directory
writer.add_directory(image_data_directory{0, 0}); // Bound Import Directory
writer.add_directory(image_data_directory{0x304C, 0x10}); // Import Address Table Directory
writer.add_directory(image_data_directory{0, 0}); // Delay Import Directory
writer.add_directory(image_data_directory{0, 0}); // CLR Runtime Header
writer.add_directory(image_data_directory{0, 0}); // Reserved
//! [ex_writer_directories]
//! [ex_writer_save]
// Recompute all the offsets in the file
writer.layout();
// Create the PE file
writer.save( filename );
//! [ex_writer_save]
}
// clang-format on
int main()
{
write_the_file("hello.exe");
return 0;
}