This commit is contained in:
Folkert 2022-09-22 21:54:45 +02:00
parent 540d3c29f9
commit 9bbe0e029f
No known key found for this signature in database
GPG key ID: 1F17F6FFD112B97C

View file

@ -35,7 +35,10 @@ struct PeMetadata {
optional_header_offset: usize,
/// Symbols that the host imports, like roc__mainForHost_1_exposed_generic
imports: Vec<String>,
/// Symbols that the host exports, like roc_alloc
exports: MutMap<String, i64>,
dynamic_relocations: DynamicRelocationsPe,
@ -361,7 +364,7 @@ pub(crate) fn surgery_pe(
.map(|s| (s.name, s.offset_in_section as u64))
.collect();
redirect_dummy_dll_functions_help(executable, &symbols, &md.imports, md.thunks_start_offset);
redirect_dummy_dll_functions(executable, &symbols, &md.imports, md.thunks_start_offset);
remove_dummy_dll_import_table(
executable,
@ -738,12 +741,7 @@ fn mmap_mut(path: &Path, length: usize) -> MmapMut {
unsafe { MmapMut::map_mut(&out_file).unwrap_or_else(|e| internal_error!("{e}")) }
}
#[allow(dead_code)]
fn redirect_dummy_dll_functions(
executable: &mut [u8],
dynamic_relocations: &DynamicRelocationsPe,
function_definition_vas: &[(String, u64)],
) {
fn find_thunks_start_offset(exec_data: &[u8], dynamic_relocations: &DynamicRelocationsPe) -> usize {
// The host executable contains indirect calls to functions that the host should provide
//
// 14000105d: e8 8e 27 00 00 call 0x1400037f0
@ -770,14 +768,13 @@ fn redirect_dummy_dll_functions(
// sources:
//
// - https://learn.microsoft.com/en-us/archive/msdn-magazine/2002/february/inside-windows-win32-portable-executable-file-format-in-detail
const W: usize = std::mem::size_of::<ImageImportDescriptor>();
let dummy_import_desc_start = dynamic_relocations.imports_offset_in_file as usize
+ W * dynamic_relocations.dummy_import_index as usize;
let dummy_import_desc =
load_struct_inplace::<ImageImportDescriptor>(executable, dummy_import_desc_start);
load_struct_inplace::<ImageImportDescriptor>(exec_data, dummy_import_desc_start);
// per https://en.wikibooks.org/wiki/X86_Disassembly/Windows_Executable_Files#The_Import_directory,
//
@ -791,87 +788,35 @@ fn redirect_dummy_dll_functions(
let dummy_thunks_address_va = dummy_import_desc.first_thunk;
let dummy_thunks_address = dummy_thunks_address_va.get(LE);
dbg!(dummy_thunks_address);
let object = object::read::pe::PeFile64::parse(&*executable).unwrap();
let imports: Vec<_> = object
.imports()
.unwrap()
.iter()
.filter(|import| import.library() == b"roc-cheaty-lib.dll")
.map(|import| {
std::str::from_utf8(import.name())
.unwrap_or_default()
.to_owned()
})
.collect();
let data: &[u8] = executable;
let dos_header = object::pe::ImageDosHeader::parse(data).unwrap();
let dos_header = object::pe::ImageDosHeader::parse(exec_data).unwrap();
let mut offset = dos_header.nt_headers_offset().into();
use object::read::pe::ImageNtHeaders;
let (nt_headers, _data_directories) = ImageNtHeaders64::parse(data, &mut offset).unwrap();
let sections = nt_headers.sections(data, offset).unwrap();
let (nt_headers, _data_directories) = ImageNtHeaders64::parse(exec_data, &mut offset).unwrap();
let sections = nt_headers.sections(exec_data, offset).unwrap();
// so we look at what section this virtual address is in
// find the section the virtual address is in
let (section_va, offset_in_file) = sections
.iter()
.find_map(|section| {
section.pe_data_containing(data, dummy_thunks_address).map(
|(_section_data, section_va)| (section_va, section.pointer_to_raw_data.get(LE)),
)
section
.pe_data_containing(exec_data, dummy_thunks_address)
.map(|(_section_data, section_va)| {
(section_va, section.pointer_to_raw_data.get(LE))
})
})
.expect("Invalid thunk virtual address");
// and get the offset in the file of 0x1400037f0
let thunks_start_offset = (dummy_thunks_address - section_va + offset_in_file) as usize;
dbg!(&imports, thunks_start_offset);
redirect_dummy_dll_functions_help(
executable,
function_definition_vas,
&imports,
thunks_start_offset,
)
(dummy_thunks_address - section_va + offset_in_file) as usize
}
#[allow(dead_code)]
fn redirect_dummy_dll_functions_help(
fn redirect_dummy_dll_functions(
executable: &mut [u8],
function_definition_vas: &[(String, u64)],
imports: &[String],
thunks_start_offset: usize,
) {
// The host executable contains indirect calls to functions that the host should provide
//
// 14000105d: e8 8e 27 00 00 call 0x1400037f0
// 140001062: 89 c3 mov ebx,eax
// 140001064: b1 21 mov cl,0x21
//
// This `call` is an indirect call (see https://www.felixcloutier.com/x86/call, our call starts
// with 0xe8, so it is relative) In other words, at runtime the program will go to 0x1400037f0,
// read a pointer-sized value there, and jump to that location.
//
// The 0x1400037f0 virtual address is located in the .rdata section
//
// Sections:
// Idx Name Size VMA LMA File off Algn
// 0 .text 0000169a 0000000140001000 0000000140001000 00000600 2**4
// CONTENTS, ALLOC, LOAD, READONLY, CODE
// 1 .rdata 00000ba8 0000000140003000 0000000140003000 00001e00 2**4
// CONTENTS, ALLOC, LOAD, READONLY, DATA
//
// Our task is then to put a valid function pointer at 0x1400037f0. The value should be a
// virtual address pointing at the start of a function (which must be located in an executable
// section)
//
// sources:
//
// - https://learn.microsoft.com/en-us/archive/msdn-magazine/2002/february/inside-windows-win32-portable-executable-file-format-in-detail
// it could be that a symbol exposed by the app is not used by the host. We must skip unused symbols
let mut targets = function_definition_vas.iter();
'outer: for (i, name) in imports.iter().enumerate() {
@ -1385,6 +1330,35 @@ mod test {
increase_number_of_sections_help(PE_DYNHOST, &new_sections, &path);
}
fn redirect_dummy_dll_functions_test(
executable: &mut [u8],
dynamic_relocations: &DynamicRelocationsPe,
function_definition_vas: &[(String, u64)],
) {
let object = object::read::pe::PeFile64::parse(&*executable).unwrap();
let imports: Vec<_> = object
.imports()
.unwrap()
.iter()
.filter(|import| import.library() == b"roc-cheaty-lib.dll")
.map(|import| {
std::str::from_utf8(import.name())
.unwrap_or_default()
.to_owned()
})
.collect();
// and get the offset in the file of 0x1400037f0
let thunks_start_offset = find_thunks_start_offset(executable, dynamic_relocations);
redirect_dummy_dll_functions(
executable,
function_definition_vas,
&imports,
thunks_start_offset,
)
}
fn link_zig_host_and_app_help(dir: &Path) {
use object::ObjectSection;
@ -1658,7 +1632,7 @@ mod test {
.into_iter()
.map(|s| (s.name, s.offset_in_section as u64))
.collect();
redirect_dummy_dll_functions(&mut app, &dynamic_relocations, &symbols);
redirect_dummy_dll_functions_test(&mut app, &dynamic_relocations, &symbols);
remove_dummy_dll_import_table(
&mut app,
@ -1917,7 +1891,7 @@ mod test {
.into_iter()
.map(|s| (s.name, s.offset_in_section as u64))
.collect();
redirect_dummy_dll_functions(&mut app, &dynamic_relocations, &symbols);
redirect_dummy_dll_functions_test(&mut app, &dynamic_relocations, &symbols);
remove_dummy_dll_import_table(
&mut app,