Driver Inspector

Heyhey!

I’ve been on windows drivers vulnerabilites a lot lately and i’ve seen that estadistically, as in usermode, there are a lot of driver developers who doesnt know how to implement a secure intercommunication channel between usermode and kernel mode when handling IOCTLs.

That is way worst when handling a particular kind of communication method called METHOD_NEITHER.

After disassembling a lot of different drivers repeating the same procedure over and over again (always looking for the same things; the driver entry procedure, the MajorFunction assignation, the ioctl_handler function..) i saw that usually it has an almost-signaturable code pattern that can be used to do an automated analysis of the disassembled binary.
So, i thought that could be very useful to have a tool to help me in the analysis, looking for code patterns to recognize where the functions used to handle the ioctls are, to identify the communication method, and maybe to find some user buffers reference (i know im the lazyest🙂.

And of course, IDAPython came to my mind.

After a quick look of the excelent Ero’s IDAPython documentation to refresh my memory i started to write the script and a few hours later i managed to get an almost usable piece of code to find the ioctl handler and the method used.

It does a crappy binary analysis looking for some code patterns to find the ioctl_handler. Then, it looks for the most common asm representations of a “switch-case” sentence including an ioctl-alike dword😀
By applying some simple bitwise operations we can determine the METHOD used in the defined IOCTL, allowing the script to know what pattern must be used to find the code who i’m interested on, the one who references the buffer supplied by the user.
I’ve writed just the minimum to find the user buffer reference for the METHOD_NEITHER method, but should be trivial to do the same for the other methods. I will do it later😀

Now, ive cleaned the code a little, deprecated the original “find_ioctl_handler_heur” function that was replaced for another one who recognizes the ioctl function handler by it reference at Driver_Entry(), and im thinking in adding more functionality, but the code will be here “as is” since now.

oh, and it has a name now: Driver Inspector

This is just a quick draft, just to test some IDAPython features and see if i’m in the right way.

#
# Driver Inspector – An IDAPython script to help the analysis of windows drivers
# Copyright (C) 2007 Anibal L. Sacco
#

”’
Author: Anibal Sacco (aLS)
Contact: anibal.sacco@coresecurity.com
Organization: Core Security Technologies
”’

log_file = 0

def Log(text):
global log_file
print text
if log_file:
file = open(log_file, “a”)
file.write(text + “\r\n”)
file.close()

def ask_for_log():
global log_file
choose = AskYN(1, “Do you wanna save a Log?”)
if choose:
log_file = AskFile(1, (“log-%s.log” % GetInputFile()), “Where do you want to save the log file?” )
if log_file:
return True
print “[+] Not logging”
return False

def analyze_ioctl_handler(function_ea):
function_end = FindFuncEnd(function_ea)
matches = []
method = 0xff

for head in Heads(function_ea, function_end):
if isCode(GetFlags(head)):
code = “%s %s %s” % (GetMnem(head),GetOpnd(head,0),GetOpnd(head,1) )
if (“sub” in code) or (“cmp” in code) and (GetOpType(head, 1) == 5) and (GetOperandValue(head, 1) > 0xffff):
is_an_ioctl_func = True # If the function has a possible ioctl it’s flagged
Log(“[+] Possible IOCTL switch-case in function %s at %08x” % (GetFunctionName(function_ea), head))
ioctl = GetOperandValue(head, 1)
method = ioctl & 3
if method == 3:
Log(“[-] Method: METHOD_NEITHER”)
elif method == 2:
Log(“[-] Method: METHOD_OUT_DIRECT”)
elif method == 1:
Log(“[-] Method: METHOD_IN_DIRECT”)
elif method == 0:
Log(“[-] Method: METHOD_BUFFERED”)

if method == 3: # If the function was flagged, find on it some reference to the user buffer
if GetOpType(head, 1) == 5:
if (“3Ch” in GetOpnd(head, 1)) or (“3Ch” in GetOpnd(head, 2)):
Log(“[-] Possible user buffer reference in function %s at %08x” % (GetFunctionName(function_ea),head))

## if method == 0:
## f

return matches

def find_ioctl_by_xref():
for head in Heads(Segments()[0], Segments()[-1:][0]):
if isCode(GetFlags(head)):
for ref_ea in DataRefsTo(head):
opnd = GetOpnd(ref_ea, 0)
if “+70h]” in opnd:
MakeFunction(head, BADADDR)
print “FUNCTION MADE!” # Debug
return head
return False

def has_xref_majorversion(function_ea):
for ref_ea in DataRefsTo(function_ea):
opnd = GetOpnd(ref_ea, 0)
if “+70h]” in opnd:
print “XREF from: %s” % GetFunctionName(ref_ea)
return True
return False

def find_opcode_in_func(function_ea, opcode):

function_start = function_ea
function_end = FindFuncEnd(function_ea) – function_ea
matches = []

for head in Heads(function_ea, function_end):
if isCode(GetFlags(head)):
code = “%s %s %s” % (GetMnem(head),GetOpnd(head,0),GetOpnd(head,1) )
for each in opcode:
if each in code:
matches.append(head)
return matches

def find_ioctl_handler_heur(function_ea):

function_start = function_ea
function_end = FindFuncEnd(function_ea) – function_ea
magic_delta = 0x70
has_irp = 0
has_iosl = 0
has_ioctl = 0

for head in Heads(function_ea, FindFuncEnd(function_ea)):
if isCode(GetFlags(head)):
## code = “%s %s %s” % (GetMnem(head),GetOpnd(head,0),GetOpnd(head,1) )
if (“Irp” in GetOpnd(head,1)) and (head < (function_ea + magic_delta)): # Finding Irp as an argument has_irp = function_ea if ("+60]" in GetOpnd(head,1)) and (head < (function_ea + magic_delta)): # Finding IO_STACK_LOCATION has_iosl = function_ea if ("+0Ch]" in GetOpnd(head,1)) and (head < (function_ea + magic_delta)) : # Finding IoControlCode has_ioctl = function_ea if has_irp or (has_ioctl and has_iosl): return True ## print "[+] Possible IOCTL Handler at %08x" % function_ea return None def main(): splash = """ ################################################################################## # Driver Inspector - An IDAPython script to help the analysis of windows drivers # # Author: Anibal Sacco (aLS) # # Contact: anibal.sacco@coresecurity.com # # Organization: Core Security Technologies # ---------------------------------------------------------------------------------- """ possible_functions = [] print "------------------------------------------------------" print "[+] Starting Driver Analysys" Wait() # Get the text segment starting address ask_for_log() Log(splash) ioctl_handler = find_ioctl_by_xref() # Try to get the ioctl_handler by it xref if not ioctl_handler: for ea in Segments(): #print "Analyzing %s segment" % SegName(ea) for function_ea in Functions(SegStart(ea), SegEnd(ea)): if find_ioctl_handler_heur(function_ea) == True: # Try to identify it looking at the code possible_functions.append(function_ea) if has_xref_majorversion(function_ea) == True: # Try to identify it by its xref ioctl_handler = function_ea break if ioctl_handler: Log("[+] IOCTL Handler found at %08x" % ioctl_handler) analyze_ioctl_handler(ioctl_handler) else: if possible_functions: print "[-] There are a few possible functions used as ioctl_handlers at:" for function in possible_functions: print "%08x" % function # Let the user choose the function to be used else: print "[-] Didn't find any function, sorry." # *Look if there are more than one possible function and in that case, # let the user select one. # *Analyze that function finding the METHOD and the buffers return 0 if __name__ == '__main__': main() [/sourcecode]

~ by aLS -- on March 22, 2007.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
%d bloggers like this: