Esempio n. 1
0
 def hook_mem_access(self, uc, access, address, size, value, user_data):
     curr_section = self.sample.unpacker.get_section(address)
     access_type = ""
     if access == UC_MEM_READ:
         access_type = "READ"
         if curr_section not in self.sections_read:
             self.sections_read[curr_section] = 1
         else:
             self.sections_read[curr_section] += 1
         self.log_mem_read and print(">>> Memory is being READ at 0x%x, data size = %u" % (address, size))
     elif access == UC_MEM_WRITE:
         access_type = "WRITE"
         self.write_targets = list(merge(self.write_targets + [(address, address + size)]))
         if curr_section not in self.sections_written:
             self.sections_written[curr_section] = 1
         else:
             self.sections_written[curr_section] += 1
         self.log_mem_write and print(
             ">>> Memory is being WRITTEN at 0x%x, data size = %u, data value = 0x%x" % (address, size, value))
     else:
         for access_name, val in unicorn_const.__dict__.items():
             if val == access and "UC_MEM" in access_name:
                 access_type = access_name[6:]  # remove UC_MEM from the access type
                 print(f"Unexpected mem access type {access_type}, addr: 0x{address:02x}")
     if any(lower <= address <= upper for lower, upper in self.mem_breakpoints):
         print(f"\x1b[31mMemory breakpoint hit! Access {access_type} to 0x{address:02x}")
         self.pause()
Esempio n. 2
0
    def do_del(self, args):
        """Removes breakpoints. Usage is the same as 'b', but the selected breakpoints and breakpoint ranges are being
deleted this time."""
        code_targets = []
        mem_targets = []
        if not args:
            self.engine.breakpoints.clear()
            self.engine.mem_breakpoints.clear()
            self.engine.apicall_handler.pending_breakpoints.clear()
        for arg in args.split(" "):
            if not arg:
                continue
            if arg == "stack":
                mem_targets += [
                    (self.engine.STACK_ADDR,
                     self.engine.STACK_ADDR + self.engine.STACK_SIZE)
                ]
            elif "m" == arg[0]:
                try:
                    parts = list(map(lambda p: int(p, 0), arg[1:].split("-")))
                    if len(parts) == 1:
                        lower = upper = parts[0]
                    else:
                        lower = min(parts)
                        upper = max(parts)
                    mem_targets += [(lower, upper)]
                except ValueError:
                    print(f"Error parsing address or range {arg}")
            elif "$" == arg[0]:
                arg = arg[1:]
                if arg in self.engine.apicall_handler.hooks.values():
                    for addr, func_name in self.engine.apicall_handler.hooks.items(
                    ):
                        if arg == func_name:
                            code_targets += [addr]
                            break
                elif arg in self.engine.apicall_handler.pending_breakpoints:
                    self.engine.apicall_handler.pending_breakpoints.remove(arg)
                else:
                    print(
                        f"Unknown method {arg}, not imported or used in pending breakpoint"
                    )
            else:
                try:
                    code_targets += [int(arg, 0)]
                except ValueError:
                    print(f"Error parsing address {arg}")
        with self.engine.data_lock:
            for t in code_targets:
                try:
                    self.engine.breakpoints.remove(t)
                except KeyError:
                    pass
            new_mem_breakpoints = []
            for b_lower, b_upper in self.engine.mem_breakpoints:
                for t_lower, t_upper in mem_targets:
                    new_mem_breakpoints += remove_range((b_lower, b_upper),
                                                        (t_lower, t_upper))
            self.engine.mem_breakpoints = list(merge(new_mem_breakpoints))
            self.print_breakpoints()
Esempio n. 3
0
    def VirtualFree(self, uc, esp, log, address, size, free_type):
        log and print(f"VirtualFree: chunk to free: 0x{address:02x}, size 0x{size:02x}, type 0x{free_type:02x}")
        new_chunks = []
        success = False
        for start, end in sorted(self.sample.allocated_chunks):
            if start <= address <= end:
                if free_type & 0x8000 and size == 0:  # MEM_RELEASE, clear whole allocated range
                    if address in self.alloc_sizes:
                        size = self.alloc_sizes[address]
                        end_addr = address + size
                        uc.mem_unmap(address, size)
                        new_chunks += remove_range((start, end), (address, end_addr))
                        success = True
                    else:
                        log and print(f"\t0x{address} is not an alloc base address!")
                        new_chunks += [(start, end)]
                elif free_type & 0x4000 and size > 0:  # MEM_DECOMMIT, free requested size
                    end_addr = address + align(size)
                    uc.mem_unmap(address, align(size))
                    new_chunks += remove_range((start, end), (address, end_addr))
                    success = True
                else:
                    log and print("\tIncorrect size + type combination!")
                    new_chunks += [(start, end)]
            else:
                new_chunks += [(start, end)]

        self.sample.allocated_chunks = list(merge(new_chunks))
        log and self.print_allocs()
        if success:
            return 1
        log and print("\tAddress range not allocated!")
        return 0
Esempio n. 4
0
    def alloc(self, log, size, uc, offset=None):
        page_size = 4 * 1024
        aligned_size = align(size, page_size)
        log and print(
            f"\tUnaligned size: 0x{size:02x}, aligned size: 0x{aligned_size:02x}"
        )
        if offset is None:
            for chunk_start, chunk_end in self.sample.allocated_chunks:
                if chunk_start <= self.dynamic_mem_offset <= chunk_end:
                    # we have to push back the dynamic mem offset as it is inside an already allocated chunk!
                    self.dynamic_mem_offset = chunk_end + 1
            offset = self.dynamic_mem_offset
            self.dynamic_mem_offset += aligned_size
        new_offset_m = offset % page_size
        aligned_address = offset  # TODO Remove hacky fix, chunks are not merged
        if (aligned_address % page_size) != 0:
            aligned_address = align(offset)

        # check if we have mapped parts of it already
        mapped_partial = False
        for chunk_start, chunk_end in self.sample.allocated_chunks:
            if chunk_start <= aligned_address < chunk_end:
                if aligned_address + aligned_size <= chunk_end:
                    log and print(f"\tAlready fully mapped")
                else:
                    log and print(
                        f"\tMapping missing piece 0x{chunk_end + 1:02x} to 0x{aligned_address + aligned_size:02x}"
                    )
                    uc.mem_map(chunk_end,
                               aligned_address + aligned_size - chunk_end)
                mapped_partial = True
                break

        if not mapped_partial:
            uc.mem_map(aligned_address, aligned_size)
        log and print(
            f"\tfrom 0x{aligned_address:02x} to 0x{(aligned_address + aligned_size):02x}"
        )
        self.sample.allocated_chunks = list(
            merge(self.sample.allocated_chunks +
                  [(aligned_address, aligned_address + aligned_size)]))
        log and self.print_allocs()
        self.alloc_sizes[aligned_address] = aligned_size
        return aligned_address
Esempio n. 5
0
    def do_b(self, args):
        """Set breakpoints. All of the options below can be combined in one command any number of times

Code breakpoint:            b <address> [<addr2> ...]
    Classic breakpoint: Emulation will stop before executing the instruction at the given
    address.

API call breakpoint:        b $<api_call_name>
    Special case of code breakpoint: Stop the emulation when a certain API call is being made.
    If this function has been declared in the sample's import table, the breakpoint will be set
    instantly. If this function will be called in the future, but is somehow not known at the
    moment (dynamically resolved via GetProcAddress), we will still stop the execution on
    call. But until GetProcAddress is instructed to return the address of this function, the
    breakpoint will be marked as 'pending'. At this point we create a hook for the function
    and mark it as a normal breakpoint.

Memory breakpoint:          b m<address>[-<upper_limit>] ...
    When prefixing the address with an 'm', emulation will stop when this address is being
    read from or written to. Optionally you can set the breakpoint to watch over a whole
    range of memory, e.g. b m0x100-0x200.

Stack breakpoint:           b stack
    Special case of memory range breakpoint: watches the whole stack space

Show current breakpoints:   b"""
        code_targets = []
        mem_targets = []
        for arg in args.split(" "):
            if not arg:
                continue
            if arg == "stack":
                mem_targets += [
                    (self.engine.STACK_ADDR,
                     self.engine.STACK_ADDR + self.engine.STACK_SIZE)
                ]
            elif "m" == arg[0]:
                try:
                    parts = list(map(lambda p: int(p, 0), arg[1:].split("-")))
                    if len(parts) == 1:
                        lower = upper = parts[0]
                    else:
                        lower = min(parts)
                        upper = max(parts)
                    mem_targets += [(lower, upper)]
                except ValueError:
                    print(f"Error parsing address or range {arg}")
            elif "$" == arg[0]:
                arg = arg[1:]
                if arg in self.engine.apicall_handler.hooks.values():
                    for addr, func_name in self.engine.apicall_handler.hooks.items(
                    ):
                        if arg == func_name:
                            code_targets += [addr]
                            break
                else:
                    self.engine.apicall_handler.register_pending_breakpoint(
                        arg)
            else:
                try:
                    code_targets += [int(arg, 0)]
                except ValueError:
                    print(f"Error parsing address {arg}")
        with self.engine.data_lock:
            self.engine.breakpoints.update(code_targets)
            self.engine.mem_breakpoints = list(
                merge(self.engine.mem_breakpoints + mem_targets))
            self.print_breakpoints()