def __init__(self, ctx): fe.log("in pslist constructor") fe.set_name("pslist") self.lookups = { "name_offset": fe.lookup_structure("task_struct", "comm"), "pid_offset": fe.lookup_structure("task_struct", "pid"), "tasks_offset": fe.lookup_structure("task_struct", "tasks"), "init_task": fe.lookup_symbol("init_task"), } e = {"event_type": fe.BE, "callback": self.be_callback} fe.event_register(e) e = { "event_type": fe.TIMER, "time_value": 0.1, # seconds "callback": self.timer_callback, } fe.event_register(e) self.pslist = {} self.log = [] self.calls = [] self.msgs = [] self.procs = [] fe.log("leaving pslist constructor")
def do_batch_pslist(self, pause=False): if pause: fe.pause_vm() calls = 0 procs = 0 msgs = 0 i = 0 maxi = 100 pido = self.lookups["pid_offset"] tasko = self.lookups["tasks_offset"] nameo = self.lookups["name_offset"] list_head = self.lookups["init_task"] + self.lookups["tasks_offset"] cur = list_head o = fe.batch_new() start_pslist = time.time() while True: o.reset() o.add("1", "READ_STR_VA", { "vaddr": cur + nameo - tasko, "pid": 0 }) # current name o.add("2", "READ_32_VA", { "vaddr": cur + pido - tasko, "pid": 0 }) # current pid o.add("3", "READ_ADDR_VA", { "vaddr": cur, "pid": 0 }) # pointer to next ts fe.batch_send(o) calls += 3 msgs += 1 procs += 1 for r in o.results(): if r["name"] == "3": cur = r["result"] # do something with result i += 1 if cur & 0xffffffffffff == list_head or i > maxi: fe.log(f"ending loop at {i}") end_pslist = time.time() self.log.append(end_pslist - start_pslist) break self.calls.append(calls) self.procs.append(procs) self.msgs.append(msgs) if pause: fe.resume_vm()
def timer_callback(self, ctx): if not self.one_way: fe.log('hi') fe.notify(json.dumps({'cmd': 'hi', 'data': time.time()})) self.one_way = True elif not self.two_way: fe.log('waiting') fe.notify(json.dumps({'cmd': 'waiting', 'data': time.time()})) self.ticks += 1
def timer_callback(self, ctx): fe.log("calling functions!") # e = fe.translate_ksym2v('init_task') # fe.log(f'TRANSLATE_KSYM2V init_task: {e}') self.do_pslist(pause=True) fe.log("done!") fe.exit()
def timer_callback(self, ctx): if not self.one_way: fe.log("hi") fe.notify(json.dumps({"cmd": "hi", "data": time.time()})) self.one_way = True elif not self.two_way: fe.log("waiting") fe.notify(json.dumps({"cmd": "waiting", "data": time.time()})) self.ticks += 1
def parse_symbols(self): self.symbols = {} for l in self.symbol_string.split("\n"): f1, t, func_name = l.split() address = int(f1, 16) self.symbols[address] = { "address": address, "t": t, "func_name": func_name } fe.log(f"{address}: {func_name}") fe.log(f"parsed {len(self.symbols)} symbols")
def __init__(self, ctx): fe.log("in memdump constructor") fe.set_name("memdump") fe.log("getting memsize") self.memsize = fe.get_memsize() fe.log(f"memsize: {self.memsize}") self.offset = 0 self.ttl = 100 # self.bound = fe.MAX_FIELD_SIZE - 1024 # self.bound = 8096 self.bound = 2 ** 22 self.did = -1 fe.event_register({"event_type": fe.BE, "callback": self.be_callback}) fe.event_register( {"event_type": fe.TIMER, "time_value": 2.0, "callback": self.timer_callback} ) self.ticks = 0 self.one_way = False self.two_way = False self.zco = zlib.compressobj() fe.log("leaving memdump constructor")
def __init__(self, ctx): fe.log("in vmi_runtime_testing constructor") fe.event_register( {"event_type": fe.TIMER, "time_value": 1.0, "callback": self.timer_callback} ) self.lookups = { "name_offset": fe.get_offset("linux_name"), "pid_offset": fe.get_offset("linux_pid"), "tasks_offset": fe.get_offset("linux_tasks"), "init_task": fe.translate_ksym2v("init_task"), } self.pslist = {}
def do_modlist(self): fe.pause_vm() start_pslist = time.time() list_head = self.lookups["modules"] next_module = self.lookups["modules"] i = 0 maxi = 100 fe.log("starting MODLIST") while True: tmp_next = fe.read_addr_va(next_module, 0) if tmp_next & 0xffffffffffff == list_head or i > maxi: fe.log("ending loop at %d" % (i, )) end_pslist = time.time() break modname = fe.read_str_va(next_module + 16, 0) fe.log("%s" % (modname, )) next_module = tmp_next i += 1 stop_pslist = time.time() fe.resume_vm() fe.log("modlist in {sec:.6f} seconds".format(sec=stop_pslist - start_pslist))
def __init__(self, ctx): fe.log('in memdump constructor') fe.set_name('memdump') fe.log('getting memsize') self.memsize = fe.get_memsize() fe.log(f'memsize: {self.memsize}') self.offset = 0 self.ttl = 100 #self.bound = fe.MAX_FIELD_SIZE - 1024 #self.bound = 8096 self.bound = 2**22 self.did = -1 fe.event_register({'event_type': fe.BE, 'callback': self.be_callback}) fe.event_register({ 'event_type': fe.TIMER, 'time_value': 2.0, 'callback': self.timer_callback }) self.ticks = 0 self.one_way = False self.two_way = False self.zco = zlib.compressobj() fe.log('leaving memdump constructor')
def __init__(self, ctx): fe.log("in arav constructor") fe.set_name("arav") self.l = { "name_offset": fe.lookup_structure("task_struct", "comm"), "pid_offset": fe.lookup_structure("task_struct", "pid"), "tasks_offset": fe.lookup_structure("task_struct", "tasks"), "mm_offset": fe.lookup_structure("task_struct", "mm"), "pgd_offset": fe.lookup_structure("mm_struct", "pgd"), "vm_file_offset": fe.lookup_structure("vm_area_struct", "vm_file"), "vm_file_path_offset": fe.lookup_structure("file", "f_path"), "path_dentry_offset": fe.lookup_structure("path", "dentry"), "dentry_d_name_offset": fe.lookup_structure("dentry", "d_name"), "dentry_d_parent_offset": fe.lookup_structure("dentry", "d_parent"), "d_name_str_offset": fe.lookup_structure("qstr", "name"), "commit_creds": fe.lookup_symbol("commit_creds"), } e = {"event_type": fe.BE, "callback": self.be_callback} fe.event_register(e) e = { "event_type": fe.TIMER, "time_value": 2.0, "callback": self.timer_callback } fe.event_register(e) self.state = INIT self.pslist = {} self.events = {} self.target_proc = {} self.last = 0.0 self.tick = 0 self.symbol_string = "" self.symbols = {} self.fmts = [] self.users = [] self.load_symbols() self.parse_symbols() fe.events_start() fe.log("leaving arav constructor")
def __init__(self, ctx): fe.log("in syscalls constructor") fe.set_name("syscalls") e = {"event_type": fe.BE, "callback": self.be_callback} fe.event_register(e) e = { "event_type": fe.TIMER, "time_value": 2.0, # seconds "callback": self.timer_callback, } fe.event_register(e) self.ticks = 0 self.calls = 0 fe.log("leaving syscalls constructor")
def __init__(self, ctx): fe.log("in rekall constructor") fe.set_name("rekall") e = {"event_type": fe.BE, "callback": self.be_callback} fe.event_register(e) e = { "event_type": fe.TIMER, "time_value": 2.0, # seconds "callback": self.timer_callback, } fe.event_register(e) self.ticks = 0 self.one_way = False self.two_way = False fe.log("leaving rekall constructor")
def do_pslist(self, pause=False): if pause: fe.pause_vm() calls = 0 procs = 0 start_pslist = time.time() list_head = self.lookups["init_task"] + self.lookups["tasks_offset"] cur_list_entry = list_head next_list_entry = fe.read_addr_va(list_head, 0) calls += 1 i = 0 maxi = 100 fe.log("starting PSLIST") while True: cur_proc = cur_list_entry - self.lookups["tasks_offset"] pid = fe.read_32_va(cur_proc + self.lookups["pid_offset"], 0) calls += 1 procname = fe.read_str_va(cur_proc + self.lookups["name_offset"], 0) calls += 1 fe.log("%5s %-16s" % (pid, procname)) self.pslist[cur_proc] = (pid, procname) cur_list_entry = next_list_entry next_list_entry = fe.read_addr_va(cur_list_entry, 0) calls += 1 i += 1 fe.log("%s == %s?" % (hex(cur_list_entry), hex(list_head))) if cur_list_entry & 0xffffffffffff == list_head or i > maxi: fe.log("ending loop at %d" % (i,)) end_pslist = time.time() # self.log.append(end_pslist-start_pslist) break procs += 1 # self.calls.append(calls) # self.procs.append(procs) if pause: fe.resume_vm() fe.log("pslist in {sec:.6f} seconds".format(sec=end_pslist - start_pslist))
def memdump_callback(self, ctx): fe.log( f'memdump_callback: coff={self.offset}, cttl={self.ttl}, memsize={self.memsize}' ) if self.ttl > 0: self.ttl -= 1 read_size = 0 batch_size = 0 chunk_arr = [] while batch_size < self.bound: try: mem = self.memdump() except IndexError as e: fe.log(f'caught {e}, all done!') self.ttl = 0 break else: zmem = self.zco.compress(mem) batch_size += len(zmem) chunk_arr.append(binascii.b2a_base64(zmem).decode()) fe.log(f'batch {batch_size} {len(mem)} -> {len(zmem)}') #res = self.memdump() #res_utf = binascii.b2a_base64(res).decode() fe.log( f'sending {self.ticks}:{batch_size} B to BE, "{chunk_arr[0][0:16]}"' ) fe.notify( json.dumps({ 'cmd': 'memdump', 'data': chunk_arr, 'ix': self.ticks, })) #'hash': hashlib.sha256(res).hexdigest()})) # TODO: for benchmarking, we do not send a hash to the be else: fe.log('ttl < 1, clearing memdump callback timer') fe.event_clear(self.did) fe.notify(json.dumps({'cmd': 'memdump_done', 'data': time.time()})) self.did = -1 self.ticks += 1
def get_vma_file(self, current_vma): path = [] path_str = "" # vma -> *file -> path -> *dentry -> qstr -> *char file_p = fe.read_addr_va(current_vma + self.l["vm_file_offset"], 0) if file_p == 0: # This is an anonymous region. pass else: dentry_p = fe.read_addr_va( file_p + self.l["vm_file_path_offset"] + self.l["path_dentry_offset"], 0) i = 0 ml = 20 while True: char_p = fe.read_addr_va( dentry_p + self.l["dentry_d_name_offset"] + self.l["d_name_str_offset"], 0, ) if char_p == 0: fe.log("char_p null") vm_file = "" else: vm_file = fe.read_str_va(char_p, 0) fe.log(vm_file) if vm_file == "/": path_str = "" for i in path[::-1]: path_str = "%s/%s" % (path_str, i) break else: path.append(vm_file) i += 1 if i > ml: break dentry_p = fe.read_addr_va( dentry_p + self.l["dentry_d_parent_offset"], 0) return path_str
def do_pslist(self): fe.pause_vm() start_pslist = time.time() list_head = self.lookups["init_task"] + self.lookups["tasks_offset"] cur_list_entry = list_head next_list_entry = fe.read_addr_va(list_head, 0) i = 0 maxi = 100 fe.log("starting PSLIST") while True: cur_proc = cur_list_entry - self.lookups["tasks_offset"] pid = fe.read_32_va(cur_proc + self.lookups["pid_offset"], 0) procname = fe.read_str_va(cur_proc + self.lookups["name_offset"], 0) fe.log("%5s %-16s" % (pid, procname)) cur_list_entry = next_list_entry next_list_entry = fe.read_addr_va(cur_list_entry, 0) i += 1 # fe.log('%s == %s?' % (hex(cur_list_entry), hex(list_head))) if cur_list_entry & 0xffffffffffff == list_head or i > maxi: # fe.log('ending loop at %d' % (i,)) end_pslist = time.time() break stop_pslist = time.time() fe.resume_vm() fe.log("pslist in {sec:.2f} seconds".format(sec=stop_pslist - start_pslist))
def __init__(self, ctx): fe.log("in Example constructor") fe.set_name("example") self.cr3_ctr = 0 self.cr3_event = None self.pslist = {} self.lookups = { "name_offset": fe.lookup_structure("task_struct", "comm"), "pid_offset": fe.lookup_structure("task_struct", "pid"), "tasks_offset": fe.lookup_structure("task_struct", "tasks"), "init_task": fe.lookup_symbol("init_task"), } fe.events_start() e = { "event_type": fe.REG, "reg_type": fe.CR3, "sync": fe.ASYNC, "callback": self.cr3_callback, } self.cr3_event = fe.event_register(e) fe.log("registered CR3 event: {eid}".format(eid=self.cr3_event)) e = { "event_type": fe.TIMER, "time_value": 10.0, # seconds "callback": self.timer_callback, } fe.event_register(e) e = {"event_type": fe.BE, "callback": self.be_callback} fe.event_register(e) fe.log("leaving Example constructor")
def timer_callback(self, ctx): fe.log("{ctr:<3} TIMER CALLBACK".format(ctr=self.cr3_ctr)) fe.log(" passed: {ctx}".format(ctx=ctx)) self.do_pslist() if self.cr3_ctr and not (self.cr3_ctr % 2) and not self.cr3_event == None: fe.log("clearing CR3 event") fe.event_clear(self.cr3_event) self.cr3_event = None
def timer_callback(self, ctx): fe.log(f"TIMER CALLBACK {self.ticks}") if self.ticks == 0: fe.log("dk_start_syscall") self.do_dk_start_syscall(self.be_callback, fe.ASYNC) if self.ticks == 10: fe.log("dk_stop_syscall") self.do_dk_stop_syscall() fe.exit() self.ticks += 1
def memdump(self): if self.offset + self.bound > self.memsize: fe.log('memsize will be exceeded') bound = self.memsize - self.offset if bound == 0: fe.log('bound==0, all done!') raise IndexError('bound==0, all done!') else: bound = self.bound res = fe.read_pa(self.offset, bound) fe.log(f'read {bound}B from offset={self.offset}, got {len(res)}B') self.offset += bound return res
def do_batch_pslist_new(self, pause=False): if pause: fe.pause_vm() fe.log("batch_pslist_new") if self.o.state in [3, 4]: self.o.state = 2 procs = 0 start_pslist = time.time() fe.batch_send(self.o) stop_pslist = time.time() self.log.append(stop_pslist - start_pslist) self.procs.append(self.o.results_size()) self.msgs.append(1) if pause: fe.resume_vm() fe.log("Results") for r in o.results(): fe.log(r)
def enumerate_proc(self, current_process): res = {} mm_ptr = fe.read_addr_va(current_process + self.l["mm_offset"], 0) fe.log(f"mm_ptr: {mm_ptr}") if mm_ptr: task_pgd_va = fe.read_addr_va(mm_ptr + self.l["pgd_offset"], 0) fe.log(f"task_pgd_va: {task_pgd_va}") task_pgd = fe.translate_kv2p(task_pgd_va) fe.log(f"task_pgd: {task_pgd}") # parent_process = fe.read_addr_va(current_process + self.l['parent'], 0) # pprocname = fe.read_str_va(parent_process + self.l['name_offset'], 0) # ppid = fe.read_32_va(parent_process + self.l['pid_offset'], 0) # map_count = fe.read_64_va(current_process + self.l['map_count'], 0) # total_vm = fe.read_64_va(current_process + self.l['total_vm'], 0) # exec_vm = fe.read_64_va(current_process + self.l['exec_vm'], 0) # stack_vm = fe.read_64_va(current_process + self.l['stack_vm'], 0) # cred = fe.read_addr_va(current_process + self.l['cred'], 0) # uid = fe.read_32_va(cred + self.l['uid'], 0) # cputime = fe.read_64_va(current_process + self.l['sched_entity'] + self.l['sum_exec_runtime'], 0) vma_head_ptr = fe.read_addr_va(mm_ptr, fe.KERNEL) fe.log(f"vma_head_ptr: {vma_head_ptr}") fullpath = self.get_vma_file(vma_head_ptr) fe.log(f"fullpath: {fullpath}") start = fe.read_addr_va(vma_head_ptr + 0, 0) # vm_area_struct: vm_start end = fe.read_addr_va(vma_head_ptr + 8, 0) # vm_area_struct: vm_end mapped_size = end - start fe.log(f"start: {start:x}, size: {mapped_size:x}") res = { "mm_ptr": mm_ptr, "task_pgd_va": task_pgd_va, "vma_head_ptr": vma_head_ptr, "fullpath": fullpath, "text_start": start, "text_end": end, } return res
def int_callback(self, ctx): self.state = TRACING address = self.events[ctx.identifier] info = self.symbols[address] func_name = info["func_name"] pid = self.target_proc["pid"] fe.log(f"int callback: {ctx}") fe.log(f"called: {func_name}") if pid != ctx.pid: fe.log(f"wrong pid {ctx.pid} called us!") if func_name == "do_log": fmt = fe.read_str_va(ctx.rsi, ctx.pid) fe.log(f"do_log fmt: {fmt}") self.fmts.append(fmt) if "userauth-request" in fmt: fe.log("userauth-request, searching for username...") user = fe.read_str_va(ctx.rdx, ctx.pid) fe.log(f"got {user}") self.users.append(user) """
def commit_creds_callback(self, ctx): fe.log(f"commit_creds: {ctx}") fe.notify(json.dumps({"cmd": "commit_creds", "data": ctx._asdict()}))
def be_callback(self, ctx): fe.log(f"be callback: {ctx}")
def be_callback(self, ctx): fe.log(f'BE CALLBACK: {ctx}') self.two_way = True # msg format: {'cmd': 'foo', 'data': 'bar', 'ix': dump_order, 'hash': hash} # ALL ASYNC # FE: hi, waiting, memdump_running, memdump_done, error # BE: memdump_cmd: go, stop msg = json.loads(ctx.message) fe.log(f'JSON message: {msg}') if msg['cmd'] == 'memdump_cmd' and msg['data'] == 'go': if self.did >= 0: fe.log(f'error, dump already in procress (eid={self.did})') fe.notify( json.dumps({ 'cmd': 'error', 'data': 'memdump already running' })) else: fe.log(f'running memdump') fe.notify( json.dumps({ 'cmd': 'memdump_running', 'data': time.time() })) self.did = fe.event_register({ 'event_type': fe.TIMER, 'time_value': 0.0, 'callback': self.memdump_callback }) fe.log(f'registered new event {self.did}') elif msg['cmd'] == 'memdump_cmd' and msg['data'] == 'stop': if self.did >= 0: fe.event_clear(self.did) self.did = -1 fe.log(f'canceled dump') else: fe.log(f'error, no dump in procress (eid={self.did})') elif msg['cmd'] == 'memdump_cmd' and msg['data'] == 'exit': fe.log('was commanded to exit...') fe.exit() fe.log('BE CALLBACK done')
def shutdown(self): # destructor fe.log('SHUTDOWN')
def timer_callback(self, ctx): now = time.time() if self.last + 10 < now: fe.log("refreshing pslist") # pslist[proc.pid] = {'name': proc.name, 'process_block_ptr': proc.process_block_ptr} self.pslist = fe.process_list() # fe.log(f'#procs: {len(self.pslist)}') for pid, proc in self.pslist.items(): if proc["name"] == "sshd": fe.log(f"found sshd: {pid} {proc}") if not self.target_proc: self.target_proc["pid"] = pid for k, v in proc.items(): self.target_proc[k] = v for k, v in self.enumerate_proc( proc["process_block_ptr"]).items(): self.target_proc[k] = v fe.log(f"loading target_proc {self.target_proc}") if self.state == INIT: fe.log(f"installing breakpoint on commit_creds") address = self.l["commit_creds"] e = { "event_type": fe.INT, "sync": fe.SYNC, "bp_pid": fe.KERNEL, "bp_addr": address, "callback": self.commit_creds_callback, } try: eid = fe.event_register(e) except Exception: fe.log(f"could not inject at commit_creds") errors.append("commit_creds") else: self.events[eid] = address fe.log(f"event is {eid}") self.symbols[address] = { "address": address, "t": "T", "func_name": "commit_creds", } self.state = INJECTED if False and self.state == INIT: fe.log(f"injecting against {self.target_proc}") self.state = INJECTED errors = [] for address, info in self.symbols.items(): if "do_log" != info["func_name"]: fe.log(f"skipping {info['func_name']}") continue bp_addr = self.target_proc["text_start"] + address pid = self.target_proc["pid"] fe.log(f"installing bp at {bp_addr:x} for {address}:{info}") e = { "event_type": fe.INT, "sync": fe.SYNC, "bp_pid": pid, "bp_addr": bp_addr, "callback": self.int_callback, } try: eid = fe.event_register(e) except Exception: fe.log(f"could not inject at {info['func_name']}") errors.append(info["func_name"]) else: self.events[eid] = address fe.log(f"event is {eid}") fe.log(f"done, errors: {errors}") if self.tick == 15: fe.log("shutting down") fe.events_stop() for eid, address in self.events.items(): fe.log(f"clearing {eid}: {self.symbols[address]['func_name']}") fe.event_clear(eid) self.events = {} print(f"formats: {self.fmts}") print(f"users: {self.users}") fe.exit() fe.log(f"tick {self.tick}") self.tick += 1 self.last = now
def do_dk_stop_syscall(self): fe.log(fe.stop_syscall(self.syscall_eid))