libscemu/emu/
peb64.rs

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); // not being_debugged
37
38    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); // peb->ldr
71        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        //log::info!("mod_base 0x{:x} pe_hdr 0x{:x}", self.mod_base, self.pe_hdr);
148
149        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        ////////
163        /*
164        emu.maps.print_maps();
165        log::info!("rva: 0x{:x} = 0x{:x} + 0x{:x} + 0x88 -> 0x{:x}", 
166            self.mod_base+self.pe_hdr+0x88,
167            self.mod_base,
168            self.pe_hdr,
169            self.export_table_rva);
170        log::info!("export_table: 0x{:x} = 0x{:x} + 0x{:x}",
171            self.export_table,
172            self.mod_base,
173            self.export_table_rva);
174        log::info!("num_of_funcs [0x{:x} + 0x18] = [0x{:x}]", 
175            self.export_table,
176            self.export_table+0x18);
177        */
178
179
180        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        //log::info!("{} == {}", libname2, flink.mod_name);
253
254        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    // get last element
274    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    // previous flink
326    log::info!("prev_flink: 0x{:x}", prev_flink);
327    //emu.maps.write_qword(prev_flink, next_flink);
328    emu.maps.write_qword(prev_flink, 0);
329
330    // next blink
331    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    /*
339     * LoadLibary* family triggers this.
340     */
341    //log::info!("************ dynamic_link_module {}", libname);
342    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    // get last element
348    loop {
349        //last_flink = flink.get_ptr();
350        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    //log::info!("last: {} {:x}", flink.mod_name, next_flink);
358
359    //let space_addr = create_ldr_entry(emu, base, pe_off, libname, last_flink, first_flink);
360    let space_addr = create_ldr_entry(emu, base, pe_off.into(), libname, first_flink, next_flink /*first_flink*/);
361    //TODO: pe_off is entry point
362
363    // point previous flink to this ldr
364    //let repl1 = emu.maps.read_qword(next_flink).unwrap();
365    emu.maps.write_qword(next_flink, space_addr); // in_load_order_links.flink
366    emu.maps.write_qword(next_flink+0x10, space_addr+0x10); // in_memory_order_links.flink
367    emu.maps.write_qword(next_flink+0x20, space_addr+0x20); // in_initialization_order_links.flink
368
369    // blink of first flink will point to last created
370    emu.maps.write_qword(first_flink + 8, space_addr); // in_load_order_links.blink
371    emu.maps.write_qword(first_flink+0x10+8, space_addr+0x10); // in_memory_order_links.blink
372    emu.maps.write_qword(first_flink+0x20+8, space_addr+0x20); // in_initialization_order_links.blink
373
374
375    //show_linked_modules(emu);
376}
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    // make space for ldr
387    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() + "\"\x00";
403    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    // http://terminus.rewolf.pl/terminus/structures/ntdll/_LDR_DATA_TABLE_ENTRY_x64.html
444
445    space_addr
446}