• 免杀之脱壳笔记


    周笔记整理——脱壳

    什么是壳?

    壳是一种软件加密保护软件,它能够保护软件不被非法修改或编译的程序。

    壳载入的过程

    1、保存入口参数

    保证外壳程序执行完后,能够跳转到正确执行的入口。

    2、获取壳本身需要使用的API地址

    3、解密源程序各个区块的数据

    壳一般按区块加密,只有在执行时才能解密,解密完后,把区块数据按照区块的定义放在内存中合适的位置。

    4、IAT的初始化

    IAT(Import Address Table,导入地址表),用于存放调用的DLL或外部函数的实际地址

    外壳程序有一个自建的输入表,PE装载器实现对自建输入表的填写。

    5、重定位项的处理

    为保证DLL每次运行都提供相同的基址,需要重定位的代码,这些代码存在于重定位表中。

    6、Hook API

    模仿Windows的工作流程,向输入表中填充相关的数据。

    填充Hook API代码的地址,间接获取程序的控制权。

    7、跳转到程序原入口点

    原入口点(OEP,original entry point):这是程序真正的入口点,程序加壳就是隐藏OEP。

    脱壳的步骤

    两个关键点:


    1、找到源入口点(OEP),以此分离壳和源程序

    2、从入口点进入能够让程序正常的运行

    具体步骤:


    • 寻找OEP

    • 抓取内存映像

    什么叫抓取内存映像?

    把内存指定地址的映像文件读出,用文件等形式等将其保存下来

    为什么要抓取内存映像?

    因为加壳的程序区块只有在内存中才会被解密,因此需在程序在内存执行时把必要的初始化数据保存下来。

    何时抓取内存映像?

    脱壳时需要在源程序没有运行起来之前,内存中“只有”外壳的初始化数据,这时抓取内存映像中的数据,有助于脱壳分析。

    如何抓取内存映像?

    工具:LordPE、PETools

    • 重建输入表

    什么是输入表? 前面已回答:外部调用的函数、DLL

    为啥要重建输入表?

    前面已分析(壳的加载过程):外壳程序加载时,需要初始化输入表,将外壳程序的输入表添加到源程序的输入表中,脱壳时,要将输入表恢复到为加壳的状态。

    怎么重建输入表?

    重建输入表的前提是获取输入表,需要了解输入表的结构,根据当前内存中的输入表,能够还原源程序的输入表。

    一些加密软件为了防止输入表被还原:填充虚拟地址(HOOK API的外壳代码的地址)到输入表。因此,重建输入表的关键是如何获取输入表。

    Windows加载器将PE文件映像到虚拟地址空间,建立输入表的过程如下,根据这个加载原理建立输入表(这只是个人的目前的观点,待后续补充)

    • DLL文件脱壳

    脱壳套件

    0、识壳:PEID、Exeinfo PE

    1、寻找OEP ——Ollydbg、dbg

    2、转存映像文件——LordPE、ProcDump

    3、重建DLL的输入表——ImportIAT

    4、构造重定位表——ImportIAT修复即可

    常用的手工寻找OEP的方法:

    法1:手动分析法

    1.用OD载入

    载入的时候不分析代码,有壳就会出现这个,没壳的就不会。

    2.单步向下跟踪F8

    • 遇到程序往回跳的(包括循环),在下一句代码处按F4,或右健单击代码,选择断点——运行到所选位置。

    • 绿色线条表示跳转没实现,不用理会,红色线条表示跳转已经实现。

    3.如果刚载入程序,在附近就有一个CALL,F7跟进去,这样很快就能到程序的OEP 。

    4.在跟踪过程中,如果运行到某个CALL程序就运行的,就在这个CALL中F7进入 。

    5.通常在大跳转的附近就会出现OEP。

    jmp XXXX

    je XXXXXX

    retn

    法2:ESP定律

    原理:ESP定律就是堆栈平衡原理。根据堆栈平衡原理,便可以通过内存断点,在入口点处,断在与入口点相对应的出口点处,而程序的出口点处一般就有个跳转指向OEP。

    为什么ESP定律能够找到OEP呢?

    在命令行下ESP的硬件访问断点,当ESP的数据发生变化时,就会引发中断,而ESP指向的是当前运行函数的栈顶,当进入OEP时,ESP的值必然会变化。因此,通过ESP的变化来定位OEP。

    具体操作如下:

    1.OD载入程序,F8步过,ESP变红。
    2.选中ESP红色的数据,右键-》数据窗口跟随-》选中16进制数据,下硬件断点。

    或者在命令行下断 dd [当前代码中的ESP地址]。

    3.F9运行程序,来到跳转处,按下F8,到达程序OEP,脱壳 。

    3.14内存溢出的原理](C:UsersmoheDesktop3.14内存溢出的原理.png)

    覆盖的是ESP、EIP指针,具体的是如何实现跳转的呢?

    法三: 内存跟踪

    1:用OD载入
    2:点击选项——》调试选项——》异常,把里面的忽略全部√上,CTRL+F2 重载程序。
    3:按ALT+M,打开内存镜象,找到第一个 .rsrc, 按F2下断点, 然后SHIFT+F9运行到断点,接着ALT+M, 打开内存镜象,找到RSRC上面的CODE,按 F2下断点。然后按SHIFT+F9,直接到达程序OEP,脱壳!

    why?

    ps:为什么是第一个.rsrc,资源段包含了模块的资源信息,一个程序存在多个 rsrc.? why? 不同区段的rsrc.有什么不同?

    //WINNT.H
    
    typedef struct _IMAGE_RESOURCE_DIRECTORY {	
    	ULONG Characteristics;
    	ULONG TimeDateStamp;
    	USHORT MajorVersion;
    	USHORT MinorVersion;
    	USHORT NumberOfNamedEntries;
    	USHORT NumberOfIdEntries;
    } IMAGE_RESO
    

    NumberOfNamedEntries和NumberOfIdEntries代替了指针,它们被用来表示这个目录附有多少入口,目录入口就在段数据之中的目录后边。

    img

    法4: 一步到达OEP

    这个方法建立在很熟悉各种壳的入口特点的基础上,通过Ctrl+F查找关键词,然后按下F2,F9运行到此处
    2.来到大跳转处,F8,脱壳。

    附上常见的壳的入口特点

    此段整理笔记来自http://blog.sina.com.cn/s/blog_414cc36d0100lde4.html

    6种常见压缩壳:

    UPX 0.89.6 - 1.02 / 1.05 - 1.24 (Delphi) stub -> Markus & Laszlo
    ASPack 2.12 -> Alexey Solodovnikov
    堀北压缩(KByS)0.28主程序脱壳
    PECompact 2.x -> Jeremy Collake
    PEncrypt 3.1 Final -> junkcodeeuk
    北斗壳 Nspack3.7

    1、UPX 0.89.6 - 1.02 / 1.05 - 1.24 (Delphi) stub -> Markus & Laszlo

    006055B0 >  60            pushad
    006055B1    BE 00605400       mov esi,STV.00546000           ; 这里使用ESP定律(具体操作见法2)
    006055B6    8DBE 00B0EBFF     lea edi,dword ptr ds:[esi+FFEBB000>
    006055BC    C787 C4201600 135F>mov dword ptr ds:[edi+1620C4],705D>
    006055C6    57            push edi
    006055C7    83CD FF          or ebp,FFFFFFFF
    006055CA    EB 0E           jmp short STV.006055DA
    ......		..............         ................
    00605727  ^E9 28CFF5FF       jmp STV.00562654             ;F8一次 直接到达OEP
    0060572C    44            inc esp
    0060572D    57            push edi
    
    

    2、ASPack 2.12 -> Alexey Solodovnikov

    0044B001 >  60          PUSHAD                        ; OD载入停在这里
    0044B002    E8 03000000    CALL acerip.0044B00A               ; ESP定律						
    0044B3B0   /75 08         JNZ SHORT acerip.0044B3BA           ;ESP后 OD停到这里, F8一次
    0044B3B2   |B8 01000000    MOV EAX,1
    0044B3B7   |C2 0C00        RETN 0C
    0044B3BA   68 BC1F4000    PUSH acerip.00401FBC
    0044B3BF    C3          RETN                         ; RETN之后 就跳到OEP
    

    3、堀北压缩(KByS)0.28主程序脱壳

    00401000 >/$  68 71EA4A00   PUSH 堀北压缩.004AEA71                ;  OD载入停到这里~
    00401005  |.  E8 01000000   CALL 堀北压缩.0040100B                ;  这里ESP定律
    
    F9 OD停到这里
    004AEA71    B8 83EA0A00    MOV EAX,0AEA83                   ; ESP停到这里
    004AEA76    BA 00004000    MOV EDX,堀北压缩.00400000
    004AEA7B   03C2          ADD EAX,EDX
    004AEA7D   FFE0          JMP EAX
    004AEA7F    B1 15         MOV CL,15
    004AEA81   0000          ADD BYTE PTR DS:[EAX],AL
    004AEA83    60          PUSHAD
    004AEA84    E8 00000000    CALL 堀北压缩.004AEA89                ; F9一次到这里
    
    F9后 循环返回到这里
    00401005  |.  E8 01000000   CALL 堀北压缩.0040100B                
    
    下面继续F9运行 (大约)15次时 OD有一次明显的时间间隔 然后停到这里
    
    00432A71    B8 E5A70000    MOV EAX,0A7E5            ;停到这里
    00432A76    BA 00004000    MOV EDX,堀北压缩.00400000
    00432A7B   03C2          ADD EAX,EDX
    00432A7D   FFE0          JMP EAX               ;到这里F7进
    00432A7F    B1 15         MOV CL,15
    00432A81   0000          ADD BYTE PTR DS:[EAX],AL
    00432A83    60          PUSHAD
    00432A84    E8 00000000    CALL 堀北压缩.00432A89
    
    进入后 (Ctrl+A 我这的OD需要分析下代码 )这里就是OEP
    0040A7E5  /.  55         PUSH EBP                 ;OEP
    0040A7E6  |.  8BEC       MOV EBP,ESP
    0040A7E8  |.  6A FF        PUSH -1
    0040A7EA  |.  68 C0F54000   PUSH 堀北压缩.0040F5C0
    0040A7EF  |.  68 00BC4000   PUSH 堀北压缩.0040BC00                ;  SE 处理程序安装
    0040A7F4  |.  64:A1 0000000>MOV EAX,DWORD PTR FS:[0]
    

    4、PECompact 2.x -> Jeremy Collake

    005B8B60 >  B8 94426000    MOV EAX,MeteorNe.00604294           ; OD载入后停到这里
    005B8B65    50          PUSH EAX
    005B8B66    64:FF35 0000000>PUSH DWORD PTR FS:[0]
    005B8B6D    64:8925 0000000>MOV DWORD PTR FS:[0],ESP            ; 这里使用ESP定律
    
    006042C3    83C4 04        ADD ESP,4   
    006042C6    55          PUSH EBP
    006042C7    53          PUSH EBX
    006042C8    51          PUSH ECX
    006042C9    57          PUSH EDI
    006042CA    56          PUSH ESI
    006042CB    52          PUSH EDX
    …………中间代码省略
    00604350    5A          POP EDX
    00604351    5E          POP ESI
    00604352    5F          POP EDI
    00604353    59          POP ECX
    00604354    5B          POP EBX
    00604355    5D          POP EBP
    00604356   FFE0          JMP EAX         //跳向OEP
    

    5、PEncrypt 3.1 Final -> junkcodeeuk

    004E3600 > $  B8 00E05500   MOV EAX,MediaFix.0055E000  ;OD停到这里 F8单步一次
    004E3605  .  FFD0       CALL EAX                       ;F7跟进此Call
    004E3607     2C         DB 2C                          ;CHAR ‘,’
    ……
    F7跟进CALL:
    0055E000   /E9 25010000    JMP MediaFix.0055E12A        //这里的跳转是实现的 F8一次即可
    0055E005   |57          PUSH EDI
    0055E006  |65:6E        OUTS DX,BYTE PTR ES:[EDI]           ; I/O 命令
    ……
    F8一次后停到这里:
    0055E12A    58          POP EAX                       ; 在该代码下方找到第一个retn语句 并下断
    0055E12B    E8 16030000    CALL MediaFix.0055E446
    0055E130    48          DEC EAX
    ……中间无用代码省去
    0055E2A7   F3:A4         REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[>
    0055E2A9    59          POP ECX
    0055E2AA    5F          POP EDI
    0055E2AB    5E          POP ESI
    0055E2AC    C3          RETN                       //这就是第一个retn语句,下断,运行停在这里。F8一次 即可通往OEP
    
    
    004E3600 > $  55         PUSH EBP                       ;   OEP
    004E3601  .  8BEC       MOV EBP,ESP
    004E3603  .  83C4 F0      ADD ESP,-10
    004E3606  .  53         PUSH EBX
    004E3607  .  B8 F0324E00   MOV EAX,MediaFix.004E32F0
    004E360C  .  E8 8737F2FF   CALL MediaFix.00406D98
    

    6、北斗壳 Nspack3.7

    
    0057A867 >  9C          PUSHFD                        ; OD载入后停到这里
    0057A868    60          PUSHAD                        ; 我们在这里ESP定律即可
    0057A869    E8 00000000    CALL 流星Nisy.0057A86E
    
    0057AAD9  - E9 5AF5F8FF    JMP 流星Nisy.0050A038               ; ESP定律后到这里 F8一次到OEP
    0057AADE    8BB5 A1F9FFFF   MOV ESI,DWORD PTR SS:[EBP-65F]
    0057AAE4   0BF6          OR ESI,ESI
    0057AAE6    0F84 97000000   JE 流星Nisy.0057AB83
    
    0050A038     55         DB 55                         ;  CHAR ‘U’//这里Ctrl+A分析一下就可以把入口点一些特征字符串分析出来
    0050A039     8B         DB 8B
    0050A03A     EC         DB EC
    0050A03B     83         DB 83
    0050A03C     C4         DB C4
    0050A03D     EC         DB EC
    0050A03E     53         DB 53                         ;  CHAR ‘S’
    
    Ctrl+A分析后的代码:
    0050A038  .  55         PUSH EBP
    0050A039  .  8BEC       MOV EBP,ESP
    0050A03B  .  83C4 EC      ADD ESP,-14
    0050A03E  .  53         PUSH EBX
    0050A03F  .  56         PUSH ESI
    
  • 相关阅读:
    ES6的模块化历史
    javaee笔记之web.xml文件内的标签到底什么意思
    iTOP4412设备驱动学习五--地址和存储的概念
    iTOP4412设备驱动学习四--嵌入式硬件研发流程PCB和原理图的查看
    iTOP4412设备驱动学习三--设备节点的生成和调用:杂项设备驱动的注册和调用
    iTOP4412设备驱动学习二--在module中注册设备
    iTOP4412设备驱动学习一--设备和驱动的注册
    Linux下阅读源代码工具安装
    结构体
    综合实例:个人银行账户管理程序
  • 原文地址:https://www.cnblogs.com/Erma/p/12499376.html
Copyright © 2020-2023  润新知