首页
社区
课程
招聘
我对混淆代码的粗浅认识
发表于: 2006-1-22 15:25 13216

我对混淆代码的粗浅认识

2006-1-22 15:25
13216

我对混淆代码的粗浅认识

首先,我只知道这个东西来源于病毒领域,没有真正学习过,更没有用过病毒引擎,完全是脱壳过程
中自己的感受,认识很肤浅,甚至完全错误。请大家多指点。

混淆代码与花指令是否可以划等号?我觉得尽管二者不能完全划清界限,但还是有区别。花指令似乎大多是
完全的垃圾代码,一般通过在编程时插入宏来实现,只要能识别出来,大多可以直接拿掉(不考虑校验),
如使用dejunk插件。

混淆代码却难以简单地剥除。比如下面这几句代码,来自ExeCryptor。

_2fimh7mp:0058E96C 68 96 3C BD 79                    push    79BD3C96h
_2fimh7mp:0058E971 58                                pop     eax
_2fimh7mp:0058E972 81 C8 28 23 76 C3                 or      eax, 0C3762328h
_2fimh7mp:0058E978 81 E8 18 61 46 D9                 sub     eax, 0D9466118h
_2fimh7mp:0058E97E 81 E0 FD 23 0B 83                 and     eax, 830B23FDh
_2fimh7mp:0058E984 E9 C3 3B FF FF                    jmp     loc_58254C

显然难以通过定义Search/Replace字符串来加以清理。调试时逐句跟很耗费精力,而计算后的结果却往往
是有意义的,需要加以注意的值。我猜测这样的代码并不是编程时实现的,可能是用单独的混淆引擎生成的。

不知道dejunk是如何实现的。我自己写过一个IDA插件,模仿dejunk的文件格式,在IDA内去掉花
指令。用字符串比较的方式来判断,比如Themida壳中的花指令(到达oep前基本就只有这1种):

[Type 1]

;        push 0
;        push reg32
;        call loc_1
;        _THREE_BYTES_JUNKCODE
;loc_1
;        pop reg32
;        mov [esp+4],reg32
;        add [esp+4],imm32        ; 这个值可变
;        inc reg32
;        push reg32
;        ret
;        _TWO_BYTES_JUNKCODE        ; bytes数可变

[imm32 = 0x14]
S = 6A00??E803000000????C3??89??24048144240414??????????C3??
R = 90909090909090909090909090909090909090909090909090909090

[imm32 = 0x15]
S = 6A00??E803000000????C3??89??24048144240415??????????C3????
R = 9090909090909090909090909090909090909090909090909090909090

[imm32 = 0x16]
S = 6A00??E803000000????C3??89??24048144240416??????????C3??????
R = 909090909090909090909090909090909090909090909090909090909090

[imm32 = 0x17]
S = 6A00??E803000000????C3??89??24048144240417??????????C3????????
R = 90909090909090909090909090909090909090909090909090909090909090

[imm32 = 0x18]
S = 6A00??E803000000????C3??89??24048144240418??????????C3??????????
R = 9090909090909090909090909090909090909090909090909090909090909090

[imm32 = 0x19]
S = 6A00??E803000000????C3??89??24048144240419??????????C3????????????
R = 909090909090909090909090909090909090909090909090909090909090909090

[imm32 = 0x1A]
S = 6A00??E803000000????C3??89??2404814424041A??????????C3??????????????
R = 90909090909090909090909090909090909090909090909090909090909090909090

[imm32 = 0x1B]
S = 6A00??E803000000????C3??89??2404814424041B??????????C3????????????????
R = 9090909090909090909090909090909090909090909090909090909090909090909090

[imm32 = 0x1C]
S = 6A00??E803000000????C3??89??2404814424041C??????????C3??????????????????
R = 909090909090909090909090909090909090909090909090909090909090909090909090

[imm32 = 0x1D]
S = 6A00??E803000000????C3??89??2404814424041D??????????C3????????????????????
R = 90909090909090909090909090909090909090909090909090909090909090909090909090

