mirror of
https://github.com/Noratrieb/portability.git
synced 2026-01-16 08:45:03 +01:00
import ordinal
This commit is contained in:
parent
64c30e201d
commit
402efaee61
1 changed files with 100 additions and 62 deletions
152
src/lib.rs
152
src/lib.rs
|
|
@ -2,7 +2,7 @@ mod emulated;
|
||||||
mod sys;
|
mod sys;
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
ffi::CStr,
|
ffi::{CStr, CString},
|
||||||
fmt::Debug,
|
fmt::Debug,
|
||||||
ops::Deref,
|
ops::Deref,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
|
|
@ -228,8 +228,7 @@ const IMAGE_FILE_MACHINE_ARM64: u16 = 0xaa64;
|
||||||
pub fn execute(pe: &[u8], executable_path: &Path) {
|
pub fn execute(pe: &[u8], executable_path: &Path) {
|
||||||
let image = load(pe, executable_path, false);
|
let image = load(pe, executable_path, false);
|
||||||
|
|
||||||
let entrypoint =
|
let entrypoint = image.base + image.opt_header.address_of_entry_point as usize;
|
||||||
image.opt_header.image_base as usize + image.opt_header.address_of_entry_point as usize;
|
|
||||||
tracing::debug!("YOLO to {:#x}", entrypoint);
|
tracing::debug!("YOLO to {:#x}", entrypoint);
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
|
|
@ -253,6 +252,10 @@ impl<'pe> Deref for Image<'pe> {
|
||||||
|
|
||||||
#[tracing::instrument(skip(pe, is_dll))]
|
#[tracing::instrument(skip(pe, is_dll))]
|
||||||
fn load<'pe>(pe: &'pe [u8], executable_path: &Path, is_dll: bool) -> Image<'pe> {
|
fn load<'pe>(pe: &'pe [u8], executable_path: &Path, is_dll: bool) -> Image<'pe> {
|
||||||
|
load_inner(pe, executable_path, is_dll)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_inner<'pe>(pe: &'pe [u8], executable_path: &Path, is_dll: bool) -> Image<'pe> {
|
||||||
let (coff_header, after_header) = parse_header(pe);
|
let (coff_header, after_header) = parse_header(pe);
|
||||||
|
|
||||||
match (std::env::consts::ARCH, coff_header.machine) {
|
match (std::env::consts::ARCH, coff_header.machine) {
|
||||||
|
|
@ -375,7 +378,7 @@ fn load<'pe>(pe: &'pe [u8], executable_path: &Path, is_dll: bool) -> Image<'pe>
|
||||||
|
|
||||||
enum LoadedDll {
|
enum LoadedDll {
|
||||||
Emulated,
|
Emulated,
|
||||||
Real(Image<'static>),
|
Real(Image<'static>, ExportDirectoryTable, Vec<CString>),
|
||||||
}
|
}
|
||||||
|
|
||||||
let dll = find_dll(&dll_name, executable_path);
|
let dll = find_dll(&dll_name, executable_path);
|
||||||
|
|
@ -391,44 +394,8 @@ fn load<'pe>(pe: &'pe [u8], executable_path: &Path, is_dll: bool) -> Image<'pe>
|
||||||
std::mem::ManuallyDrop::new(unsafe { memmap2::Mmap::map(&file).unwrap() });
|
std::mem::ManuallyDrop::new(unsafe { memmap2::Mmap::map(&file).unwrap() });
|
||||||
let mmap = unsafe { &*(&**mmap as *const [u8]) };
|
let mmap = unsafe { &*(&**mmap as *const [u8]) };
|
||||||
|
|
||||||
let image = load(&mmap, &path, true);
|
let img: Image<'static> = load(&mmap, &path, true);
|
||||||
LoadedDll::Real(image)
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
panic!("could not find dll {dll_name:?}");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let import_lookups = bytemuck::cast_slice::<u8, u64>(
|
|
||||||
&image.loaded[import_directory.import_address_table_rva as usize..],
|
|
||||||
)
|
|
||||||
.to_vec();
|
|
||||||
for (i, import_lookup) in import_lookups.iter().enumerate() {
|
|
||||||
let import_lookup = *import_lookup;
|
|
||||||
if import_lookup == 0 {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
let ordinal_name_flag = import_lookup >> 63;
|
|
||||||
if ordinal_name_flag == 1 {
|
|
||||||
let ordinal_number = import_lookup & 0xFFFF;
|
|
||||||
tracing::debug!(" import by ordinal: {ordinal_number}");
|
|
||||||
todo!("unsupported, import by ordinal");
|
|
||||||
} else {
|
|
||||||
let hint_name_table_rva = import_lookup & 0xFFFF_FFFF;
|
|
||||||
let hint = bytemuck::cast_slice::<u8, u16>(
|
|
||||||
&image.loaded[hint_name_table_rva as usize..][..2],
|
|
||||||
)[0];
|
|
||||||
let func_name =
|
|
||||||
CStr::from_bytes_until_nul(&image.loaded[hint_name_table_rva as usize + 2..])
|
|
||||||
.unwrap();
|
|
||||||
tracing::debug!("import by name: hint={hint} name={func_name:?}");
|
|
||||||
|
|
||||||
let resolved_va = match &dll {
|
|
||||||
LoadedDll::Emulated => emulated::emulate(dll_name, func_name.to_str().unwrap())
|
|
||||||
.unwrap_or_else(|| {
|
|
||||||
panic!("could not find function {func_name:?} in dll {dll_name:?}");
|
|
||||||
}),
|
|
||||||
LoadedDll::Real(img) => {
|
|
||||||
// Read the single export directory table from the front
|
// Read the single export directory table from the front
|
||||||
// https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#export-directory-table
|
// https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#export-directory-table
|
||||||
|
|
||||||
|
|
@ -445,7 +412,10 @@ fn load<'pe>(pe: &'pe [u8], executable_path: &Path, is_dll: bool) -> Image<'pe>
|
||||||
&img[img.opt_header.export_table.va as usize..]
|
&img[img.opt_header.export_table.va as usize..]
|
||||||
[..size_of::<ExportDirectoryTable>()],
|
[..size_of::<ExportDirectoryTable>()],
|
||||||
)[0];
|
)[0];
|
||||||
tracing::debug!(?export_directory_table, "Export Directory Table of {dll_name}");
|
tracing::debug!(
|
||||||
|
?export_directory_table,
|
||||||
|
"Export Directory Table of {dll_name}"
|
||||||
|
);
|
||||||
|
|
||||||
// This is not aligned..?
|
// This is not aligned..?
|
||||||
let mut names = vec![];
|
let mut names = vec![];
|
||||||
|
|
@ -455,14 +425,88 @@ fn load<'pe>(pe: &'pe [u8], executable_path: &Path, is_dll: bool) -> Image<'pe>
|
||||||
{
|
{
|
||||||
let name = u32::from_ne_bytes(img[name_ptr..][..4].try_into().unwrap());
|
let name = u32::from_ne_bytes(img[name_ptr..][..4].try_into().unwrap());
|
||||||
let name = CStr::from_bytes_until_nul(&img[name as usize..]).unwrap();
|
let name = CStr::from_bytes_until_nul(&img[name as usize..]).unwrap();
|
||||||
names.push(name);
|
names.push(name.to_owned());
|
||||||
tracing::debug!(?name, "DLL {dll_name} has export");
|
tracing::debug!(?name, "DLL {dll_name} has export");
|
||||||
}
|
}
|
||||||
|
|
||||||
let idx = if names.get(hint as usize) == Some(&func_name) {
|
LoadedDll::Real(img, export_directory_table, names)
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
panic!("could not find dll {dll_name:?}");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let import_lookups = bytemuck::cast_slice::<u8, u64>(
|
||||||
|
&image.loaded[import_directory.import_address_table_rva as usize..],
|
||||||
|
)
|
||||||
|
.to_vec();
|
||||||
|
for (i, import_lookup) in import_lookups.iter().enumerate() {
|
||||||
|
let import_lookup = *import_lookup;
|
||||||
|
if import_lookup == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn compute_export_rva(
|
||||||
|
export_directory_table: &ExportDirectoryTable,
|
||||||
|
unbiased_ordinal: usize,
|
||||||
|
img: &Image<'_>,
|
||||||
|
) -> usize {
|
||||||
|
let eat_addr_rva = export_directory_table.export_address_table_rva as usize
|
||||||
|
+ (unbiased_ordinal * 4);
|
||||||
|
let export_rva = u32::from_ne_bytes(img[eat_addr_rva..][..4].try_into().unwrap());
|
||||||
|
|
||||||
|
if (img.opt_header.export_table.va
|
||||||
|
..(img.opt_header.export_table.va + img.opt_header.export_table.size))
|
||||||
|
.contains(&export_rva)
|
||||||
|
{
|
||||||
|
todo!("symbol forwarding")
|
||||||
|
}
|
||||||
|
|
||||||
|
export_rva as usize
|
||||||
|
}
|
||||||
|
|
||||||
|
let ordinal_name_flag = import_lookup >> 63;
|
||||||
|
let resolved_va = if ordinal_name_flag == 1 {
|
||||||
|
let ordinal_number = import_lookup & 0xFFFF;
|
||||||
|
tracing::debug!(" import by ordinal: {ordinal_number}");
|
||||||
|
|
||||||
|
match &dll {
|
||||||
|
LoadedDll::Emulated => panic!("unsupported: emulated import via ordinal"),
|
||||||
|
LoadedDll::Real(img, export_directory_table, _) => {
|
||||||
|
// https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#export-ordinal-table
|
||||||
|
let unbiased_ordinal =
|
||||||
|
ordinal_number as usize - export_directory_table.ordinal_base as usize;
|
||||||
|
|
||||||
|
let export_rva = compute_export_rva(
|
||||||
|
export_directory_table,
|
||||||
|
unbiased_ordinal as usize,
|
||||||
|
img,
|
||||||
|
);
|
||||||
|
|
||||||
|
img.base + export_rva as usize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let hint_name_table_rva = import_lookup & 0xFFFF_FFFF;
|
||||||
|
let hint = bytemuck::cast_slice::<u8, u16>(
|
||||||
|
&image.loaded[hint_name_table_rva as usize..][..2],
|
||||||
|
)[0];
|
||||||
|
let func_name =
|
||||||
|
CStr::from_bytes_until_nul(&image.loaded[hint_name_table_rva as usize + 2..])
|
||||||
|
.unwrap();
|
||||||
|
tracing::debug!("import by name: hint={hint} name={func_name:?}");
|
||||||
|
|
||||||
|
match &dll {
|
||||||
|
LoadedDll::Emulated => emulated::emulate(dll_name, func_name.to_str().unwrap())
|
||||||
|
.unwrap_or_else(|| {
|
||||||
|
panic!("could not find function {func_name:?} in dll {dll_name:?}");
|
||||||
|
}),
|
||||||
|
LoadedDll::Real(img, export_directory_table, names) => {
|
||||||
|
let idx =
|
||||||
|
if names.get(hint as usize) == Some(&func_name.to_owned()) {
|
||||||
hint as usize
|
hint as usize
|
||||||
} else {
|
} else {
|
||||||
names.binary_search(&func_name).unwrap_or_else(|_| {
|
names.binary_search(&func_name.to_owned()).unwrap_or_else(|_| {
|
||||||
panic!("could not find function {func_name:?} in dll {dll_name}")
|
panic!("could not find function {func_name:?} in dll {dll_name}")
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
@ -474,20 +518,15 @@ fn load<'pe>(pe: &'pe [u8], executable_path: &Path, is_dll: bool) -> Image<'pe>
|
||||||
);
|
);
|
||||||
let unbiased_ordinal = ordinal_table[idx];
|
let unbiased_ordinal = ordinal_table[idx];
|
||||||
|
|
||||||
let eat_addr_rva = export_directory_table.export_address_table_rva as usize
|
let export_rva = compute_export_rva(
|
||||||
+ (unbiased_ordinal as usize * 4);
|
export_directory_table,
|
||||||
let export_rva =
|
unbiased_ordinal as usize,
|
||||||
u32::from_ne_bytes(img[eat_addr_rva..][..4].try_into().unwrap());
|
img,
|
||||||
|
);
|
||||||
if (img.opt_header.export_table.va
|
|
||||||
..(img.opt_header.export_table.va + img.opt_header.export_table.size))
|
|
||||||
.contains(&export_rva)
|
|
||||||
{
|
|
||||||
todo!("symbol forwarding of {func_name:?} in {dll_name}")
|
|
||||||
}
|
|
||||||
|
|
||||||
img.base + export_rva as usize
|
img.base + export_rva as usize
|
||||||
}
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(size_of::<usize>(), size_of::<u64>());
|
assert_eq!(size_of::<usize>(), size_of::<u64>());
|
||||||
|
|
@ -496,7 +535,6 @@ fn load<'pe>(pe: &'pe [u8], executable_path: &Path, is_dll: bool) -> Image<'pe>
|
||||||
.copy_from_slice(&resolved_va.to_ne_bytes());
|
.copy_from_slice(&resolved_va.to_ne_bytes());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
tracing::debug!("applying section protections");
|
tracing::debug!("applying section protections");
|
||||||
for section in section_table {
|
for section in section_table {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue