Esempio n. 1
0
def cli(context, snapshot_str, coverage, max_time, max_iterations,
        display_delay, stop_on_crash, resume, input, input_size, workdir):

    whvp.init_log()

    if ":" in snapshot_str:
        hostname, port = snapshot_str.split(":")
        snapshot = RpycSnapshot(hostname, int(port))
    else:
        path = snapshot_str
        snapshot = DumpSnapshot(path)

    context = snapshot.get_initial_context()

    tracer = whvp.Tracer(snapshot.memory_access_callback)

    if resume is None:
        os.makedirs(workdir, exist_ok=True)
        guid = str(uuid.uuid4())
        fuzzer_workdir = os.path.join(workdir, guid)
        os.makedirs(fuzzer_workdir)

        input = int(input, 16)
        input_size = int(input_size, 16)

    else:
        fuzzer_workdir = resume

    whvp.log(F"fuzzer workdir is {fuzzer_workdir}")

    crashes_path = os.path.join(fuzzer_workdir, "crashes")
    os.makedirs(crashes_path, exist_ok=True)

    corpus_path = os.path.join(fuzzer_workdir, "corpus")
    os.makedirs(corpus_path, exist_ok=True)

    fuzzer = whvp.Fuzzer(fuzzer_workdir)

    trace_params = snapshot.get_params()

    trace_params["limit"] = 0
    trace_params["coverage"] = coverage
    trace_params["save_context"] = False
    trace_params["save_instructions"] = False

    fuzz_params = {
        "max_iterations": max_iterations,
        "max_time": max_time,
        "input": input,
        "input_size": input_size,
        "stop_on_crash": stop_on_crash,
        "display_delay": display_delay,
        "snapshot": snapshot_str
    }

    path = os.path.join(fuzzer_workdir, "params.json")
    with open(path, "w") as fp:
        json.dump(fuzz_params, fp, indent=2)

    fuzzer.run(tracer, context, trace_params, fuzz_params)
Esempio n. 2
0
def test_complex_trace():
    with open(os.path.join("tests", "sdb", "context.json"), "r") as fp:
        context = json.load(fp)

    for r in ["cs", "ss", "ds", "es", "fs", "gs"]:
        context[r] = {
            "selector": context[r],
            "base": 0,
            "limit": 0,
            "flags": 0,
        }

    def callback(gpa, gva):
        path = os.path.join("tests", "sdb", "mem", F"{gpa:016x}.bin")
        if os.path.exists(path):
            with open(path, "rb") as fp:
                data = fp.read()

            if data:
                return data
            else:
                print("no data")
        else:
            print(F"missing file {path}")

    tracer = whvp.Tracer(callback)
    # context["rflags"] |= 0x100

    tracer.set_initial_context(context)

    params = {"coverage": "no",
              "limit": 0,
              "save_context": False,
              "save_instructions": False,
              "excluded_addresses": {
              },
              "return_address": context["return_address"]}

    result = tracer.run(params)
    print(result)
    coverage = result.get_coverage()

    assert len(coverage) == 1

    tracer.set_initial_context(context)
    tracer.restore_snapshot()

    params["coverage"] = "instrs"

    result = tracer.run(params)
    print(result)
    coverage = result.get_coverage()

    assert len(coverage) == 59120
Esempio n. 3
0
def test_complex_trace2():
    with open(os.path.join("tests", "sdb", "context.json"), "r") as fp:
        context = json.load(fp)

    for r in ["cs", "ss", "ds", "es", "fs", "gs"]:
        context[r] = {
            "selector": context[r],
            "base": 0,
            "limit": 0,
            "flags": 0,
        }

    def callback(gpa, gva):
        path = os.path.join("tests", "sdb", "mem", F"{gpa:016x}.bin")
        if os.path.exists(path):
            with open(path, "rb") as fp:
                data = fp.read()

            if data:
                return data
            else:
                print("no data")
        else:
            print(F"missing file {path}")

    tracer = whvp.Tracer(callback)

    tracer.set_initial_context(context)

    params = {"coverage": "hit",
              "limit": 0,
              "excluded_addresses": {
              },
              "save_context": False,
              "save_instructions": False,
              "return_address": context["return_address"]}

    result = tracer.run(params)
    print(result)
    coverage = result.get_coverage()
    seen = result.get_unique_addresses()
    status = result.get_status()
    # FIXME: check with seen
    assert status == "Success"
    assert len(coverage) == len(seen)
Esempio n. 4
0
def cli(crashes, output, snapshot, limit):
    whvp.init_log()

    if ":" in snapshot:
        hostname, port = snapshot.split(":")
        snapshot = RpycSnapshot(hostname, int(port))
    else:
        path = snapshot
        snapshot = DumpSnapshot(path)

    context = snapshot.get_initial_context()
    params = snapshot.get_params()

    tracer = whvp.Tracer(snapshot.memory_access_callback)

    os.makedirs(output, exist_ok=True)

    traces_dir = os.path.join(output, "traces")
    os.makedirs(traces_dir, exist_ok=True)

    buckets_dir = os.path.join(output, "buckets")
    os.makedirs(buckets_dir, exist_ok=True)

    coverages = {}

    files = [crash for crash in os.listdir(crashes) if crash.endswith(".bin")]
    whvp.log(F"loaded {len(files)} crash(es)")
    whvp.log(F"gathering coverage")
    for index, f in enumerate(files):
        coverage_path = os.path.join(traces_dir, f + ".trace.json")
        if os.path.exists(coverage_path):
            whvp.log(F"coverage exists for {f}, loading from file")
            with open(coverage_path, "r") as fp:
                coverage = json.load(fp)
        else:
            whvp.log(F"doing coverage for {f}")
            whvp.log("replaying input")
            replay = os.path.join(crashes, f)
            with open(replay, "rb") as fp:
                replay_data = fp.read()

            path = os.path.splitext(replay)[0] + ".json"
            with open(path, "r") as fp:
                replay_params = json.load(fp)

            tracer.set_initial_context(context)
            params["limit"] = 0
            params["coverage"] = "no"
            params["save_context"] = False
            params["save_instructions"] = False

            whvp.log("first run to map memory")
            trace = tracer.run(params)
            tracer.restore_snapshot()

            tracer.write_virtual_memory(replay_params["input"], replay_data)

            params["limit"] = 0
            params["coverage"] = "instrs"
            params["save_context"] = False
            params["save_instructions"] = False

            whvp.log("second run to replay crash")
            tracer.set_initial_context(context)
            trace = tracer.run(params)
            tracer.restore_snapshot()

            coverage = trace.get_coverage()
            seen = trace.get_unique_addresses()
            status = trace.get_status()
            time = trace.get_elapsed_time()
            whvp.log(F"executed {len(coverage)} instruction(s), {len(seen)} were unique in {time} ({status})")

            whvp.log(F"saving trace to {coverage_path}")
            trace.save(coverage_path)

            with open(coverage_path, "r") as fp:
                coverage = json.load(fp)

        coverages[f] = coverage

    buckets = collections.defaultdict(list)

    for f in files:
        m = hashlib.sha1()
        for (address, context) in coverages[f]["coverage"][-limit:]:
            data = F"{address:016x}"
            m.update(bytes(data, encoding="utf-8"))

        bucket = m.hexdigest()
        buckets[bucket].append(f)

    whvp.log(F"triaged {len(files)} crash(es)")
    whvp.log(F"found {len(buckets)} unique crash(es)")
    for bucket, duplicates in buckets.items():
        whvp.log(F"bucket {bucket} contains {len(duplicates)} file(s)")

        bucket_path = os.path.join(buckets_dir, bucket)
        os.makedirs(bucket_path, exist_ok=True)

        for d in duplicates:
            src = os.path.join(crashes, d)
            shutil.copy(src, bucket_path)

            src = os.path.join(crashes, os.path.splitext(d)[0] + ".json")
            shutil.copy(src, bucket_path)
