Beispiel #1
0
    def queue_run(self, run_type, ep, run_args=[]):
        run = Run()
        if not isinstance(run_type, str):
            raise ApiEmuError('Invalid run type')
        if not isinstance(ep, int):
            raise ApiEmuError('Invalid run entry point')
        if not any((isinstance(run_args, list), isinstance(run_args, tuple))):
            raise ApiEmuError('Invalid run args')

        run.type = run_type
        run.start_addr = ep
        run.args = run_args
        self.emu.add_run(run)
Beispiel #2
0
    def run_shellcode(self, sc_addr, offset=0):
        """
        Begin emulating position independent code (i.e. shellcode) to prepare for emulation
        """

        target = None
        for sc_path, _sc_addr, size in self.pic_buffers:
            if _sc_addr == sc_addr:
                target = _sc_addr
                break

        if not target:
            raise Win32EmuError("Invalid shellcode address")

        stack_commit = 0x4000

        self.stack_base, stack_addr = self.alloc_stack(stack_commit)
        self.set_func_args(self.stack_base, self.return_hook, 0x7000)

        run = Run()
        run.type = "shellcode"
        run.start_addr = sc_addr + offset
        run.instr_cnt = 0
        args = [
            self.mem_map(1024, tag="emu.shellcode_arg_%d" % (i), base=0x41420000 + i)
            for i in range(4)
        ]
        run.args = args

        self.reg_write(_arch.X86_REG_ECX, 1024)

        self.add_run(run)

        # Create an empty process object for the shellcode if none is
        # supplied
        container = self.init_container_process()
        if container:
            self.processes.append(container)
            self.curr_process = container
        else:
            p = objman.Process(self)
            self.processes.append(p)
            self.curr_process = p

        mm = self.get_address_map(sc_addr)
        if mm:
            mm.set_process(self.curr_process)

        t = objman.Thread(self, stack_base=self.stack_base, stack_commit=stack_commit)
        self.om.objects.update({t.address: t})
        self.curr_process.threads.append(t)

        self.curr_thread = t

        peb = self.alloc_peb(self.curr_process)

        # Set the TEB
        self.init_teb(t, peb)

        self.start()
Beispiel #3
0
    def next_driver_func(self, drv):

        func_addr = None
        func_handler = None

        if self.curr_run.type is not None:
            self.curr_run.ret_val = self.get_return_val()

        # Check if theres anything in the run queue
        if len(self.run_queue):
            return

        if not self.all_entrypoints:
            return

        # TODO right now just use the first device object that was created
        dev = None
        if len(drv.devices):
            dev = drv.devices[0]

        # Run any remaining IRP handlers
        for hdlr, i in (
            (self.irp_mj_create, ddk.IRP_MJ_CREATE),
            (self.irp_mj_dev_io, ddk.IRP_MJ_DEVICE_CONTROL),
            (self.irp_mj_read, ddk.IRP_MJ_READ),
            (self.irp_mj_write, ddk.IRP_MJ_WRITE),
            (self.irp_mj_close, ddk.IRP_MJ_CLOSE),
            (self.irp_mj_cleanup, ddk.IRP_MJ_CLEANUP),
        ):

            # Did we run this mj func yet?
            if i not in [r.type for r in self.runs]:
                func_handler = hdlr
                func_addr = int(drv.mj_funcs[i])

                if not func_addr:
                    continue
                break

        if len(self.delayed_runs):
            [self.add_run(r) for r in self.delayed_runs]
            self.delayed_runs = []

        if not func_addr or not dev:
            # We are done here, call the unload routine
            self.driver_unload(drv)
            return

        irp = func_handler(func_addr, dev)

        run = Run()
        run.type = i
        run.start_addr = func_addr
        run.instr_cnt = 0
        run.args = (dev.address, irp.address)
        self.add_run(run)
Beispiel #4
0
    def driver_unload(self, drv):
        """
        Call the unload routine for a driver
        """

        if not drv.on_unload or drv.unload_called:
            self.on_emu_complete()
            return

        stk_ptr = self.get_stack_ptr()
        self.set_func_args(stk_ptr, self.exit_hook, drv.address)
        self.set_pc(drv.on_unload)

        run = Run()
        run.type = EP_DRIVER_UNLOAD
        run.start_addr = drv.on_unload
        run.instr_cnt = 0
        run.args = (drv.address, )
        run.ret_val = None
        self.add_run(run)
        drv.unload_called = True
Beispiel #5
0
    def run_module(self, module, all_entrypoints=False):
        """
        Begin emulating a previously loaded module

        Arguments:
            module: Module to emulate
        """

        if not module:
            self.stop()
            raise Win32EmuError('Module not found')

        # Check if any TLS callbacks exist, these run before the module's entry point
        tls = module.get_tls_callbacks()
        for i, cb_addr in enumerate(tls):
            base = module.get_base()
            if base < cb_addr < base + module.get_image_size():
                run = Run()
                run.start_addr = cb_addr
                run.type = 'tls_callback_%d' % (i)
                run.args = [base, DLL_PROCESS_ATTACH, 0]
                self.add_run(run)

        # Queue up the module's main entry point
        ep = module.base + module.ep

        run = Run()
        run.start_addr = ep

        main_exe = None
        if not module.is_exe():
            run.args = [module.base, DLL_PROCESS_ATTACH, 0]
            run.type = 'dll_entry.DLL_PROCESS_ATTACH'
            container = self.init_container_process()
            if container:
                self.processes.append(container)
                self.curr_process = container
        else:
            run.type = 'module_entry'
            main_exe = module
            run.args = [
                self.mem_map(8, tag='emu.module_arg_%d' % (i))
                for i in range(4)
            ]

        if main_exe:
            self.user_modules = [main_exe] + self.user_modules

        self.add_run(run)

        if all_entrypoints:
            # Only emulate a subset of all the exported functions
            # There are some modules (such as the windows kernel) with
            # thousands of exports
            exports = [
                k for k in module.get_exports()[:MAX_EXPORTS_TO_EMULATE]
            ]

            if exports:
                args = [
                    self.mem_map(8,
                                 tag='emu.export_arg_%d' % (i),
                                 base=0x41420000) for i in range(4)
                ]  # noqa
                for exp in exports:
                    if exp.name in ('DllMain', 'ServiceMain'):
                        continue
                    run = Run()
                    if exp.name:
                        fn = exp.name
                    else:
                        fn = 'no_name'

                    run.type = 'export.%s' % (fn)
                    run.start_addr = exp.address
                    # Here we set dummy args to pass into the export function
                    run.args = args
                    # Store these runs and only queue them before the unload
                    # routine this is because some exports may not be ready to
                    # be called yet
                    self.add_run(run)

        # Create an empty process object for the module if none is
        # supplied
        if len(self.processes) == 0:
            p = objman.Process(self,
                               path=module.get_emu_path(),
                               base=module.base,
                               pe=module,
                               cmdline=self.command_line)
            self.curr_process = p
            self.om.objects.update({p.address: p})
            mm = self.get_address_map(module.base)
            if mm:
                mm.process = self.curr_process

        t = objman.Thread(self,
                          stack_base=self.stack_base,
                          stack_commit=module.stack_commit)

        self.om.objects.update({t.address: t})
        self.curr_process.threads.append(t)
        self.curr_thread = t

        peb = self.alloc_peb(self.curr_process)

        # Set the TEB
        self.init_teb(t, peb)

        # Begin emulation
        self.start()
