Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: nccgroup/DriverBuddy
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: master
Choose a base ref
...
head repository: HyperionGray/DriverBuddy
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: master
Choose a head ref
Able to merge. These branches can be automatically merged.
  • 2 commits
  • 11 files changed
  • 2 contributors

Commits on Jun 22, 2020

  1. port to 7.4

    A committed Jun 22, 2020
    Copy the full SHA
    2b0c11d View commit details
  2. Update README.MD

    hyp3ri0n-ng authored Jun 22, 2020
    Copy the full SHA
    4a6933c View commit details
16 changes: 9 additions & 7 deletions DriverBuddy.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
from idaapi import *
from idautils import *
from idc import *
from ida_auto import auto_wait
from DriverBuddy import data
from DriverBuddy import ioctl


'''#######################################################################################
DriverBuddy.py: Entry point for IDA python plugin used in Windows driver
vulnerability research.
Written by Braden Hollembaek and Adam Pond of NCC Group
#######################################################################################'''
def PLUGIN_ENTRY():
return DriverBuddyPlugin()

class DriverBuddyPlugin(plugin_t):
flags = PLUGIN_UNL
@@ -28,7 +33,7 @@ def init(self):

def run(self, args):
print "[+] Welcome to Driver Buddy"
autoWait() # Wait for IDA autoanalysis to complete
auto_wait() # Wait for IDA autoanalysis to complete
driver_entry = data.is_driver()
if driver_entry == "":
print "[-] No DriverEntry stub found"
@@ -49,13 +54,10 @@ def run(self, args):
return

def decode(self, _=0):
if idc.GetOpType(idc.ScreenEA(), 1) != 5: # Immediate
if idc.get_operand_type(idc.get_screen_ea(), 1) != 5: # Immediate
return
value = idc.GetOperandValue(idc.ScreenEA(), 1) & 0xffffffff
value = idc.get_operand_value(idc.get_screen_ea(), 1) & 0xffffffff
ioctl.get_ioctl_code(value)

def term(self):
pass

def PLUGIN_ENTRY():
return DriverBuddyPlugin()
pass
Binary file added DriverBuddy/__init__.pyc
Binary file not shown.
6 changes: 3 additions & 3 deletions DriverBuddy/data.py
Original file line number Diff line number Diff line change
@@ -67,7 +67,7 @@ def populate_function_map():
ret = False
# Populate function_map with sub functions
for address in Functions():
name = GetFunctionName(address)
name = get_func_name(address)
functions_map[name] = address
ret = True
# Populate function_map with import functions
@@ -228,7 +228,7 @@ def is_driver():
driver_entry_address=""
print "[+] Checking for DriverEntry..."
for ea in Segments():
for funcea in Functions(SegStart(ea),SegEnd(ea)):
fn = GetFunctionName(funcea)
for funcea in Functions(get_segm_start(ea),get_segm_end(ea)):
fn = get_func_name(funcea)
if fn == "DriverEntry":
return funcea
Binary file added DriverBuddy/data.pyc
Binary file not shown.
20 changes: 10 additions & 10 deletions DriverBuddy/ioctl.py
Original file line number Diff line number Diff line change
@@ -136,23 +136,23 @@ def get_ioctl_code(ioctl_code):
#####################################################################'''
def find_ioctls():
error = False
cur = MinEA()
max = MaxEA()
cur = inf_get_min_ea()
max = inf_get_max_ea()
print "[+] Searching for IOCTLS found by IDA..."
while cur < max:
cur = FindText(cur, SEARCH_DOWN, 0, 0, "IoControlCode")
cur = find_text(cur, SEARCH_DOWN, 0, 0, "IoControlCode")
if cur == BADADDR:
break
else:
if GetOpType(cur, 0) == 5:
OpDecimal(cur, 0)
get_ioctl_code(int(GetOpnd(cur,0)))
if get_operand_type(cur, 0) == 5:
op_dec(cur, 0)
get_ioctl_code(int(print_operand(cur,0)))
error = True
elif GetOpType(cur, 1) == 5:
OpDecimal(cur, 1)
get_ioctl_code(int(GetOpnd(cur,1)))
elif get_operand_type(cur, 1) == 5:
op_dec(cur, 1)
get_ioctl_code(int(print_operand(cur,1)))
error = True
else:
print "[-] Couldn't get IOCTL from %s at address %s " % (GetDisasm(cur), hex(cur))
cur = NextHead(cur)
cur = next_head(cur)
return error
Binary file added DriverBuddy/ioctl.pyc
Binary file not shown.
14 changes: 8 additions & 6 deletions DriverBuddy/wdf.py
Original file line number Diff line number Diff line change
@@ -5,9 +5,11 @@
from idautils import *
from idaapi import *
from idc import *
from ida_bytes import create_struct
from ida_bytes import FF_QWORD

# Architecture dependent globals
FF_PTR = FF_QWRD # FF_DWRD
FF_PTR = FF_QWORD # FF_DWRD
get_ptr = get_64bit # get_32bit
ptr_size = 8 # 4

@@ -474,7 +476,7 @@ def add_struct(version):

def populate_wdf():
# find data sections
segment_starts = [get_segm_by_name('.data').startEA, get_segm_by_name('.rdata').startEA]
segment_starts = [get_segm_by_name('.data').start_ea, get_segm_by_name('.rdata').start_ea]
for ea in segment_starts:
if ea != BADADDR:
# find "KmdfLibrary" unicode string in .rdata section
@@ -483,15 +485,15 @@ def populate_wdf():
log('Found "KmdfLibrary" unicode string at ' + hex(idx))
addr = get_first_dref_to(idx)
# hacky logic fix , consider only the minor portion
version = int(str(Dword(addr+ptr_size+0x4)))
version = int(str(get_wide_dword(addr+ptr_size+0x4)))
id = add_struct(version)
if id != -1:
log('Success')
wdf_func = get_ptr(addr+ptr_size+0x10)
size = GetStrucSize(id)
log('doStruct (size=' + hex(size) + ') at ' + hex(wdf_func))
size = get_struc_size(id)
log('create_struct (size=' + hex(size) + ') at ' + hex(wdf_func))
do_unknown_range(wdf_func, size, 0)
if doStruct(wdf_func, size, id) and set_name(wdf_func, 'WdfFunctions', 0):
if create_struct(wdf_func, size, id) and set_name(wdf_func, 'WdfFunctions', 0):
log('Success')
else:
log('Failure')
Binary file added DriverBuddy/wdf.pyc
Binary file not shown.
94 changes: 47 additions & 47 deletions DriverBuddy/wdm.py
Original file line number Diff line number Diff line change
@@ -22,12 +22,12 @@

def check_for_fake_driver_entry(driver_entry_address):
address = get_func(driver_entry_address)
end_address = address.endEA
while GetMnem(end_address) !="jmp" and GetMnem(end_address) !="call":
end_address = address.end_ea
while print_insn_mnem(end_address) !="jmp" and print_insn_mnem(end_address) !="call":
end_address -= 0x1
real_driver_entry_address = LocByName(GetOpnd(end_address, 0))
real_driver_entry_address = get_name_ea_simple(print_operand(end_address, 0))
print "[+] Found real DriverEntry address of %08x" % real_driver_entry_address
MakeName(real_driver_entry_address, "Real_Driver_Entry")
set_name(real_driver_entry_address, "Real_Driver_Entry")
return real_driver_entry_address

