feat(pe): 添加PE文件构建器功能
新增PE库的基础设施包括: - 创建README.md文档,说明代码参考rust cargo的object库实现 - 配置cbuild.toml包依赖,添加scc_utils依赖项 - 定义scc_pe_builder.h头文件,包含PE构建器的数据结构和API函数 - 实现PE文件的段管理、头信息处理和文件写入功能
This commit is contained in:
102
libs/target/pe/src/main.c
Normal file
102
libs/target/pe/src/main.c
Normal file
@@ -0,0 +1,102 @@
|
||||
#include <scc_pe_builder.h>
|
||||
#include <scc_pe_idata.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int main() {
|
||||
const char data[] = "Hello, World from SCC PE Builder!\n\0";
|
||||
|
||||
/* clang-format off */
|
||||
const char code[] = {
|
||||
// sub rsp, 0x28 ; 为函数调用分配栈空间
|
||||
0x48, 0x83, 0xEC, 0x28,
|
||||
// lea rcx, [rip + data_offset] ; 将字符串地址加载到RCX(第一个参数)
|
||||
0x48, 0x8D, 0x0D, 0x00, 0x00, 0x00, 0x00,
|
||||
// call qword ptr [rip + puts_iat] ; 通过IAT调用puts
|
||||
0xFF, 0x15, 0x00, 0x00, 0x00, 0x00,
|
||||
// add rsp, 0x28 ; 恢复栈空间
|
||||
0x48, 0x83, 0xC4, 0x28,
|
||||
// xor eax, eax ; 设置返回值为0
|
||||
0x33, 0xC0,
|
||||
// ret ; 返回
|
||||
0xC3,
|
||||
};
|
||||
/* clang-format on */
|
||||
scc_pe_builder_t builder = {0};
|
||||
scc_pe_builder_init(&builder, true, 4096, 512);
|
||||
scc_pe_reserve_header(&builder, 3);
|
||||
scc_pe_section_range code_range = scc_pe_reserve_section_header(
|
||||
&builder, (BYTE *)".text\0\0",
|
||||
IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE,
|
||||
sizeof(code), sizeof(code));
|
||||
|
||||
scc_pe_section_range data_range = scc_pe_reserve_section_header(
|
||||
&builder, (BYTE *)".data\0\0",
|
||||
IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ |
|
||||
IMAGE_SCN_MEM_WRITE,
|
||||
sizeof(data), sizeof(data));
|
||||
|
||||
scc_winpe_idata_builder_t idata_builder;
|
||||
scc_winpe_idata_lib_vec_t idata_libs;
|
||||
scc_vec_init(idata_libs);
|
||||
scc_winpe_idata_lib_t ucrtbase;
|
||||
ucrtbase.name = "ucrtbase.dll";
|
||||
scc_vec_init(ucrtbase.symbol_names);
|
||||
scc_vec_push(ucrtbase.symbol_names, "puts");
|
||||
scc_vec_push(idata_libs, ucrtbase);
|
||||
scc_pe_idata_builder_init(&idata_builder, &idata_libs);
|
||||
u32 idata_size = scc_pe_reserve_idata(&idata_builder);
|
||||
scc_pe_section_range idata_range = scc_pe_reserve_section_header(
|
||||
&builder, (BYTE *)".idata\0",
|
||||
IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ |
|
||||
IMAGE_SCN_MEM_WRITE,
|
||||
idata_size, idata_size);
|
||||
scc_vec_at(builder.image_data_directory_vec, IMAGE_DIRECTORY_ENTRY_IMPORT) =
|
||||
(IMAGE_DATA_DIRECTORY){.VirtualAddress = idata_range.virual_address,
|
||||
.Size = idata_range.virual_size};
|
||||
scc_pe_buffer_t idata_buffer =
|
||||
scc_pe_construct_idata(&idata_builder, &idata_range);
|
||||
|
||||
u32 entry_point_offset = 0;
|
||||
u64 base_address = 0x140000000;
|
||||
u32 entry_point = code_range.virual_address + entry_point_offset;
|
||||
scc_pe_config_t config = (scc_pe_config_t){
|
||||
.machine = IMAGE_FILE_MACHINE_AMD64,
|
||||
.time_date_stamp = 0,
|
||||
.characteristics =
|
||||
IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_LARGE_ADDRESS_AWARE,
|
||||
.major_linker_version = 14,
|
||||
.minor_linker_version = 0,
|
||||
.address_of_entry_point = entry_point,
|
||||
.image_base = base_address,
|
||||
.major_operating_system_version = 6,
|
||||
.minor_operating_system_version = 0,
|
||||
.major_image_version = 0,
|
||||
.minor_image_version = 0,
|
||||
.major_subsystem_version = 6,
|
||||
.minor_subsystem_version = 0,
|
||||
.subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI,
|
||||
.dll_characteristics = IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA |
|
||||
IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE |
|
||||
IMAGE_DLLCHARACTERISTICS_NX_COMPAT,
|
||||
.size_of_stack_reserve = 0x100000,
|
||||
.size_of_stack_commit = 0x1000,
|
||||
.size_of_heap_reserve = 0x100000,
|
||||
.size_of_heap_commit = 0x1000,
|
||||
};
|
||||
|
||||
// FIXME 需要确保宿主机为小端
|
||||
*(u32 *)((u8 *)code + 7) =
|
||||
(data_range.virual_address + 0) - (code_range.virual_address + 7 + 4);
|
||||
*(u32 *)((u8 *)code + 13) =
|
||||
(u64)scc_pe_idata_get_symbol_rva(&idata_builder, "puts") -
|
||||
(code_range.virual_address + 13 + 4);
|
||||
|
||||
scc_pe_write_header(&builder, &config);
|
||||
scc_pe_write_section(&builder, &code_range, (u8 *)code, sizeof(code));
|
||||
scc_pe_write_section(&builder, &data_range, (u8 *)data, sizeof(data));
|
||||
scc_pe_write_section(&builder, &idata_range,
|
||||
scc_vec_unsafe_get_data(idata_buffer),
|
||||
scc_vec_size(idata_buffer));
|
||||
|
||||
scc_pe_dump_to_file(&builder, "hello_world.exe");
|
||||
}
|
||||
369
libs/target/pe/src/scc_pe_builder.c
Normal file
369
libs/target/pe/src/scc_pe_builder.c
Normal file
@@ -0,0 +1,369 @@
|
||||
#include <scc_pe_builder.h>
|
||||
|
||||
#define reserve_align(offset, size) ((offset) + ((size) - 1)) & ~((size) - 1)
|
||||
|
||||
void scc_pe_builder_init(scc_pe_builder_t *builder, bool is_64,
|
||||
u32 section_alignment, u32 file_alignment) {
|
||||
scc_memset(builder, 0, sizeof(scc_pe_builder_t));
|
||||
builder->is_64 = is_64;
|
||||
builder->section_alignment = section_alignment;
|
||||
builder->file_alignment = file_alignment;
|
||||
builder->file_offset = 0;
|
||||
}
|
||||
|
||||
static u32 reserve_file(scc_pe_builder_t *builder, u32 len, u32 align) {
|
||||
if (len == 0) {
|
||||
return len;
|
||||
}
|
||||
|
||||
builder->file_offset = reserve_align(builder->file_offset, align);
|
||||
u32 offset = builder->file_offset;
|
||||
builder->file_offset += len;
|
||||
LOG_INFO("reserve_file %u bytes at %u [%u]", len, offset,
|
||||
builder->file_offset);
|
||||
return offset;
|
||||
}
|
||||
|
||||
static u32 reserve_virtual(scc_pe_builder_t *builder, u32 len, u32 align) {
|
||||
if (len == 0) {
|
||||
return len;
|
||||
}
|
||||
|
||||
u32 offset = builder->virtual_offset;
|
||||
builder->virtual_offset += len;
|
||||
builder->virtual_offset = reserve_align(builder->virtual_offset, align);
|
||||
LOG_INFO("reserve_virtual %u bytes at %u [%u]", len, offset,
|
||||
builder->virtual_offset);
|
||||
return offset;
|
||||
}
|
||||
|
||||
static void padding_util(scc_pe_builder_t *builder, u32 len) {
|
||||
if (builder->buffer.size > len) {
|
||||
LOG_FATAL("padding_util less than buffer size [%u]:[%u]",
|
||||
builder->buffer.size, len);
|
||||
return;
|
||||
}
|
||||
|
||||
for (usize i = builder->buffer.size; i < len; i++) {
|
||||
scc_vec_push(builder->buffer, 0);
|
||||
}
|
||||
|
||||
Assert(builder->buffer.size == len);
|
||||
}
|
||||
|
||||
void scc_pe_reserve_dos_header_and_stub(scc_pe_builder_t *builder) {
|
||||
Assert(builder->file_offset == 0);
|
||||
reserve_file(builder, sizeof(IMAGE_DOS_HEADER), 1);
|
||||
reserve_file(builder, 64, 1);
|
||||
}
|
||||
|
||||
void scc_pe_reserve_nt_header(scc_pe_builder_t *builder,
|
||||
usize data_directory_num) {
|
||||
builder->nt_headers_offset =
|
||||
reserve_file(builder,
|
||||
builder->is_64 ? sizeof(IMAGE_NT_HEADERS64)
|
||||
: sizeof(IMAGE_NT_HEADERS32),
|
||||
8);
|
||||
|
||||
LOG_INFO("scc_pe_reserve_nt_header %u", builder->nt_headers_offset);
|
||||
scc_vec_init(builder->image_data_directory_vec);
|
||||
for (usize i = 0; i < data_directory_num; i += 1) {
|
||||
scc_vec_push(builder->image_data_directory_vec,
|
||||
(IMAGE_DATA_DIRECTORY){0});
|
||||
}
|
||||
reserve_file(builder, sizeof(IMAGE_DATA_DIRECTORY) * data_directory_num, 1);
|
||||
}
|
||||
|
||||
void scc_pe_reserve_section_headers(scc_pe_builder_t *builder,
|
||||
u32 num_of_section) {
|
||||
builder->section_header_num = num_of_section;
|
||||
reserve_file(builder, sizeof(IMAGE_SECTION_HEADER) * num_of_section, 1);
|
||||
builder->file_offset =
|
||||
reserve_align(builder->file_offset, builder->file_alignment);
|
||||
builder->sizeof_headers = builder->file_offset;
|
||||
reserve_virtual(builder, builder->file_offset, builder->section_alignment);
|
||||
}
|
||||
|
||||
void scc_pe_reserve_header(scc_pe_builder_t *builder, u32 num_of_section) {
|
||||
scc_pe_reserve_dos_header_and_stub(builder);
|
||||
scc_pe_reserve_nt_header(builder, IMAGE_NUMBEROF_DIRECTORY_ENTRIES);
|
||||
scc_pe_reserve_section_headers(builder, num_of_section);
|
||||
}
|
||||
|
||||
void scc_pe_write_dos_header_and_stub(scc_pe_builder_t *builder) {
|
||||
IMAGE_DOS_HEADER dos_header;
|
||||
dos_header.e_magic = IMAGE_DOS_SIGNATURE;
|
||||
dos_header.e_cblp = 0x90;
|
||||
dos_header.e_cp = 3;
|
||||
dos_header.e_crlc = 0;
|
||||
dos_header.e_cparhdr = 4;
|
||||
dos_header.e_minalloc = 0;
|
||||
dos_header.e_maxalloc = 0xFFFF;
|
||||
dos_header.e_ss = 0x00;
|
||||
dos_header.e_sp = 0xB8;
|
||||
dos_header.e_csum = 0;
|
||||
dos_header.e_ip = 0x00;
|
||||
dos_header.e_cs = 0x00;
|
||||
dos_header.e_lfarlc = 0x40;
|
||||
dos_header.e_ovno = 0x00;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
dos_header.e_res[i] = 0x00;
|
||||
}
|
||||
dos_header.e_oemid = 0x00;
|
||||
dos_header.e_oeminfo = 0x00;
|
||||
for (int i = 0; i < 10; i++) {
|
||||
dos_header.e_res2[i] = 0x00;
|
||||
}
|
||||
dos_header.e_lfanew = builder->nt_headers_offset;
|
||||
|
||||
for (usize i = 0; i < sizeof(dos_header); ++i) {
|
||||
scc_vec_push(builder->buffer, ((u8 *)(&dos_header))[i]);
|
||||
}
|
||||
static const u8 dos_header_bytes[] = {
|
||||
0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd, 0x21, 0xb8, 0x01,
|
||||
0x4c, 0xcd, 0x21, 0x54, 0x68, 0x69, 0x73, 0x20, 0x70, 0x72, 0x6f,
|
||||
0x67, 0x72, 0x61, 0x6d, 0x20, 0x63, 0x61, 0x6e, 0x6e, 0x6f, 0x74,
|
||||
0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6e, 0x20, 0x69, 0x6e, 0x20,
|
||||
0x44, 0x4f, 0x53, 0x20, 0x6d, 0x6f, 0x64, 0x65, 0x2e, 0x0d, 0x0d,
|
||||
0x0a, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
for (usize i = 0; i < sizeof(dos_header_bytes); i++) {
|
||||
scc_vec_push(builder->buffer, ((u8 *)(&dos_header_bytes))[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void scc_pe_write_nt_header_with_config(scc_pe_builder_t *builder,
|
||||
const scc_pe_config_t *config) {
|
||||
IMAGE_NT_HEADERS32 nt_headers32 = {0};
|
||||
IMAGE_NT_HEADERS64 nt_headers64 = {0};
|
||||
|
||||
// 写入PE签名
|
||||
DWORD *signature =
|
||||
builder->is_64 ? &nt_headers64.Signature : &nt_headers32.Signature;
|
||||
*signature = SCC_LE32(IMAGE_NT_SIGNATURE);
|
||||
|
||||
// 构建文件头
|
||||
IMAGE_FILE_HEADER *file_header =
|
||||
builder->is_64 ? &nt_headers64.FileHeader : &nt_headers32.FileHeader;
|
||||
file_header->Machine = SCC_LE16(config->machine);
|
||||
file_header->NumberOfSections = SCC_LE16(builder->section_header_num);
|
||||
file_header->TimeDateStamp = SCC_LE32(config->time_date_stamp);
|
||||
file_header->PointerToSymbolTable = SCC_LE32(builder->symbol_offset);
|
||||
file_header->NumberOfSymbols = SCC_LE32(builder->symbol_num);
|
||||
// 设置可选头大小
|
||||
if (builder->is_64) {
|
||||
file_header->SizeOfOptionalHeader =
|
||||
SCC_LE16(sizeof(IMAGE_OPTIONAL_HEADER64) +
|
||||
scc_vec_size(builder->image_data_directory_vec) *
|
||||
sizeof(IMAGE_DATA_DIRECTORY));
|
||||
} else {
|
||||
file_header->SizeOfOptionalHeader =
|
||||
SCC_LE16(sizeof(IMAGE_OPTIONAL_HEADER32) +
|
||||
scc_vec_size(builder->image_data_directory_vec) *
|
||||
sizeof(IMAGE_DATA_DIRECTORY));
|
||||
}
|
||||
file_header->Characteristics = SCC_LE16(config->characteristics);
|
||||
|
||||
// 根据是否为64位写入不同的可选头
|
||||
if (builder->is_64) {
|
||||
IMAGE_OPTIONAL_HEADER64 *optional = &nt_headers64.OptionalHeader;
|
||||
optional->Magic = SCC_LE16(IMAGE_NT_OPTIONAL_HDR64_MAGIC);
|
||||
optional->MajorLinkerVersion = config->major_linker_version;
|
||||
optional->MinorLinkerVersion = config->minor_linker_version;
|
||||
optional->SizeOfCode = SCC_LE32(builder->sizeof_code);
|
||||
optional->SizeOfInitializedData = SCC_LE32(builder->sizeof_init_data);
|
||||
optional->SizeOfUninitializedData =
|
||||
SCC_LE32(builder->sizeof_uninit_data);
|
||||
optional->AddressOfEntryPoint =
|
||||
SCC_LE32(config->address_of_entry_point);
|
||||
optional->BaseOfCode = SCC_LE32(builder->baseof_code);
|
||||
optional->ImageBase = SCC_LE64(config->image_base);
|
||||
optional->SectionAlignment = SCC_LE32(builder->section_alignment);
|
||||
optional->FileAlignment = SCC_LE32(builder->file_alignment);
|
||||
optional->MajorOperatingSystemVersion =
|
||||
SCC_LE16(config->major_operating_system_version);
|
||||
optional->MinorOperatingSystemVersion =
|
||||
SCC_LE16(config->minor_operating_system_version);
|
||||
optional->MajorImageVersion = SCC_LE16(config->major_image_version);
|
||||
optional->MinorImageVersion = SCC_LE16(config->minor_image_version);
|
||||
optional->MajorSubsystemVersion =
|
||||
SCC_LE16(config->major_subsystem_version);
|
||||
optional->MinorSubsystemVersion =
|
||||
SCC_LE16(config->minor_subsystem_version);
|
||||
optional->Win32VersionValue = SCC_LE32(0);
|
||||
optional->SizeOfImage = SCC_LE32(builder->virtual_offset);
|
||||
optional->SizeOfHeaders = SCC_LE32(builder->sizeof_headers);
|
||||
optional->CheckSum = SCC_LE32(0);
|
||||
optional->Subsystem = SCC_LE16(config->subsystem);
|
||||
optional->DllCharacteristics = SCC_LE16(config->dll_characteristics);
|
||||
optional->SizeOfStackReserve = SCC_LE64(config->size_of_stack_reserve);
|
||||
optional->SizeOfStackCommit = SCC_LE64(config->size_of_stack_commit);
|
||||
optional->SizeOfHeapReserve = SCC_LE64(config->size_of_heap_reserve);
|
||||
optional->SizeOfHeapCommit = SCC_LE64(config->size_of_heap_commit);
|
||||
optional->LoaderFlags = SCC_LE32(0);
|
||||
optional->NumberOfRvaAndSizes =
|
||||
SCC_LE32(scc_vec_size(builder->image_data_directory_vec));
|
||||
} else {
|
||||
IMAGE_OPTIONAL_HEADER32 *optional = &nt_headers32.OptionalHeader;
|
||||
optional->Magic = SCC_LE16(IMAGE_NT_OPTIONAL_HDR32_MAGIC);
|
||||
optional->MajorLinkerVersion = config->major_linker_version;
|
||||
optional->MinorLinkerVersion = config->minor_linker_version;
|
||||
optional->SizeOfCode = SCC_LE32(builder->sizeof_code);
|
||||
optional->SizeOfInitializedData = SCC_LE32(builder->sizeof_init_data);
|
||||
optional->SizeOfUninitializedData =
|
||||
SCC_LE32(builder->sizeof_uninit_data);
|
||||
optional->AddressOfEntryPoint =
|
||||
SCC_LE32(config->address_of_entry_point);
|
||||
optional->BaseOfCode = SCC_LE32(builder->baseof_code);
|
||||
optional->BaseOfData = SCC_LE32(builder->baseof_data); // 32位特有的字段
|
||||
optional->ImageBase =
|
||||
SCC_LE32((uint32_t)(config->image_base & 0xFFFFFFFF));
|
||||
optional->SectionAlignment = SCC_LE32(builder->section_alignment);
|
||||
optional->FileAlignment = SCC_LE32(builder->file_alignment);
|
||||
optional->MajorOperatingSystemVersion =
|
||||
SCC_LE16(config->major_operating_system_version);
|
||||
optional->MinorOperatingSystemVersion =
|
||||
SCC_LE16(config->minor_operating_system_version);
|
||||
optional->MajorImageVersion = SCC_LE16(config->major_image_version);
|
||||
optional->MinorImageVersion = SCC_LE16(config->minor_image_version);
|
||||
optional->MajorSubsystemVersion =
|
||||
SCC_LE16(config->major_subsystem_version);
|
||||
optional->MinorSubsystemVersion =
|
||||
SCC_LE16(config->minor_subsystem_version);
|
||||
optional->Win32VersionValue = SCC_LE32(0);
|
||||
optional->SizeOfImage = SCC_LE32(builder->virtual_offset);
|
||||
optional->SizeOfHeaders = SCC_LE32(builder->sizeof_headers);
|
||||
optional->CheckSum = SCC_LE32(0);
|
||||
optional->Subsystem = SCC_LE16(config->subsystem);
|
||||
optional->DllCharacteristics = SCC_LE16(config->dll_characteristics);
|
||||
optional->SizeOfStackReserve =
|
||||
SCC_LE32((uint32_t)(config->size_of_stack_reserve & 0xFFFFFFFF));
|
||||
optional->SizeOfStackCommit =
|
||||
SCC_LE32((uint32_t)(config->size_of_stack_commit & 0xFFFFFFFF));
|
||||
optional->SizeOfHeapReserve =
|
||||
SCC_LE32((uint32_t)(config->size_of_heap_reserve & 0xFFFFFFFF));
|
||||
optional->SizeOfHeapCommit =
|
||||
SCC_LE32((uint32_t)(config->size_of_heap_commit & 0xFFFFFFFF));
|
||||
optional->LoaderFlags = SCC_LE32(0);
|
||||
optional->NumberOfRvaAndSizes =
|
||||
SCC_LE32(scc_vec_size(builder->image_data_directory_vec));
|
||||
}
|
||||
|
||||
if (builder->is_64) {
|
||||
for (usize i = 0; i < sizeof(nt_headers64); i++) {
|
||||
scc_vec_push(builder->buffer, ((u8 *)(&nt_headers64))[i]);
|
||||
}
|
||||
} else {
|
||||
for (usize i = 0; i < sizeof(nt_headers32); i++) {
|
||||
scc_vec_push(builder->buffer, ((u8 *)(&nt_headers32))[i]);
|
||||
}
|
||||
}
|
||||
|
||||
scc_vec_foreach(builder->image_data_directory_vec, i) {
|
||||
IMAGE_DATA_DIRECTORY *data =
|
||||
&scc_vec_at(builder->image_data_directory_vec, i);
|
||||
for (usize i = 0; i < sizeof(IMAGE_DATA_DIRECTORY); i++) {
|
||||
scc_vec_push(builder->buffer, ((u8 *)(data))[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void scc_pe_write_section_headers(scc_pe_builder_t *builder) {
|
||||
Assert(builder->section_header_num ==
|
||||
builder->image_section_header_vec.size);
|
||||
scc_vec_foreach(builder->image_section_header_vec, i) {
|
||||
IMAGE_SECTION_HEADER *section_header =
|
||||
&scc_vec_at(builder->image_section_header_vec, i);
|
||||
for (usize j = 0; j < sizeof(IMAGE_SECTION_HEADER); j += 1) {
|
||||
scc_vec_push(builder->buffer, ((u8 *)section_header)[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void scc_pe_write_header(scc_pe_builder_t *builder, scc_pe_config_t *config) {
|
||||
scc_vec_init(builder->buffer);
|
||||
scc_pe_write_dos_header_and_stub(builder);
|
||||
padding_util(builder, builder->nt_headers_offset);
|
||||
scc_pe_write_nt_header_with_config(builder, config);
|
||||
scc_pe_write_section_headers(builder);
|
||||
}
|
||||
|
||||
scc_pe_section_range scc_pe_reserve_section_header(scc_pe_builder_t *builder,
|
||||
BYTE name[8],
|
||||
u32 characteristics,
|
||||
u32 virtual_size,
|
||||
u32 data_size) {
|
||||
scc_pe_section_range range = {0};
|
||||
range.virual_address =
|
||||
reserve_virtual(builder, virtual_size, builder->section_alignment);
|
||||
range.virual_size = virtual_size;
|
||||
|
||||
range.file_size = reserve_align(data_size, builder->file_alignment);
|
||||
range.file_offset =
|
||||
range.file_size != 0
|
||||
? reserve_file(builder, range.file_size, builder->file_alignment)
|
||||
: 0;
|
||||
|
||||
u32 aligned_virtual_size =
|
||||
reserve_align(virtual_size, builder->file_alignment);
|
||||
|
||||
if (characteristics & IMAGE_SCN_CNT_CODE) {
|
||||
if (!builder->baseof_code) {
|
||||
builder->baseof_code = range.virual_address;
|
||||
}
|
||||
builder->sizeof_code += aligned_virtual_size;
|
||||
} else if (characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA) {
|
||||
if (!builder->baseof_data) {
|
||||
builder->baseof_data = range.virual_address;
|
||||
}
|
||||
builder->sizeof_init_data += aligned_virtual_size;
|
||||
} else if (characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA) {
|
||||
if (!builder->baseof_data) {
|
||||
builder->baseof_data = range.virual_address;
|
||||
}
|
||||
builder->sizeof_uninit_data += aligned_virtual_size;
|
||||
}
|
||||
|
||||
IMAGE_SECTION_HEADER section_header = (IMAGE_SECTION_HEADER){
|
||||
.Name[0] = name[0],
|
||||
.Name[1] = name[1],
|
||||
.Name[2] = name[2],
|
||||
.Name[3] = name[3],
|
||||
.Name[4] = name[4],
|
||||
.Name[5] = name[5],
|
||||
.Name[6] = name[6],
|
||||
.Name[7] = name[7],
|
||||
.Misc.VirtualSize = SCC_LE32(range.virual_size),
|
||||
.VirtualAddress = SCC_LE32(range.virual_address),
|
||||
.SizeOfRawData = SCC_LE32(range.file_size),
|
||||
.PointerToRawData = SCC_LE32(range.file_offset),
|
||||
.PointerToRelocations = SCC_LE32(0),
|
||||
.PointerToLinenumbers = SCC_LE32(0),
|
||||
.NumberOfRelocations = SCC_LE16(0),
|
||||
.NumberOfLinenumbers = SCC_LE16(0),
|
||||
.Characteristics = SCC_LE32(characteristics),
|
||||
};
|
||||
scc_vec_push(builder->image_section_header_vec, section_header);
|
||||
return range;
|
||||
}
|
||||
|
||||
void scc_pe_write_section(scc_pe_builder_t *builder,
|
||||
scc_pe_section_range *range, u8 *data,
|
||||
usize data_size) {
|
||||
if (range == null || data == null || data_size == 0) {
|
||||
return;
|
||||
}
|
||||
padding_util(builder, range->file_offset);
|
||||
for (usize i = 0; i < data_size; i += 1) {
|
||||
scc_vec_push(builder->buffer, data[i]);
|
||||
}
|
||||
usize size = scc_vec_size(builder->buffer);
|
||||
size = reserve_align(size, builder->file_alignment);
|
||||
padding_util(builder, size);
|
||||
}
|
||||
|
||||
void scc_pe_dump_to_file(scc_pe_builder_t *builder, const char *file_path) {
|
||||
scc_file_t fp = scc_fopen(file_path, SCC_FILE_WRITE);
|
||||
scc_fwrite(fp, builder->buffer.data, builder->buffer.size);
|
||||
scc_fclose(fp);
|
||||
}
|
||||
171
libs/target/pe/src/scc_pe_idata.c
Normal file
171
libs/target/pe/src/scc_pe_idata.c
Normal file
@@ -0,0 +1,171 @@
|
||||
#include <scc_pe_idata.h>
|
||||
|
||||
// RVA Relative Virtual Address
|
||||
static inline IMAGE_IMPORT_DESCRIPTOR
|
||||
image_import_descriptor_init(u32 import_lookup_table_rva, u32 name_rva,
|
||||
u32 import_address_table_rva) {
|
||||
IMAGE_IMPORT_DESCRIPTOR iid = {0};
|
||||
iid.DUMMYUNIONNAME.OriginalFirstThunk = SCC_LE32(import_lookup_table_rva);
|
||||
iid.TimeDateStamp = SCC_LE32(0);
|
||||
iid.ForwarderChain = SCC_LE32(0);
|
||||
iid.Name = SCC_LE32(name_rva);
|
||||
iid.FirstThunk = SCC_LE32(import_address_table_rva);
|
||||
return iid;
|
||||
};
|
||||
|
||||
static void scc_winpe_hnt_builder_push(scc_winpe_hnt_builder_t *builder,
|
||||
const char *name, u16 hint);
|
||||
static void scc_winpe_hnt_builder_init(scc_winpe_hnt_builder_t *builder) {
|
||||
scc_vec_init(builder->data);
|
||||
builder->section_offset = 0;
|
||||
scc_hashtable_init(&builder->str_map,
|
||||
(scc_hashtable_hash_func_t)scc_strhash32,
|
||||
(scc_hashtable_equal_func_t)scc_strcmp);
|
||||
}
|
||||
|
||||
static void scc_winpe_hnt_builder_push(scc_winpe_hnt_builder_t *builder,
|
||||
const char *name, u16 hint) {
|
||||
///< 可选哈希表去重
|
||||
if (scc_hashtable_get(&builder->str_map, name)) {
|
||||
return;
|
||||
}
|
||||
scc_hashtable_set(&builder->str_map, name, (void *)(u64)builder->data.size);
|
||||
|
||||
/// FIXME WARNING需要转换为little endian
|
||||
scc_vec_push(builder->data, hint >> 8);
|
||||
scc_vec_push(builder->data, hint & 0xff);
|
||||
|
||||
while (*name) {
|
||||
scc_vec_push(builder->data, *name);
|
||||
name++;
|
||||
}
|
||||
scc_vec_push(builder->data, 0);
|
||||
|
||||
if (scc_vec_size(builder->data) % 2 != 0) {
|
||||
scc_vec_push(builder->data, 0);
|
||||
}
|
||||
|
||||
// return scc_vec_size(builder->data);
|
||||
Assert(scc_vec_size(builder->data) % 2 == 0);
|
||||
}
|
||||
|
||||
static u64 scc_winpe_hnt_get_offset(scc_winpe_hnt_builder_t *builder,
|
||||
const char *name) {
|
||||
return (u64)scc_hashtable_get(&builder->str_map, name);
|
||||
}
|
||||
|
||||
void scc_pe_idata_builder_init(scc_winpe_idata_builder_t *builder,
|
||||
scc_winpe_idata_lib_vec_t *idata_libs) {
|
||||
scc_vec_init(builder->buffer);
|
||||
builder->idata_libs = *idata_libs;
|
||||
|
||||
scc_winpe_hnt_builder_init(&builder->hnt_builder);
|
||||
|
||||
scc_hashtable_init(&builder->iat_map,
|
||||
(scc_hashtable_hash_func_t)scc_strhash32,
|
||||
(scc_hashtable_equal_func_t)scc_strcmp);
|
||||
}
|
||||
|
||||
u32 scc_pe_reserve_idata(scc_winpe_idata_builder_t *builder) {
|
||||
u32 idata_size = (scc_vec_size(builder->idata_libs) + 1) *
|
||||
sizeof(IMAGE_IMPORT_DESCRIPTOR);
|
||||
|
||||
scc_vec_foreach(builder->idata_libs, i) {
|
||||
scc_winpe_idata_lib_t *lib = &scc_vec_at(builder->idata_libs, i);
|
||||
idata_size += (scc_vec_size(lib->symbol_names) + 1) * 2 *
|
||||
sizeof(IMAGE_THUNK_DATA64);
|
||||
scc_winpe_hnt_builder_push(&builder->hnt_builder, lib->name, 0);
|
||||
|
||||
scc_vec_foreach(lib->symbol_names, j) {
|
||||
scc_winpe_hnt_builder_push(&builder->hnt_builder,
|
||||
scc_vec_at(lib->symbol_names, j), 0);
|
||||
}
|
||||
}
|
||||
builder->hnt_builder.section_offset = idata_size;
|
||||
idata_size += scc_vec_size(builder->hnt_builder.data);
|
||||
|
||||
scc_vec_realloc(builder->buffer, idata_size);
|
||||
scc_vec_size(builder->buffer) = idata_size;
|
||||
return idata_size;
|
||||
}
|
||||
|
||||
scc_pe_buffer_t scc_pe_construct_idata(scc_winpe_idata_builder_t *builder,
|
||||
scc_pe_section_range *idata_range) {
|
||||
u32 idata_rva = idata_range->virual_address;
|
||||
u32 hnt_offset = builder->hnt_builder.section_offset;
|
||||
|
||||
usize import_file_count = scc_vec_size(builder->idata_libs);
|
||||
usize current_offset =
|
||||
(import_file_count + 1) * sizeof(IMAGE_IMPORT_DESCRIPTOR);
|
||||
scc_vec_foreach(builder->idata_libs, i) {
|
||||
scc_winpe_idata_lib_t *lib = &scc_vec_at(builder->idata_libs, i);
|
||||
scc_winpe_lookup_table_vec_t lookup_table;
|
||||
scc_vec_init(lookup_table);
|
||||
|
||||
scc_vec_foreach(lib->symbol_names, j) {
|
||||
u64 name_offset = scc_winpe_hnt_get_offset(
|
||||
&builder->hnt_builder, scc_vec_at(lib->symbol_names, j));
|
||||
u64 name_rva = idata_rva + hnt_offset + name_offset;
|
||||
|
||||
IMAGE_THUNK_DATA64 lookup_table_entry = {.u1.AddressOfData =
|
||||
name_rva};
|
||||
scc_vec_push(lookup_table, lookup_table_entry);
|
||||
}
|
||||
scc_vec_push(lookup_table, (IMAGE_THUNK_DATA64){0});
|
||||
usize table_size =
|
||||
scc_vec_size(lookup_table) * sizeof(IMAGE_THUNK_DATA64);
|
||||
|
||||
usize ilt_offset = current_offset;
|
||||
usize iat_offset = ilt_offset + table_size;
|
||||
current_offset += table_size * 2;
|
||||
|
||||
scc_vec_foreach(lib->symbol_names, j) {
|
||||
// 构造IAT链接
|
||||
scc_hashtable_set(
|
||||
&builder->iat_map, scc_vec_at(lib->symbol_names, j),
|
||||
(void *)(usize)(idata_rva + j * sizeof(IMAGE_THUNK_DATA64)) +
|
||||
iat_offset);
|
||||
}
|
||||
|
||||
usize name_rva = idata_rva + hnt_offset +
|
||||
scc_winpe_hnt_get_offset(&builder->hnt_builder,
|
||||
lib->name); ///< hashtable get
|
||||
|
||||
// 构造并写入导入目录项
|
||||
// The address of an ASCII string that contains the name of the DLL.
|
||||
// This address is relative to the image base.
|
||||
// https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#import-directory-table
|
||||
// so add 2 to skip the two bytes of the Hint
|
||||
IMAGE_IMPORT_DESCRIPTOR dir_entry = image_import_descriptor_init(
|
||||
ilt_offset + idata_rva, name_rva + 2, iat_offset + idata_rva);
|
||||
scc_memcpy(
|
||||
&scc_vec_at(builder->buffer, i * sizeof(IMAGE_IMPORT_DESCRIPTOR)),
|
||||
&dir_entry,
|
||||
sizeof(IMAGE_IMPORT_DESCRIPTOR)); // FIXME 大小端
|
||||
|
||||
Assert(table_size ==
|
||||
scc_vec_size(lookup_table) * sizeof(IMAGE_THUNK_DATA64));
|
||||
|
||||
// 转换为字节序列并写入
|
||||
// FIXME 大小端
|
||||
// 写入ILT表
|
||||
scc_memcpy(&scc_vec_at(builder->buffer, ilt_offset),
|
||||
&scc_vec_at(lookup_table, 0), table_size);
|
||||
// 写入IAT表
|
||||
scc_memcpy(&scc_vec_at(builder->buffer, iat_offset),
|
||||
&scc_vec_at(lookup_table, 0), table_size);
|
||||
}
|
||||
|
||||
// 添加NULL终止的目录项
|
||||
IMAGE_IMPORT_DESCRIPTOR null_entry = image_import_descriptor_init(0, 0, 0);
|
||||
scc_memcpy(&scc_vec_at(builder->buffer,
|
||||
import_file_count * sizeof(IMAGE_IMPORT_DESCRIPTOR)),
|
||||
&null_entry, sizeof(IMAGE_IMPORT_DESCRIPTOR));
|
||||
|
||||
// 填充Hint/Name表
|
||||
scc_memcpy(&scc_vec_at(builder->buffer, hnt_offset),
|
||||
&scc_vec_at(builder->hnt_builder.data, 0),
|
||||
scc_vec_size(builder->hnt_builder.data));
|
||||
|
||||
return builder->buffer;
|
||||
}
|
||||
Reference in New Issue
Block a user