显然,这里只有一种套路,但用字符串匹配,代码有任何变化,都需要新的S/R对,非常笨拙。到了
Themida的虚拟机部分,完全对付不了混淆代码。不知道用正则表达式能否做得灵活些(那个我也没
用过;-)。

为了读Themida的VM代码,重新写了个插件,希望能比上面的稍微"聪明"一点。程序大致分几步:

1. 清除由单条指令实现的垃圾代码
   指完全可以用nop替代的指令,基本上只有 lea r32,[r32]类型

   另外,把变形的jmp替换,如:

   _11d0000:011D173E 68 59 0F 2D 27            push    272D0F59h
   _11d0000:011D1743 81 2C 24 52 FA 0F 26      sub     dword ptr [esp], 260FFA52h
   _11d0000:011D174A C3                        retn        ; 这里等于jmp loc_11D1507

2. 清除垃圾指令序列
   指可以用nop替换的指令序列,如:

   _11d0000:011D001E F7 D8    neg     eax
   _11d0000:011D0020 F7 D8    neg     eax

   _11d0000:011D261C 4B       dec     ebx
   _11d0000:011D261D F7 D3    not     ebx
   _11d0000:011D261F F7 DB    neg     ebx

   _11d0000:011D80CD 57       push    edi
   _11d0000:011D80CE F7 1C 24 neg     dword ptr [esp]
   _11d0000:011D80D1 5F       pop     edi
   _11d0000:011D80D2 F7 DF    neg     edi

   需要注意的是,从第2步起,所有的代码模式中间都可能夹杂着其他的垃圾指令,如lea r32,[r32]
   或jmp。这也是第1步先行替换的原因(以简化判断)。如:

   _11d0000:011D1736 68 00 00 00 00                          push    0
   _11d0000:011D173B 29 2C 24                                sub     [esp], ebp
   _11d0000:011D173E 68 59 0F 2D 27                          push    272D0F59h
   _11d0000:011D1743 81 2C 24 52 FA 0F 26                    sub     dword ptr [esp], 260FFA52h
   _11d0000:011D174A C3                                      retn        ; 这里等于jmp loc_11D1507
   _11d0000:011D1507 5D                                      pop     ebp
   _11d0000:011D1508 F7 DD                                   neg     ebp

   这里垃圾代码被jmp分成了2段。

   由于对各种代码序列的识别顺序难以安排,一些模式可能要在别的代码被处理后才能识别,对给定的地址范围,
   插件需要运行3次才能清理干净.

3. 对可以按模式匹配的指令加以简化
  
   比如:

   _11d0000:011D01F6 68 76 5E 00 00     push    5E76h
   _11d0000:011D01FB 89 04 24           mov     [esp], eax

   等价于push eax

   _11d0000:011D3563 31 F7              xor     edi, esi
   _11d0000:011D3565 31 FE              xor     esi, edi
   _11d0000:011D3567 31 F7              xor     edi, esi

   等价于xchg esi,edi

4. 简化push/pop指令对
   这个可以归入3,但数量众多,所以单独处理,如:

   _11d0000:011D5547 52                push    edx
   _11d0000:011D5548 BA C5 42 00 00    mov     edx, 42C5h
   _11d0000:011D554D 01 57 08          add     [edi+8], edx
   _11d0000:011D5550 5A                pop     edx

   等价于 add [edi+8],42C5h

5. 简化mov r8/r32,imm指令

   如:

   _11d0000:011D55EC BA BC 55 00 00     mov     edx, 55BCh
   _11d0000:011D55F1 C1 EA 09           shr     edx, 9
   _11d0000:011D55F4 4A                 dec     edx
   _11d0000:011D55F5 E9 40 FC FF FF     jmp     loc_11D523A        ; 夹杂了jmp
   _11d0000:011D523A 81 CA D6 2B 00 00  or      edx, 2BD6h
   _11d0000:011D5240 81 F2 3A 24 00 00  xor     edx, 243Ah
   _11d0000:011D5246 81 F2 5E 73 00 00  xor     edx, 735Eh
   _11d0000:011D524C 81 F2 64 83 FF FF  xor     edx, 0FFFF8364h

   等价于mov edx, 0FFFFFFFFh

