zoukankan      html  css  js  c++  java
  • 倚天屠龙(一):妙用IDA Pro--利用IDAPython编写调试插件

    一:前言

      虽然静态分析有Radare2,Hopper这种新星之秀,动态调试有Ollydbg,Windbg这种老牌霸主,但是IDA Pro仍然是大部分二进制安全工程师最喜爱的工具,除了价格过于昂贵,基本无懈可击。在笔者眼里,它有下面几个特点是别的工具无法比拟的

      1:反编译插件,说它是当今世界最好的反编译器也不为过,这个革命性的插件,极大的降低逆向工程的门槛,也极大的提高了逆向工程师的工作效率。 

      2:IDA的编程接口,单纯的任何工具无法满足安全工程师的所有使用需求,但是完善的SDK包给了这个工具无限可能,特别在自动批量化处理的方面,如虎添翼。  

      3:以数据库的形式保存,方便对文件进行任何操作并保存

      并不是其它的功能就不优秀了,相反,它的其它功能也很强大,比如FLART功能,等等。这系列文章主要以IDA IDC,SDK编程,IDAPython变成的具体案例为主,插叙IDA的各种奇淫巧技。

    二:准备工作

      先回答一个问题:

      1:为什么用IDAPython,而不是用 IDC或者IDA SDK编程?

        IDC可以快速解决一些简单的问题,但是对于复杂的问题,就有点力不从心了。IDA SDK包文档过少,而且在调试相关的API,BUG比较多,使用比较难受,相比于起来,IDAPython可以调用IDC和           IDA SDK包的所有函数,而且文档资料丰富。

      当然,之前你需要懂Python,逆向工程,能熟练使用IDA Pro,懂得调试的一些常规知识。再加上一个IDA Pro6.8带IdaPython即可。

    三:编写

      第一步:先来看一下插件的框架

    class myIdaPlugin(plugin_t):
        flags=0
        wanted_name="my ida plugin"
        wanted_hotkey="Alt+c"
        comment="my ida plugin"
        help="Something helpful"
        
        def init(self):
            return PLUGIN_KEEP
            
        def term(self):
            pass
            
        def run(self,arg):        
            pass
            
    def PLUGIN_ENTRY():
        return myIdaPlugin()    

      其中,flags规定了Ida在不同情况下怎么处理插件,一般为0。

      wanted_name为插件名称,comments为插件注释,help为帮助字符串,wanted_hotkey为快捷键,没有则赋为空值。

      其中最重要的是那三个函数了,init()函数用于加载你的插件,term()函数用于卸载时的清理活动(释放内存,结束处理,保存状态等等)

      第二步:看一下调试框架

    from idaapi import *  
      
    class MyDbgHook(DBG_Hooks):  
        """ Own debug hook class that implementd the callback functions """  
      
        def dbg_process_start(self, pid, tid, ea, name, base, size):  
            print("MyDbgHook : Process started, pid=%d tid=%d name=%s" % (pid, tid, name))  
      
        def dbg_process_exit(self, pid, tid, ea, code):  
            print("MyDbgHook : Process exited pid=%d tid=%d ea=0x%x code=%d" % (pid, tid, ea, code))  
      
        def dbg_library_unload(self, pid, tid, ea, info):  
            print("MyDbgHook : Library unloaded: pid=%d tid=%d ea=0x%x info=%s" % (pid, tid, ea, info))  
            return 0  
      
        def dbg_process_attach(self, pid, tid, ea, name, base, size):  
            print("MyDbgHook : Process attach pid=%d tid=%d ea=0x%x name=%s base=%x size=%x" % (pid, tid, ea, name, base, size))  
      
        def dbg_process_detach(self, pid, tid, ea):  
            print("MyDbgHook : Process detached, pid=%d tid=%d ea=0x%x" % (pid, tid, ea))  
            return 0  
      
        def dbg_library_load(self, pid, tid, ea, name, base, size):  
            print "MyDbgHook : Library loaded: pid=%d tid=%d name=%s base=%x" % (pid, tid, name, base)  
      
        def dbg_bpt(self, tid, ea):  
            print "MyDbgHook : Break point at %s[0x%x] pid=%d" % (GetFunctionName(ea), ea, tid)  
            idaapi.continue_process()  
            return 0  
      
        def dbg_suspend_process(self):  
            print "MyDbgHook : Process suspended"  
      
        def dbg_exception(self, pid, tid, ea, exc_code, exc_can_cont, exc_ea, exc_info):  
            print("MyDbgHook : Exception: pid=%d tid=%d ea=0x%x exc_code=0x%x can_continue=%d exc_ea=0x%x exc_info=%s" % (  
                pid, tid, ea, exc_code & idaapi.BADADDR, exc_can_cont, exc_ea, exc_info))  
            return 0  
      
        def dbg_trace(self, tid, ea):  
            print("MyDbgHook : Trace tid=%d ea=0x%x" % (tid, ea))  
            return 0  
      
        def dbg_step_into(self):  
            print("MyDbgHook : Step into")  
            self.dbg_step_over()  
      
        def dbg_run_to(self, pid, tid=0, ea=0):  
            print "MyDbgHook : Runto: tid=%d" % tid  
            idaapi.continue_process()  
        
        def dbg_step_over(self):  print("MyDbgHook : 0x%x %s" % (eip, GetDisasm(eip)))  
    debughook = MyDbgHook()  
    debughook.hook()  

       这里是调试框架,代码看起来很长,其实,只要在插件框架的init函数进行初始化,即可。然后在调试过程中,会因为各种事件而触发各种函数,从而触发自己需要的操作,实现自动化脱壳或者anti-debug等功能。

      第三步:研究实现x64和x32位antii-anti-debug功能

        一般anti-anti-debug功能从两方面着手 ,一方面patch内存,一方面是hook函数。

        Patch内存:这需要获取FS(x86)/GS(x64)指向的地址,这里提供三种方法,第一种直接使用IDApython提供的API接口

    fsBase = regval_t()
    get_reg_val("fs",fsBase)
    return internal_get_sreg_base(idaapi.get_current_thread(),int(fsBase.ival) )
    

        但这种在64位上无效,估计是IDA自身Bug,已经提交给 hex-ray公司了。

        第二种是利用appcall函数来调用windows api得到,这种过于复杂。

        第三种是通过注入dll,来直接用asm汇编进行编程,这里可以使用IDA的APPCALL机制来实现LoadLibrary操作,代码如下:

       def LoadLibrary(self,dll_name):
            return Appcall.proto("kernel32_LoadLibraryA","int __stdcall LoadLibrary(const char * fn);")(dll_name)    
    

        之后就可以直接patch_long(addr,byte)了

        Hook函数:如上文,最简单的方法是采用dll注入,采用APPCALL来加载并调用函数,如下

        def callfunc(self,funcname):
            if self.bits == "x86":
                return Appcall.proto("stealthx86_"+funcname,"bool _stdcall "+funcname+"();")();
            else:
                return Appcall.proto("stealthx64_"+funcname,"bool _stdcall "+funcname+"();")();
    

         关于需要注入的dll,由于不在本文 内容中,请自行探究。

      关于一些调试过程中自动化处理的一些,留待下一篇继续讲解。

        

  • 相关阅读:
    iOS 苹果开发证书失效的解决方案(Failed to locate or generate matching signing assets)
    iOS NSArray数组过滤
    App Store2016年最新审核规则
    iOS 根据字符串数目,自定义Label等控件的高度
    iOS 证书Bug The identity used to sign the executable is no longer valid 解决方案
    Entity FrameWork 增删查改的本质
    EF容器---代理类对象
    Entity FrameWork 延迟加载本质(二)
    Entity FrameWork 延迟加载的本质(一)
    Entity FrameWork 增删查改
  • 原文地址:https://www.cnblogs.com/0xJDchen/p/7527236.html
Copyright © 2011-2022 走看看