1use crate::emu;
2use crate::emu::structures::LdrDataTableEntry64;
3use crate::emu::structures::OrdinalTable;
4use crate::emu::structures::PEB64;
5use crate::emu::structures::TEB64;
6use crate::emu::structures::PebLdrData64;
7
8pub fn init_ldr(emu: &mut emu::Emu) -> u64 {
9 let ldr_sz = PebLdrData64::size();
10 let ldr_addr = emu.maps.lib64_alloc(ldr_sz as u64).expect("cannot alloc the LDR");
11 emu.maps.create_map("ldr", ldr_addr, ldr_sz as u64).expect("cannot create ldr map");
12 let module_entry = create_ldr_entry(emu, 0, 0, "loader.exe", 0, 0);
13 let mut ldr = PebLdrData64::new();
14 ldr.initializated = 1;
15 ldr.in_load_order_module_list.flink = module_entry;
16 ldr.in_load_order_module_list.blink = module_entry;
17 ldr.in_memory_order_module_list.flink = module_entry+0x10;
18 ldr.in_memory_order_module_list.blink = module_entry+0x10;
19 ldr.in_initialization_order_module_list.flink = module_entry+0x20;
20 ldr.in_initialization_order_module_list.blink = module_entry+0x20;
21 ldr.entry_in_progress.flink = module_entry;
22 ldr.entry_in_progress.blink = module_entry;
23 ldr.save(ldr_addr, &mut emu.maps);
24
25 return ldr_addr;
26}
27
28pub fn init_peb(emu: &mut emu::Emu) {
29 let ldr = init_ldr(emu);
30
31 let peb_addr = emu.maps.lib64_alloc(PEB64::size() as u64).expect("cannot alloc the PEB64");
32 let mut peb_map = emu.maps.create_map("peb", peb_addr, PEB64::size() as u64).expect("cannot create peb map");
33 let process_parameters = 0x521e20;
34 let peb = PEB64::new(0, ldr, process_parameters);
35 peb.save(&mut peb_map);
36 emu.maps.write_byte(peb_addr + 2, 0); let teb_addr = emu.maps.lib64_alloc(TEB64::size() as u64).expect("cannot alloc the TEB64");
39 let mut teb_map = emu.maps.create_map("teb", teb_addr, TEB64::size() as u64).expect("cannot create teb map");
40 let teb = TEB64::new(peb_addr);
41 teb.save(&mut teb_map);
42
43}
44
45pub fn update_peb_image_base(emu: &mut emu::Emu, base: u64) {
46 let peb = emu.maps.get_mem("peb");
47 let peb_base = peb.get_base();
48 emu.maps.write_qword(peb_base + 0x10, base);
49}
50
51
52#[derive(Debug)]
53pub struct Flink {
54 flink_addr: u64,
55 pub mod_base: u64,
56 pub mod_name: String,
57 pub pe_hdr: u64,
58
59 pub export_table_rva: u64,
60 pub export_table: u64,
61 pub num_of_funcs: u64,
62 pub func_name_tbl_rva: u64,
63 pub func_name_tbl: u64,
64}
65
66impl Flink {
67 pub fn new(emu: &mut emu::Emu) -> Flink {
68 let peb = emu.maps.get_mem("peb");
69 let peb_base = peb.get_base();
70 let ldr = peb.read_qword(peb_base + 0x18); let flink = emu
72 .maps
73 .read_qword(ldr + 0x10)
74 .expect("peb64::new() error reading flink");
75
76 Flink {
77 flink_addr: flink,
78 mod_base: 0,
79 mod_name: String::new(),
80 pe_hdr: 0,
81 export_table_rva: 0,
82 export_table: 0,
83 num_of_funcs: 0,
84 func_name_tbl_rva: 0,
85 func_name_tbl: 0,
86 }
87 }
88
89 pub fn print(&self) {
90 log::info!("{:#x?}", self);
91 }
92
93 pub fn get_ptr(&self) -> u64 {
94 return self.flink_addr;
95 }
96
97 pub fn set_ptr(&mut self, addr: u64) {
98 self.flink_addr = addr;
99 }
100
101 pub fn load(&mut self, emu: &mut emu::Emu) {
102 self.get_mod_base(emu);
103 self.get_mod_name(emu);
104 self.get_pe_hdr(emu);
105 self.get_export_table(emu);
106 }
107
108 pub fn get_mod_base(&mut self, emu: &mut emu::Emu) {
109 self.mod_base = emu
110 .maps
111 .read_qword(self.flink_addr + 0x30)
112 .expect("error reading mod_addr");
113 }
114
115 pub fn set_mod_base(&mut self, base: u64, emu: &mut emu::Emu) {
116 self.mod_base = base;
117 emu.maps.write_qword(self.flink_addr + 0x30, base);
118 }
119
120 pub fn get_mod_name(&mut self, emu: &mut emu::Emu) {
121 let mod_name_ptr = emu
122 .maps
123 .read_qword(self.flink_addr + 0x60)
124 .expect("error reading mod_name_ptr");
125 self.mod_name = emu.maps.read_wide_string(mod_name_ptr);
126 }
127
128 pub fn has_module(&self) -> bool {
129 if self.mod_base == 0 || self.flink_addr == 0 {
130 return false;
131 }
132 return true;
133 }
134
135 pub fn get_pe_hdr(&mut self, emu: &mut emu::Emu) {
136 self.pe_hdr = match emu.maps.read_dword(self.mod_base + 0x3c) {
137 Some(hdr) => hdr as u64,
138 None => 0,
139 };
140 }
141
142 pub fn get_export_table(&mut self, emu: &mut emu::Emu) {
143 if self.pe_hdr == 0 {
144 return;
145 }
146
147 self.export_table_rva = match emu
150 .maps
151 .read_dword(self.mod_base + self.pe_hdr + 0x88) {
152 Some(rva) => rva as u64,
153 None => 0,
154 };
155
156 if self.export_table_rva == 0 {
157 return;
158 }
159
160 self.export_table = self.export_table_rva + self.mod_base;
161
162 self.num_of_funcs = emu
181 .maps
182 .read_dword(self.export_table + 0x18)
183 .expect("error reading the num_of_funcs") as u64;
184 self.func_name_tbl_rva = emu
185 .maps
186 .read_dword(self.export_table + 0x20)
187 .expect(" error reading func_name_tbl_rva") as u64;
188 self.func_name_tbl = self.func_name_tbl_rva + self.mod_base;
189 }
190
191 pub fn get_function_ordinal(&self, emu: &mut emu::Emu, function_id: u64) -> OrdinalTable {
192 let mut ordinal = OrdinalTable::new();
193 let func_name_rva = emu
194 .maps
195 .read_dword(self.func_name_tbl + function_id * 4)
196 .expect("error reading func_rva") as u64;
197 ordinal.func_name = emu.maps.read_string(func_name_rva + self.mod_base);
198 ordinal.ordinal_tbl_rva = emu
199 .maps
200 .read_dword(self.export_table + 0x24)
201 .expect("error reading ordinal_tbl_rva") as u64;
202 ordinal.ordinal_tbl = ordinal.ordinal_tbl_rva + self.mod_base;
203 ordinal.ordinal = emu
204 .maps
205 .read_word(ordinal.ordinal_tbl + 2 * function_id)
206 .expect("error reading ordinal") as u64;
207 ordinal.func_addr_tbl_rva = emu
208 .maps
209 .read_dword(self.export_table + 0x1c)
210 .expect("error reading func_addr_tbl_rva") as u64;
211 ordinal.func_addr_tbl = ordinal.func_addr_tbl_rva + self.mod_base;
212 ordinal.func_rva = emu
213 .maps
214 .read_dword(ordinal.func_addr_tbl + 4 * ordinal.ordinal)
215 .expect("error reading func_rva") as u64;
216 ordinal.func_va = ordinal.func_rva + self.mod_base;
217
218 ordinal
219 }
220
221 pub fn get_next_flink(&self, emu: &mut emu::Emu) -> u64 {
222 return emu
223 .maps
224 .read_qword(self.flink_addr)
225 .expect("error reading next flink") as u64;
226 }
227
228 pub fn get_prev_flink(&self, emu: &mut emu::Emu) -> u64 {
229 return emu
230 .maps
231 .read_qword(self.flink_addr + 8)
232 .expect("error reading prev flink") as u64;
233 }
234
235 pub fn next(&mut self, emu: &mut emu::Emu) {
236 self.flink_addr = self.get_next_flink(emu);
237 self.load(emu);
238 }
239}
240
241pub fn get_module_base(libname: &str, emu: &mut emu::Emu) -> Option<u64> {
242 let mut libname2: String = libname.to_string().to_lowercase();
243 if !libname2.ends_with(".dll") {
244 libname2.push_str(".dll");
245 }
246
247 let mut flink = Flink::new(emu);
248 flink.load(emu);
249
250 let first_flink = flink.get_ptr();
251 loop {
252 if libname.to_string().to_lowercase() == flink.mod_name.to_string().to_lowercase()
255 || libname2 == flink.mod_name.to_string().to_lowercase()
256 {
257 return Some(flink.mod_base);
258 }
259 flink.next(emu);
260
261 if flink.get_ptr() == first_flink {
262 break;
263 }
264 }
265 return None;
266}
267
268pub fn show_linked_modules(emu: &mut emu::Emu) {
269 let mut flink = Flink::new(emu);
270 flink.load(emu);
271 let first_flink = flink.get_ptr();
272
273 loop {
275 let pe1 = match emu.maps.read_byte(flink.mod_base + flink.pe_hdr) {
276 Some(b) => b,
277 None => 0,
278 };
279 let pe2 = match emu.maps.read_byte(flink.mod_base + flink.pe_hdr + 1) {
280 Some(b) => b,
281 None => 0,
282 };
283 log::info!(
284 "0x{:x} {} flink:{:x} blink:{:x} base:{:x} pe_hdr:{:x} {:x}{:x}",
285 flink.get_ptr(),
286 flink.mod_name,
287 flink.get_next_flink(emu),
288 flink.get_prev_flink(emu),
289 flink.mod_base,
290 flink.pe_hdr,
291 pe1,
292 pe2
293 );
294 flink.next(emu);
295 if flink.get_ptr() == first_flink {
296 return;
297 }
298 }
299}
300
301pub fn update_ldr_entry_base(libname: &str, base: u64, emu: &mut emu::Emu) {
302 let mut flink = Flink::new(emu);
303 flink.load(emu);
304 while flink.mod_name.to_lowercase() != libname.to_lowercase() {
305 flink.next(emu);
306 }
307 flink.set_mod_base(base, emu);
308}
309
310pub fn dynamic_unlink_module(libname: &str, emu: &mut emu::Emu) {
311 let mut prev_flink: u64 = 0;
312 let next_flink: u64;
313
314 let mut flink = Flink::new(emu);
315 flink.load(emu);
316 while flink.mod_name != libname {
317 log::info!("{}", flink.mod_name);
318 prev_flink = flink.get_ptr();
319 flink.next(emu);
320 }
321
322 flink.next(emu);
323 next_flink = flink.get_ptr();
324
325 log::info!("prev_flink: 0x{:x}", prev_flink);
327 emu.maps.write_qword(prev_flink, 0);
329
330 log::info!("next_flink: 0x{:x}", next_flink);
332 emu.maps.write_qword(next_flink + 4, prev_flink);
333
334 show_linked_modules(emu);
335}
336
337pub fn dynamic_link_module(base: u64, pe_off: u32, libname: &str, emu: &mut emu::Emu) {
338 let mut last_flink: u64;
343 let mut flink = Flink::new(emu);
344 flink.load(emu);
345 let first_flink = flink.get_ptr();
346
347 loop {
349 flink.next(emu);
351 if flink.get_next_flink(emu) == first_flink {
352 break;
353 }
354 }
355 let next_flink: u64 = flink.get_ptr();
356
357 let space_addr = create_ldr_entry(emu, base, pe_off.into(), libname, first_flink, next_flink );
361 emu.maps.write_qword(next_flink, space_addr); emu.maps.write_qword(next_flink+0x10, space_addr+0x10); emu.maps.write_qword(next_flink+0x20, space_addr+0x20); emu.maps.write_qword(first_flink + 8, space_addr); emu.maps.write_qword(first_flink+0x10+8, space_addr+0x10); emu.maps.write_qword(first_flink+0x20+8, space_addr+0x20); }
377
378pub fn create_ldr_entry(
379 emu: &mut emu::Emu,
380 base: u64,
381 entry_point: u64,
382 libname: &str,
383 next_flink: u64,
384 prev_flink: u64,
385) -> u64 {
386 let sz = LdrDataTableEntry64::size() + 0x40 + (1024*2);
388 let space_addr = emu
389 .maps
390 .alloc(sz)
391 .expect("cannot alloc few bytes to put the LDR for LoadLibraryA");
392 let mut lib = libname.to_string();
393 lib.push_str(".ldr");
394 let mut image_sz = 0;
395 if base > 0 {
396 let pe_hdr = emu.maps.read_dword(base as u64 + 0x3c).unwrap() as u64;
397 image_sz = emu.maps.read_qword(base as u64 + pe_hdr + 0x50).unwrap() as u64;
398 }
399 let mem = emu.maps.create_map(lib.as_str(), space_addr, sz).expect("cannot create ldr entry map");
400 mem.write_byte(space_addr + sz - 1, 0x61);
401
402 let full_libname = "C:\\Windows\\System32\\".to_string() + &libname.to_string();
404
405 let mut ldr = LdrDataTableEntry64::new();
406 if next_flink != 0 {
407 ldr.in_load_order_links.flink = next_flink;
408 ldr.in_load_order_links.blink = prev_flink;
409 ldr.in_memory_order_links.flink = next_flink+0x10;
410 ldr.in_memory_order_links.blink = prev_flink+0x10;
411 ldr.in_initialization_order_links.flink = next_flink+0x20;
412 ldr.in_initialization_order_links.blink = prev_flink+0x20;
413 ldr.hash_links.flink = next_flink+0x7f;
414 ldr.hash_links.blink = prev_flink+0x7f;
415 } else {
416 ldr.in_load_order_links.flink = space_addr;
417 ldr.in_load_order_links.blink = space_addr;
418 ldr.in_memory_order_links.flink = space_addr+0x10;
419 ldr.in_memory_order_links.blink = space_addr+0x10;
420 ldr.in_initialization_order_links.flink = space_addr+0x20;
421 ldr.in_initialization_order_links.blink = space_addr+0x20;
422 ldr.hash_links.flink = space_addr+0x7f;
423 ldr.hash_links.blink = space_addr+0x7f;
424 }
425 ldr.dll_base = base;
426 ldr.entry_point = entry_point;
427 ldr.size_of_image = image_sz;
428 ldr.full_dll_name.length = full_libname.len() as u16 * 2;
429 ldr.full_dll_name.maximum_length = full_libname.len() as u16 * 2 + 4;
430 ldr.full_dll_name.buffer = space_addr + LdrDataTableEntry64::size();
431 ldr.base_dll_name.length = libname.len() as u16 * 2;
432 ldr.base_dll_name.maximum_length = libname.len() as u16 * 2 + 2;
433 ldr.base_dll_name.buffer = space_addr + LdrDataTableEntry64::size() + full_libname.len() as u64 * 2 + 10;
434 ldr.flags = 0;
435 ldr.load_count = 0;
436 ldr.tls_index = 0;
437 ldr.hash_links.flink = next_flink;
438 ldr.hash_links.blink = prev_flink;
439 mem.write_wide_string(space_addr + LdrDataTableEntry64::size(), &(full_libname.clone() + "\x00\x00"));
440 mem.write_wide_string(space_addr + LdrDataTableEntry64::size() + full_libname.len() as u64 * 2 +10, &(libname.to_string() + "\x00"));
441 ldr.save(space_addr, &mut emu.maps);
442
443 space_addr
446}