6. 简化mov mem32,imm32指令
   如:

   _11d0000:011D0054 C7 47 18 F9 28 00 00    mov     dword ptr [edi+18h], 28F9h
   _11d0000:011D005B F7 57 18                not     dword ptr [edi+18h]
   _11d0000:011D005E 31 FB                   xor     ebx, edi        ; 垃圾
   _11d0000:011D0060 31 FB                   xor     ebx, edi        ; 垃圾
   _11d0000:011D0062 F7 5F 18                neg     dword ptr [edi+18h]
   _11d0000:011D0065 81 67 18 C0 3B 00 00    and     dword ptr [edi+18h], 3BC0h
   _11d0000:011D006C 81 6F 18 EB 64 00 00    sub     dword ptr [edi+18h], 64EBh
   _11d0000:011D0073 8D 36                   lea     esi, [esi]        ; 垃圾
   _11d0000:011D0075 81 6F 18 D5 C3 FF FF    sub     dword ptr [edi+18h], 0FFFFC3D5h

   等价于mov dword ptr [edi+18h], 0

   暂时就只做了这些,Themida虚拟机里的混淆代码实在太多,要想清理干净恐怕是不容易。这只
是个尝试,希望把代码搞得可读性强些。另外,处理后的代码与原始代码看起来差别较大,调试起
来也难看,可以考虑做个OD插件(不会;-),或着把IDA的数据贴过去。现在bug不少,贴过去肯定是
跑不起来,只是个试验品。

   编码中一个突出问题是对代码的正确识别。IDA SDK中提供的isCode,isData,isHead,个人感觉
不大好用,经常出现误判或漏掉数据。在代码识别时我直接使用了z0mbie写的XDE反汇编引擎。但
仍有问题,主要是对8为寄存器访问代码,不能正确给出src_set和dst_set,不得已自己判断指令。

   对代码进行识别时,和以前用字符串匹配没有太多区别,只是增强了读入代码数据的过程(跳过
nop,及在jmp的目的地址继续)。这样就限制了仍然不能做得足够灵活。尤其是同样的助记符可能
对应不只一个opcode,使代码更加冗长。

下面是一个bug例子。

_11d0000:011D0451 30 6F 20                                xor     [edi+20h], ch
_11d0000:011D0454 66 8B 0C 24                             mov     cx, [esp]
_11d0000:011D0458 83 C4 02                                add     esp, 2          ; DeObfuscated code

_11d0000:011D045B 90 90 90 90 90 90 90 90+                db 0Dh dup(90h)

_11d0000:011D0468 E9 B8 07 00 00                          jmp     loc_11D0C25

_11d0000:011D046D 90 90 90 90 90 90 90 90                 db 8 dup(90h)
_11d0000:011D0475 90 90 90 90 90 90 90 90+byte_11D0475    db 0Bh dup(90h)         ; CODE XREF: _11d0000:011D037Dj

_11d0000:011D0480 C1 E8 02                                shr     eax, 2
_11d0000:011D0483 C1 E0 03                                shl     eax, 3
_11d0000:011D0486 09 C0                                   or      eax, eax
_11d0000:011D0488 0F 84 73 FD FF FF                       jz      loc_11D0201

已经经过前4步处理。011D0468的jmp是正确的。但第5步错误地将011D0469的B8 07 00 00 90
误判为mov eax,xxxxxxxx,而后续的指令也恰好满足判断条件:

_11d0000:011D0480 C1 E8 02                                shr     eax, 2
_11d0000:011D0483 C1 E0 03                                shl     eax, 3
_11d0000:011D0486 09 C0                                   or      eax, eax

这3句都是在对同一寄存器操作,且源对象集不包括内存数据或别的寄存器,于是判别为
符合条件的指令序列,进行合并。最后暂且改为连续判断4条指令是否符合条件。少清理
一些总比弄错了好。

   
    怎样才能更加灵活? 也许可以考虑定义一套类似脚本的东西,用来描述混淆代码模式。
