【文章标题】: 菜鸟手脱FSG2.0并修复导入表笔记
【文章作者】: firefly
【软件名称】: FSG加壳记事本
【下载地址】: 看雪工具下载
【加壳方式】: FSG2.0
【软件介绍】: winxp sp2,OllyICE,ODBGScript1.62
【作者声明】: 菜鸟脱壳学习笔记,失误之处烦请大家指正。
--------------------------------------------------------------------------------
【详细过程】
  首先用FSG2.0将记事本加壳,然后用OD载入加壳的记事本, 如下所示:

代码:
  01000154 >  8725 6CF40101   xchg    dword ptr [101F46C], esp
  0100015A    61              popad
  0100015B    94              xchg    eax, esp
  0100015C    55              push    ebp
  0100015D    A4              movs    byte ptr es:[edi], byte ptr [esi]
  0100015E    B6 80           mov     dh, 80
  01000160    FF13            call    dword ptr [ebx]
  01000162  ^ 73 F9           jnb     short 0100015D
  01000164    33C9            xor     ecx, ecx
  01000166    FF13            call    dword ptr [ebx]
  01000168    73 16           jnb     short 01000180
  0100016A    33C0            xor     eax, eax
  0100016C    FF13            call    dword ptr [ebx]
  0100016E    73 1F           jnb     short 0100018F
  01000170    B6 80           mov     dh, 80
  01000172    41              inc     ecx
  01000173    B0 10           mov     al, 10
  01000175    FF13            call    dword ptr [ebx]
  01000177    12C0            adc     al, al
  01000179  ^ 73 FA           jnb     short 01000175
  0100017B    75 3A           jnz     short 010001B7
  0100017D    AA              stos    byte ptr es:[edi]
  0100017E  ^ EB E0           jmp     short 01000160
  01000180    FF53 08         call    dword ptr [ebx+8]
  01000183    02F6            add     dh, dh
  01000185    83D9 01         sbb     ecx, 1
  01000188    75 0E           jnz     short 01000198
  0100018A    FF53 04         call    dword ptr [ebx+4]
  0100018D    EB 24           jmp     short 010001B3
  0100018F    AC              lods    byte ptr [esi]
  01000190    D1E8            shr     eax, 1
  01000192    74 2D           je      short 010001C1
  01000194    13C9            adc     ecx, ecx
  01000196    EB 18           jmp     short 010001B0
  01000198    91              xchg    eax, ecx
  01000199    48              dec     eax
  0100019A    C1E0 08         shl     eax, 8
  0100019D    AC              lods    byte ptr [esi]
  0100019E    FF53 04         call    dword ptr [ebx+4]
  010001A1    3B43 F8         cmp     eax, dword ptr [ebx-8]
  010001A4    73 0A           jnb     short 010001B0
  010001A6    80FC 05         cmp     ah, 5
  010001A9    73 06           jnb     short 010001B1
  010001AB    83F8 7F         cmp     eax, 7F
  010001AE    77 02           ja      short 010001B2
  010001B0    41              inc     ecx
  010001B1    41              inc     ecx
  010001B2    95              xchg    eax, ebp
  010001B3    8BC5            mov     eax, ebp
  010001B5    B6 00           mov     dh, 0
  010001B7    56              push    esi
  010001B8    8BF7            mov     esi, edi
  010001BA    2BF0            sub     esi, eax
  010001BC    F3:A4           rep     movs byte ptr es:[edi], byte ptr [esi]
  010001BE    5E              pop     esi
  010001BF  ^ EB 9F           jmp     short 01000160
  010001C1    5E              pop     esi
  ; 此处循环处理导入表
  010001C2    AD              lods    dword ptr [esi]
  010001C3    97              xchg    eax, edi
  010001C4    AD              lods    dword ptr [esi]
  010001C5    50              push    eax
  010001C6    FF53 10         call    dword ptr [ebx+10]         ; kernel32.LoadLibraryA
  010001C9    95              xchg    eax, ebp
  010001CA    8B07            mov     eax, dword ptr [edi]
  010001CC    40              inc     eax
  010001CD  ^ 78 F3           js      short 010001C2
  010001CF    75 03           jnz     short 010001D4
  ; 这里跳到OEP
  010001D1    FF63 0C         jmp     dword ptr [ebx+C] 
  010001D4    50              push    eax
  010001D5    55              push    ebp
  010001D6    FF53 14         call    dword ptr [ebx+14]         ; kernel32.GetProcAddress
  010001D9    AB              stos    dword ptr es:[edi]
  010001DA  ^ EB EE           jmp     short 010001CA
  
  用F8大概的走一哈,走到010001C6处可以看到这里调用LoadLibraryA,接下来又
  调用GetProcAddress,并把地址保存,跟两边可以发现这里其实是一个循环,大
  致可以确定这里是处理导入表的。观察这里的这个循环,可以看到
  010001D1    FF63 0C         jmp     dword ptr [ebx+C]
  是跳出该循环的,我们在这里下断,F9运行,果然中断在010001D1,可开心了:P
  再F8一哈就到0100739D这里,多么熟悉的OEP啊,dump之,光偷着乐了。
  
代码:
  0100739D   .  6A 70         push    70
  0100739F   .  68 98180001   push    01001898
  010073A4   .  E8 BF010000   call    01007568
  010073A9   .  33DB          xor     ebx, ebx
  010073AB   .  53            push    ebx                           ; /pModule => NULL
  010073AC   .  8B3D CC100001 mov     edi, dword ptr [10010CC]      ; |kernel32.GetModuleHandleA
  010073B2   .  FFD7          call    edi                           ; \GetModuleHandleA
  010073B4   .  66:8138 4D5A  cmp     word ptr [eax], 5A4D
  010073B9   .  75 1F         jnz     short 010073DA
  010073BB   .  8B48 3C       mov     ecx, dword ptr [eax+3C]
  010073BE   .  03C8          add     ecx, eax
  010073C0   .  8139 50450000 cmp     dword ptr [ecx], 4550
  010073C6   .  75 12         jnz     short 010073DA
  
  很不幸,我dump后,发现程序不能运行,这不是扯淡吗,这么个软柿子被捏了,居然
  最后还摆一道。没办法。因为程序运行提示xxxx函数不能xxxx,就怀疑是导入表出了
  问题。咋办,导入表我不专业啊,只好硬着头皮上了。谁让壳是咱加的,把原始的记
  事本拿出来,看看导入表与加壳的有啥不同。这里我费了半天工夫,才发现,原来
  FSG把导入表中的作为结束的00000000替换成了FFFFFF7F或者FFFFFFFF,只要重新改写
  回来就OK了。由于记事本导入了多个函数,密密麻麻的一片,很不好搞,所以我就琢
  磨着写了一个脚本,刚学的写脚本,可能有些地方写的不合理,还烦请大家指正。
  
代码:
  /*****************************************\
   *   FSG 2.0 IAT Fix Script by firefly   *
   *                                       *
  \*****************************************/
    VAR iat_addr
    VAR iat_size
    VAR con
    VAR i
    mov i, 0
  
    ASK "Please Input the IAT Address"
    mov iat_addr, $RESULT
  
      
    ASK "Please Input the IAT Size"
    mov iat_size, $RESULT
  
  REP:
    mov con, [iat_addr], 3
    cmp con, 0FFFFFF
    jne Next
    fill iat_addr, 4, 0
  Next:
    add i, 4
    cmp i, iat_size
    add iat_addr, 4
    jbe REP
  
    MSG ":) Now you can dump it!"
  
 运行脚本需要输入导入表的起始地址还有大小,脚本将遍历导入表替换FFFFFFFF和FFFFFF7F。
  另外这里再总结一哈如何找到导入表,随便找一个函数调用,如
代码:
  010073AB   .  53            push    ebx                           ; /pModule => NULL
  010073AC   .  8B3D CC100001 mov     edi, dword ptr [10010CC]      ; |kernel32.GetModuleHandleA
  010073B2   .  FFD7          call    edi                           ; \GetModuleHandleA
  可以看到010073AC处将10010CC内存中的地址赋值给edi,然后call edi就调用了GetModuleHandleA,
  那10010CC处一定位于导入表中,上下翻一下,刚好,记事本的导入表位于一个段的开始,从01001000开始,
  最后找到有8个字节0的地方,就是导入表结束,在OD中用鼠标选一哈,就可以知道其大小为0x350,如下所示。
  
