1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
use crate::maps::mem64::Permission;
use crate::tests::helpers;
use crate::winapi::winapi64;
use crate::*; // Assuming crate root has winapi module public or we can access it.
// If `winapi` mod is not public, we might have issues.
// Existing tests import `use crate::*;`.
// `lib.rs` usually has `pub mod winapi;`.
#[test]
fn test_write_file() {
helpers::setup();
let mut emu = emu64();
// Setup stack
emu.regs_mut().rsp = 0x8000;
emu.maps
.create_map("stack", 0x0, 0x10000, Permission::READ_WRITE);
// Setup buffer
let buff_addr = 0x100000;
emu.maps
.create_map("buffer", buff_addr, 0x1000, Permission::READ_WRITE);
emu.maps.write_string(buff_addr, "Hello WinAPI");
// Setup arguments for WriteFile
// BOOL WriteFile(
// HANDLE hFile,
// LPCVOID lpBuffer,
// DWORD nNumberOfBytesToWrite,
// LPDWORD lpNumberOfBytesWritten,
// LPOVERLAPPED lpOverlapped
// );
// RCX = hFile (dummy handle)
emu.regs_mut().rcx = 0x1234;
// RDX = lpBuffer
emu.regs_mut().rdx = buff_addr;
// R8 = nNumberOfBytesToWrite
emu.regs_mut().r8 = 12;
// R9 = lpNumberOfBytesWritten (pointer)
let written_ptr = 0x200000;
emu.maps
.create_map("written", written_ptr, 0x1000, Permission::READ_WRITE);
emu.regs_mut().r9 = written_ptr;
// Stack param: lpOverlapped (at rsp + 0x28, shadow space 0x20)
// Actually WriteFile implementation reads `rsp + 0x20`.
// "read_qword(emu.regs().rsp + 0x20)"
// Typically shadow space is 32 bytes (0x20). The 5th arg is at rsp+0x28.
// If the impl reads 0x20 directly, it might mean it assumes the specialized handling or I verified line 12: `emu.regs().rsp + 0x20`.
// Wait, the line 12 says: `emu.maps.read_qword(emu.regs().rsp + 0x20)`.
// Typically parameters are: rcx, rdx, r8, r9. Stack: [rsp+0x28] (5th), [rsp+0x30] (6th).
// If it reads +0x20, it might be reading the shadow space slot for the 5th arg? No, shadow space is 0x0..0x20. 5th arg is at 0x28.
// Let's assume the implementation expects the caller to have pushed/reserved stack.
// If I just set RSP, +0x20 is valid memory.
// I should write 0 to it (NULL overlapped).
emu.maps.write_qword(emu.regs().rsp + 0x20, 0);
// Call the function directly
winapi64::kernel32::WriteFile(&mut emu);
// Check Result
// RAX should be 1 (TRUE)
assert_eq!(emu.regs().rax, 1, "WriteFile failed (returned 0)");
// Read bytes written
let bytes = emu.maps.read_dword(written_ptr).unwrap();
assert_eq!(bytes, 12);
}
#[test]
fn test_get_module_handle_64() {
helpers::setup();
let mut emu = emu64();
// HMODULE GetModuleHandleA(
// LPCSTR lpModuleName
// );
// "kernel32.dll"
let name_addr = 0x20000;
emu.maps
.create_map("data", name_addr, 0x1000, Permission::READ_WRITE);
emu.maps.write_string(name_addr, "kernel32.dll");
// Create the expected module map "kernel32.pe"
emu.maps.create_map(
"kernel32.pe",
0x7FF10000000,
0x10000,
Permission::READ_EXECUTE,
);
emu.regs_mut().rcx = name_addr;
winapi64::kernel32::GetModuleHandleA(&mut emu);
let h_mod = emu.regs().rax;
assert_eq!(
h_mod, 0x7FF10000000,
"GetModuleHandleA('kernel32.dll') returned incorrect base"
);
}
#[test]
fn test_close_handle_64() {
helpers::setup();
let mut emu = emu64();
// CloseHandle checks if handle exists in global map.
// If not, it panics.
// We need to create a valid handle first.
// Use `handler_create` from helper? It's pub?
// helper::handler_create(name) -> handle
let handle = crate::winapi::helper::handler_create("dummy_file");
emu.regs_mut().rcx = handle;
winapi64::kernel32::CloseHandle(&mut emu);
// Expect 1
assert_eq!(emu.regs().rax, 1);
}
#[test]
fn test_virtual_alloc() {
helpers::setup();
let mut emu = emu64();
// LPVOID VirtualAlloc(
// LPVOID lpAddress,
// SIZE_T dwSize,
// DWORD flAllocationType,
// DWORD flProtect
// );
emu.regs_mut().rcx = 0; // lpAddress
emu.regs_mut().rdx = 0x1000; // dwSize
emu.regs_mut().r8 = 0x1000 | 0x2000; // MEM_COMMIT | MEM_RESERVE
emu.regs_mut().r9 = 0x40; // PAGE_EXECUTE_READWRITE
winapi64::kernel32::VirtualAlloc(&mut emu);
let base = emu.regs().rax;
assert!(base != 0, "VirtualAlloc failed");
// Verify memory access
emu.maps.write_dword(base, 0xDEADBEEF);
let val = emu.maps.read_dword(base).unwrap();
assert_eq!(val, 0xDEADBEEF);
}