mirror of
https://github.com/Noratrieb/portability.git
synced 2026-01-15 16:25:02 +01:00
import ordinal
This commit is contained in:
parent
64c30e201d
commit
402efaee61
1 changed files with 100 additions and 62 deletions
162
src/lib.rs
162
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,8 +394,42 @@ 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)
|
|
||||||
|
// Read the single export directory table from the front
|
||||||
|
// https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#export-directory-table
|
||||||
|
|
||||||
|
// The export table consists of 3 tables.
|
||||||
|
// The Export Address Table is indexed by unbiased ordinals and contains the function pointers.
|
||||||
|
// If you have an ordinal, you need to subtract OrdinalBase to get the actual ordinal.
|
||||||
|
// If you do not have an ordinal but just have a name, you need to figure out the ordinal from the name.
|
||||||
|
// To do this, you binary search the asc sorted Name Pointer Table to find the index there.
|
||||||
|
// Then you look up the found index in the Ordinal Table (which has the same size) and grab the ordinal from there.
|
||||||
|
// Proceed with that ordinal to the Export Address Table as usual.
|
||||||
|
// You may be able to skip the binary search of the "hint" of the import is the correct index already.
|
||||||
|
|
||||||
|
let export_directory_table = bytemuck::cast_slice::<u8, ExportDirectoryTable>(
|
||||||
|
&img[img.opt_header.export_table.va as usize..]
|
||||||
|
[..size_of::<ExportDirectoryTable>()],
|
||||||
|
)[0];
|
||||||
|
tracing::debug!(
|
||||||
|
?export_directory_table,
|
||||||
|
"Export Directory Table of {dll_name}"
|
||||||
|
);
|
||||||
|
|
||||||
|
// This is not aligned..?
|
||||||
|
let mut names = vec![];
|
||||||
|
for name_ptr in (export_directory_table.name_pointer_rva as usize..)
|
||||||
|
.step_by(4)
|
||||||
|
.take(export_directory_table.number_of_name_pointers as usize)
|
||||||
|
{
|
||||||
|
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();
|
||||||
|
names.push(name.to_owned());
|
||||||
|
tracing::debug!(?name, "DLL {dll_name} has export");
|
||||||
|
}
|
||||||
|
|
||||||
|
LoadedDll::Real(img, export_directory_table, names)
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
panic!("could not find dll {dll_name:?}");
|
panic!("could not find dll {dll_name:?}");
|
||||||
|
|
@ -408,11 +445,47 @@ fn load<'pe>(pe: &'pe [u8], executable_path: &Path, is_dll: bool) -> Image<'pe>
|
||||||
if import_lookup == 0 {
|
if import_lookup == 0 {
|
||||||
break;
|
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 ordinal_name_flag = import_lookup >> 63;
|
||||||
if ordinal_name_flag == 1 {
|
let resolved_va = if ordinal_name_flag == 1 {
|
||||||
let ordinal_number = import_lookup & 0xFFFF;
|
let ordinal_number = import_lookup & 0xFFFF;
|
||||||
tracing::debug!(" import by ordinal: {ordinal_number}");
|
tracing::debug!(" import by ordinal: {ordinal_number}");
|
||||||
todo!("unsupported, import by ordinal");
|
|
||||||
|
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 {
|
} else {
|
||||||
let hint_name_table_rva = import_lookup & 0xFFFF_FFFF;
|
let hint_name_table_rva = import_lookup & 0xFFFF_FFFF;
|
||||||
let hint = bytemuck::cast_slice::<u8, u16>(
|
let hint = bytemuck::cast_slice::<u8, u16>(
|
||||||
|
|
@ -423,49 +496,20 @@ fn load<'pe>(pe: &'pe [u8], executable_path: &Path, is_dll: bool) -> Image<'pe>
|
||||||
.unwrap();
|
.unwrap();
|
||||||
tracing::debug!("import by name: hint={hint} name={func_name:?}");
|
tracing::debug!("import by name: hint={hint} name={func_name:?}");
|
||||||
|
|
||||||
let resolved_va = match &dll {
|
match &dll {
|
||||||
LoadedDll::Emulated => emulated::emulate(dll_name, func_name.to_str().unwrap())
|
LoadedDll::Emulated => emulated::emulate(dll_name, func_name.to_str().unwrap())
|
||||||
.unwrap_or_else(|| {
|
.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:?}");
|
||||||
}),
|
}),
|
||||||
LoadedDll::Real(img) => {
|
LoadedDll::Real(img, export_directory_table, names) => {
|
||||||
// Read the single export directory table from the front
|
let idx =
|
||||||
// https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#export-directory-table
|
if names.get(hint as usize) == Some(&func_name.to_owned()) {
|
||||||
|
hint as usize
|
||||||
// The export table consists of 3 tables.
|
} else {
|
||||||
// The Export Address Table is indexed by unbiased ordinals and contains the function pointers.
|
names.binary_search(&func_name.to_owned()).unwrap_or_else(|_| {
|
||||||
// If you have an ordinal, you need to subtract OrdinalBase to get the actual ordinal.
|
|
||||||
// If you do not have an ordinal but just have a name, you need to figure out the ordinal from the name.
|
|
||||||
// To do this, you binary search the asc sorted Name Pointer Table to find the index there.
|
|
||||||
// Then you look up the found index in the Ordinal Table (which has the same size) and grab the ordinal from there.
|
|
||||||
// Proceed with that ordinal to the Export Address Table as usual.
|
|
||||||
// You may be able to skip the binary search of the "hint" of the import is the correct index already.
|
|
||||||
|
|
||||||
let export_directory_table = bytemuck::cast_slice::<u8, ExportDirectoryTable>(
|
|
||||||
&img[img.opt_header.export_table.va as usize..]
|
|
||||||
[..size_of::<ExportDirectoryTable>()],
|
|
||||||
)[0];
|
|
||||||
tracing::debug!(?export_directory_table, "Export Directory Table of {dll_name}");
|
|
||||||
|
|
||||||
// This is not aligned..?
|
|
||||||
let mut names = vec![];
|
|
||||||
for name_ptr in (export_directory_table.name_pointer_rva as usize..)
|
|
||||||
.step_by(4)
|
|
||||||
.take(export_directory_table.number_of_name_pointers as usize)
|
|
||||||
{
|
|
||||||
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();
|
|
||||||
names.push(name);
|
|
||||||
tracing::debug!(?name, "DLL {dll_name} has export");
|
|
||||||
}
|
|
||||||
|
|
||||||
let idx = if names.get(hint as usize) == Some(&func_name) {
|
|
||||||
hint as usize
|
|
||||||
} else {
|
|
||||||
names.binary_search(&func_name).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}")
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
// https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#export-ordinal-table
|
// https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#export-ordinal-table
|
||||||
let ordinal_table = bytemuck::cast_slice::<u8, u16>(
|
let ordinal_table = bytemuck::cast_slice::<u8, u16>(
|
||||||
|
|
@ -474,27 +518,21 @@ 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>());
|
||||||
image.loaded[import_directory.import_address_table_rva as usize..]
|
image.loaded[import_directory.import_address_table_rva as usize..]
|
||||||
[i * size_of::<u64>()..][..size_of::<u64>()]
|
[i * size_of::<u64>()..][..size_of::<u64>()]
|
||||||
.copy_from_slice(&resolved_va.to_ne_bytes());
|
.copy_from_slice(&resolved_va.to_ne_bytes());
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue