通过call指令看静态IAT HOOK 实践EPO

    技术2025-04-02  26

     

    Call的几种不同形式

    序号

    指令

    反汇编

    含义

    1

    FF    D7

    Call    edi

    Call reg/call [reg+xx]

    2

    E8    68F9FEFF

    call    01001F51

    Call 立即数

    3

    FF15  EC110001

    call    dword ptr [10011EC]

    Call dowrd ptr[立即数]

     

    FF指令

    01013FE6 FFD0 call eax 01013FE8 FFD3 call ebx 01013FEA FFD1 call ecx 01013FEC FFD2 call edx 01013FEE FFD7 call edi 01013FF0 FFD6 call esi 01013FF2 FF10 call dword ptr [eax] 01013FF4 FF93 10325476 call dword ptr [ebx+76543210] 由此可见依FF为特征码的call都是于寄存器打交道的,而且其后缀部分长度不易确定

     

     

     

    F8FF15

     

    01013FB0 E8 6C036486 call 87654321 01013FB5 E8 47C0FEFE call 00000001 01013FBA E8 53509081 call 82919012 01013FBF 90 nop 01013FC0 FF15 65769800 call dword ptr [987665] 01013FC6 FF15 99999999 call dword ptr [99999999] 01013FCC FF15 00000000 call dword ptr [0] 依F8与FF15为特征码的call 其后缀长度都是占sizeof(DWORD)大小

     

     

    而由于PE调用的时候都是采用

    Call dword ptr[xx00]  

    xxooIAT

     

    所以

    EPO (EntryPoint Obscuring)入口模糊技术的时候

    我采用办法是

    eop + xx()这里我从xx>=20开始搜索 太小的话 杀软扫描力度要大一些

    我从一个偏值开始查找

    FF 15 YYYY 

    然后判断YYYY是否在IAT返回内

    如果是则表明该callcall api

    我们可以将YYY修改为我们的目标代码 ZZZ

    执行完之后jmp 回到YYY

     

    实践

    通过搜索 call dword ptr[立即数]

    FF 15 XX XX XX XX

    然后判断XXXXXXXXIAT范围内以后开始修改

    修改的流程如下

    call    dword ptr [10011F4]为例

    此处的代码如下

    0101256B    FF15 F4110001   call    dword ptr [10011F4] ; msvcrt.__getmainargs

    01012571    8945 D0         mov     dword ptr [ebp-30], eax

    01012574    68 2C120001     push    calc.0100122C

    01012579    68 28120001     push    calc.01001228

    修改为

    0101256B    E8 F0BF0000    call    0101E560

    01012570    90              nop

    01012571    8945 D0         mov     dword ptr [ebp-30], eax

    01012574    68 2C120001     push    calc.0100122C

    01012579    68 28120001     push    calc.01001228

    关键点是将FF15 F4110001转换成了E8 F0BF0000  90

    0101E560处的代码为

    0101E560    一段维持了堆栈平衡的shellcode

    ……

    0101E564  - FF25 F4110001   jmp     dword ptr [10011F4>; msvcrt.__getmainargs

    比如

    0101E560    50              push    eax

    0101E561    58              pop     eax

    0101E562    53              push    ebx

    0101E563    5B              pop     ebx

    0101E564  - FF25 F4110001   jmp     dword ptr [10011F4>; msvcrt.__getmainargs

    这样程序的流程除了执行我们的代码意外 对原程序也不会有大的影响,如果我们替换的

    指令不在循环范围呢 则也只执行一次,非常不错

     

     

     

     

    今晚我对以上内容进行了实践  ,发现时可行的,准确率也很高,但是如果想达到高命中率需要巧妙的设定搜索范围,

    而且最好不要局限于FF15 CALL 同样可以对FF25 jmp进行修改

    但是发现这种方法有的函数HOOK 不杀 有的杀  所以还达不到我的要求

    现在采用衍生方案

    修改E8 CALL   然后判断E8后面的是否指向一个函数  如果是则进行修改

    这种方案,比先前IAT静态HOOK的方案更加灵活多变  

    而如何判断E8后的立即数差值是否指向一个函数呢?

     

    通过函数特征码 00401750 > 55 push ebp 00401751 8BEC mov ebp, esp 这是一个最普通的函数的特征码 那么流程就是 1:搜索E8 CALL 2:通过CALL后的立即数差值与当前地址计算出目标函数基地址 3:判断基地址处的内容是否为55 8B EC 如果是则进行HOOK否则下一个 如果在搜索范围内找不到 则寻找下一个目标  

    最新回复(0)