利用Immunity Debugger部署钩子

本文介绍如何在Immunity Debugger中部署软钩子和硬钩子,以捕获函数参数和跟踪内存变化。LogBpHook用于在断点触发时不暂停程序并收集信息。FastLogHook则涉及汇编桩,适用于频繁调用的函数。通过实例演示了对printf函数的钩子设置,并提醒了在printf返回值捕获上的挑战。参考PyCommands目录下的相关脚本以了解更多细节。
摘要由CSDN通过智能技术生成
ImmDbg提供了多种钩子。
1. 软钩子

软钩子针对各种不同调试事件发生时调用的,调试事件如断点、异常、加载或卸载dll、创建或销毁进程线程等。

以断点命中时触发钩子LogBpHook为例:

import immlib
from immlib import LogBpHook
import struct

#首先继承LogBpHook定义自己的钩子类,重点实现run函数
class MyHook(LogBpHook):
    def __init__(self):
        LogBpHook.__init__(self)
    def run(self, regs):
		#钩子触发时要执行的任务,regs中保存各个寄存器的值
        imm = immlib.Debugger()
        bytes=imm.readMemory( regs['ESP'] + 4, 0x8) #该处读取8个字节
        (format_addr,arg) = struct.unpack("LL", bytes) #解压bytes为两个4字节的数
        buf = ""
        offset = 0
        while True:
            byte = imm.readMemory(format_addr+offset,1) #读取1个字节
            if byte != '\x00':
                buf += byte
                offset += 1
                continue
            else:
                break
        imm.log("%s %d" % (buf,int(arg))) #输出printf的第一个和第二个参数

#然后在主函数中初始化该类的实例,并绑定函数地址
def main(args):
    imm = immlib.Debugger()
    hook = MyHook()
    func = imm.getAddress("msvcrt.printf") #获得函数printf的地址
    imm.log("%08x" % func)
    hook.add("hookprintf", func) #绑定函数地址
    return 'hook printf'

上面的脚本用于捕获printf函数第一个参数和第二个参数(默认第一个参数为格式化字符串),加载被调试程序后直接运行上面的脚本部署钩子,然后运行程序就可以收集printf参数信息。

值得注意的是,LogBpHook钩子并不会暂停程序,程序会一直执行,断点命中是暗中进行并调用钩子函数完成自动化信息收集。

软钩子的具体用法还可参考PyCommands\hookheap.py

2. 硬钩子

硬钩子适用于对调用频繁的函数下钩子,通过布置一个汇编代码桩(stub)来使得代码执行流在钩子命中时重定向至钩子代码处。

FastLogHook 针对cdecl函数调用约定
STDCALLFastLogHook 针对stdcall函数调用约定

构建硬钩子的框架
imm = immlib.Debugger()
fast = immlib.FastLogHook( imm ) #实例化一个钩子对象
 
fast.logFunction( address, num_arguments )
num_num_arguments为被下钩子函数的参数个数
要在函数头部设置钩子捕获参数,num_num_arguments设置为相应的值
要在函数出口设置钩子,num_num_arguments设置为0

fast.logRegister( register ) 
跟踪特定寄存器的值
register可以是"EAX","EBP","ESP"等

fast.logBaseDisplacement( register, offset) 
一般适合跟踪栈上参数,register设置为"EBP"或"ESP"

fast.logDirectMemory( address ) 

记录内存地址address上的值

只要钩子命中,与之配套的log函数就会触发,它会把所有捕获的数据信息放在专为FastLogHook对象分配内存中
fast.logAll() 可以获得这块内存区域的所有数据记录,为嵌套列表类型,格式如下:
{(hook_address,(arg1,agr2,...)),(hook_address,(arg1,agr2,...)), ...}

还是以捕获printf函数参数为例进行说明。

import immlib
import immutils

DESC = "hook printf" #description

def getRet( imm, addr,  max_opcodes = 300 ):
    for a in range( 0, max_opcodes ):
        op = imm.disasmForward( addr )
        if op.isRet():
##            if op.getImmConst() == 0xC3:
            op = imm.disasmBackward( addr, 2)
            return op.getAddress()
        addr = op.getAddress()
    return 0x0



def unHook( imm ): 
    fast = imm.getKnowledge( "hook_printf" )
    if not fast:
        imm.log( "hook_printf:未能获取钩子记录" )
        return
    if not fast.isHooked():
        imm.log( "hook_printf:未曾安装钩子" )
        return
    if fast.unHook():
        imm.log( "hook_printf:已卸载全部钩子" )
        return
    return

def Hook( imm ):

    msvcrt = imm.getModule( "msvcrt.dll" )
    if not msvcrt:
        imm.log( "cannot find msvcrt.dll module" )
        return
    
    #暂停调试器
    imm.pause()
    #获取printf的地址
    printf_addr = imm.getAddress( "msvcrt.printf" )
    imm.log( "hook printf head at: 0x%08x" % printf_addr)
    
    #确保模块代码已经被调试器分析过
    if not msvcrt.isAnalysed():
        imm.analyseCode( msvcrt.getCodebase() )

    
    #对于printf因为要获取返回值,所以hook在函数尾部
    printf_tail = getRet( imm, printf_addr, 1000 )
    imm.log( "hook printf tail at: 0x%08x" % printf_tail)
    imm.addKnowledge( "hook_printf", (printf_addr,printf_tail) ) #保存钩子的地址
    #获取hook对象
    fast = immlib.FastLogHook( imm )
    #在printf头部设置钩子
    fast.logFunction(printf_addr) #默认两个参数
    fast.logBaseDisplacement( "ESP", 0x04 )#arg1
    fast.logBaseDisplacement( "ESP", 0x08 )#arg2

    #在printf尾部设置钩子
    fast.logFunction(printf_tail)
    fast.logBaseDisplacement( "EBP", -0x20 )#reture value
    
    #启用钩子
    fast.Hook()
    #将取到的数据保存,供以后读取
    imm.addKnowledge( "my_hook", fast, force_add = 1 )
    return

def main(args):
    imm = immlib.Debugger()
    if len(args) == 0:
        fast = imm.getKnowledge( "my_hook" )
        if not fast:
            imm.log( "hook_printf no log data" )
            return
        log_list = fast.getAllLog()
        (printf_head,printf_tail) = imm.getKnowledge("hook_printf")
        for a in log_list:
            if a[0] == printf_head:
                imm.log("printf(0x%08x, 0x%08x)" % \
                        (a[1][0],a[1][1])) #arg1和arg2
            else:
                imm.log("return value is: %d" % a[1][0])
        return ""
    if args[0] == "unhook":
        unHook( imm )
        return ""
    if args[0] == "hook":
        Hook( imm )
        return ""
加载程序,运行脚本!hook_printf.py hook,然后运行程序;

程序结束后,再运行脚本!hook_printf.py,在log窗口即可看到结果。

但是在printf函数尾部设置钩子捕获返回值没有成功(printf的返回值为参数个数,在上例中参数个数必须为2)

硬钩子的具体用法还可参考PyCommands\hippie.py

关于ImmDbg非常好一篇教程:Starting to write Immunity Debugger PyCommands : my cheatsheet

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值