然后对描述字符串进行分析,类似于编译过程。另外再用一个汇编引擎,从得到的结果汇编
出所有可能的opcode组合用于判断。这些东西已经超出我的能力了,写这篇东西,希望抛砖
引玉,哪位高人开发出能用于实战的工具。

    插件在IDA 4.7下使用,没有处理的混淆代码还有很多(我怀疑如果榨干全部水份,有
用的代码不组三分之一)。源码过分丑陋,就不拿出来献眼了;-)

附件:themida.rar


[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 7
支持
分享
最新回复 (20)
雪    币: 233
活跃值: (130)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
2
只能学习
2006-1-22 15:30
0
雪    币: 494
活跃值: (629)
能力值: ( LV9,RANK:1210 )
在线值:
发帖
回帖
粉丝
3
南蛮妈妈到底是谁的马甲?
2006-1-22 15:33
0
雪    币: 10734
活跃值: (2449)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
太强了 学习都不够资格 仰视
2006-1-22 16:14
0
雪    币: 101
活跃值: (17)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
学习学习
不懂中.
2006-1-22 17:02
0
雪    币: 211
活跃值: (40)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
最初由 softworm 发布
南蛮妈妈到底是谁的马甲?

可能是喜欢仙剑的人
2006-1-22 17:35
0
雪    币: 215
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
我觉得如果榨干全部水份,有用的代码实际上能有10%就不错.可能是这一部分认为有用的代码+下面认为有用的代码+下下面的......共同组成了一个没用的东西.
2006-1-22 17:44
0
雪    币: 223
活跃值: (101)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
好文章啊  长见识的了
2006-1-22 18:26
0
雪    币: 61
活跃值: (160)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
9
学习。
上传的附件:
2006-1-22 19:34
0
雪    币: 6075
活跃值: (2236)
能力值: (RANK:1060 )
在线值:
发帖
回帖
粉丝
10
用反汇编一遍一遍扫描也许可以。
一次扫描一个套路,那些reg变化只要注意解码ModR/M就行了。
jmp可以不管直接模拟继续扫,把垃圾序列枪毙。
2006-1-23 09:12
0
雪    币: 207
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
最初由 softworm 发布
南蛮妈妈到底是谁的马甲?


可能是以前太历害了得罪某些共亨软件作者,才改名成这样。
2006-1-23 10:06
0
雪    币: 207
活跃值: (40)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
最初由 softworm 发布
南蛮妈妈到底是谁的马甲?


大师兄认为南蛮妈妈是个神秘人物
2006-1-23 11:09
0
雪    币: 50
活跃值: (145)
能力值: ( LV12,RANK:290 )
在线值:
发帖
回帖
粉丝
13
还分不出来,看看
2006-1-23 14:27
0
雪    币: 184
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
感觉是xiaohui
2006-1-24 22:03
0
雪    币: 111
活跃值: (55)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
15
南蛮妈妈喧宾夺主了
目的达到了,恩恩~
2006-2-5 09:34
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
都是厉害的角色,那个南蛮妈妈有看他的文章不过认识是谁
2006-2-6 08:42
0
雪    币: 250
活跃值: (103)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
17
好,顶!
2006-2-7 20:50
0
雪    币: 238
活跃值: (326)
能力值: ( LV12,RANK:450 )
在线值:
发帖
回帖
粉丝
18
IDA 的 IsCode, FindCode 对付花指令,垃圾代码和OD的反汇编其实都一样,根本就没有任何办法,这也不能怪 IDA 无能,IDA 和 OD 和现在所有的反汇编所使用的方法都是根据从前往后,见到代码就硬翻译成汇编助记符,我总在想,为什么 CPU 却从不会受这些花指令的影响,总是能正确的执行,其实道理很简单就是所谓的"顺藤摸瓜",所以有时间想尝试修改OD,让反汇编过程沿CPU执行的路径来进行,当然这可能是梦想.也可能永远都没有时间.
2006-2-8 17:55
0
雪    币: 223
活跃值: (70)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
19
嘿嘿,好象是*哥
2006-2-9 09:35
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
20
看后一头雾水,学习中。。。
2006-2-9 10:08
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
21
请教一下,Themida(使用code replace加密部分代码)的程式有人可以破解出来吗?,完全解密,估计国内没有多少个能做到~
2006-2-10 09:34
0
游客
登录 | 注册 方可回帖
返回
//