Beispiel #6
0
    def prepare_module_for_emulation(self, module, all_entrypoints, entrypoints):
        if not module:
            self.stop()
            raise Win32EmuError("Module not found")

        # Check if any TLS callbacks exist, these run before the module's entry point
        tls = module.get_tls_callbacks()
        for i, cb_addr in enumerate(tls):
            base = module.get_base()
            if base < cb_addr < base + module.get_image_size():
                run = Run()
                run.start_addr = cb_addr
                run.type = "tls_callback_%d" % (i)
                run.args = [base, DLL_PROCESS_ATTACH, 0]
                self.add_run(run)

        ep = module.base + module.ep

        run = Run()
        run.start_addr = ep

        main_exe = None
        if not module.is_exe():
            run.args = [module.base, DLL_PROCESS_ATTACH, 0]
            run.type = "dll_entry.DLL_PROCESS_ATTACH"
            container = self.init_container_process()
            if container:
                self.processes.append(container)
                self.curr_process = container
        else:
            run.type = "module_entry"
            main_exe = module
            run.args = [
                self.mem_map(8, tag="emu.module_arg_%d" % (i)) for i in range(4)
            ]

        if main_exe:
            self.user_modules = [main_exe] + self.user_modules
        # we consider this run only if all entry_points is selected or DLL_PROCESS_ATTACH is in the entrypoints
        if all_entrypoints or "DLL_PROCESS_ATTACH" in entrypoints:
            self.add_run(run)

        if all_entrypoints or entrypoints:
            # Only emulate a subset of all the exported functions
            # There are some modules (such as the windows kernel) with
            # thousands of exports
            exports = [k for k in module.get_exports()[:MAX_EXPORTS_TO_EMULATE]]

            if exports:
                args = [
                    self.mem_map(8, tag="emu.export_arg_%d" % (i), base=0x41420000)
                    for i in range(4)
                ]  # noqa
                for exp in exports:
                    if exp.name in ("DllMain",):
                        continue
                    if all_entrypoints or exp.name in entrypoints:
                        run = Run()
                        if exp.name:
                            fn = exp.name
                        else:
                            fn = "no_name"

                        run.type = "export.%s" % (fn)
                        run.start_addr = exp.address
                        if exp.name == "ServiceMain":
                            # ServiceMain accepts a (argc, argv) pair like main().
                            #
                            # now, we're not exactly sure if we're in A or W mode.
                            # maybe there are some hints we could take to guess this.
                            # instead, we'll assume W mode and use default service name "IPRIP".
                            #
                            # hack: if we're actually in A mode, then string routines
                            # will think the service name is "I" which isn't perfect,
                            # but might still be good enough.
                            #
                            # layout:
                            #   argc: 1
                            #   argv:
                            #     0x00:    (argv[0]) pointer to +0x10 -+
                            #     0x04/08: (argv[1]) 0x0               |
                            #     0x10:    "IPRIP"  <------------------+
                            svc_name = "IPRIP\x00".encode("utf-16le")
                            argc = 1
                            argv = self.mem_map(
                                len(svc_name) + 0x10,
                                tag="emu.export_ServiceMain_argv",
                                base=0x41420000,
                            )

                            self.write_ptr(argv, argv + 0x10)
                            self.mem_write(argv + 0x10, svc_name)

                            run.args = [argc, argv]
                        else:
                            # Here we set dummy args to pass into the export function
                            run.args = args
                        # Store these runs and only queue them before the unload
                        # routine this is because some exports may not be ready to
                        # be called yet
                        self.add_run(run)

        return
Beispiel #7
0
    def run_module(self, module, all_entrypoints=False):
        """
        Begin emulation fo a previously loaded kernel module
        """

        self.all_entrypoints = all_entrypoints

        # Create the service key for the driver
        drv = self.create_driver_object(pe=module)
        svc_key = self.regman.create_key(drv.get_reg_path())
        # Create the values for the service key
        svc_key.create_value('ImagePath', regdefs.REG_EXPAND_SZ,
                             module.get_emu_path())
        svc_key.create_value('Type', regdefs.REG_DWORD,
                             0x1)  # SERVICE_KERNEL_DRIVER
        svc_key.create_value('Start', regdefs.REG_DWORD,
                             0x3)  # SERVICE_DEMAND_START
        svc_key.create_value('ErrorControl', regdefs.REG_DWORD,
                             0x1)  # SERVICE_ERROR_NORMAL

        # Create the parameters subkey
        self.regman.create_key(drv.get_reg_path() + '\\Parameters')

        if module.ep > 0:

            ep = module.base + module.ep

            run = Run()
            run.type = EP_DRIVER_ENTRY
            run.start_addr = ep
            run.instr_cnt = 0
            run.args = [drv.address, drv.reg_path_ptr]
            self.add_run(run)

        if self.all_entrypoints:
            # Only emulate a subset of all the exported functions
            # There are some modules (such as the windows kernel) with thousands of exports
            exports = [
                k for k in module.get_exports()[:MAX_EXPORTS_TO_EMULATE]
            ]

            if exports:
                args = [
                    self.mem_map(8, tag='emu.export_arg_%d' % (i))
                    for i in range(4)
                ]
                for exp in exports:
                    run = Run()
                    if exp.name:
                        fn = exp.name
                    else:
                        fn = 'no_name'
                    run.type = 'export.%s' % (fn)
                    run.start_addr = exp.address
                    # Here we set dummy args to pass into the export function
                    run.args = args
                    # Store these runs and only queue them before the unload routine
                    # this is because some exports may not be ready to be called yet
                    self.delayed_runs.append(run)

        self.start()