'''#######################################################################################
@@ -52,17 +52,17 @@ def locate_ddc(driver_entry_address):
# Enumerate the DriverEntry function and check if DriverObject struct loads address of DispatchDeviceControl
prev_instruction = driver_entry_func[0]
for i in driver_entry_func[1:]:
if ddc_offset in GetOpnd(i, 0)[4:] and GetMnem(prev_instruction) == "lea":
real_ddc = LocByName(GetOpnd(prev_instruction, 1))
print "[+] Found DispatchDeviceControl 0x%08x" % real_ddc
MakeName(real_ddc, "DispatchDeviceControl")
dispatch["ddc"] = real_ddc
if didc_offset in GetOpnd(i, 0)[4:] and GetMnem(prev_instruction) == "lea":
real_didc = LocByName(GetOpnd(prev_instruction, 1))
print "[+] Found DispatchInternalDeviceControl 0x%08x" % real_didc
MakeName(real_didc, "DispatchInternalDeviceControl")
dispatch["didc"] = real_didc
prev_instruction = i
if ddc_offset in print_operand(i, 0)[4:] and print_insn_mnem(prev_instruction) == "lea":
real_ddc = get_name_ea_simple(print_operand(prev_instruction, 1))
print "[+] Found DispatchDeviceControl 0x%08x" % real_ddc
set_name(real_ddc, "DispatchDeviceControl")
dispatch["ddc"] = real_ddc
if didc_offset in print_operand(i, 0)[4:] and print_insn_mnem(prev_instruction) == "lea":
real_didc = get_name_ea_simple(print_operand(prev_instruction, 1))
print "[+] Found DispatchInternalDeviceControl 0x%08x" % real_didc
set_name(real_didc, "DispatchInternalDeviceControl")
dispatch["didc"] = real_didc
prev_instruction = i

if "ddc" in dispatch: # This is whats important so if we have it, bail
return dispatch
@@ -77,8 +77,8 @@ def locate_ddc(driver_entry_address):
iocode = "0xDEADB33F"
iostack_location = "[rdx+0B8h]"
for i in instructions:
if iostack_location in GetOpnd(i, 1):
iostack_register = GetOpnd(i,0)
if iostack_location in print_operand(i, 1):
iostack_register = print_operand(i,0)
iocode = "["+iostack_register + "+18h]"
if iocode in GetDisasm(i):
ddc_list.append(f)
@@ -88,10 +88,10 @@ def locate_ddc(driver_entry_address):
for ddc in ddc_list:
for count, refs in enumerate(XrefsTo(ddc,0)):
reffunc = get_func(refs.frm)
if reffunc is not None and reffunc.startEA == driver_entry_address:
if reffunc is not None and reffunc.start_ea == driver_entry_address:
real_ddc[count] = ddc
print "[+] Possible DispatchDeviceControl 0x%08x" % ddc
MakeName(ddc, "Possible_DispatchDeviceControl%r" % count)
set_name(ddc, "Possible_DispatchDeviceControl%r" % count, SN_CHECK)

if real_ddc != {}: return real_ddc
else: return None
@@ -110,9 +110,9 @@ def locate_ddc(driver_entry_address):

def define_ddc(ddc_address):
# Special hidden ida function to load "standard structures"
irp_id = Til2Idb(-1, "IRP")
io_stack_location_id = Til2Idb(-1, "IO_STACK_LOCATION")
device_object_id = Til2Idb(-1, "DEVICE_OBJECT")
irp_id = import_type(-1, "IRP")
io_stack_location_id = import_type(-1, "IO_STACK_LOCATION")
device_object_id = import_type(-1, "DEVICE_OBJECT")
# Register canaries
io_stack_reg = "STR8SWAGGABRUH"
irp_reg = "STR8SWAGGABRUH"
@@ -126,88 +126,88 @@ def define_ddc(ddc_address):
# Scan instructions until we discover rcx, or rdx being used
for i in instructions:
disasm = GetDisasm(i)
src = GetOpnd(i, 1)
src = print_operand(i, 1)
if "rdx" in disasm and rdx_flag != 1 or irp_reg in disasm and irp_reg_flag !=1:
# Check for IO_STACK_LOCATION
if "+0B8h" in disasm:
if "rdx+0B8h" in src or irp_reg + "+0B8h" in src:
OpStroffEx(i, 1, irp_id, 0)
op_stroff(i, 1, irp_id, 0)
# If it is a mov, we want to save where IO_STACK_LOCATION is
if GetMnem(i) == "mov":
io_stack_reg = GetOpnd(i, 0)
if print_insn_mnem(i) == "mov":
io_stack_reg = print_operand(i, 0)
io_stack_flag = 0
print "[+] Stored IO_STACK_LOCATION in %s" % io_stack_reg
else:
OpStroffEx(i, 0, irp_id, 0)
op_stroff(i, 0, irp_id, 0)
print "[+] Made struct IO_STACK_LOCATION"
# Check for SystemBuffer
elif "+18h" in disasm:
if "rdx+18h" in src or irp_reg + "+18h" in src:
OpStroffEx(i, 1, irp_id, 0)
op_stroff(i, 1, irp_id, 0)
else:
OpStroffEx(i, 0, irp_id, 0)
op_stroff(i, 0, irp_id, 0)
print "[+] Made struct IRP+SystemBuffer"
# Check for IoStatus.Information
elif "+38h" in disasm:
if "rdx+38h" in src or irp_reg + "+38h" in src:
OpStroffEx(i, 1, irp_id, 0)
op_stroff(i, 1, irp_id, 0)
else:
OpStroffEx(i, 0, irp_id, 0)
op_stroff(i, 0, irp_id, 0)
print "[+] Made struct IRP+IoStatus.Information"
# Need to keep track of where IRP is being moved
elif GetMnem(i) == "mov" and (src == "rdx" or src == irp_reg):
irp_reg = GetOpnd(i, 0)
elif print_insn_mnem(i) == "mov" and (src == "rdx" or src == irp_reg):
irp_reg = print_operand(i, 0)
irp_reg_flag = 0
print "[+] Stored IRP in %s" % irp_reg
# rdx got clobbered
elif GetMnem(i) == "mov" and GetOpnd(i, 0) == "rdx":
elif print_insn_mnem(i) == "mov" and print_operand(i, 0) == "rdx":
print "[+] rdx got clobbered %s" % GetDisasm(i)
rdx_flag = 1
# irp_reg got clobbered
elif GetMnem(i) == "mov" and GetOpnd(i, 0) == irp_reg:
elif print_insn_mnem(i) == "mov" and print_operand(i, 0) == irp_reg:
irp_reg_flag = 1
else:
"[-] Something weird happened %s" % GetDisasm(i)
elif "rcx" in disasm and rcx_flag != 1:
# Check for DEVICE_OBJECT.Extension
if "rcx+40h" in disasm:
if "rcx+40h" in src:
OpStroffEx(i, 1, device_object_id, 0)
op_stroff(i, 1, device_object_id, 0)
else:
OpStroffEx(i, 0, device_object_id, 0)
op_stroff(i, 0, device_object_id, 0)
print "[+] Made struct DEVICE_OBJECT.Extension"
# Need to keep track of where DEVICE_OBJECT is being moved
elif GetMnem(i) == "mov" and src == "rcx":
device_object_reg = GetOpnd(i, 0)
elif print_insn_mnem(i) == "mov" and src == "rcx":
device_object_reg = print_operand(i, 0)
print "[+] Stored DEVICE_OBJECT in %s" % device_object_reg
# rcx got clobbered
elif GetMnem(i) == "mov" and GetOpnd(i, 0) == "rcx":
elif print_insn_mnem(i) == "mov" and print_operand(i, 0) == "rcx":
rcx_flag = 1
elif io_stack_reg in disasm and io_stack_flag != 1:
print "[+] io_stack_reg= %s in %s" % (io_stack_reg, GetDisasm(i))
# Check for DeviceIoControlCode which is IO_STACK_LOCATION+18h
if io_stack_reg + "+18h" in disasm:
if io_stack_reg + "+18h" in src:
OpStroffEx(i, 1, io_stack_location_id, 0)
op_stroff(i, 1, io_stack_location_id, 0)
else:
OpStroffEx(i, 0, io_stack_location_id, 0)
op_stroff(i, 0, io_stack_location_id, 0)
print "[+] Made struct IO_STACK_LOCATION+DeviceIoControlCode"
# Check for InputBufferLength which is IO_STACK_LOCATION+10h
elif io_stack_reg in "+10h" in disasm:
if io_stack_reg + "+10h" in src:
OpStroffEx(i, 1, io_stack_location_id, 0)
op_stroff(i, 1, io_stack_location_id, 0)
else:
OpStroffEx(i, 1, io_stack_location_id, 0)
op_stroff(i, 1, io_stack_location_id, 0)
print "[+] Made struct IO_STACK_LOCATION+InputBufferLength"
# Check for OutputBufferLength which is IO_STACK_LOCATION+8
elif io_stack_reg + "+8" in disasm:
if io_stack_reg + "+8" in src:
OpStroffEx(i, 1, io_stack_location_id, 0)
op_stroff(i, 1, io_stack_location_id, 0)
else:
OpStroffEx(i, 0, io_stack_location_id, 0)
op_stroff(i, 0, io_stack_location_id, 0)
print "[+] Made struct IO_STACK_LOCATION+OutputBufferLength"
# io_stack_reg is being clobbered
elif GetMnem(i) == "mov" and GetOpnd(i, 0) == io_stack_reg:
elif print_insn_mnem(i) == "mov" and print_operand(i, 0) == io_stack_reg:
io_stack_flag = 1
else:
continue
Binary file added DriverBuddy/wdm.pyc
Binary file not shown.
5 changes: 5 additions & 0 deletions README.MD
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@

This is a port of Driver buddy by nccgroup to IDA 7.4. IDA 7.4 broke many plugins, this a fixed version of this plugin that aids with driver analysis. It is for Python 2 + IDA.

## OriginalDriverBuddy Docs:

## Quickstart

### DriverBuddy Installation Instructions