flatcc 发表于 2021-9-13 16:21

手脱花指令及IDA脚本编写

综合许多篇帖子而成,大多参考以末尾参考文章形式给出,适用于初学者,感谢大家提出意见。可结合末尾源码参考学习。感觉有用的话感谢大佬们点个赞。
## 简介
### 作用
- 欺骗反汇编器,让反汇编器无法正确反汇编出汇编代码,具体来说是破坏了反编译的分析,使得栈指针在反编译引擎中出现异常
- 从而加大静态分析的难度,使得逆向分析人员难以识别代码的真正意图

### 原理
由于反编译器的工作原理一般是线性扫描算法或递归下降反汇编算法。
- 线性扫描反汇编算法从程序的入口点开始反汇编,然后对整个代码进行扫描,反汇编扫描其过程中所遇到的每条指令。那么线性扫描算法的缺点也就显而易见了,由于其不定常的指令格式,在反汇编扫描过程中无法区分数据与代码,从而导致将代码段中嵌入的数据误解释为指令的操作码,以致最后得到错误的反汇编结果。
- 递归下降算法,递归下降算法通过程序的控制流来确定反汇编的下一条指令,遇到非控制转移指令时顺序进行反汇编,而遇到控制转移指令时则从转移地址处开始进行反汇编。该算法的缺点在于难于准确确定间接转移的目的地址。

### PATCH方法
先在IDA中开启字节码的显示,我这里设置显示的字节码是8。


以下图中的花指令为例,我们鼠标光标点到0x004560FF,然后按快捷键`D`,在下方为指令的地址0x00456100地址处,按快捷键`C`将其转换为指令。然后将0x004560FF处的`0xE8`Patch为`0x90`,也就是打补丁为nop指令。

然后保持副本即可。

## 实现案例
### 简单花指令-多层JMP嵌套
如下是单层的JMP形式:
```asm
jmp LABEL1
db junk_code;
LABEL1:
```
甚至如下的多层嵌套:
```c
//简单花指令-多层JMP嵌套
void example1()
{
        __asm {
                jmp LABEL1;
                _emit 68h;
        LABEL1:
                jmp LABEL2;
                _emit 0CDh;
                _emit 20h;
        LABEL2:
                jmp LABEL3;
                _emit 0E8h;
        LABEL3:
        }
        a = 99;
}
```
如下图,因为IDA使用的是递归下降算法进行反汇编,所以这种花指令可以被IDA轻松识别。

### 互补条件代替JMP跳转
类似如下形式,无论如何都会跳转到LABEL1处:
```asm
jz LABEL1
jnz LABEL1
db junk_code
LABEL1:
```
在如下代码中,先对eax进行xor之后,再进行test比较,zf标志位肯定为1,就肯定执行`jz LABEL2;`,也就是说中间0xC7永远不会执行。要记得:先压栈保存eax的值,最后再把eax的值pop出来。
```c
void example2_1()
{
        __asm {
                push eax;
                xor eax, eax;
                test eax, eax;
                jnzLABEL1;
                jz LABEL2;
        LABEL1:
                _emit 0xC7;
        LABEL2:
                pop eax;
        }
        a = 21;
}
```
如下图,我们可以看到,IDA虽然识别栈帧错误,但是正确的程序流还是比较清晰的。

再如下,我们将中间填充代码改为`0x21`,混淆效果明显了一些,结果如下。


那么我们再来一个加强版,代码如下:
```c
void example2_3()
{
        __asm {
                xor eax, eax;
                test eax, eax;
                je LABEL1;
                jne LABEL2;
        LABEL2 :
                _emit 0x5e;
                and eax, ebx;
                _emit 0x50;
                xor eax, ebx;
                _emit 0x74;
                add eax, edx;
        LABEL1:
        }
        a = 23;
}
```


### call&ret构造花指令
如下案例,代码中的esp存储的就是函数返回地址,对+8,就是函数的返回地址+8,正好盖过代码中的函数指令和垃圾数据。
```c
void example3()
{

        __asm {
                call LABEL9;
                _emit 0x83;
        LABEL9:
                add dword ptr ss : , 8;
                ret;
                __emit 0xF3;
        }
        a = 3;
}
```

如下图所示,是上述花指令代码的效果,这里最好自己动态跟以下。

> call 指令的直观理解:push 函数返回地址; jmp 立即数
> ret 指令的直观理解:pop eip; add esp,4

### 利用函数返回确定值
有些函数返回值是确定的,比如我们自己写的函数,返回值可以是任意非零整数,就可以自己构造永恒跳转。

还有些API函数也是如此,比如在Win下`HMODULE LoadLibraryA(LPCSTR lpLibFileName);`函数,如果
我们故意传入一个不存在的模块名称,那么他就会返回一个确定的值`NULL`,此时就可以通过这个函数来构造永恒跳转。如下例子:
```c
void example4_1()
{

        LoadLibrary(L"./hhhh");//函数返回值存储于eax中
        __asm{
                cmp eax, 0;
                jc LABEL6_1;
                jnc LABEL6_2;
        LABEL6_1:
                _emit 0xE8;
        LABEL6_2:
        }
        a = 41;
}
```
混淆效果如下:


### call和ret的组合
如下代码:
```c
void __declspec(naked)__cdecl example5(int* a)//裸函数,开辟和释放堆栈由我们自己写。
{//55 8b ec 83
        __asm
        {
                push ebp
                mov ebp, esp
                sub esp, 0x40
                push ebx
                push esi
                push edi
                mov eax, 0xCCCCCCCC
                mov ecx, 0x10
                lea edi, dword ptr ds :
                rep stos dword ptr es :
        }

        *a = 5;
        __asm
        {
               call LABEL9;
               _emit 0xE8;
               _emit 0x01;
               _emit 0x00;
               _emit 0x00;
               _emit 0x00;
                               
       LABEL9:
               push eax;
               push ebx;
               leaeax, dword ptr ds : ; //将ebp的地址存放于eax
               add dword ptr ss : , 26;//该地址存放的值正好是函数返回值,
                                                                                          //不过该地址并不固定,根据调试所得。加26正好可以跳到下面的mov指令,该值也是调试计算所得
               pop eax;
               pop ebx;
               pop eax;
               jmp eax;
               __emit 0xE8;
               _emit 0x03;
               _emit 0x00;
               _emit 0x00;
               _emit 0x00;
               mov eax, dword ptr ss : ;//将原本的eax值返回eax寄存器

        }

        __asm
        {
                pop edi
                pop esi
                pop ebx
                mov esp, ebp
                pop ebp
                ret
        }
}
```


也就是说思路有很多种,按照自己喜欢的方式组合,只要不影响其他正常代码的运行就可以,如下也是比较好的两种思路
#### call嵌套的其他思路1
```assembly
        call LABEL1
        db 0E8h
LABEL2:
        jmp LABEL3
        db 0
        db 0
        db 0E8h
        db 0F6h
        db 0FFh
        db OFFh
        db OFFh
LABEL1:
        :call LABEL2
LABEL3:
        add esp,8
```

#### call嵌套的其他思路2
```assembly
        push eax
        call LABEL1
        db 29h
        db 5Ah
LABEL1:
        POP eax
        imul eax,3
        call LABEL2
        db 29h
        db5Ah
LABEL2:
        add esp,4
        pop eax
```

## 花指令原理另类利用
当我们理解了花指令的原理后,我们可以在将花指令中的垃圾数据替换为一些特定的特征码,可以对应的$“定位功能”$,尤其在(https://blog.csdn.net/dontbecoder/article/details/8754729?utm_source=app)这个反调试技术中可以运用。例如:
```
asm
{
Jz Label
Jnz Label
_emit 'h'
_emit 'E'
_emit 'l'
_emit 'L'
_emit 'e'
_emit 'w'
_emit 'o'
_emit 'R'
_emit 'l'
_emit 'D'
Label:
}
```
将这串特征码hElLowoRlD嵌入到代码中,那我们只需要在当前进程中搜索hElLowoRlD字符串,就可以定位到当前代码位置,然后对下面的代码进行SMC自解密。

### 小结
构造永恒跳转,添加垃圾数据

## 综合题目案例
### IDC脚本去花
我们以题目`.exe`为例子,分析一段花指令,使用IDA中的快捷键`D`和`C`来手动过花指令。手动分析清楚其流程后,我们可以写一个脚本,来批量匹配花指令的模式`NOP`掉影响静态分析的代码。


写好的IDC脚本如下:
```c
//文件名:test.idc
#include <idc.idc>
static main()
{
    auto x,FBin,ProcRange;
    FBin = "E8 0A 00 00 00 E8 EB 0C 00 00 E8 F6 FF FF FF";
    //目标 = "E8 0A tel:00 00 00 90 EB 0C tel:90 90 90 90 90 90 90";
    //花指令1的特征码
    for (x = FindBinary(MinEA(),0x03,FBin);x != BADADDR;x = FindBinary(x,0x03,FBin))
    {
            x=x+5; //返回的x是第一个E8的地址,
                  //加上5是第二个E8的地址
            PatchByte (x,0x90);//nop掉
            x = x + 3; //00
            PatchByte (x,0x90);
            x++;//00 E8
            PatchWord (x,0x9090);
            x =x + 2 ; //F6 FF FF FF
            PatchDword(x,0x90909090);
    }
}
```

### 使用IDAPython去花
```python
import idautils
import idc

def my_nop(addr, endaddr):
    while addr < endaddr:
      patch_byte(addr, 0x90)
      addr += 1
      
pattern = "E8 0A 00 00 00 E8 EB 0C 00 00 E8 F6 FF FF FF"
cur_addr = 0x456000
end_addr = 0x467894

while cur_addr<end_addr:
    cur_addr = idc.find_binary(cur_addr,SEARCH_DOWN,pattern)
    print("patch address: " + str(cur_addr)) # 打印提示信息
    if cur_addr == idc.BADADDR:
      break
    else:
      my_nop(cur_addr+5,cur_addr+6)
      my_nop(cur_addr+8,cur_addr+14)
    cur_addr = idc.next_head(cur_addr)
```

附带源码:


## 参考
- 反汇编基础:<https://tinytracer.com/archives/反汇编基础/>
- 自动获取驱动程序IO控制码初级版:<https://bbs.pediy.com/thread-153965.htm>
- 花指令总结:<https://www.anquanke.com/post/id/236490>
- 反编译系列教程(上):<http://drops.xmd5.com/static/drops/papers-13686.html>
- _emit伪指令:<https://docs.microsoft.com/zh-cn/cpp/assembler/inline/emit-pseudoinstruction?view=msvc-160>
- IDAPython官方文档:<https://hex-rays.com/products/ida/support/idapython_docs/>
- IDAPython脚本示例:<https://www.cnblogs.com/shenshuoyaoyouguang/p/13841078.html>
- IDAPython动态调试开发技巧:<https://www.bbsmax.com/A/x9J27Lgg56/>

heartingrass 发表于 2022-9-19 13:53

本帖最后由 heartingrass 于 2022-9-19 15:24 编辑

flatcc 发表于 2022-9-16 17:49
我想想啊,有遇到实例嘛,可以探讨下楼主可以试一试,感觉这个长跳转就无法进行模式匹配了,需要消除长跳转,然后拼接代码,可能要利用到一些功能模块,另外完全借助IDA分析,也存在指令识别错误或未识别的情况。


dump2.exe:第二段代码是32bit,里面有大量花指令,需要进行清除之后,才方便进行程序逻辑分析。花指令的特征主要有如下几处:
一、连续的指令
1、ebp、esp还原【是后面的特例】
seg000:000CC824 014 55                         push    ebp
seg000:000CC825 018 89 E5                     mov   ebp, esp
seg000:000CC827 018 8D 64 24 FC                  lea   esp,
seg000:000CC82B 01C 89 EC                     mov   esp, ebp
seg000:000CC82D 01C 5D                         pop   ebp

2、esp还原【是后面的特例】

seg000:000C5FBA 01C 52                            push    edx
seg000:000C5FBB 020 8D 64 24 04                   lea   esp,

3、无用指令【待核实,只有一处】
seg000:0021C40D 84 56 C7                              test    , dl
seg000:0021C410 08 00                                 or      , al
二、存有大量跳转指令
1、ebp、esp还原【中间嵌入长跳转】
seg000:000CC824 014 55                            push    ebp
seg000:000CC825 018 89 E5                         mov   ebp, esp
seg000:000CC827 018 8D 64 24 FC                   lea   esp,
seg000:000CC82B 01C 89 EC                         mov   esp, ebp
seg000:000CC82D 01C 5D                            pop   ebp

2、esp还原【中间嵌入长跳转】
seg000:000C5FBA 01C 52                            push    edx
seg000:000C5FBB 020 8D 64 24 04                   lea   esp,

3、pushf、popf还原【中间嵌入长跳转】
seg000:002A0496                               loc_2A0496:                           ; CODE XREF: seg000:00000001↑j
seg000:002A0496 9C                                          pushf
seg000:002A0497 51                                          push    ecx
seg000:002A0498 50                                          push    eax
seg000:002A0499 31 C0                                       xor   eax, eax
seg000:002A049B
seg000:002A049B                               loc_2A049B:                           ; CODE XREF: seg000:002A04B3↓j
seg000:002A049B 83 F8 03                                    cmp   eax, 3
seg000:002A049E 74 15                                       jz      short loc_2A04B5
seg000:002A04A0 40                                          inc   eax
seg000:002A04A1 81 E9 2E CD 9B A2                           sub   ecx, 0A29BCD2Eh
seg000:002A04A7 81 C9 07 48 0C 20                           or      ecx, 200C4807h
seg000:002A04AD 81 D9 2B 22 BB B1                           sbb   ecx, 0B1BB222Bh
seg000:002A04B3 72 E6                                       jb      short loc_2A049B
seg000:002A04B5
seg000:002A04B5                               loc_2A04B5:                           ; CODE XREF: seg000:002A049E↑j
seg000:002A04B5 58                                          pop   eax
seg000:002A04B6 59                                          pop   ecx
seg000:002A04B7 9D                                          popf
4、pushf、popf还原【中间嵌入长跳转、还嵌套自身】
seg000:002AE278 9C                                          pushf
seg000:002AE279 E9 5E 37 FB FF                              jmp   loc_2619DC
seg000:002619DC                               loc_2619DC:                           ; CODE XREF: seg000:002AE279↓j
seg000:002619DC 52                                          push    edx
seg000:002619DD 51                                          push    ecx
seg000:002619DE 9C                                          pushf 【此处 嵌套了自身】
seg000:002619DF 50                                          push    eax
seg000:002619E0 52                                          push    edx
seg000:002619E1 31 D2                                       xor   edx, edx
seg000:002619E3
seg000:002619E3                               loc_2619E3:                           ; CODE XREF: seg000:002619F8↓j
seg000:002619E3 83 FA 0A                                    cmp   edx, 0Ah
seg000:002619E6 74 12                                       jz      short loc_2619FA
seg000:002619E8 42                                          inc   edx
seg000:002619E9 05 3F 86 3A 6F                              add   eax, 6F3A863Fh
seg000:002619EE 0D 99 24 DF 25                              or      eax, 25DF2499h
seg000:002619F3 05 D0 BA 30 4B                              add   eax, 4B30BAD0h
seg000:002619F8 7E E9                                       jle   short loc_2619E3
seg000:002619FA
seg000:002619FA                               loc_2619FA:                           ; CODE XREF: seg000:002619E6↑j
seg000:002619FA 5A                                          pop   edx
seg000:002619FB 58                                          pop   eax
seg000:002619FC 9D                                          popf
seg000:002619FD E9 B6 62 EC FF                              jmp   loc_127CB8
seg000:00127CB8                               loc_127CB8:                           ; CODE XREF: seg000:002619FD↓j
seg000:00127CB8 31 C9                                       xor   ecx, ecx
seg000:00127CBA
seg000:00127CBA                               loc_127CBA:                           ; CODE XREF: seg000:000FAD33↑j
seg000:00127CBA 83 F9 06                                    cmp   ecx, 6
seg000:00127CBD 55                                          push    ebp
seg000:00127CBE 89 E5                                       mov   ebp, esp
seg000:00127CC0 8D 64 24 FC                                 lea   esp,
seg000:00127CC4 89 EC                                       mov   esp, ebp
seg000:00127CC6 5D                                          pop   ebp
seg000:00127CC7 E9 E0 48 F4 FF                              jmp   loc_6C5AC
seg000:0006C5AC                               loc_6C5AC:                              ; CODE XREF: seg000:00127CC7↓j
seg000:0006C5AC 0F 84 15 0A FF FF                           jz      loc_5CFC7
seg000:0006C5B2 41                                          inc   ecx
seg000:0006C5B3 E9 78 7B 1B 00                              jmp   loc_224130
seg000:00224130                               loc_224130:                           ; CODE XREF: seg000:0006C5B3↑j
seg000:00224130 81 FA 6B 15 C8 6D                           cmp   edx, 6DC8156Bh
seg000:00224136 81 E2 38 42 C7 AF                           and   edx, 0AFC74238h
seg000:0022413C E9 EC 6B ED FF                              jmp   loc_FAD2D
seg000:000FAD2D                               loc_FAD2D:                              ; CODE XREF: seg000:0022413C↓j
seg000:000FAD2D 81 DA FA A1 7F 86                           sbb   edx, 867FA1FAh
seg000:000FAD33 0F 80 81 CF 02 00                           jo      loc_127CBA
seg000:000FAD39 E9 89 22 F6 FF                              jmp   loc_5CFC7
seg000:0005CFC7                               loc_5CFC7:                              ; CODE XREF: seg000:loc_6C5AC↓j
seg000:0005CFC7                                                                     ; seg000:000FAD39↓j
seg000:0005CFC7 59                                          pop   ecx
seg000:0005CFC8 5A                                          pop   edx
seg000:0005CFC9 E9 54 CF 1E 00                              jmp   loc_249F22
seg000:00249F22                               loc_249F22:                           ; CODE XREF: seg000:0005CFC9↑j
seg000:00249F22 9D                                          popf
seg000:00249F23 8D 64 24 04                                 lea   esp,
seg000:00249F27 E9 4B AA E9 FF                              jmp   loc_E4977
seg000:000E4977                               loc_E4977:                              ; CODE XREF: seg000:00249F27↓j
seg000:000E4977 E9 C5 2E 1A 00                              jmp   loc_287841
seg000:00287841                               loc_287841:                           ; CODE XREF: seg000:loc_E4977↑j
seg000:00287841 9D                                          popf
这两个花指令的简略特征是:
9C                            pushf
52                            push    edx
51                            push    ecx
31 C9                         xor   ecx, ecx
83 F9 08                      cmp   ecx, 8            【JZ 后续代码 的最后一个有条件跳转会 跳转到此处】
0F 84 A2 17 E4 FF             jz      loc_E9020
59                            pop   ecx
5A                            pop   edx
9D                            popf
【JZ】后续代码特征1:
47                            inc   edi
81 EA 4A 0A 6A C8             sub   edx, 0C86A0A4Ah
81 F2 F7 12 2D EE             xor   edx, 0EE2D12F7h
81 EA C6 07 02 1C             sub   edx, 1C0207C6h
0F 89 FB E3 13 00             jns   loc_1D2296
特征2:
43                            inc   ebx
1D F3 63 58 CC                sbb   eax, 0CC5863F3h
25 DC C9 C5 7F                and   eax, 7FC5C9DCh
05 C8 9D D9 2E                add   eax, 2ED99DC8h
0F 8D FB 01 FA FF             jge   loc_1A7C7E


特征3:
41                            inc   ecx
3D 7C AA 0E E6                cmp   eax, 0E60EAA7Ch
35 93 5A FA 84                xor   eax, 84FA5A93h
1D 64 15 D9 23                sbb   eax, 23D91564h
0F 88 B0 7F EA FF             js      loc_158A72
特征4:
41                            inc   ecx
81 D2 B7 D6 07 45             adc   edx, 4507D6B7h
81 CA 5A 03 73 78             or      edx, 7873035Ah
81 C2 10 EA 7D 71             add   edx, 717DEA10h
0F 88 E1 61 03 00             js      loc_1CC00A
特征5:

41                            inc   ecx
15 CB 30 92 03                adc   eax, 39230CBh
25 86 2C C9 70                and   eax, 70C92C86h
15 17 1C 96 C5                adc   eax, 0C5961C17h
0F 86 FE 34 11 00             jbe   loc_2077A4

附件是:x32程序片段,不可执行,里面是一大堆的花指令。

njzyjyyd 发表于 2021-9-13 18:31

学习学习!

guangzisam 发表于 2021-9-13 19:43

总结的很好。研究很有深度

白云点缀的蓝 发表于 2021-9-14 12:32

vmp的代码能还原不

mic2zac 发表于 2021-9-14 17:36

知识盲区了

submariner 发表于 2021-9-14 18:23

好复杂,看着头晕

fyh505099 发表于 2021-9-14 23:10

学习学习,谢谢分享

残风逝雪夜阑天 发表于 2021-9-14 23:28

感谢分享

zhhispig 发表于 2021-9-14 23:44

除了案例都看懂了 感谢分享

gba626 发表于 2021-9-15 04:32

学习了 感谢分享
页: [1] 2 3 4 5 6 7
查看完整版本: 手脱花指令及IDA脚本编写