Esempio n. 5
0
def cli(snapshot, coverage, save_context, save_instructions, save_trace,
        replay, max_time):
    whvp.init_log()

    if ":" in snapshot:
        hostname, port = snapshot.split(":")
        snapshot = RpycSnapshot(hostname, int(port))
    else:
        path = snapshot
        snapshot = DumpSnapshot(path)

    context = snapshot.get_initial_context()
    params = snapshot.get_params()

    tracer = whvp.Tracer(snapshot.memory_access_callback)

    # FIXME: rename to set_context
    tracer.set_initial_context(context)

    params["limit"] = 0
    params["coverage"] = coverage
    params["save_context"] = save_context
    params["save_instructions"] = save_instructions
    if max_time != 0:
        params["max_time"] = max_time

    whvp.log("running tracer")
    trace = tracer.run(params)

    coverage = trace.get_coverage()
    seen = trace.get_unique_addresses()
    status = trace.get_status()
    time = trace.get_elapsed_time()
    whvp.log(
        F"executed {len(coverage)} instruction(s), {len(seen)} were unique in {time} ({status})"
    )

    pages = tracer.restore_snapshot()
    whvp.log(F"{pages} page(s) were modified")
    # FIXME: get dirty pages, code pages, data pages

    if replay:
        whvp.log("replaying input")
        with open(replay, "r") as fp:
            replay_params = json.load(fp)

        path = os.path.splitext(replay)[0] + ".bin"
        with open(path, "rb") as fp:
            replay_data = fp.read()

        tracer.set_initial_context(context)
        orig_data = tracer.read_virtual_memory(replay_params["input"],
                                               replay_params["input_size"])

        input = helpers.Input(replay_params["input"], orig_data)
        whvp.log("input bytes:")
        print(input.diff(replay_data))

        whvp.log("running tracer with modified input")
        tracer.write_virtual_memory(replay_params["input"], replay_data)
        trace = tracer.run(params)

        coverage = trace.get_coverage()
        seen = trace.get_unique_addresses()
        status = trace.get_status()
        time = trace.get_elapsed_time()
        whvp.log(
            F"executed {len(coverage)} instruction(s), {len(seen)} were unique in {time} ({status})"
        )

    if save_trace:
        whvp.log(F"saving trace to {save_trace}")
        trace.save(save_trace)
Esempio n. 6
0
def test_basic_trace():
    with open(os.path.join("tests", "RtlInitUnicodeString.json"), "r") as fp:
        context = json.load(fp)

    regs = context["regs"]
    regs["rflags"] = 0x40246
    regs["efer"] = context["efer"]

    for r in ["cs", "ss", "ds", "es", "fs", "gs"]:
        regs[r] = {
            "selector": regs[r],
            "base": 0,
            "limit": 0,
            "flags": 0,
        }

    def callback(gpa, gva):
        pfn = gpa >> 12
        print(F"writing pfn {pfn:x}")

        data = context["pfn"].get(str(pfn))
        if data:
            data = base64.b64decode(data)
            return data
        else:
            print("unknown pfn")

    tracer = whvp.Tracer(callback)

    tracer.set_initial_context(regs)

    params = {"limit": 25,
              "coverage": "instrs",
              "save_context": False,
              "save_instructions": False,
              "excluded_addresses": {
              },
              "return_address": context["return_address"]}

    result = tracer.run(params)
    print(result)
    coverage = result.get_coverage()
    print(coverage)
    assert len(coverage) == 5
    assert len(coverage[0]) == 1
    instructions = result.get_instructions()
    assert len(instructions) == 0

    tracer.set_initial_context(regs)
    params["save_context"] = True

    result = tracer.run(params)
    print(result)
    coverage = result.get_coverage()
    print(coverage)
    assert len(coverage) == 5
    assert len(coverage[0]) == 18
    instructions = result.get_instructions()
    assert len(instructions) == 0

    tracer.set_initial_context(regs)
    params["save_instructions"] = True

    result = tracer.run(params)
    print(result)
    instructions = result.get_instructions()
    print(instructions)
    assert len(instructions) == 5