Skip to content
This repository has been archived by the owner on Mar 6, 2022. It is now read-only.

Commit

Permalink
better delta reproducer
Browse files Browse the repository at this point in the history
  • Loading branch information
2xic committed Jul 6, 2019
1 parent cbe620e commit a32d0ed
Show file tree
Hide file tree
Showing 13 changed files with 318 additions and 60 deletions.
50 changes: 22 additions & 28 deletions dynamic/emulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,22 @@ def __init__(self, target):
self.logging = False

self.target = target
self.emulator = Uc(UC_ARCH_X86, UC_MODE_64)

self.boot()

'''
should make a better way to reset each part of the emulator.
'''
def boot(self):
self.emulator = Uc(UC_ARCH_X86, UC_MODE_64)
stack_handler.__init__(self)
memory_mapper.__init__(self)
msr_helper.__init__(self)
strace.__init__(self)

# need to set register first or bugs happen.
registers.__init__(self)

msr_helper.__init__(self)


self.setup_vsdo()

Expand Down Expand Up @@ -129,7 +137,7 @@ def __init__(self, target):
"max_hit_count":7
}
)

self.unicorn_debugger.jump_op("xgetbv", {
"edx":0,
"eax":0x7
Expand All @@ -139,21 +147,9 @@ def __init__(self, target):

})

self.unicorn_debugger.trace_registers("rdi")
# print(self.emulator.mem_read(0x400000 + 0xb1eb8, 16))
# print(self.emulator.mem_read(0x400000 + 0xe8, 16))
# print(self.target.file[0xe8:0xe8+4])
# exit(0)
# print(self.tar)
# print(self.target.file[232:232+32])#[:4])
# print(self.target.program_headers)
# exit(0)


# self.unicorn_debugger.print_at("0x401449")
# self.unicorn_debugger.add_breakpoint(0x4541c0)
# self.unicorn_debugger.add_adress_trace(0x4541cf, ["eflags"])
# self.unicorn_debugger.add_adress_trace(0x4541b4, ["rdi"])
# self.unicorn_debugger.trace_registers("rdi")
# self.unicorn_debugger.trace_registers("rax")

def log_text(self, text, style=None, level=0):
if(self.logging):
Expand All @@ -179,7 +175,7 @@ def run(self, non_stop=False):
# callback for tracing basic blocks
def hook_block(uc, address, size, user_data):
#self.log_bold_text(">>> Tracing call block at 0x%x(%s), block size = 0x%x" % (address, self.unicorn_debugger.determine_location(address) , size))
print(">>> Tracing call block at 0x%x(%s), block size = 0x%x" % (address, self.unicorn_debugger.determine_location(address) , size))
#print(">>> Tracing call block at 0x%x(%s), block size = 0x%x" % (address, self.unicorn_debugger.determine_location(address) , size))
self.log_text(uc.reg_read(UC_X86_REG_RBP))

def hook_mem_invalid(uc, access, address, size, value, user_data):
Expand All @@ -198,13 +194,8 @@ def hook_code(mu, address, size, user_data):
if(self.address_instruction_lookup.get(hex(address), None) == None):
self.address_instruction_lookup[hex(address)] = instruction_info(bytes(mu.mem_read(address, size)))

# for index, register_tuple in enumerate(self.db_registers):
# self.db.add_register_hit(hex(address), register_tuple[0], mu.reg_read(register_tuple[1]))
# self.db.add_memory_trace(register_tuple[0], mu.reg_read(register_tuple[1]), address, int(index < 1))
register_tuple = self.db_registers[2]


self.db.add_memory_trace(register_tuple[0], mu.reg_read(register_tuple[1]), self.unicorn_debugger.current_address, 0)
for index, register_tuple in enumerate(self.db_registers):
self.db.add_register_hit(hex(address), register_tuple[0], mu.reg_read(register_tuple[1]))
self.db.force_increment_op()

self.unicorn_debugger.tick(address, size)
Expand Down Expand Up @@ -298,6 +289,9 @@ def get_memory_data(self, address, excecution_round=0):


def get_latest_register_write(self, register, op_count, excecution_round=0):
return self.db.latest_memory_commit(register, excecution_round, op_count)

try:
return self.db.latest_memory_commit(register, excecution_round, op_count)
except Exception as e:
print(e)
return 0xdeadbeef

69 changes: 60 additions & 9 deletions dynamic/helper_scripts/delta.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import sys
sys.path.insert(0, "../../")
from common.printer import *
from elf.utils import get_symbol_name as elf_get_symbol_name

def split_safe(input_list, index):
if(index < len(input_list)):
Expand All @@ -17,8 +18,16 @@ def unicorn_report(refrence, op_count, last_address):
state = refrence.address_instruction_lookup[last_address][0]
bold_print("Latest instruction : %s" % ("".join(state[0])))
for i in state[1]:
if("flags" in i.lower()):
continue
# print(i)
bold_print("Where %s was last changed : 0x%x" % (i, refrence.get_latest_register_write(i, op_count)))

