飘云阁

 找回密码
 加入我们

QQ登录

只需一步,快速开始

查看: 11633|回复: 4

[求助] FSG v1.10 (Eng) -> dulek/xt] [Overlay] *壳 求脱壳方法

[复制链接]

该用户从未签到

发表于 2015-4-12 22:24:06 | 显示全部楼层 |阅读模式
求指导方法,自己尝试用通用的脱壳方法脱,脱不出来,网上这种壳的资料也少,找不到相关的方法。
PYG19周年生日快乐!
  • TA的每日心情
    开心
    2018-9-27 19:17
  • 签到天数: 31 天

    [LV.5]常住居民I

    发表于 2015-4-12 23:48:53 | 显示全部楼层
    本帖最后由 lucky_789 于 2015-4-12 23:50 编辑

    几年前分析过一个FSG2.0的壳,碰巧笔记还在,给你参考一下吧,1.1应该不会比2.0复杂。


    【软件】加了FSG 2.0 -> bart/xt壳的win98记事本程序,由天草老师教程中提供。
    【工具】OD、PEiD
    【声明】未经本人同意,本文谢绝转载。

    PEiD查看,是FSG 2.0 -> bart/xt,用OD载入。在开始分析之前,先了解一下该壳的概貌,在OD的数据窗口中看一下头部信息:

    00400000  4D 5A 00 00 | 00 00 00 00 | 00 00 00 00 | 50 45 00 00  MZ..........PE..
    00400010  4C 01 02 00 | 46 53 47 21 | 00 00 00 00 | 00 00 00 00  L.FSG!........
    00400020  E0 00 0F 01 | 0B 01 00 00 | 00 40 00 00 | 00 70 00 00  ? ...@...p..
    00400030  00 00 00 00 | 54 01 00 00 | 00 10 00 00 | 0C 00 00 00  ....T.........
    00400040  00 00 40 00 | 00 10 00 00 | 00 02 00 00 | 04 00 00 00  ..@..........
    00400050  00 00 00 00 | 04 00 00 00 | 00 00 00 00 | 00 50 01 00  ............P.
    00400060  00 02 00 00 | 00 00 00 00 | 02 00 00 00 | 00 00 10 00  .............
    00400070  00 10 00 00 | 00 00 10 00 | 00 10 00 00 | 00 00 00 00  .............
    00400080  10 00 00 00 | 00 00 00 00 | 00 00 00 00 | A8 44 01 00  ...........―.
    00400090  84 00 00 00 | 00 E0 00 00 | 90 33 00 00 | 00 00 00 00  ?...?.?......
    。。。

    我们可以看到:
    1、这个压缩壳真是“压缩到了牙齿”:
    其一,DOS头部被挤占,只剩下e_magic等前6个成员以及e_lfanew共16个字节。
    其二,PE头被移到了0040000C处。(这样,PE头的BaseOfData成员--数据区段起始RVA--就与e_lfanew相重叠了,有影响吗?我们看到区段表表明只有2个区段,名称都被抹去了,再看看内存窗口,原来是代码段和资源(输入表)两个区段,并没有数据段,所以不会影响。)
    其三,DOS头、PE头、区段表总大小被压缩为200h(512)字节,而程序入口点RVA为0000154,即壳的引导部分被插入到了文件头部区段表末尾的空白区,几乎没浪费一个字节,呵呵。
    2、PE头的文件创建日期和时间字段被填充了壳标志“FSG!”。
    3、输入表首地址RVA=000144A8,去004144A8看看,发现输入表只有一个IID,OriginalFirstThunk和FirstThunk都指向00414500,只有两个函数,即kernel32.LoadLibraryA和kernel32.GetProcAddress,紧随其后的是这两个函数的名称。

    好了,大致了解了这些,正式开始分析。


    00400154 F>  8725 EC444100   xchg dword ptr [4144EC],esp                 ; ds:[004144EC]处是加壳时存放的是指向8个预设值的指针
    0040015A     61              popad                                       ; 用pop方式给8个寄存器传递预设值(但esp是不受预设值的影响)
    0040015B     94              xchg eax,esp                                ; 恢复堆栈。eax中是正常程序入口时esp的值

    下面开始解压代码:
    0040015C     55              push ebp
    0040015D     A4              movs byte ptr es:[edi],byte ptr [esi]       ; ds:[esi]=[00411390]=00,es:[edi]=[00401000]=00
    0040015E     B6 80           mov dh,80
    00400160     FF13            call dword ptr [ebx]
    00400162   ^ 73 F9           jnb short FSG_2_0.0040015D
    00400164     33C9            xor ecx,ecx
    00400166     FF13            call dword ptr [ebx]
    00400168     73 16           jnb short FSG_2_0.00400180
    0040016A     33C0            xor eax,eax
    0040016C     FF13            call dword ptr [ebx]
    0040016E     73 1F           jnb short FSG_2_0.0040018F
    00400170     B6 80           mov dh,80
    00400172     41              inc ecx
    00400173     B0 10           mov al,10
    00400175     FF13            call dword ptr [ebx]
    00400177     12C0            adc al,al
    00400179   ^ 73 FA           jnb short FSG_2_0.00400175
    0040017B     75 3A           jnz short FSG_2_0.004001B7
    0040017D     AA              stos byte ptr es:[edi]
    0040017E   ^ EB E0           jmp short FSG_2_0.00400160
    00400180     FF53 08         call dword ptr [ebx+8]
    00400183     02F6            add dh,dh
    00400185     83D9 01         sbb ecx,1
    00400188     75 0E           jnz short FSG_2_0.00400198
    0040018A     FF53 04         call dword ptr [ebx+4]
    0040018D     EB 24           jmp short FSG_2_0.004001B3
    0040018F     AC              lods byte ptr [esi]
    00400190     D1E8            shr eax,1
    00400192     74 2D           je short FSG_2_0.004001C1
    00400194     13C9            adc ecx,ecx
    00400196     EB 18           jmp short FSG_2_0.004001B0
    00400198     91              xchg eax,ecx
    00400199     48              dec eax
    0040019A     C1E0 08         shl eax,8
    0040019D     AC              lods byte ptr [esi]
    0040019E     FF53 04         call dword ptr [ebx+4]
    004001A1     3B43 F8         cmp eax,dword ptr [ebx-8]
    004001A4     73 0A           jnb short FSG_2_0.004001B0
    004001A6     80FC 05         cmp ah,5
    004001A9     73 06           jnb short FSG_2_0.004001B1
    004001AB     83F8 7F         cmp eax,7F
    004001AE     77 02           ja short FSG_2_0.004001B2
    004001B0     41              inc ecx
    004001B1     41              inc ecx
    004001B2     95              xchg eax,ebp
    004001B3     8BC5            mov eax,ebp
    004001B5     B6 00           mov dh,0
    004001B7     56              push esi
    004001B8     8BF7            mov esi,edi
    004001BA     2BF0            sub esi,eax
    004001BC     F3:A4           rep movs byte ptr es:[edi],byte ptr [esi]
    004001BE     5E              pop esi
    004001BF   ^ EB 9F           jmp short FSG_2_0.00400160                  ; 循环
    至此解压完毕。

    下面开始填充IAT:
    004001C1     5E              pop esi                                     ; 堆栈 [0012FFC0]=00406000,这里是加壳时保存的一张表,内容是输入表涉及的所有dll库名称及各dll对应的IAT指针。
    004001C2   / AD              lods dword ptr [esi]                        ; 取IAT首地址
    004001C3   | 97              xchg eax,edi                                ; IAT首地址->edi
    004001C4   | AD              lods dword ptr [esi]                        ; 取dll库名称
    004001C5   | 50              push eax                                    ; /dll库名称(如ASCII "SHELL32.dll")
    004001C6   | FF53 10         call dword ptr [ebx+10]                     ; \kernel32.LoadLibraryA
    004001C9   | 95              xchg eax,ebp                                ; dll库句柄->ebp
    004001CA   |/8B07            mov eax,dword ptr [edi]                     ; /取函数名地址
    004001CC   ||40              inc eax                                     ; |函数名地址(如ASCII "DragFinish")
    004001CD   \|78 F3           js short FSG_2_0.004001C2                   ; |FSG壳在这里做了小动作,正常情况下不同dll的IAT之间是用00000000分隔,而我们从数据窗口可以看到,[edi]处是用7FFFFFFF来分隔的,最后一个dll的IAT末尾是FFFFFFFF,许多朋友脱壳后不能运行,原因就在这里!当[edi]处是7FFFFFFF时表示还有dll的函数没处理完,在这里跳去处理下一个dll的函数。
    004001CF    |75 03           jnz short FSG_2_0.004001D4                  ; |是结束标志(FFFFFFFF+1=0)则跳出循环,否则就是函数名地址,需要继续填充。
    004001D1    |FF63 0C         jmp dword ptr [ebx+C]                       ; |全部填充完毕,则到这里跳往OEP
    004001D4    |50              push eax                                    ; |/参数2:函数名。ASCII "DragFinish"
    004001D5    |55              push ebp                                    ; ||参数1:动态库句柄
    004001D6    |FF53 14         call dword ptr [ebx+14]                     ; |\kernel32.GetProcAddress
    004001D9    |AB              stos dword ptr es:[edi]                     ; |填充IAT
    004001DA   ^\EB EE           jmp short FSG_2_0.004001CA                  ; \循环处理下一个函数
    004001DC     33C9            xor ecx,ecx                                 ; 这里是前面解压子函数[ebx+4]的入口。不用管
    004001DE     41              inc ecx                                     ; 这里是前面解压子函数[ebx+8]的入口。不用管
    004001DF     FF13            call dword ptr [ebx]
    004001E1     13C9            adc ecx,ecx
    004001E3     FF13            call dword ptr [ebx]
    004001E5   ^ 72 F8           jb short FSG_2_0.004001DF
    004001E7     C3              retn

    004010CC     55              push ebp                                    ; 这里就是OEP
    004010CD     8BEC            mov ebp,esp
    004010CF     83EC 44         sub esp,44
    004010D2     56              push esi
    004010D3     FF15 E4634000   call dword ptr [4063E4]                     ; kernel32.GetCommandLineA
    004010D9     8BF0            mov esi,eax

    下面就是脱壳了。直接用OD的OllyDump插件脱壳,运行会报错,原因很简单,就是上面分析中提到的IAT分隔标志问题。解决办法也很简单,在到达OEP后,在反汇编窗口中找一个API函数,如“004010D3 call dword ptr [4063E4] ; kernel32.GetCommandLineA”,在这行右键-在数据窗口中跟随-内存地址,数据窗口中上下看看,将IAT中的所有7FFFFFFF和FFFFFFFF修改成00000000,再dump即可运行,无需ImportREC修复。


    小结:
    FSG 2.0 -> bart/xt是一个早期的压缩壳,简单的作了一点保护措施。
    一、本壳的压缩方面
    1、该壳删除了文件的DOS头,只保留了必要的16个字节,壳自解压代码全部存放文件头中。

    2、该壳将文件包含代码段在内的全部区段合并在一起,将压缩的数据放入一个新增加的段中,同时将原文件的代码、数据、资源等所有内容抽掉,连原各段的名称也在文件头中抹掉。

    3、壳代码在运行时,直接将整个压缩的数据解压到代码段中,然后填充IAT,再跳往OEP。

    二、输入表处理方面
    1、将输入表指向了一个壳中的伪输入表,伪输入表中只保留了1个IID且除NAME和FIRSTTHUNK外的其他3个成员为空,而dll名称(KERNEL32.dll)则附在了文件头中壳代码结束处,IAT只有两个函数,即kernel32.LoadLibraryA和kernel32.GetProcAddress,供壳使用。

    2、加壳时破坏了原输入表,取而代之的是一张信息表,保存的信息是IAT首地址和它对应的dll库名称指针。IAT中填充的是处理过的函数名地址,壳在运行时,先根据信息表中的指针取出dll库名称,再LoadLibraryA调入该库,获得句柄;然后根据信息表中对应的IAT首地址,取出一个地址,该地址+1后即得到函数名,然后GetProcAddress获取函数地址,最后覆盖被篡改的IAT。

    3、该壳在给文件加壳时,就对IAT除篡改函数地址外,还将不同dll的IAT数组之间的结束标志篡改,最后一个dll的IAT末尾由FFFFFFFF替代00000000,而前面的dll的IAT之间用的是7FFFFFFF。壳在装载函数时,根据这两个数+1的结果(而不是直接根据信息表)来判断是继续填充下一IAT数组还是结束填充,如果是继续填充,则从信息表中取出dll库名称地址和IAT首地址,循环处理。为何要搞的这么麻烦?相信你已经明白了--那就是反脱壳。许多新手朋友在顺利脱掉这个壳后,程序却不能运行,软件作者要的就是这个结果,呵呵。我们的对策也很简单,上面已作了说明,就是在填充完IAT后,将那些7FFFFFFF和FFFFFFFF恢复成00000000,程序就跑起来了。

    4、该壳没有采取反调试措施,只是一个小技巧将跳往OEP的指令夹在处理IAT的循环代码中间,信奉“不往回跳”的新手朋友,往往就容易跑飞了。但壳代码除解压代码外,总共才十几行指令,也隐藏不了什么秘密,毕竟只是压缩壳。




    PYG19周年生日快乐!

    该用户从未签到

     楼主| 发表于 2015-4-13 22:30:29 | 显示全部楼层
    本帖最后由 xswolf 于 2015-4-13 22:31 编辑
    lucky_789 发表于 2015-4-12 23:48
    几年前分析过一个FSG2.0的壳,碰巧笔记还在,给你参考一下吧,1.1应该不会比2.0复杂。

    谢谢了,不过看了你发的资料,跟你那分析的过程差别太大了。没头绪。这个是原文件你分析看看,这种应该要怎么入手好。不是求破的,自己学习的 下载地址 奇易QQ6.67版        http://pan.baidu.com/s/1i35Wkdf

    点评

    有木马呀,杀毒软件报木马  详情 回复 发表于 2015-6-16 21:37
    PYG19周年生日快乐!

    该用户从未签到

    发表于 2015-6-16 21:37:48 | 显示全部楼层
    xswolf 发表于 2015-4-13 22:30
    谢谢了,不过看了你发的资料,跟你那分析的过程差别太大了。没头绪。这个是原文件你分析看看,这种应该要 ...

    有木马呀,杀毒软件报木马
    PYG19周年生日快乐!
    您需要登录后才可以回帖 登录 | 加入我们

    本版积分规则

    快速回复 返回顶部 返回列表