代码:
  C8 6F DA 77 F0 6B DA 77 7D 8F DC 77 FD D5 DC 77 83 78 DA 77 1B 76 DA 77 CC D7 DA 77 FF FF FF 7F
  60 D2 18 77 FF FF FF 7F B1 DD F0 77 FF 3E F2 77 41 E0 F0 77 6F 6E EF 77 16 F1 F0 77 AD 7F EF 77
  61 BE EF 77 1F 40 F2 77 97 9A EF 77 BC 7E EF 77 8F 4B F2 77 00 F5 F1 77 D1 61 EF 77 6F 83 EF 77
  7A 5A EF 77 69 99 EF 77 0A 6C EF 77 C9 7D EF 77 EB 5E EF 77 EF D4 EF 77 03 3B F0 77 AC 3B F0 77
  EA 99 EF 77 80 5B EF 77 FF FF FF 7F 28 97 80 7C 9C 92 80 7C 27 A4 80 7C D4 A7 80 7C 10 9F 80 7C
  75 37 83 7C D3 3F 83 7C 19 FF 80 7C 82 FE 80 7C 6D 0C 81 7C 8E 93 80 7C E5 17 80 7C 16 1E 80 7C
  F5 DD 80 7C 7D 46 84 7C 77 1D 80 7C A1 B6 80 7C EE 1E 80 7C 2F FC 80 7C 62 15 81 7C 2F 99 80 7C
  8D 99 80 7C 09 9A 80 7C B1 2E 83 7C 5E A3 80 7C 1D 2E 83 7C 46 96 87 7C 47 9B 80 7C 64 BA 80 7C
  0E 18 80 7C 60 07 81 7C 96 A9 80 7C 20 99 80 7C A0 AD 80 7C 83 6F 81 7C 32 0F 81 7C D7 ED 80 7C
  E1 EE 80 7C 4C B7 80 7C CC A9 80 7C C6 97 80 7C EF B9 80 7C BC 25 83 7C 31 03 93 7C 87 0D 81 7C
  40 03 93 7C D4 A0 80 7C 27 09 83 7C 8F 4B 83 7C 70 30 81 7C 44 20 83 7C 31 1F 83 7C 15 99 80 7C
  74 B9 80 7C F8 9B 80 7C 05 B9 80 7C 2A 2E 86 7C FF FF FF 7F E0 70 64 7D 12 07 5E 7D AE AF 5F 7D
  3B 24 63 7D FF FF FF 7F AE B6 D1 77 58 BF D1 77 9D 86 D1 77 C7 86 D1 77 5F 55 D2 77 85 3E D2 77
  1E C2 D1 77 3C B3 D1 77 EA DA D1 77 3B 1F D3 77 A4 D8 D1 77 4B BE D1 77 27 BE D1 77 87 03 D3 77
  D2 90 D1 77 36 9E D1 77 E0 12 D2 77 70 DB D1 77 7F AF D1 77 FE 2C D2 77 69 9D D1 77 4C D8 D2 77
  25 FC D1 77 D5 EE D1 77 F0 BE D1 77 94 08 D2 77 36 BC D1 77 D1 E1 D2 77 34 AF D1 77 F9 D7 D1 77
  10 F7 D2 77 9A DB D1 77 9B 92 D1 77 71 BE D1 77 7F DD D1 77 4F 7D D2 77 B6 CD D1 77 9C 8F D1 77
  EC DB D1 77 F5 B5 D1 77 A4 19 D6 77 69 D8 D1 77 D5 86 D2 77 C8 BD D1 77 76 BD D1 77 92 52 D2 77
  BA B8 D1 77 FE DA D1 77 7D 1A D3 77 25 02 D3 77 27 F1 D2 77 37 02 D3 77 8F 8F D2 77 87 F7 D1 77
  8C 0C D2 77 7A 14 D3 77 0A 63 D6 77 2B D6 D1 77 A6 88 D1 77 CE 3D D2 77 60 DA D1 77 32 52 D2 77
  B6 A9 D1 77 65 3D D2 77 C9 59 D2 77 2F B7 D1 77 6C 18 D3 77 01 8A D1 77 F6 8B D1 77 1E 94 D1 77
  C2 D8 D2 77 CB 8C D1 77 C6 91 D1 77 B7 17 D3 77 FF FF FF FF 90 60 F7 72 90 53 F7 72 49 57 F7 72
  FF FF FF 7F D6 48 34 76 96 86 33 76 29 9D 34 76 A9 C4 33 76 86 19 32 76 65 7C 33 76 CA 86 33 76
  CE 00 33 76 F3 7C 33 76 FF FF FF 7F AE 2D C0 77 9A 9E C0 77 CE 9E C0 77 A3 AE C1 77 3D AB C1 77
  B6 9E C0 77 36 D0 BE 77 94 5C C0 77 77 CE BE 77 2F 80 C1 77 0C FB C0 77 7E 9E C0 77 AC 17 C3 77
  EB EE BE 77 67 9D C0 77 75 D6 C1 77 D8 23 C3 77 A4 F1 BE 77 DB F1 BE 77 7C 53 C0 77 2F EE C1 77
  6B 80 C1 77 FF FF FF 7F 00 00 00 00 00 00 00 00
  
  
  
--------------------------------------------------------------------------------
【经验总结】
  貌似对于一般的壳主要需要找到OEP,并且稍微处理一哈导入表,往了再哪看到的,一般的壳再处理完导入表时就会跳到OEP
  。而一般的壳处理导入表都离不开LoadLibraryAGetProcAddress两个函数。所以,在脱壳的时候时刻注意这两个函数。
  
--------------------------------------------------------------------------------

                                                       2008年01月30日 15:57:41