Created
August 14, 2016 02:53
-
-
Save herrcore/b3143dde185cecda7c1dee7ffbce5d2c to your computer and use it in GitHub Desktop.
IDA Python plugin - Decode IOCTL Codes
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
############################################################################################ | |
## | |
## Quick IOCTL Decoder! | |
## | |
## All credit for actual IOCTL decode logic: | |
## http://www.osronline.com/article.cfm?article=229 | |
## | |
## | |
## To install: | |
## Copy script into plugins directory, i.e: C:\Program Files\IDA 6.8\plugins | |
## | |
## To run: | |
## Highlight IOCTL then right click and select "Decode IOCTL" or press PLUGIN_HOTKEY | |
## The decoded IOCTL data will be added as a comment and displayed in the IDA cli | |
## | |
############################################################################################ | |
__VERSION__ = '0.1' | |
__AUTHOR__ = '@herrcore' | |
PLUGIN_NAME = "Quick IOCTL Decoder" | |
PLUGIN_HOTKEY = 'Ctrl-Alt-I' | |
import idaapi | |
class IOCTL_Decoder(): | |
DEVICE = [None]*55 | |
DEVICE[1]="BEEP" | |
DEVICE[2]="CD_ROM" | |
DEVICE[3]="CD_ROM_FILE_SYSTEM" | |
DEVICE[4]="CONTROLLER" | |
DEVICE[5]="DATALINK" | |
DEVICE[6]="DFS" | |
DEVICE[7]="DISK" | |
DEVICE[8]="DISK_FILE_SYSTEM" | |
DEVICE[9]="FILE_SYSTEM" | |
DEVICE[10]="INPORT_PORT" | |
DEVICE[11]="KEYBOARD" | |
DEVICE[12]="MAILSLOT" | |
DEVICE[13]="MIDI_IN" | |
DEVICE[14]="MIDI_OUT" | |
DEVICE[15]="MOUSE" | |
DEVICE[16]="MULTI_UNC_PROVIDER" | |
DEVICE[17]="NAMED_PIPE" | |
DEVICE[18]="NETWORK" | |
DEVICE[19]="NETWORK_BROWSER" | |
DEVICE[20]="NETWORK_FILE_SYSTEM" | |
DEVICE[21]="NULL" | |
DEVICE[22]="PARALLEL_PORT" | |
DEVICE[23]="PHYSICAL_NETCARD" | |
DEVICE[24]="PRINTER" | |
DEVICE[25]="SCANNER" | |
DEVICE[26]="SERIAL_MOUSE_PORT" | |
DEVICE[27]="SERIAL_PORT" | |
DEVICE[28]="SCREEN" | |
DEVICE[29]="SOUND" | |
DEVICE[30]="STREAMS" | |
DEVICE[31]="TAPE" | |
DEVICE[32]="TAPE_FILE_SYSTEM" | |
DEVICE[33]="TRANSPORT" | |
DEVICE[34]="UNKNOWN" | |
DEVICE[35]="VIDEO" | |
DEVICE[36]="VIRTUAL_DISK" | |
DEVICE[37]="WAVE_IN" | |
DEVICE[38]="WAVE_OUT" | |
DEVICE[39]="8042_PORT" | |
DEVICE[40]="NETWORK_REDIRECTOR" | |
DEVICE[41]="BATTERY" | |
DEVICE[42]="BUS_EXTENDER" | |
DEVICE[43]="MODEM" | |
DEVICE[44]="VDM" | |
DEVICE[45]="MASS_STORAGE" | |
DEVICE[46]="SMB" | |
DEVICE[47]="KS" | |
DEVICE[48]="CHANGER" | |
DEVICE[49]="SMARTCARD" | |
DEVICE[50]="ACPI" | |
DEVICE[51]="DVD" | |
DEVICE[52]="FULLSCREEN_VIDEO" | |
DEVICE[53]="DFS_FILE_SYSTEM" | |
DEVICE[54]="DFS_VOLUME" | |
def __init__(self, control_code): | |
self.control_code = control_code | |
def decode(self): | |
out={} | |
device_val = (self.control_code >> 16) & 0xFFF | |
funcVal = (self.control_code >> 2) & 0xFFF | |
if (device_val <= 54) and (device_val != 0): | |
device_string = self.DEVICE[device_val]+ " ("+hex(device_val)+")" | |
else: | |
device_string = hex(device_val) | |
function_string = hex(funcVal) | |
out["device"] = device_string | |
out["function"] = function_string | |
access = (self.control_code >> 14) & 3 | |
method = self.control_code & 3 | |
access_string = "" | |
if access == 0: | |
access_string = "FILE_ANY_ACCESS" | |
elif access == 1: | |
access_string = "FILE_READ_ACCESS" | |
elif access == 2: | |
access_string = "FILE_WRITE_ACCESS" | |
elif access == 3: | |
access_string = "Read and Write" | |
method_string = "" | |
if method == 0: | |
method_string = "METHOD_BUFFERED" | |
elif method == 1: | |
method_string = "METHOD_IN_DIRECT" | |
elif method == 2: | |
method_string = "METHOD_OUT_DIRECT" | |
elif method == 3: | |
method_string = "METHOD_NEITHER" | |
out["access"] = access_string | |
out["method"] = method_string | |
return out | |
class IDAIOCTLDecoder(): | |
@staticmethod | |
def decode(): | |
ea = ScreenEA() | |
if ea == idaapi.BADADDR: | |
idaapi.msg(PLUGIN_NAME + " ERROR: Could not get get_screen_ea()") | |
return | |
str_id = idaapi.get_highlighted_identifier() | |
if not str_id: | |
idaapi.msg(PLUGIN_NAME + " ERROR: No Ioctl Code highlighted!") | |
return | |
try: | |
if str_id[-1] == 'h': | |
code = int(str_id[:-1], 16) | |
elif str_id[-1] == 'o': | |
code = int(str_id[:-1], 8) | |
elif str_id[-1] == 'b': | |
code = int(str_id[:-1], 2) | |
else: | |
code = int(str_id) | |
except ValueError: | |
idaapi.msg(PLUGIN_NAME + " ERROR: Not a valid Ioctl Code: " + str(str_id)) | |
return | |
try: | |
decoder = IOCTL_Decoder(code) | |
ioctl_data = decoder.decode() | |
#print decoded IOCTL to cli | |
msg_string = "That IOCTL decodes to: \n\tDevice: %s \n\tFunction: %s \n\tAccess: %s \n\tMethod: %s" | |
idaapi.msg(msg_string % (ioctl_data["device"], ioctl_data["function"], ioctl_data["access"], ioctl_data["method"])) | |
#add decoded IOCTL as comment | |
comment_string = "dwIoControlCode: \n\t\tDevice: %s \n\t\tFunction: %s \n\t\tAccess: %s \n\t\tMethod: %s" | |
idaapi.set_cmt(ea, comment_string % (ioctl_data["device"], ioctl_data["function"], ioctl_data["access"], ioctl_data["method"]), 0) | |
except Exception as e: | |
idaapi.msg(PLUGIN_NAME + " ERROR: " + str(e)) | |
return | |
class IOCTLDecodeHandler(idaapi.action_handler_t): | |
def activate(self, ctx): | |
IDAIOCTLDecoder.decode() | |
def update(self, ctx): | |
return idaapi.AST_ENABLE_ALWAYS | |
class QuickIOCTLDecoderHooks(idaapi.UI_Hooks): | |
def finish_populating_tform_popup(self, form, popup): | |
tft = idaapi.get_tform_type(form) | |
if tft == idaapi.BWN_DISASM: | |
# Note the 'None' as action name (1st parameter). | |
# That's because the action will be deleted immediately | |
# after the context menu is hidden anyway, so there's | |
# really no need giving it a valid ID. | |
desc = idaapi.action_desc_t(None, 'Decode IOCTL', IOCTLDecodeHandler()) | |
idaapi.attach_dynamic_action_to_popup(form, popup, desc, None) | |
class QuickIOCTLDecoder(idaapi.plugin_t): | |
flags = idaapi.PLUGIN_UNL | |
comment = "Decode IOCTL codes!" | |
help = "Highlight IOCTL and right-click 'Decode IOCTL'" | |
wanted_name = PLUGIN_NAME | |
wanted_hotkey = PLUGIN_HOTKEY | |
def init(self): | |
idaapi.msg("Initializing: %s\n" % PLUGIN_NAME) | |
global hooks | |
hooks = QuickIOCTLDecoderHooks() | |
re = hooks.hook() | |
return idaapi.PLUGIN_OK | |
def run(self, arg): | |
IDAIOCTLDecoder.decode() | |
pass | |
def term(self): | |
pass | |
def PLUGIN_ENTRY(): | |
return QuickIOCTLDecoder() | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Sigh. There is already a decent IOCTL decoder plugin for IDA
It doesn't have the right-click-decode option that my script has (or the inline comments) but it has more IOCTL codes... you should probably just use it. I guess this is what I get for not googling first.
Sad panda.