Example #1
0
def get_basic_block_ends(vw):
    """
    Return the set of VAs that are the last instructions of basic blocks.
    """
    index = set([])
    for funcva in vw.getFunctions():
        f = viv_utils.Function(vw, funcva)
        for bb in f.basic_blocks:
            if len(bb.instructions) == 0:
                continue
            index.add(bb.instructions[-1].va)
    return index
Example #2
0
def test_api_features(mimikatz):
    features = extract_function_features(
        viv_utils.Function(mimikatz.vw, 0x403BAC))
    assert capa.features.insn.API("advapi32.CryptAcquireContextW") in features
    assert capa.features.insn.API("advapi32.CryptAcquireContext") in features
    assert capa.features.insn.API("advapi32.CryptGenKey") in features
    assert capa.features.insn.API("advapi32.CryptImportKey") in features
    assert capa.features.insn.API("advapi32.CryptDestroyKey") in features
    assert capa.features.insn.API("CryptAcquireContextW") in features
    assert capa.features.insn.API("CryptAcquireContext") in features
    assert capa.features.insn.API("CryptGenKey") in features
    assert capa.features.insn.API("CryptImportKey") in features
    assert capa.features.insn.API("CryptDestroyKey") in features
Example #3
0
 def identify(self, vivisect_workspace, function_vas):
     candidate_functions = {}
     # walk over every instruction
     for fva in function_vas:
         f = viv_utils.Function(vivisect_workspace, fva)
         for n_bb in range(0, len(f.basic_blocks)):
             bb = f.basic_blocks[n_bb]
             try:
                 instructions = bb.instructions
                 for n_instr in range(0, len(bb.instructions)):
                     i = instructions[n_instr]
                     if i.mnem == "xor":
                         if i.opers[0] != i.opers[1]:
                             logger.debug(
                                 "suspicious XOR instruction at 0x%08X in function 0x%08X: %s",
                                 i.va, fva, i)
                             if (n_instr - 1) > 0 and (
                                     n_instr + 1) < len(instructions) - 1:
                                 logger.debug(
                                     "Instructions: %s;  %s;  %s",
                                     instructions[n_instr - 1],
                                     i,
                                     instructions[n_instr + 1],
                                 )
                             if self.is_security_cookie(f, n_bb, n_instr):
                                 logger.debug(
                                     "XOR related to security cookie: %s",
                                     i)
                             else:
                                 logger.debug("unusual XOR: %s", i)
                                 candidate_functions[
                                     fva] = 1.0  # TODO scoring
             except envi.InvalidInstruction:
                 logger.warning(
                     "Invalid instruction encountered in basic block, skipping: 0x%x",
                     bb.va)
                 continue
     return candidate_functions
Example #4
0
    def identify(self, vivisect_workspace, fvas):
        candidate_functions = {}
        for fva in fvas:
            f = viv_utils.Function(vivisect_workspace, fva)
            mnems = set([])
            shift_mnems = set(["shl", "shr", "sar", "sal", "rol", "ror"])
            for bb in f.basic_blocks:
                try:
                    for i in bb.instructions:
                        mnems.add(i.mnem)
                        if i.mnem in shift_mnems:
                            self.d(
                                "shift instruction: %s va: 0x%x function: 0x%x",
                                i, i.va, f.va)
                except envi.InvalidInstruction:
                    self.w(
                        "Invalid instruction encountered in basic block, skipping: 0x%x",
                        bb.va)
                    continue

            candidate_functions[fva] = 1 - (len(shift_mnems - mnems) /
                                            float(len(shift_mnems)))
            self.d("0x%x %f", fva, candidate_functions[fva])
        return candidate_functions
Example #5
0
def test_function_calls_from(sample_9324d1a8ae37a36ae560c37448c9705a):
    features = extract_function_features(
        viv_utils.Function(sample_9324d1a8ae37a36ae560c37448c9705a.vw,
                           0x406F60))
    assert capa.features.Characteristic("calls from") in features
    assert len(features[capa.features.Characteristic("calls from")]) == 23
Example #6
0
def test_function_calls_to64(sample_lab21_01):
    features = extract_function_features(
        viv_utils.Function(sample_lab21_01.vw, 0x1400052D0))  # memcpy
    assert capa.features.Characteristic("calls to") in features
    assert len(features[capa.features.Characteristic("calls to")]) == 8
Example #7
0
def test_stackstring_features(mimikatz):
    features = extract_function_features(
        viv_utils.Function(mimikatz.vw, 0x4556E5))
    assert capa.features.Characteristic("stack string") in features
Example #8
0
def test_segment_access_features(sample_a933a1a402775cfa94b6bee0963f4b46):
    features = extract_function_features(
        viv_utils.Function(sample_a933a1a402775cfa94b6bee0963f4b46.vw,
                           0xABA6FEC))
    assert capa.features.Characteristic("fs access") in features
Example #9
0
def test_unmapped_immediate_memory_reference_features(sample_al_khaser_x86):
    features = extract_function_features(
        viv_utils.Function(sample_al_khaser_x86.vw, 0x41AAB4))
    assert capa.features.insn.Number(0x7FFE02D4) in features
Example #10
0
def test_offset_arch_features(mimikatz):
    features = extract_function_features(
        viv_utils.Function(mimikatz.vw, 0x40105D))
    assert capa.features.insn.Offset(0x0) in features
    assert capa.features.insn.Offset(0x0, arch=ARCH_X32) in features
    assert capa.features.insn.Offset(0x0, arch=ARCH_X64) not in features
Example #11
0
def test_number_arch_features(mimikatz):
    features = extract_function_features(
        viv_utils.Function(mimikatz.vw, 0x40105D))
    assert capa.features.insn.Number(0xFF) in features
    assert capa.features.insn.Number(0xFF, arch=ARCH_X32) in features
    assert capa.features.insn.Number(0xFF, arch=ARCH_X64) not in features
Example #12
0
def test_bytes_pointer_features(mimikatz):
    features = extract_function_features(
        viv_utils.Function(mimikatz.vw, 0x44EDEF))
    assert capa.features.Bytes(
        "INPUTEVENT".encode("utf-16le")).evaluate(features) == True
Example #13
0
def test_string_pointer_features(mimikatz):
    features = extract_function_features(
        viv_utils.Function(mimikatz.vw, 0x44EDEF))
    assert capa.features.String("INPUTEVENT") in features
Example #14
0
def test_basic_block_count(sample_9324d1a8ae37a36ae560c37448c9705a):
    features = extract_function_features(
        viv_utils.Function(sample_9324d1a8ae37a36ae560c37448c9705a.vw,
                           0x406F60))
    assert len(features[capa.features.basicblock.BasicBlock()]) == 26
Example #15
0
 def get_functions(self):
     for va in sorted(self.vw.getFunctions()):
         yield viv_utils.Function(self.vw, va)
Example #16
0
def test_indirect_call_features(sample_a933a1a402775cfa94b6bee0963f4b46):
    features = extract_function_features(
        viv_utils.Function(sample_a933a1a402775cfa94b6bee0963f4b46.vw,
                           0xABA68A0))
    assert capa.features.Characteristic("indirect call") in features
    assert len(features[capa.features.Characteristic("indirect call")]) == 3
Example #17
0
def test_byte_features64(sample_lab21_01):
    features = extract_function_features(
        viv_utils.Function(sample_lab21_01.vw, 0x1400010C0))
    wanted = capa.features.Bytes(b"\x32\xA2\xDF\x2D\x99\x2B\x00\x00")
    # use `==` rather than `is` because the result is not `True` but a truthy value.
    assert wanted.evaluate(features) == True
Example #18
0
 def get_functions(self):
     for va in sorted(self.vw.getFunctions()):
         yield add_va_int_cast(viv_utils.Function(self.vw, va))
Example #19
0
def test_nzxor_features(mimikatz):
    features = extract_function_features(
        viv_utils.Function(mimikatz.vw, 0x410DFC))
    assert capa.features.Characteristic("nzxor") in features  # 0x0410F0B
Example #20
0
def find_decoding_function_features(
        vw,
        functions,
        disable_progress=False) -> Tuple[Dict[int, Dict], Dict[int, str]]:
    decoding_candidate_functions: DefaultDict[
        int, Dict] = collections.defaultdict(dict)

    library_functions: Dict[int, str] = dict()

    pbar = tqdm.tqdm
    if disable_progress:
        logger.info("identifying decoding function features...")
        # do not use tqdm to avoid unnecessary side effects when caller intends
        # to disable progress completely
        pbar = lambda s, *args, **kwargs: s

    functions = sorted(functions)
    n_funcs = len(functions)

    pb = pbar(functions,
              desc="finding decoding function features",
              unit=" functions",
              postfix="skipped 0 library functions")
    with logging_redirect_tqdm(), redirecting_print_to_tqdm():
        for f in pb:
            function_address = int(f)

            if is_thunk_function(vw, function_address):
                continue

            if viv_utils.flirt.is_library_function(vw, function_address):
                # TODO handle j_j_j__free_base (lib function wrappers), e.g. 0x140035AF0 in d2ca76...
                # TODO ignore function called to by library functions
                function_name = viv_utils.get_function_name(
                    vw, function_address)
                logger.debug("skipping library function 0x%x (%s)",
                             function_address, function_name)
                library_functions[function_address] = function_name
                n_libs = len(library_functions)
                percentage = 100 * (n_libs / n_funcs)
                if isinstance(pb, tqdm.tqdm):
                    pb.set_postfix_str("skipped %d library functions (%d%%)" %
                                       (n_libs, percentage))
                continue

            f = viv_utils.Function(vw, function_address)

            function_data = {"meta": get_function_meta(f), "features": list()}

            # meta data features
            function_data["features"].append(
                BlockCount(function_data["meta"].get("block_count")))
            function_data["features"].append(
                InstructionCount(
                    function_data["meta"].get("instruction_count")))
            function_data["features"].append(
                Arguments(function_data["meta"].get("api",
                                                    []).get("arguments")))

            for feature in extract_function_features(f):
                function_data["features"].append(feature)

            for bb in f.basic_blocks:
                for feature in extract_basic_block_features(f, bb):
                    function_data["features"].append(feature)

                for insn in bb.instructions:
                    for feature in extract_insn_features(f, bb, insn):
                        function_data["features"].append(feature)

            for feature in abstract_features(function_data["features"]):
                function_data["features"].append(feature)

            function_data["score"] = get_function_score_weighted(
                function_data["features"])

            logger.debug("analyzed function 0x%x - total score: %f",
                         function_address, function_data["score"])
            for feat in function_data["features"]:
                logger.trace("  %s", feat)

            decoding_candidate_functions[function_address] = function_data

        return decoding_candidate_functions, library_functions
Example #21
0
import sys

import viv_utils

vw = viv_utils.getWorkspace(sys.argv[1])
for f in vw.getFunctions():
    f = viv_utils.Function(vw, f)
    print("function: " + hex(f.va))

    for bb in f.basic_blocks:
        print("basic block: " + hex(bb.va))

        for insn in bb.instructions:
            print("instruction: " + hex(insn.va))