Skip to content

Instantly share code, notes, and snippets.

@Wenzel
Created June 5, 2018 13:48
Show Gist options
  • Save Wenzel/efd9d6f4a0e0577e4ce7afe5d3ddf400 to your computer and use it in GitHub Desktop.
Save Wenzel/efd9d6f4a0e0577e4ce7afe5d3ddf400 to your computer and use it in GitHub Desktop.
#!/usr/bin/env python3
"""
Usage:
bug_sstep.py [options] <vm_name> <symbol>
Options:
-h --help Show this screen.
--sstep Use singlestepping instead of emulation
"""
import sys
import signal
from pprint import pprint
from docopt import docopt
from libvmi import Libvmi, INIT_DOMAINNAME, INIT_EVENTS
from libvmi.event import MemEvent, MemAccess, SingleStepEvent, EventResponse
from utils import dtb_to_pname, pause
# catch SIGINT
# we cannot rely on KeyboardInterrupt when we are in
# the vmi.listen() call
interrupted = False
def signal_handler(signal, frame):
global interrupted
interrupted = True
def cb_mem_event(vmi, event):
# pprint(event.to_dict())
if event.cffi_event.x86_regs.rip != event.data['target_vaddr']:
# page hit, but we are not at the right address
if event.data['sstep']:
# lift page permissions
print("lift page permissions")
vmi.clear_event(event.data['mem_event'])
# toogle singlestep ON
return EventResponse.TOGGLE_SINGLESTEP
else:
# emulate this instruction and continue
return EventResponse.EMULATE
else:
# hit
pname = dtb_to_pname(vmi, event.cffi_event.x86_regs.cr3)
print('At {}: {}'.format(event.data['symbol'], pname))
vmi.pause_vm()
event.data['interrupted'] = True
return EventResponse.EMULATE
def cb_ss_event(vmi, event):
# out of the frame ?
if event.cffi_event.ss_event.gfn != event.data['target_gfn']:
print("reregister event")
# reregister mem event
vmi.register_event(event.data['mem_event'])
# toggle singlestep OFF
return EventResponse.TOGGLE_SINGLESTEP
def cb_ss_event_userland(vmi, event):
print("cb_ss_event_test, rip: {}".format(
hex(event.cffi_event.x86_regs.rip)
))
def main(args):
vm_name = args['<vm_name>']
symbol = args['<symbol>']
sstep_enabled = args['--sstep']
# register SIGINT
signal.signal(signal.SIGINT, signal_handler)
with Libvmi(vm_name, INIT_DOMAINNAME | INIT_EVENTS) as vmi:
vaddr = vmi.translate_ksym2v(symbol)
paddr = vmi.translate_kv2p(vaddr)
frame = paddr >> 12
print("symbol: {} vaddr: {} paddr: {} frame: {}".format(
symbol, hex(vaddr), hex(paddr), hex(frame)))
user_data = {
'symbol': symbol,
'target_vaddr': vaddr,
'target_gfn': frame,
'mem_event': None,
'sstep': sstep_enabled,
'interrupted': False
}
num_vcpus = vmi.get_num_vcpus()
ss_event = SingleStepEvent(range(num_vcpus), cb_ss_event, data=user_data, enable=False)
mem_event = MemEvent(MemAccess.X, cb_mem_event, gfn=frame, data=user_data)
user_data['mem_event'] = mem_event
with pause(vmi):
vmi.register_event(ss_event)
vmi.register_event(mem_event)
# listen
while not user_data['interrupted']:
print("Waiting for events ({} events pending)".format(vmi.are_events_pending()))
vmi.listen(1000)
print("Stop listening")
# clear buffer
vmi.listen(0)
# clear events
vmi.clear_event(mem_event)
vmi.clear_event(ss_event)
print("single stepping until userland...")
# create a new ss_event
ss_event = SingleStepEvent(range(num_vcpus), cb_ss_event_userland,
data=user_data)
vmi.register_event(ss_event)
vmi.resume_vm()
interrupted = False
while not interrupted:
print("Waiting for events ({} events pending)".format(vmi.are_events_pending()))
vmi.listen(1000)
if __name__ == '__main__':
args = docopt(__doc__)
ret = main(args)
sys.exit(ret)
@Wenzel
Copy link
Author

Wenzel commented Jun 5, 2018

Usage: sudo ./venv/bin/python examples/bug_sstep.py xenwin7 KiStartUserThread --sstep

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment