libscemu/emu/
script.rs

1use crate::emu;
2use crate::emu::peb32;
3use crate::emu::peb64;
4use crate::emu::structures;
5use std::fs::File;
6use std::io::BufRead;
7use std::io::BufReader;
8use std::vec::Vec;
9
10pub struct Script {
11    code: Vec<String>,
12    result: u64,
13    skip: bool,
14    looped: u64,
15    trace: bool,
16}
17
18impl Script {
19    pub fn new() -> Script {
20        Script {
21            code: Vec::new(),
22            result: 0,
23            skip: false,
24            looped: 0,
25            trace: false,
26        }
27    }
28
29    pub fn load(&mut self, filename: &str) {
30        // log::info!("loading script: {}", filename);
31        let file = File::open(filename).unwrap();
32        let buf = BufReader::new(file);
33
34        for line in buf.lines() {
35            if let Ok(line) = line {
36                self.code.push(line);
37            }
38        }
39    }
40
41    pub fn resolve(&self, arg: &str, i: usize, emu: &mut emu::Emu) -> u64 {
42        if arg == "result" {
43            return self.result;
44        } else if arg.starts_with("0x") {
45            let a = match self.to_hex(&arg) {
46                Some(v) => v,
47                None => {
48                    panic!("error in line {}, bad hexa", i);
49                }
50            };
51            return a;
52        }
53        return emu.regs.get_by_name(arg);
54    }
55
56    pub fn to_int(&self, s: &str) -> Option<u64> {
57        let value: u64 = match u64::from_str_radix(s, 10) {
58            Ok(value) => value,
59            Err(_) => return None,
60        };
61
62        Some(value)
63    }
64
65    pub fn to_hex(&self, s: &str) -> Option<u64> {
66        let mut x = s.to_string();
67        if x.ends_with('h') {
68            x = x[0..x.len() - 1].to_string();
69        }
70        if x.starts_with("0x") {
71            x = x[2..x.len()].to_string();
72        }
73
74        let value: u64 = match u64::from_str_radix(x.as_str(), 16) {
75            Ok(value) => value,
76            Err(_) => return None,
77        };
78
79        Some(value)
80    }
81
82    pub fn run(&mut self, emu: &mut emu::Emu) {
83        emu.running_script = true;
84        let mut i = 0;
85
86        loop {
87            i += 1;
88
89            if i > self.code.len() {
90                break;
91            }
92            let line = &self.code[i - 1];
93            if line.len() == 0 || line.starts_with(";") {
94                continue;
95            }
96            let args: Vec<&str> = line.split_whitespace().collect();
97
98            if self.trace {
99                log::info!("==> {} {}", i, line);
100            }
101
102            if line == "endif" {
103                self.skip = false;
104                continue;
105            }
106
107            if self.skip {
108                continue;
109            }
110
111            match args[0] {
112                "pr" => {
113                    log::info!("result: 0x{:x}", self.result);
114                }
115                "p" => {
116                    if args.len() < 2 {
117                        log::info!(
118                            "error in line {}, `p` command needs a message to be printed",
119                            i
120                        );
121                        return;
122                    }
123                    let msg = args
124                        .iter()
125                        .skip(1)
126                        .map(|s| s.to_owned())
127                        .collect::<Vec<_>>()
128                        .join(" ");
129
130                    log::info!("{}", msg);
131                }
132                "q" => std::process::exit(1),
133                "r" => {
134                    if args.len() == 1 {
135                        if emu.cfg.is_64bits {
136                            emu.featured_regs64();
137                        } else {
138                            emu.featured_regs32();
139                        }
140                    } else {
141                        self.result = emu.regs.get_by_name(&args[1]);
142
143                        match args[1] {
144                            "rax" => emu.regs.show_rax(&emu.maps, 0),
145                            "rbx" => emu.regs.show_rbx(&emu.maps, 0),
146                            "rcx" => emu.regs.show_rcx(&emu.maps, 0),
147                            "rdx" => emu.regs.show_rdx(&emu.maps, 0),
148                            "rsi" => emu.regs.show_rsi(&emu.maps, 0),
149                            "rdi" => emu.regs.show_rdi(&emu.maps, 0),
150                            "rbp" => log::info!("\trbp: 0x{:x}", emu.regs.rbp),
151                            "rsp" => log::info!("\trsp: 0x{:x}", emu.regs.rsp),
152                            "rip" => log::info!("\trip: 0x{:x}", emu.regs.rip),
153                            "eax" => emu.regs.show_eax(&emu.maps, 0),
154                            "ebx" => emu.regs.show_ebx(&emu.maps, 0),
155                            "ecx" => emu.regs.show_ecx(&emu.maps, 0),
156                            "edx" => emu.regs.show_edx(&emu.maps, 0),
157                            "esi" => emu.regs.show_esi(&emu.maps, 0),
158                            "edi" => emu.regs.show_edi(&emu.maps, 0),
159                            "esp" => log::info!("\tesp: 0x{:x}", emu.regs.get_esp() as u32),
160                            "ebp" => log::info!("\tebp: 0x{:x}", emu.regs.get_ebp() as u32),
161                            "eip" => log::info!("\teip: 0x{:x}", emu.regs.get_eip() as u32),
162                            "r8" => emu.regs.show_r8(&emu.maps, 0),
163                            "r9" => emu.regs.show_r9(&emu.maps, 0),
164                            "r10" => emu.regs.show_r10(&emu.maps, 0),
165                            "r11" => emu.regs.show_r11(&emu.maps, 0),
166                            "r12" => emu.regs.show_r12(&emu.maps, 0),
167                            "r13" => emu.regs.show_r13(&emu.maps, 0),
168                            "r14" => emu.regs.show_r14(&emu.maps, 0),
169                            "r15" => emu.regs.show_r15(&emu.maps, 0),
170                            "r8d" => emu.regs.show_r8d(&emu.maps, 0),
171                            "r9d" => emu.regs.show_r9d(&emu.maps, 0),
172                            "r10d" => emu.regs.show_r10d(&emu.maps, 0),
173                            "r11d" => emu.regs.show_r11d(&emu.maps, 0),
174                            "r12d" => emu.regs.show_r12d(&emu.maps, 0),
175                            "r13d" => emu.regs.show_r13d(&emu.maps, 0),
176                            "r14d" => emu.regs.show_r14d(&emu.maps, 0),
177                            "r15d" => emu.regs.show_r15d(&emu.maps, 0),
178                            "r8w" => emu.regs.show_r8w(&emu.maps, 0),
179                            "r9w" => emu.regs.show_r9w(&emu.maps, 0),
180                            "r10w" => emu.regs.show_r10w(&emu.maps, 0),
181                            "r11w" => emu.regs.show_r11w(&emu.maps, 0),
182                            "r12w" => emu.regs.show_r12w(&emu.maps, 0),
183                            "r13w" => emu.regs.show_r13w(&emu.maps, 0),
184                            "r14w" => emu.regs.show_r14w(&emu.maps, 0),
185                            "r15w" => emu.regs.show_r15w(&emu.maps, 0),
186                            "r8l" => emu.regs.show_r8l(&emu.maps, 0),
187                            "r9l" => emu.regs.show_r9l(&emu.maps, 0),
188                            "r10l" => emu.regs.show_r10l(&emu.maps, 0),
189                            "r11l" => emu.regs.show_r11l(&emu.maps, 0),
190                            "r12l" => emu.regs.show_r12l(&emu.maps, 0),
191                            "r13l" => emu.regs.show_r13l(&emu.maps, 0),
192                            "r14l" => emu.regs.show_r14l(&emu.maps, 0),
193                            "r15l" => emu.regs.show_r15l(&emu.maps, 0),
194                            "xmm0" => log::info!("\txmm0: 0x{:x}", emu.regs.xmm0),
195                            "xmm1" => log::info!("\txmm1: 0x{:x}", emu.regs.xmm1),
196                            "xmm2" => log::info!("\txmm2: 0x{:x}", emu.regs.xmm2),
197                            "xmm3" => log::info!("\txmm3: 0x{:x}", emu.regs.xmm3),
198                            "xmm4" => log::info!("\txmm4: 0x{:x}", emu.regs.xmm4),
199                            "xmm5" => log::info!("\txmm5: 0x{:x}", emu.regs.xmm5),
200                            "xmm6" => log::info!("\txmm6: 0x{:x}", emu.regs.xmm6),
201                            "xmm7" => log::info!("\txmm7: 0x{:x}", emu.regs.xmm7),
202                            "xmm8" => log::info!("\txmm8: 0x{:x}", emu.regs.xmm8),
203                            "xmm9" => log::info!("\txmm9: 0x{:x}", emu.regs.xmm9),
204                            "xmm10" => log::info!("\txmm10: 0x{:x}", emu.regs.xmm10),
205                            "xmm11" => log::info!("\txmm11: 0x{:x}", emu.regs.xmm11),
206                            "xmm12" => log::info!("\txmm12: 0x{:x}", emu.regs.xmm12),
207                            "xmm13" => log::info!("\txmm13: 0x{:x}", emu.regs.xmm13),
208                            "xmm14" => log::info!("\txmm14: 0x{:x}", emu.regs.xmm14),
209                            "xmm15" => log::info!("\txmm15: 0x{:x}", emu.regs.xmm15),
210                            _ => log::info!("unknown register r `{}` in line {}", args[1], i),
211                        }
212                    }
213                }
214                "rc" => {
215                    if args.len() != 3 {
216                        log::info!("expected: rc <register> <value>");
217                    } else {
218                        let value: u64 = self.resolve(args[2], i, emu);
219                        emu.regs.set_by_name(args[1], value);
220                    }
221                }
222                "mr" | "rm" => {
223                    if args.len() < 2 {
224                        log::info!("error in line {}, command `mr` without arguments", i);
225                        return;
226                    }
227
228                    let ins = args
229                        .iter()
230                        .skip(1)
231                        .map(|s| s.to_owned())
232                        .collect::<Vec<_>>()
233                        .join(" ");
234
235                    let addr: u64 = emu.memory_operand_to_address(&ins);
236                    let value = match emu.memory_read(&ins) {
237                        Some(v) => v,
238                        None => {
239                            log::info!("error in line {}, bad address.", i);
240                            return;
241                        }
242                    };
243                    self.result = value;
244                    log::info!("0x{:x}", value);
245                }
246                "mw" | "wm" => {
247                    // mw 0x11223344 dword ptr [eax + 3]
248
249                    if args.len() < 3 {
250                        log::info!("error in line {}, command `mw` without arguments", i);
251                        return;
252                    }
253
254                    let ins = args
255                        .iter()
256                        .skip(2)
257                        .map(|s| s.to_owned())
258                        .collect::<Vec<_>>()
259                        .join(" ");
260
261                    let value = self.resolve(args[1], i, emu);
262
263                    if !emu.memory_write(&ins, value) {
264                        log::info!("error in line {}, cannot write on `{}`", i, args[1]);
265                        return;
266                    }
267                }
268                "mwb" => {
269                    let addr = self.resolve(args[1], i, emu);
270                    let bytes = args
271                        .iter()
272                        .skip(1)
273                        .take(args.len() - 2)
274                        .map(|s| s.to_owned())
275                        .collect::<Vec<_>>()
276                        .join(" ");
277
278                    emu.maps.write_spaced_bytes(addr, &bytes);
279                }
280                "b" => {
281                    emu.bp.show();
282                }
283                "ba" => {
284                    if args.len() < 2 {
285                        log::info!("error in line {}, address is missing", i);
286                        return;
287                    }
288                    let addr = self.resolve(args[1], i, emu);
289                    emu.bp.set_bp(addr);
290                }
291                "bmr" => {
292                    if args.len() < 2 {
293                        log::info!("error in line {}, address is missing", i);
294                        return;
295                    }
296                    let addr = self.resolve(args[1], i, emu);
297
298                    emu.bp.set_mem_read(addr);
299                }
300                "bmw" => {
301                    if args.len() < 2 {
302                        log::info!("error in line {}, address is missing", i);
303                        return;
304                    }
305                    let addr = self.resolve(args[1], i, emu);
306                    emu.bp.set_mem_write(addr);
307                }
308                "bi" => {
309                    if args.len() < 2 {
310                        log::info!("error in line {}, number is missing", i);
311                        return;
312                    }
313                    let num = match self.to_int(args[1]) {
314                        Some(v) => v,
315                        None => {
316                            log::info!("error in line {}, bad number", i);
317                            return;
318                        }
319                    };
320                    emu.bp.set_instruction(num);
321                    emu.exp = num;
322                }
323                "bc" => {
324                    emu.bp.clear_bp();
325                    emu.exp = emu.pos + 1;
326                }
327                "bcmp" => {
328                    emu.break_on_next_cmp = true;
329                }
330                "cls" => {
331                    log::info!("{}", emu.colors.clear_screen);
332                }
333                "s" => {
334                    if emu.cfg.is_64bits {
335                        emu.maps.dump_qwords(emu.regs.rsp, 10);
336                    } else {
337                        emu.maps.dump_dwords(emu.regs.get_esp(), 10);
338                    }
339                }
340                "v" => {
341                    if emu.cfg.is_64bits {
342                        emu.maps.dump_qwords(emu.regs.rbp - 0x100, 100);
343                    } else {
344                        emu.maps.dump_dwords(emu.regs.get_ebp() - 0x100, 100);
345                    }
346                    emu.maps
347                        .get_mem("stack")
348                        .print_dwords_from_to(emu.regs.get_ebp(), emu.regs.get_ebp() + 0x100);
349                }
350                "sv" => {
351                    if args.len() < 2 {
352                        log::info!("error in line {}, number is missing", i);
353                        return;
354                    }
355                    let num = match self.to_int(args[1]) {
356                        Some(v) => v,
357                        None => {
358                            log::info!("error in line {}, bad number", i);
359                            return;
360                        }
361                    };
362                    emu.cfg.verbose = num as u32;
363                }
364                "tr" => {
365                    if args.len() < 2 {
366                        log::info!("error in line {}, register is missing", i);
367                        return;
368                    }
369                    emu.cfg.trace_reg = true;
370                    emu.cfg.reg_names.push(args[1].to_string());
371                }
372                "trc" => {
373                    emu.cfg.trace_reg = false;
374                    emu.cfg.reg_names.clear();
375                }
376                "c" => {
377                    emu.is_running
378                        .store(1, std::sync::atomic::Ordering::Relaxed);
379                    emu.run(None);
380                }
381                "cr" => {
382                    emu.break_on_next_return = true;
383                    emu.is_running
384                        .store(1, std::sync::atomic::Ordering::Relaxed);
385                    emu.run(None);
386                }
387                "f" => emu.flags.print(),
388                "fc" => emu.flags.clear(),
389                "fz" => emu.flags.f_zf = !emu.flags.f_zf,
390                "fs" => emu.flags.f_sf = !emu.flags.f_sf,
391                "mc" => {
392                    // mc mymap 1024
393                    if args.len() != 3 {
394                        log::info!("error in line {}, mc <mapname> <size>", i);
395                        return;
396                    }
397                    let sz = match self.to_int(&args[2]) {
398                        Some(v) => v,
399                        None => {
400                            log::info!("error in line {}, bad size", i);
401                            return;
402                        }
403                    };
404                    let addr = match emu.maps.alloc(sz) {
405                        Some(a) => a,
406                        None => {
407                            log::info!("error in line {}, memory full", i);
408                            return;
409                        }
410                    };
411                    emu.maps.create_map(&args[1], addr, sz);
412                    log::info!("allocated {} at 0x{:x} sz: {}", &args[1], addr, sz);
413                    self.result = addr;
414                }
415                "mca" => {
416                    // mc mymap <addr> <sz>
417                    if args.len() != 4 {
418                        log::info!("error in line {}, mc <mapname> <addr> <size>", i);
419                        return;
420                    }
421                    let addr = self.resolve(args[2], i, emu);
422                    let sz = match self.to_int(&args[3]) {
423                        Some(v) => v,
424                        None => {
425                            log::info!("error in line {}, bad size", i);
426                            return;
427                        }
428                    };
429                    emu.maps.create_map(&args[1], addr, sz);
430                    log::info!("allocated {} at 0x{:x} sz: {}", &args[1], addr, sz);
431                }
432                "ml" => {
433                    // ml <mapname> <file>
434                    if args.len() != 3 {
435                        log::info!("error in line {}, `ml` needs mapname and a filename", i);
436                        return;
437                    }
438                    emu.maps.get_mem(&args[1]).load(&args[2]);
439                }
440                "mn" => {
441                    // mn <address>
442                    if args.len() != 2 {
443                        log::info!("error in line {}, `mn` needs an address", i);
444                        return;
445                    }
446
447                    let addr = self.resolve(args[1], i, emu);
448
449                    let name = match emu.maps.get_addr_name(addr) {
450                        Some(n) => n,
451                        None => {
452                            log::info!("error in line {}, address not found on any map", i);
453                            return;
454                        }
455                    };
456
457                    let mem = emu.maps.get_mem(&name);
458                    if emu.cfg.is_64bits {
459                        log::info!(
460                            "map: {} 0x{:x}-0x{:x} ({})",
461                            name,
462                            mem.get_base(),
463                            mem.get_bottom(),
464                            mem.size()
465                        );
466                    } else {
467                        log::info!(
468                            "map: {} 0x{:x}-0x{:x} ({})",
469                            name,
470                            mem.get_base() as u32,
471                            mem.get_bottom() as u32,
472                            mem.size()
473                        );
474                    }
475                }
476                "ma" => {
477                    emu.maps.show_allocs();
478                }
479                "md" => {
480                    // md <addr>
481                    if args.len() != 2 {
482                        log::info!("error in line {}, address missing", i);
483                        return;
484                    }
485
486                    let addr = self.resolve(args[1], i, emu);
487
488                    emu.maps.dump(addr);
489                }
490                "mrd" => {
491                    // mrd <addr> <n>
492                    if args.len() != 3 {
493                        log::info!("error in line {}, address or number of dwords missing", i);
494                        return;
495                    }
496
497                    let addr = self.resolve(args[1], i, emu);
498
499                    let num = match self.to_int(&args[2]) {
500                        Some(v) => v,
501                        None => {
502                            log::info!("error in line {}, bad number", i);
503                            return;
504                        }
505                    };
506
507                    emu.maps.dump_dwords(addr, num);
508                }
509                "mrq" => {
510                    // mrq <addr> <n>
511                    if args.len() != 3 {
512                        log::info!("error in line {}, address or number of qwords missing", i);
513                        return;
514                    }
515
516                    let addr = self.resolve(args[1], i, emu);
517
518                    let num = match self.to_int(&args[2]) {
519                        Some(v) => v,
520                        None => {
521                            log::info!("error in line {}, bad number", i);
522                            return;
523                        }
524                    };
525
526                    emu.maps.dump_qwords(addr, num);
527                }
528                "mds" => {
529                    // mds <addr>
530                    if args.len() != 2 {
531                        log::info!("error in line {}, address is missing", i);
532                        return;
533                    }
534
535                    let addr = self.resolve(args[1], i, emu);
536
537                    if emu.cfg.is_64bits {
538                        log::info!("0x{:x}: '{}'", addr, emu.maps.read_string(addr));
539                    } else {
540                        log::info!("0x{:x}: '{}'", addr as u32, emu.maps.read_string(addr));
541                    }
542                }
543                "mdw" => {
544                    // mdw <addr>
545                    if args.len() != 2 {
546                        log::info!("error in line {}, address is missing", i);
547                        return;
548                    }
549
550                    let addr = self.resolve(args[1], i, emu);
551
552                    if emu.cfg.is_64bits {
553                        log::info!("0x{:x}: '{}'", addr, emu.maps.read_wide_string(addr));
554                    } else {
555                        log::info!("0x{:x}: '{}'", addr as u32, emu.maps.read_wide_string(addr));
556                    }
557                }
558                "mdd" => {
559                    // mdd <addr> <sz> <filename>
560                    if args.len() != 4 {
561                        log::info!("error in line {}, address, size or filename is missing", i);
562                        return;
563                    }
564
565                    let addr = self.resolve(args[1], i, emu);
566
567                    let sz = match self.to_int(&args[2]) {
568                        Some(v) => v,
569                        None => {
570                            log::info!("error in line {}, bad size", i);
571                            return;
572                        }
573                    };
574
575                    if sz <= 0 {
576                        log::info!("error in line {}, bad size", i);
577                        return;
578                    }
579                    emu.maps.save(addr, sz, args[3].to_string());
580                }
581                "mdda" => {
582                    // mdda <folder>
583                    if args.len() != 2 {
584                        log::info!("error in line {}, foler is needed", i);
585                        return;
586                    }
587                    emu.maps.save_all_allocs(args[1].to_string());
588                }
589                "mt" => {
590                    if emu.maps.mem_test() {
591                        log::info!("mem tests passed ok.");
592                    } else {
593                        log::info!("memory errors.");
594                    }
595                }
596                "eip" => {
597                    // eip <addr>
598                    if args.len() != 2 {
599                        log::info!("error in line {}, address is missing", i);
600                        return;
601                    }
602
603                    let addr = self.resolve(args[1], i, emu);
604
605                    emu.set_eip(addr, false);
606                }
607                "rip" => {
608                    // rip <addr>
609                    if args.len() != 2 {
610                        log::info!("error in line {}, address is missing", i);
611                        return;
612                    }
613
614                    let addr = self.resolve(args[1], i, emu);
615
616                    emu.set_rip(addr, false);
617                }
618                "push" => {
619                    // push <hexvalue>
620                    if args.len() != 2 {
621                        log::info!("error in line {}, hex value is missing", i);
622                        return;
623                    }
624
625                    let value = self.resolve(args[1], i, emu);
626
627                    if emu.cfg.is_64bits {
628                        emu.stack_push64(value);
629                    } else {
630                        emu.stack_push32((value & 0xffffffff) as u32);
631                    }
632                }
633                "pop" => {
634                    // pop
635                    if args.len() != 1 {
636                        log::info!("error in line {}, no args required.", i);
637                        return;
638                    }
639
640                    if emu.cfg.is_64bits {
641                        let value = emu.stack_pop64(false).expect("pop failed");
642                        log::info!("poped value 0x{:x}", value);
643                        self.result = value;
644                    } else {
645                        let value = emu.stack_pop32(false).expect("pop failed");
646                        log::info!("poped value 0x{:x}", value);
647                        self.result = value as u64;
648                    }
649                }
650                "fpu" => emu.fpu.print(),
651                "md5" => {
652                    // md5 <mapname>
653                    if args.len() != 2 {
654                        log::info!("error in line {}, no args required.", i);
655                        return;
656                    }
657
658                    let mem = emu.maps.get_mem(&args[1]);
659                    let md5 = mem.md5();
660                    log::info!("md5sum: {:x}", md5);
661                }
662                "ss" => {
663                    // ss <mapname> <string>
664                    if args.len() < 2 {
665                        log::info!("error in line {}, need map name and string", i);
666                        return;
667                    }
668
669                    let kw = args
670                        .iter()
671                        .skip(2)
672                        .map(|s| s.to_owned())
673                        .collect::<Vec<_>>()
674                        .join(" ");
675
676                    let result = match emu.maps.search_string(&kw, &args[1]) {
677                        Some(v) => v,
678                        None => {
679                            log::info!("string not found");
680                            return;
681                        }
682                    };
683
684                    for addr in result.iter() {
685                        if emu.cfg.is_64bits {
686                            log::info!("found 0x{:x} '{}'", *addr, emu.maps.read_string(*addr));
687                        } else {
688                            log::info!(
689                                "found 0x{:x} '{}'",
690                                *addr as u32,
691                                emu.maps.read_string(*addr)
692                            );
693                        }
694                    }
695                }
696                "sb" => {
697                    // sb <map> <spaced bytes>
698                    if args.len() < 2 {
699                        log::info!("error in line {}, need map name and spaced bytes", i);
700                        return;
701                    }
702
703                    let bytes = args
704                        .iter()
705                        .skip(2)
706                        .map(|s| s.to_owned())
707                        .collect::<Vec<_>>()
708                        .join(" ");
709
710                    if emu.maps.search_spaced_bytes(&bytes, &args[1]).len() == 0 {
711                        log::info!("bytes not found.");
712                    }
713                }
714                "sba" => {
715                    // sba <spaced bytes>
716
717                    let bytes = args
718                        .iter()
719                        .skip(1)
720                        .map(|s| s.to_owned())
721                        .collect::<Vec<_>>()
722                        .join(" ");
723
724                    let results = emu.maps.search_spaced_bytes_in_all(&bytes);
725                    for addr in results.iter() {
726                        log::info!("found at 0x{:x}", addr);
727                        self.result = *addr;
728                    }
729                }
730                "ssa" => {
731                    // ssa <string>
732
733                    let s = args
734                        .iter()
735                        .skip(1)
736                        .map(|s| s.to_owned())
737                        .collect::<Vec<_>>()
738                        .join(" ");
739
740                    emu.maps.search_string_in_all(s);
741                }
742                "seh" => {
743                    log::info!("0x{:x}", emu.seh);
744                }
745                "veh" => {
746                    log::info!("0x{:x}", emu.veh);
747                }
748                "ll" => {
749                    // ll <addr>
750                    let addr = self.resolve(args[1], i, emu);
751                    let mut ptr = addr;
752                    loop {
753                        log::info!("- 0x{:x}", ptr);
754                        ptr = match emu.maps.read_dword(ptr) {
755                            Some(v) => v.into(),
756                            None => break,
757                        };
758                        if ptr == 0 || ptr == addr {
759                            break;
760                        }
761                    }
762                }
763                "n" => {
764                    emu.step();
765                }
766                "m" => {
767                    emu.maps.print_maps();
768                }
769                "ms" => {
770                    // ms <keyword>
771                    if args.len() != 2 {
772                        log::info!("error in line {}, `ms` command needs a keyword", i);
773                        return;
774                    }
775                    emu.maps.print_maps_keyword(&args[1]);
776                }
777                "d" => {
778                    // d <addr> <sz>
779                    if args.len() != 3 {
780                        log::info!("error in line {}, `d` command needs an address to disasemble and amount of bytes", i);
781                        return;
782                    }
783
784                    let addr = self.resolve(args[1], i, emu);
785
786                    let sz = match self.to_int(&args[2]) {
787                        Some(v) => v,
788                        None => {
789                            log::info!("error in line {}, bad size", i);
790                            return;
791                        }
792                    };
793
794                    emu.disassemble(addr, sz as u32);
795                }
796                "ldr" => {
797                    // ldr
798                    if emu.cfg.is_64bits {
799                        peb64::show_linked_modules(emu);
800                    } else {
801                        peb32::show_linked_modules(emu);
802                    }
803                }
804                "iat" => {
805                    // iat <keyword>
806                    if args.len() != 2 {
807                        log::info!("error in line {}, keyword expected", i);
808                        return;
809                    }
810
811                    let addr: u64;
812                    let lib: String;
813                    let name: String;
814                    if emu.cfg.is_64bits {
815                        (addr, lib, name) = emu::winapi64::kernel32::search_api_name(emu, &args[1]);
816                    } else {
817                        (addr, lib, name) = emu::winapi32::kernel32::search_api_name(emu, &args[1]);
818                    }
819
820                    if addr == 0 {
821                        log::info!("api not found on iat.");
822                    } else {
823                        log::info!("found: 0x{:x} {}!{}", addr, lib, name);
824                    }
825                }
826                "iatx" => {
827                    // iatx <api>
828                    //TODO: implement this well
829                    if args.len() != 2 {
830                        log::info!("error in line {}, api expected", i);
831                        return;
832                    }
833
834                    let addr: u64;
835                    let lib: String;
836                    let name: String;
837                    if emu.cfg.is_64bits {
838                        (addr, lib, name) = emu::winapi64::kernel32::search_api_name(emu, &args[1]);
839                    } else {
840                        (addr, lib, name) = emu::winapi32::kernel32::search_api_name(emu, &args[1]);
841                    }
842
843                    if addr == 0 {
844                        log::info!("api not found on iat.");
845                    } else {
846                        log::info!("found: 0x{:x} {}!{}", addr, lib, name);
847                    }
848                }
849                "iatd" => {
850                    // iatd <module>
851                    if args.len() != 2 {
852                        log::info!("error in line {}, module expected", i);
853                        return;
854                    }
855                    if emu.cfg.is_64bits {
856                        emu::winapi64::kernel32::dump_module_iat(emu, &args[1]);
857                    } else {
858                        emu::winapi32::kernel32::dump_module_iat(emu, &args[1]);
859                    }
860                }
861                "dt" => {
862                    // dt <structure> <address>
863                    if args.len() != 3 {
864                        log::info!("error in line {}, structure and address expected", i);
865                        return;
866                    }
867
868                    let addr = self.resolve(args[2], i, emu);
869
870                    match args[1] {
871                        "peb" => {
872                            let s = structures::PEB::load(addr, &emu.maps);
873                            s.print();
874                        }
875                        "teb" => {
876                            let s = structures::TEB::load(addr, &emu.maps);
877                            s.print();
878                        }
879                        "peb_ldr_data" => {
880                            let s = structures::PebLdrData::load(addr, &emu.maps);
881                            s.print();
882                        }
883                        "ldr_data_table_entry" => {
884                            let s = structures::LdrDataTableEntry::load(addr, &emu.maps);
885                            s.print();
886                        }
887                        "list_entry" => {
888                            let s = structures::ListEntry::load(addr, &emu.maps);
889                            s.print();
890                        }
891                        "cppeh_record" => {
892                            let s = structures::CppEhRecord::load(addr, &emu.maps);
893                            s.print();
894                        }
895                        "exception_pointers" => {
896                            let s = structures::ExceptionPointers::load(addr, &emu.maps);
897                            s.print();
898                        }
899                        "eh3_exception_registgration" => {
900                            let s = structures::Eh3ExceptionRegistration::load(addr, &emu.maps);
901                            s.print();
902                        }
903                        "memory_basic_information" => {
904                            let s = structures::MemoryBasicInformation::load(addr, &emu.maps);
905                            s.print();
906                        }
907                        "peb64" => {
908                            let s = structures::PEB64::load(addr, &emu.maps);
909                            s.print();
910                        }
911                        "teb64" => {
912                            let s = structures::TEB64::load(addr, &emu.maps);
913                            s.print();
914                        }
915                        "ldrdatatableentry64" => {
916                            let s = structures::LdrDataTableEntry64::load(addr, &emu.maps);
917                            s.print();
918                        }
919                        "image_export_directory" => {
920                            let s = structures::ImageExportDirectory::load(addr, &emu.maps);
921                            s.print();
922                        }
923
924                        _ => log::info!("unrecognized structure."),
925                    }
926                }
927                "if" => {
928                    // if result == rax
929                    // if rbx > 0x123
930
931                    if args.len() != 4 {
932                        log::info!("error in line {}, incomplete `if`", i);
933                        return;
934                    }
935
936                    let a: u64 = self.resolve(args[1], i, emu);
937                    let b: u64 = self.resolve(args[3], i, emu);
938
939                    if args[2] == "==" {
940                        if a != b {
941                            self.skip = true;
942                        }
943                    } else if args[2] == "!=" {
944                        if a == b {
945                            self.skip = true;
946                        }
947                    } else if args[2] == ">" {
948                        if a <= b {
949                            self.skip = true;
950                        }
951                    } else if args[2] == "<" {
952                        if a >= b {
953                            self.skip = true;
954                        }
955                    } else if args[2] == ">=" {
956                        if a < b {
957                            self.skip = true;
958                        }
959                    } else if args[2] == "<=" {
960                        if a > b {
961                            self.skip = true;
962                        }
963                    } else {
964                        log::info!("error in line {}, if with worng operator", i);
965                        return;
966                    }
967                }
968                "console" => {
969                    emu.spawn_console();
970                }
971                "call" => {
972                    // call <addr> <args>
973                    if args.len() < 2 {
974                        panic!("error in line {}, call with no address", i);
975                    }
976
977                    let addr = self.resolve(args[1], i, emu);
978
979                    // push arguments
980                    for j in (2..args.len()).rev() {
981                        let v = self.resolve(args[j], i, emu);
982                        if emu.cfg.is_64bits {
983                            emu.stack_push64(v);
984                        } else {
985                            emu.stack_push32(v as u32);
986                        }
987                    }
988
989                    // push return address
990                    let retaddr: u64;
991                    if emu.cfg.is_64bits {
992                        retaddr = emu.regs.rip;
993                        emu.stack_push64(emu.regs.rip);
994                    } else {
995                        retaddr = emu.regs.get_eip();
996                        emu.stack_push32(emu.regs.get_eip() as u32);
997                    }
998
999                    if emu.cfg.is_64bits {
1000                        emu.set_rip(addr, false);
1001                    } else {
1002                        emu.set_eip(addr, false);
1003                    }
1004
1005                    emu.is_running
1006                        .store(1, std::sync::atomic::Ordering::Relaxed);
1007                    emu.run(Some(retaddr));
1008                }
1009                "set" => {
1010                    //set <hexnum>
1011                    if args.len() < 2 {
1012                        panic!("error in line {}, call with no value", i);
1013                    }
1014
1015                    let value = self.resolve(args[1], i, emu);
1016
1017                    self.result = value;
1018                }
1019                "loop" => {
1020                    self.looped = i as u64;
1021                }
1022                "endloop" => {
1023                    if self.result <= 1 {
1024                        self.looped = 0;
1025                        continue;
1026                    }
1027
1028                    self.result -= 1;
1029                    i = self.looped as usize;
1030                    continue;
1031                }
1032                "trace" => {
1033                    self.trace = true;
1034                }
1035
1036                _ => panic!("error in line {}, unknown command", i),
1037            }
1038        }
1039    }
1040}