# new_breakpoint = input("Do you want to rerun unicorn with a breakpoint?\n")
# print("we set a breakpoint at {}".format())




def run_check(unicorn_refrence=None):
print("\n")
Expand All @@ -32,22 +41,37 @@ def run_check(unicorn_refrence=None):
last_agrement = None

can_catch_up = True
trace_register = True
trace_register = False

op_count = 0

while i < len(unicorn) and j < len(gdb):
if(unicorn[i].strip() == (split_safe(gdb[j].strip().split(" "), 1)) or (unicorn[i].strip() == gdb[j].strip().split("\t")[0].split(" ")[-1] )):
last_register_state = None

hit_count = {

}

while i < len(unicorn) and j < len(gdb) and 0 < len(unicorn[i]):
if(unicorn[i].strip() == (split_safe(gdb[j].strip().split(" "), 1)) or (unicorn[i].strip() == gdb[j].strip().split("\t")[0].split(" ")[-1])):
if("=>" in gdb[j]):
last_agrement = unicorn[i].strip()

hit_count[last_agrement] = hit_count.get(last_agrement, 0) + 1

op_count += 1
else:
if("=>" in gdb[j]):
if(unicorn[i].strip() != gdb[j]):
unicorn_val = int(unicorn[i].strip(), 16)
gdb_val = int(gdb[j].strip().split(" ")[1].strip(), 16)

print("last agreement {}".format(last_agrement))
# look_up_code_section(unicorn_refrence)


print(hex(unicorn_refrence.get_latest_register_write("rax", op_count)))

print("last agreement {} (hit {})".format(last_agrement, hit_count[last_agrement]))
print(elf_get_symbol_name(unicorn_refrence.target, int(int(last_agrement, 16))))
print(((unicorn[i - 1].strip(), gdb[j - 1].strip().split(" ")[1])))
print(((unicorn[i].strip(), gdb[j].strip().split(" ")[1])))
old_i, old_j = i, j
Expand Down Expand Up @@ -102,22 +126,49 @@ def run_check(unicorn_refrence=None):
# not perfect, but usally you want to higher up in memory.
bold_print("stuck in loop? (blame %s )" % ("gdb" if(gdb_val < unicorn_val) else "unicorn"))
print("")


command = input("continue ? \n")
if(command == "cc"):
last_register_state = [unicorn_val, gdb_val]
elif(command[:2] == "0x"):
if(0 < len(command)):
unicorn_refrence.boot()
unicorn_refrence.unicorn_debugger.add_breakpoint(int(command, 16))
unicorn_refrence.run()

continue

elif(trace_register):
unicorn_val, gdb_val = unicorn[i], gdb[j].strip().split("\t")[0].split(" ")[-1]
if not (last_register_state == None):
if(unicorn_val == last_register_state[0] and gdb_val == last_register_state[1]):
i += 1
j += 1
continue

bold_print("Mismatch register value....")
print("From address : 0x%x" % int(unicorn[i - 3], 16))
print(unicorn[i])
print("unicorn %s, gdb %s " % (unicorn_val, gdb_val))
print(gdb[j])

unicorn_report(unicorn_refrence, op_count, unicorn[i - 3])
# print( gdb[j].strip().split("\t")[0].split(" ")[-1])
# input("continue ? ")
print("exiting ....")
exit(0)

command = input("continue ? \n")
if(command == "cc"):
last_register_state = [unicorn_val, gdb_val]
elif(command[:2] == "0x"):
if(0 < len(command)):
unicorn_refrence.boot()
unicorn_refrence.unicorn_debugger.add_breakpoint(int(command, 16))
unicorn_refrence.run()

i += 1
j += 1

if(i < len(gdb)):
bold_print("EARLY EXIT, did something bad happend with unicorn? [unicorn i, vs gbd j : %i vs %i" % (i, len(gdb)))

bold_print("Disagreement with gdb == %i" % (disagreement_count))
print("This can be error with handling of instruction or the simple fact that unicorn can have placed something more accesible than gdb.")
print("For instance, enviorment variables are stored more clossely with unicorn")
Expand Down
50 changes: 50 additions & 0 deletions dynamic/helper_scripts/gdb_reproducer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import gdb
import sys
import os
sys.path.insert(0, "/".join(os.path.realpath(__file__).split("/")[:-1]))
sys.path.insert(0, "./")
from stack_string import *
#gdb.execute('file /root/test/test_binaries/small_c_hello')
#gdb.execute('file /root/test/test_binaries/static_small')

# gdb -q -x ./dynamic/helper_scripts/gdb_reproducer.py /root/test/test_binaries/static_small


break_adress = 0x4541cf
hit_counts = None# 11

output = gdb.execute('break *{}'.format(hex(break_adress)), to_string=True)
output = gdb.execute('run', to_string=True)

registers = [
"rax"
]


if(hit_counts != None):
for i in range(hit_counts):
gdb.execute("c")

for register in registers:
hex_2_string(gdb.execute('x ${}'.format(register.lower()), to_string=True))

hex_2_string("0xe1d")
exit(0)

while True:
try:
for register in registers:
padding = 0
while True:
print( gdb.execute('i r {}'.format(register.lower(), padding), to_string=True))
hex_2_string(gdb.execute('i r {}'.format(register.lower(), padding), to_string=True))
if "0" in gdb.execute('i r {}'.format(register.lower(), padding), to_string=True).replace("0x", ""):
break
padding += 4

gdb.execute("c", to_string=True)
except Exception as e:
print(e)
break

gdb.execute('quit', to_string=True)
12 changes: 4 additions & 8 deletions dynamic/helper_scripts/stack_string.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@





import struct
import struct
def hex_2_string(input_stirng, big=False):
if(":" in input_stirng):
input_stirng = input_stirng.split(":")[1]
Expand All @@ -27,8 +23,8 @@ def hex_2_string(input_stirng, big=False):
print("".join(results), end="")
except Exception as e:
print("*ERROR* : ".format(input_stirng))
# print("")


hex_2_string("0x6f6f722f")
print("\n")
if __name__ == "__main__":
hex_2_string("0x7fffffffee43: 0x6f6f722f")

42 changes: 42 additions & 0 deletions dynamic/helper_scripts/unicorn_reproduce.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import sys
sys.path.insert(0, "../../")
sys.path.insert(0, "../")
sys.path.insert(0, "./")

from common.printer import *
import os
import sys
from common.web import *
from common.terminal import *
import dynamic.helper_scripts.delta as delta_compatibility

break_adress = 0x4541b4
hit_counts = 11


file = "/root/test/test_binaries/static_small"

target = model(elf(file), None)

def call_back(emulator_object):
location = emulator_object.reg_read(eval("UC_X86_REG_RDI"))
pretty_print_bytes(emulator_object.mem_read(location, 8))


target.dynamic.unicorn_debugger.add_breakpoint(break_adress, call_back)

target.run_emulator(force=True, thread=False)

# python3 ./dynamic/helper_scripts/unicorn_reproduce.py


'''
okay so at 0x00000000004541b4
mov rax, rdi
rax will only get 0xe1d, I don't know why...
rdi hold the value 0x7fffffffee1d
unicorn and gdb both agree on the value that rdi points to....
maybe bug with mov?
'''
12 changes: 10 additions & 2 deletions dynamic/stack.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,15 @@ def align_stack(self):
def init_stack(self):
start = self.stack_pointer

'''
i'm testing over ssh, so having ssh on the stack makes it easier
to debug with gdb.
'''
envp = list(reversed([
"SSH_CONNECTION=127.0.01 49940 127.0.01 22",

"SSH_CONNECTION=127.0.01 49940 127.0.01 22",
"_=/usr/bin/gdb",
"OLDP",
"XDG_SESSION_ID=1369",
"USER=root",
"PWD=/root",
Expand All @@ -90,7 +96,9 @@ def init_stack(self):
"LOGNAME=root",
"XDG_RUNTIME_DIR=/run/user/0",
"PATH=/root/.cargo/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"padding=true"]))
]))


envp_location = [

]
Expand Down
5 changes: 4 additions & 1 deletion dynamic/strace.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@


from common.printer import *

class strace(object):
def __init__(self):
Expand All @@ -14,4 +15,6 @@ def get_all_syscalls(self):
def add_syscall(self, name_with_arguments):
new_syscall = self.db.add_syscall_entry()
for syscall_entry_element in name_with_arguments:
self.db.syscall_argument_string(str(syscall_entry_element), new_syscall)
self.db.syscall_argument_string(str(syscall_entry_element), new_syscall)

bold_print("syscall %s" % (" ".join(name_with_arguments)))
4 changes: 4 additions & 0 deletions dynamic/syscall_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ def hook_syscall64(mu, user_data):
mu.reg_write(UC_X86_REG_RBX, old_brk)
mu.reg_write(UC_X86_REG_RCX, 0x400994)

# mu.emu_stop()
# user_data.set_msr(mu, user_data.FSMSR , user_data.brk )
# mu.emu_start(rip + user_data.unicorn_debugger.current_size, 0xdeadbeef)

user_data.add_syscall(["brk", hex(mu.reg_read(UC_X86_REG_RBP))])

elif(rax == 0x9):
Expand Down
Loading

0 comments on commit a32d0ed

Please sign in to comment.