• 手工脱壳之 未知IAT加密壳 【IAT加密+混淆+花指令】【哈希加密】【OD脚本】


    一、工具及壳介绍

    使用工具:Ollydbg,PEID,ImportREC,LoadPE,OllySubScript

    未知IAT加密壳

    二、初步脱壳 

    尝试用ESP定律。

       

       

    疑似OEP,VC6.0特征

       

       

    进第一个CALL查看

       

       

    确认是OEP。

    OEP地址 = 47148b,RVA = 7148b

       

       

    导入表函数信息出了问题。

    查看IAT引用。

    IAT表被加密。所以ImproREC才检测失败。

       

       

    三、解析IAT加密方式

    先API方面考虑。 

    壳修复exe IAT时,需要调用相关API,用LoadPE查看壳的导入表信息。

    可见,推测,LoadLibrary 和 GetProAddress 是 隐藏调用 或 自我实现的。

       

       

    采取硬件断点的方式:

    在被加密的IAT表的最顶端,下硬件断点。

       

       

    首次断下,执行代码是在内存地址上,说明壳是在自己申请的内存上执行代码的。

    回溯分析函数。

       

    进一步分析,确认是memcoy

    查看memcoy参数,数据窗口跟随,发现是壳首次调用解密TEXT段

    改换在memcpy下断点,第二次断下。

    第二次断下,是往IAT填RVA。

       

       

    接下来断下的每一次,是往IAT填内存地址,内存地址数据窗口跟随。

       

    IAT引用的顺序是这样的:

    CALL à 壳的内存代码 à 真正的API

    所以壳是在中间加了一层内存代码,并且内存代码里包含混淆花指令。

    三、锁定IAT加密点

    在memcpy进RVA后,依旧在IAT首部下硬件断点。

    得知壳进行内存的操作后,顺便在API下断,VirtualAlloc

       

    记录一下,一共申请了三次内存。

       

    在硬件断点断下的地方。

    由于汇编中掺杂着混淆和花指令,(具体见最后部分)。 

    确定目标:在壳修复IAT过程,寻 取出的函数地址 和 475000(往IAT填的内存地址)。

    操作:多观察寄存器窗口 和 堆栈窗口

    在当前指令下硬件断点,并开始单步步入(混淆代码的CALL F8会跑飞)

    记录异样:

    DLL基地址

    查看地址,是遍历时的RVA

     出现字符串,并在代码循环中逐步减少,疑似DLL INT取得的函数名。

     查看地址,确认是。

       

    按经验,在壳中,比较函数名的汇编代码有两种规律:

    壳调用比较函数:在字符串完整或全没时,跟踪到返回指令,回溯分析函数和函数周围的函数调用。

    壳采用比较循环:纯代码循环比较字符串。找到字符串比较条件的临界点,一般下一条是条件跳转指令,跳出循环。

    由于代码是混淆过的,跳来跳出乱跳,很明显是属于比较循环。

       

    比较字符串,如果采用rep的方式的话,结果一般会设置标志位跳转,再返回布尔值。

    上面是TEST AL, AL,判断字符串是否结尾。壳可能进行长度记录,或是对整个字符串进行了特殊操作。

    当比较结束时,跟踪结果,寻找函数地址 

    发现壳是对函数名进行哈希加密,并拿哈希值与 要寻函数的哈希值比较,来锁定函数。

    下条件断点,当匹配正确后,下一步应该就是从DLL IAT取函数地址了

       

    取出的函数地址:

       

    为后面OD脚本做准备:

    跳过CALL,需在下一条指令下硬件断点:

    记录下一条指令地址:0x002E08D5,RVA = 08D5

       

    接下来找 把函数地址放进exe IAT的指令,观察475000开始的地址。

     中间经过memcpy,应该是把内存代码往刚申请的内存上填,然后把内存地址赋给IAT。

       

    寻到IAT的地址: 

    然后就是把内存地址IAT地址上填了

       

     为后面OD脚本做准备:

    跳过CALL,需在下一条指令下硬件断点:

    记录下一条指令地址:0x2E1A36,RVA =1A36

    由于壳代码是在申请出来的内存上执行的,需要确定内存基址,就需要确定申请内存的指令。

    寻到申请内存的指令:

       

      为后面OD脚本做准备:

    记录下一条指令地址:0x47A381。

       

    四、OD脚本

    前面的准备材料:

    OEP 地址 = 0x47148b
    
    得到申请内存地址:0x47A381
    
    取IAT指令地址RVA:08D5
    
    存IAT指令地址RVA:1A36

       

    OD脚本:

    //清除所有硬件断点
    
    BPHWC
    
    //清除所有软件断点
    
    BC
    
    //清除所有内存断点
    
    BPMC
    
    
    //壳申请内存基地址
    
    VAR BaseAddress
    
    //IAT地址
    
    VAR IATAddress
    
       
    //得到申请内存基地址指令
    
    BPHWS 47A381,"x"
    
    //OEP断点
    
    BPHWS 47148b,"x"
    
    
    _LOOP:
    
    RUN
    
       
    //内存基地址判断
    
    CMP eip,47A381
    
    JNZ _Sign1
    
       
    MOV BaseAddress,eax
    
    
    //取IAT指令
    
    BPHWS BaseAddress+1A36,"x"
    
    //存IAT指令
    
    BPHWS BaseAddress+08D5,"x"
    
       
    _Sign1:
    
    
    //取IAT判断
    
    CMP eip,BaseAddress+1A36
    
    JNZ _Sign2
    
    
    MOV IATAddress,eax
    
    
    _Sign2:
    
    
    //存IAT的地方
    
    CMP eip,BaseAddress+8D5
    
    JNZ _Sign3
    
    
    MOV [edx],IATAddress
    
    
    _Sign3:
    
       
    //OEP
    
    CMP eip,47148b
    
    JNZ _LOOP
    
    
    MSG "到达OEP"

    再次Dump,成功解析。 

       

    成功运行。

       

    五、混淆和花指令 

    代码中出现很多这样的指令:

    call xxx
    
    xxx    LEA ESP,DWORD PTR SS:[ESP+0x4]
    
    实际上等价于jmp    xxx

    很多地方都是 混淆和花指令结合:

       

    有关混淆和花指令详细,可以参考下一篇,下一个壳采用了大量的花指令和混淆:

    手工脱壳之 PESpin加密壳【SHE链硬件反调试】【IAT重定向】【混淆+花指令】

       

    个人总结:

    附件:

     未知加密壳

    KIDofot

  • 相关阅读:
    修改linux下某一个文件夹下所有文件内容
    jenkins对结果进行断言问题
    linux 循环处理文件夹下所有文件脚本
    LR java Vuser 相关依赖JAR包,配置文件处置方法
    Jmeter函数 唯一取值 笔记
    jmeter+java vuser+rmi+dubbo脚本
    eclipse快捷键
    猫狗队列
    用固定长度的数组实现stack queue
    两个单链表相交的问题
  • 原文地址:https://www.cnblogs.com/KIDofot/p/8641380.html
Copyright © 2020-2023  润新知