Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

readfile #68

Merged
merged 7 commits into from
Jan 12, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 26 additions & 23 deletions libmwemu/src/structures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1925,6 +1925,7 @@ impl SystemInfo32 {
}
}

#[derive(Debug)]
pub struct SystemInfo64 {
oem_id: u32,
processor_architecture: u32,
Expand All @@ -1949,38 +1950,40 @@ impl Default for SystemInfo64 {
impl SystemInfo64 {
pub fn new() -> SystemInfo64 {
SystemInfo64 {
oem_id: 0x1337,
processor_architecture: 9,
oem_id: 0,
processor_architecture: 9, // PROCESSOR_ARCHITECTURE_AMD64
reserved: 0,
page_size: 4090,
min_app_addr: 0,
max_app_addr: 0,
active_processor_mask: 1,
number_of_processors: 4,
processor_type: 586,
page_size: 4096,
min_app_addr: 0x10000,
max_app_addr: 0x7FFFFFFEFFFF,
active_processor_mask: 0xFF,
number_of_processors: 8,
processor_type: 8664,
alloc_granularity: 65536,
processor_level: 5,
processor_revision: 255,
processor_level: 6,
processor_revision: 0xA201,
}
}

pub fn save(&mut self, addr: u64, maps: &mut Maps) {
maps.write_dword(addr, self.oem_id);
maps.write_dword(addr + 4, self.processor_architecture);
maps.write_word(addr + 8, self.reserved);
maps.write_dword(addr + 10, self.page_size);
maps.write_qword(addr + 14, self.min_app_addr);
maps.write_qword(addr + 22, self.max_app_addr);
maps.write_qword(addr + 30, self.active_processor_mask);
maps.write_dword(addr + 38, self.number_of_processors);
maps.write_dword(addr + 42, self.processor_type);
maps.write_dword(addr + 46, self.alloc_granularity);
maps.write_word(addr + 50, self.processor_level);
maps.write_word(addr + 52, self.processor_revision);
// First union/struct (4 bytes total)
maps.write_word(addr + 0, self.processor_architecture as u16);
maps.write_word(addr + 2, self.reserved);

// Rest of the structure
maps.write_dword(addr + 4, self.page_size);
maps.write_qword(addr + 8, self.min_app_addr);
maps.write_qword(addr + 16, self.max_app_addr);
maps.write_qword(addr + 24, self.active_processor_mask);
maps.write_dword(addr + 32, self.number_of_processors);
maps.write_dword(addr + 36, self.processor_type);
maps.write_dword(addr + 40, self.alloc_granularity);
maps.write_word(addr + 44, self.processor_level);
maps.write_word(addr + 46, self.processor_revision);
}

pub fn size(&self) -> usize {
54
48
}
}

Expand Down
9 changes: 9 additions & 0 deletions libmwemu/src/winapi32/kernel32.rs
Original file line number Diff line number Diff line change
Expand Up @@ -935,6 +935,15 @@ fn DisconnectNamedPipe(emu: &mut emu::Emu) {
emu.regs.rax = 1;
}

/*
BOOL ReadFile(
[in] HANDLE hFile,
[out] LPVOID lpBuffer,
[in] DWORD nNumberOfBytesToRead,
[out, optional] LPDWORD lpNumberOfBytesRead,
[in, out, optional] LPOVERLAPPED lpOverlapped
);
*/
fn ReadFile(emu: &mut emu::Emu) {
let file_hndl = emu
.maps
Expand Down
225 changes: 220 additions & 5 deletions libmwemu/src/winapi64/crt_runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,11 @@ pub fn gateway(addr: u64, emu: &mut emu::Emu) -> String {
"_initialize_onexit_table" => _initialize_onexit_table(emu),
"_register_onexit_function" => _register_onexit_function(emu),
"_get_initial_narrow_environment" => _get_initial_narrow_environment(emu),
"realloc" => realloc(emu),
"__p___argv" => __p___argv(emu),
"__p___argc" => __p___argc(emu),
"__acrt_iob_func" => __acrt_iob_func(emu),
"__stdio_common_vfprintf" => __stdio_common_vfprintf(emu),
_ => {
if emu.cfg.skip_unimplemented == false {
if emu.cfg.dump_on_exit && emu.cfg.dump_filename.is_some() {
Expand Down Expand Up @@ -94,22 +97,58 @@ fn _get_initial_narrow_environment(emu: &mut emu::Emu) {
);

// TODO: Implement this
emu.regs.rax = 0;
}

// char*** CDECL __p___argv(void) { return &MSVCRT___argv; }
fn __p___argv(emu: &mut emu::Emu) {
let argv = emu.regs.rcx;

log::info!(
"{}** {} crt_runtime!__p___argv argv: 0x{:x} {}",
"{}** {} crt_runtime!__p___argv {}",
emu.colors.light_red,
emu.pos,
argv,
emu.colors.nc
);

// TODO: Implement this
// First, allocate space for argv array (pointer array)
// We'll allocate space for 2 pointers - one for program name and null terminator
let argv_array_addr = emu
.maps
.alloc(16) // 2 * sizeof(pointer) on x64
.expect("crt_runtime!__p___argv cannot allocate argv array");
emu.maps.create_map(&format!("alloc_{:x}", argv_array_addr), argv_array_addr, 16);

// Allocate space for program name string (using a dummy name)
let prog_name = "program.exe\0";
let prog_name_addr = emu
.maps
.alloc(prog_name.len() as u64)
.expect("crt_runtime!__p___argv cannot allocate program name");
emu.maps.create_map(&format!("alloc_{:x}", prog_name_addr), prog_name_addr, 16);

// Write program name string
emu.maps.write_string(prog_name_addr, prog_name);

// Write argv array:
// argv[0] = pointer to program name
emu.maps.write_qword(argv_array_addr, prog_name_addr);
// argv[1] = null terminator
emu.maps.write_qword(argv_array_addr + 8, 0);

// Allocate space for pointer to argv array
let p_argv_addr = emu
.maps
.alloc(8) // sizeof(pointer) on x64
.expect("crt_runtime!__p___argv cannot allocate p_argv");
emu.maps.create_map(&format!("alloc_{:x}", p_argv_addr), p_argv_addr, 8);

// Write pointer to argv array
emu.maps.write_qword(p_argv_addr, argv_array_addr);

// Return pointer to argv
emu.regs.rax = p_argv_addr;
}

// int* CDECL __p___argc(void) { return &MSVCRT___argc; }
fn __p___argc(emu: &mut emu::Emu) {
let argc = emu.regs.rcx;

Expand All @@ -121,5 +160,181 @@ fn __p___argc(emu: &mut emu::Emu) {
emu.colors.nc
);

let argc_addr = emu
.maps
.alloc(4)
.expect("crt_runtime!__p___argc cannot allocate");
emu.maps.create_map(&format!("alloc_{:x}", argc_addr), argc_addr, 4);
emu.maps.write_dword(argc_addr, 1);
emu.regs.rax = argc_addr;
}

/*
FILE * CDECL __acrt_iob_func(int index)
{
return &__iob_func()[index];
}
*/

fn __acrt_iob_func(emu: &mut emu::Emu) {
let index = emu.regs.rcx;

log::info!(
"{}** {} crt_runtime!__acrt_iob_func index: 0x{:x} {}",
emu.colors.light_red,
emu.pos,
index,
emu.colors.nc
);

// TODO: Implement this
emu.regs.rax = 0;
}

/*
_ACRTIMP int __cdecl __stdio_common_vfprintf(unsigned __int64,FILE*,const char*,_locale_t,__ms_va_list);
*/
fn parse_format_specifiers(fmt: &str) -> Vec<&str> {
let mut specs = Vec::new();
let mut chars = fmt.chars().peekable();

while let Some(c) = chars.next() {
if c == '%' {
if let Some(next) = chars.next() {
if next != '%' { // Skip %% (literal %)
specs.push(match next {
'd' | 'i' => "int",
'x' | 'X' => "hex",
'p' => "ptr",
's' => "str",
// Add other format specifiers as needed
_ => "unknown"
});
}
}
}
}
specs
}

fn __stdio_common_vfprintf(emu: &mut emu::Emu) {
let options = emu.regs.rcx; // _In_ options
let file = emu.regs.rdx; // _In_ FILE*
let format = emu.regs.r8; // _In_ format string ptr
let locale = emu.regs.r9; // _In_opt_ locale
let va_list = emu
.maps
.read_qword(emu.regs.rsp + 0x20) // 20 bytes of shadow space?
.expect("crt_runtime!__stdio_common_vfprintf cannot read_qword va_list");

// Just try to read the format string
let fmt_str = emu.maps.read_string(format);
let specs = parse_format_specifiers(&fmt_str);

log::info!(
"{}** {} crt_runtime!__stdio_common_vfprintf options: 0x{:x} file: 0x{:x} format: '{}' locale: 0x{:x} va_list: 0x{:x} {}",
emu.colors.light_red,
emu.pos,
options,
file,
fmt_str,
locale,
va_list,
emu.colors.nc
);

let mut current_ptr = va_list;
for spec in specs {
match spec {
"int" | "hex" | "ptr" => {
let arg = emu.maps.read_qword(current_ptr).expect("crt_runtime!__stdio_common_vfprintf cannot read_qword arg");
current_ptr += 8; // Move to next arg
log::info!("arg: {:016x}", arg);
}
"str" => {
let str_ptr = emu.maps.read_qword(current_ptr).expect("crt_runtime!__stdio_common_vfprintf cannot read_qword str_ptr");
let string = emu.maps.read_string(str_ptr);
current_ptr += 8;
log::info!("string: {}", string);
}
_ => {
unimplemented!("crt_runtime!__stdio_common_vfprintf unknown format character: {}", spec);
}
}
}

// Return success (1) - this is super basic
emu.regs.rax = 1;
}

fn realloc(emu: &mut emu::Emu) {
let addr = emu.regs.rcx;
let size = emu.regs.rdx;

if addr == 0 {
if size == 0 {
emu.regs.rax = 0;
return;
} else {
let base = emu.maps.alloc(size).expect("msvcrt!malloc out of memory");

emu.maps
.create_map(&format!("alloc_{:x}", base), base, size)
.expect("msvcrt!malloc cannot create map");

log::info!(
"{}** {} msvcrt!realloc 0x{:x} {} =0x{:x} {}",
emu.colors.light_red,
emu.pos,
addr,
size,
base,
emu.colors.nc
);

emu.regs.rax = base;
return;
}
}

if size == 0 {
log::info!(
"{}** {} msvcrt!realloc 0x{:x} {} =0x1337 {}",
emu.colors.light_red,
emu.pos,
addr,
size,
emu.colors.nc
);

emu.regs.rax = 0x1337; // weird msvcrt has to return a random unallocated pointer, and the program has to do free() on it
return;
}

let mem = emu
.maps
.get_mem_by_addr(addr)
.expect("msvcrt!realloc error getting mem");
let prev_size = mem.size();

let new_addr = emu.maps.alloc(size).expect("msvcrt!realloc out of memory");

emu.maps
.create_map(&format!("alloc_{:x}", new_addr), new_addr, size)
.expect("msvcrt!realloc cannot create map");

emu.maps.memcpy(new_addr, addr, prev_size);
emu.maps.dealloc(addr);

log::info!(
"{}** {} msvcrt!realloc 0x{:x} {} =0x{:x} {}",
emu.colors.light_red,
emu.pos,
addr,
size,
new_addr,
emu.colors.nc
);

emu.regs.rax = new_addr;
}
Loading
Loading