首页
论坛
课程
招聘
[原创]自动获取驱动程序IO控制码初级版
2012-7-27 17:22 9113

[原创]自动获取驱动程序IO控制码初级版

2012-7-27 17:22
9113
"""

Galaxy Security Lab Driver Analysis for IDA Pro

Author :dragonltx
Time   :2012-7-27

"""
看了Justin的《Python灰帽子》的第十章,里面提到可以用Immunity Debugger来加载驱动,并通过driverlib来获取驱动程序的io控制码,遂用Immunity Debugger加载一个驱动试试,发现加载失败,于是给Justin发了封邮件,没鸟我。

后来想了想,既然是用Immunity Debugger静态分析驱动来获取驱动程序的io控制码,还不如用IDA来分析,于是有了这篇文章。本文给出的获取驱动程序的io控制码的脚本采用IDA Python,可以给IDA Python新手当作参考,高手略过。

一、获取驱动设备名
def getDeviceName():
    """
    Get Device Name from a driver. 
    @rtype:   void
    @returns: void
    """
    ea = 0
    while True:
     ea =  FindText(ea, SEARCH_NEXT | SEARCH_REGEX, 0, 0, "\\\\Device\\\\")
     string = GetString(ea, -1, ASCSTR_UNICODE)
     if string is None:
        continue
     else:
        #Message("Find in %x\n" % ea)
        Message("device is %s\n" % string)
	break

通过FindText这个函数来查找包含“\\Device\\”这个函数的偏移地址,然后通过GetString来获取字符串,如果获取的字符串为空,继续查找。两个函数的原型如下:


二、获取分发函数地址
def getDispatchAddress():
    """
    Get Device Dispatch Address from a driver. 
    @rtype:   int
    @returns: Dispatch Address
    """
    ea = 0
    ea =  FindText(ea,  SEARCH_DOWN |SEARCH_NEXT | SEARCH_REGEX, 0, 0, "mov *dword *ptr *\\[[a-zA-Z]* *\\+ *70h\\],[a-zA-Z0-9_ ]*")
    #ea =  FindText(ea, SEARCH_NEXT | SEARCH_REGEX, 0, 0, "test *[a-zA-Z]*, +[a-zA-Z]*")
    #Message("Find in %x\n" % ea)
    if ea == BADADDR:
        Message("Cann't find the Dispatch address")
        address = BADADDR
    else:
        address = GetOperandValue(ea,1)
        Message("Dispatch address is %x\n" % address)
	return address
       
首先用FindText查找mov dword ptr [edx+70h], offset sub_11010类似这种形式的指令,通过正则匹配查找。找到后,用GetOperandValue函数获取第二个操作数的值,即是分发函数的地址。函数原型如下:
       
三、获取一个函数的所有指令
def getFunctionInstructions():
    """
    Get All Instructions from a function.
    Here,Just Get All Instructions Offset,and store them in list
    @rtype:   List
    @returns: List of All Instructions
    """
    Instructions = []
    DispatchBeginAddress = getDispatchAddress()
    if DispatchBeginAddress == BADADDR:
       Message("Cann't find the Function Instructions List")
       return None
    DispatchEndAddress = GetFunctionAttr(DispatchBeginAddress,FUNCATTR_END)
    i =  DispatchBeginAddress
    while True:
      #Instructions.append(GetDisasm(i))
      Instructions.append(i)
      tmp = i + ItemSize(i)
      if tmp < DispatchEndAddress:
         i = i + ItemSize(i)
      else:
         break
    address = i
    return Instructions

通过GetFunctionAttr获取函数的结束地址,再通过ItemSize来获取每条指令的大小,然后循环遍历即可获得这个函数的所有指令的偏移地址。这边先获取所有指令的偏移地址,而不是指令,下面获取io控制码会用到。函数原型如下:


四、获取驱动程序的所有io控制码
def getIoctlCode():
    """
    Get All IoctlCodes from a driver. 
    @rtype:   List
    @returns: List of All IoctlCodes
    """
    isConditionalJmp             = False
    isFirst                      = True
    BaseRegister                 = None
    OperRegister                 = None
    IoctlCode                    = []
    DispatchFunctionInstructions = []
    DispatchFunctionInstructions = getFunctionInstructions()[::-1]
    if DispatchFunctionInstructions == None:
       Message("Cann't get the IoctlCodes")
       return
    for i in DispatchFunctionInstructions:
      #Message("The instrucion of this function is %x\n" % i)
      mnem = GetMnem(i)
      if "jz" in mnem or "je" in mnem:
         isConditionalJmp = True
         continue
        
      if "cmp" in mnem and isConditionalJmp and isFirst:
         sisConditionalJmp = False
         BaseRegister  = GetOpnd(i,0)
         IoctlCode.append(GetOperandValue(i,1))  
         isFirst = False
         continue
         
      if "cmp" in mnem and isConditionalJmp and not isFirst:
         isConditionalJmp = False
         OperRegister  =  GetOpnd(i,0)
         if OperRegister == BaseRegister:
            IoctlCode.append(GetOperandValue(i,1))   
      
          
    for i in IoctlCode:
        Message("The ioctlcode of this driver is %x\n" % i)
获取分发函数的所有指令偏移后,倒序查找。如果碰到是jz或者是je的,且接下来是cmp的指令,并且比较操作的寄存器是否一样,一样的话,则把io控制码存储。(这样还是不够准确的,如果碰到其他的jz且连着jmp的指令,但不是io控制码。纯自动分析有时候不能识别)。相关函数原型如下:


后话:
1、上面实现的自动获取io控制码的比较简单,有些情况没有考虑到,算是初级版。
2、只能用来获取派遣函数形式如下的分发函数地址,

而下面的方式就不行,分发函数的赋值形式跟上面不同。


3、获取io控制码时,如果只有一个io控制码,并且有其他jz、cmp组合时,靠自动分析是不知道哪个是io控制码的。
4、上面的脚本可以当作IDA Python的练手,有兴趣的可以继续改进。

【公告】【iPhone 13、ipad、iWatch】11月15日中午12:00,看雪·众安 2021 KCTF秋季赛 正式开赛【攻击篇】!!!文末有惊喜~

上传的附件:
收藏
点赞0
打赏
分享
最新回复 (10)
雪    币: 99
活跃值: 活跃值 (10)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
dEARMoON 活跃值 2012-7-27 18:59
2
0
switch的优化形式有很多,cmp比较只是最简单的一种,该脚本只能识别最简单的IOCTL.
之前有写过,效果不太好,可以转换一下思路.
另外感谢楼主分享.
雪    币: 893
活跃值: 活跃值 (16)
能力值: ( LV9,RANK:330 )
在线值:
发帖
回帖
粉丝
jasonnbfan 活跃值 8 2012-7-27 20:14
3
0
mark IO控制码 感谢楼主共享
雪    币: 686
活跃值: 活跃值 (10)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
badboynt 活跃值 2012-7-27 20:37
4
0
正在研究deviceIOControl机制 感谢lz分享
雪    币: 303
活跃值: 活跃值 (111)
能力值: ( LV15,RANK:310 )
在线值:
发帖
回帖
粉丝
dragonltx 活跃值 6 2012-7-27 20:47
5
0
是这样的,Immunity Debugger里面的driverlib也只考虑了最简单的情况,这种单纯靠静态分析比较困难,只是分享下IDA Python的实例!哈哈!有兴趣的兄弟可以考虑继续优化!
雪    币: 0
活跃值: 活跃值 (24)
能力值: ( LV8,RANK:120 )
在线值:
发帖
回帖
粉丝
tihty 活跃值 2 2012-7-27 22:13
6
0
Python
雪    币: 909
活跃值: 活跃值 (54)
能力值: ( LV12,RANK:310 )
在线值:
发帖
回帖
粉丝
yuansunxue 活跃值 6 2012-7-27 23:02
7
0
学习 学习 python是个好东西
雪    币: 301
活跃值: 活跃值 (35)
能力值: ( LV13,RANK:330 )
在线值:
发帖
回帖
粉丝
HSQ 活跃值 8 2012-8-4 18:00
8
0
学习,”似乎“很有用的方法
雪    币: 99
活跃值: 活跃值 (10)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
dEARMoON 活跃值 2012-8-30 15:25
9
0
可以考虑利用IDA的F5来做,会方便很多
雪    币: 177
活跃值: 活跃值 (286)
能力值: (RANK:290 )
在线值:
发帖
回帖
粉丝
viphack 活跃值 4 2012-8-30 16:15
10
0
mark马克£
雪    币: 215
活跃值: 活跃值 (22)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
wngbx 活跃值 2020-11-30 11:40
11
0
python好强大,谢谢楼主分享
游客
登录 | 注册 方可回帖
返回