zoukankan      html  css  js  c++  java
  • 逆向脱壳——基本知识

    基本知识

    加壳程序

    • 1、壳是什么?
    • 加壳是可执行程序资源压缩,是保护文件的常用手段。加壳过的程序可以直接运行,但是不能查看源代码,要经过脱壳才可以查看源代码。
    • 2、加壳的原理是什么?壳是怎么运作的?
    • 加壳是利用特殊的算法,对EXE、DLL文件里的资源进行压缩、加密。类似WINZIP 的效果,只不过这个压缩之后的文件,可以独立运行,解压过程完全隐蔽,都在内存中完成。它们附加在原程序上通过Windows加载器载入内存后,先于原始程序执行,得到控制权,执行过程中对原始程序进行解密、还原,还原完成后再把控制权交还给原始程序,执行原来的代码部分。加上外壳后,原始程序代码在磁盘文件中一般是以加密后的形式存在的,只在执行时在内存中还原,这样就可以比较有效地防止破解者对程序文件的非法修改,同时也可以防止程序被静态反编译。
    • 简单来说,壳可以完成代码的压缩和实时解压执行,加壳程序可以正常执行,但是看不到原来的代码,反编译的时候看不懂。
    • 3、壳的分类
    • 壳的类型通常分为压缩壳和加密壳两类。
    • 压缩壳的特点是减小软件体积大小,加密保护不是重点。
    • 加密壳种类比较多,不同的壳侧重点不同,一些壳单纯保护程序,另一些壳提供额外的功能,如提供注册机制、使用次数、时间限制等。

    脱壳

    • 1、对特定的壳可以用专门的脱壳软件进行脱壳。
    • 2、也可以手动脱壳

    OD

    反汇编工具OD=OllyDebug,OllyDbg 是一种具有可视化界面的 32 位汇编-分析调试器。它的特别之处在于可以在没有源代码时解决问题,并且可以处理其它编译器无法解决的难题。

    手动脱壳的基本思路

    • 1、用软件查壳,可用PEID或者ExeinfoPE查壳。
    • 2、用进行OD动态反汇编,找到程序真正的入口。
    • 3、用OD插件或者loadPE脱壳。

    OEP

    • OEP:(Original Entry Point),程序的入口点。软件加壳一般隐藏了程序真实的OEP(或者用了假的OEP), 我们需要寻找程序真正的OEP,才可以完成脱壳。
      一般加壳程序在使用Ollydbg等动态调试工具时,会停在壳的预处理块。即处在对于程序原始代码块的解压或解密操作之前,在运行完程序自脱壳模块后,会停留在程序加壳之前的OEP位置,此时是dump程序的最佳时期。脱壳时在真实OEP处下int3断点,就可以捕捉到程序代码段完全恢复的状态。因此,寻找加壳程序的正确OEP,也成了手动脱壳时的第一要务。

    OPE的基本特征

    VC6

    • 区段特征

    • 入口特征

    • EBP为基指针(Base Pointer)寄存器,用它可直接存取堆栈中的数据;

    • ESP为堆栈指针(Stack Pointer)寄存器,用它只可访问栈顶。

    • push ebp;保存ebp内容以便调用完后恢复;此时esp <- esp - 4

    • mov ebp esp; 保存调用前栈顶地址以便调用完后恢复,用ebp来保存当前esp。

    VS2008和VS2013

    • 入口特征

    • 第一行是call XXXX

    • 第二行是 jmp XXXX

    • call里面是push ebp mov ebp esp

    常见语言的入口点:

    VB:

    004012D4 > 68 54474000 push QQ个性网.00404754
    004012D9 E8 F0FFFFFF call <jmp.&MSVBVM60.#100>
    004012DE 0000 add byte ptr ds:[eax],al
    004012E0 0000 add byte ptr ds:[eax],al
    004012E2 0000 add byte ptr ds:[eax],al
    004012E4 3000 xor byte ptr ds:[eax],al
    004012E6 0000 add byte ptr ds:[eax],al
    004012E8 48 dec eax

    delphi:

    004A5C54 > 55 push ebp
    004A5C55 8BEC mov ebp,esp
    004A5C57 83C4 F0 add esp,-10
    004A5C5A B8 EC594A00 mov eax,openpro.004A59EC

    BC++:

    00401678 > /EB 10 jmp short btengine.0040168A
    0040167A |66:623A bound di,dword ptr ds:[edx]
    0040167D |43 inc ebx
    0040167E |2B2B sub ebp,dword ptr ds:[ebx]
    00401680 |48 dec eax
    00401681 |4F dec edi
    00401682 |4F dec edi
    00401683 |4B dec ebx
    00401684 |90 nop
    00401685 -|E9 98005400 jmp 00941722
    0040168A A1 8B005400 mov eax,dword ptr ds:[54008B]
    0040168F C1E0 02 shl eax,2
    00401692 A3 8F005400 mov dword ptr ds:[54008F],eax
    00401697 52 push edx
    00401698 6A 00 push 0
    0040169A E8 99D01300 call <jmp.&KERNEL32.GetModuleHandleA>
    0040169F 8BD0 mov edx,eax

    VC++:

    0040A41E > 55 push ebp
    0040A41F 8BEC mov ebp,esp
    0040A421 6A FF push -1
    0040A423 68 C8CB4000 push 跑跑排行.0040CBC8
    0040A428 68 A4A54000 push <jmp.&MSVCRT._except_handler3>
    0040A42D 64:A1 00000000 mov eax,dword ptr fs:[0]
    0040A433 50 push eax
    0040A434 64:8925 0000000>mov dword ptr fs:[0],esp
    0040A43B 83EC 68 sub esp,68
    0040A43E 53 push ebx
    0040A43F 56 push esi
    0040A440 57 push edi

    MASM(汇编):

    004035C9 > 6A 00 push 0
    004035CB E8 A20A0000 call <jmp.&kernel32.GetModuleHandleA>
    004035D0 A3 5B704000 mov dword ptr ds:[40705B],eax
    004035D5 68 80000000 push 80
    004035DA 68 2C754000 push 11.0040752C
    004035DF FF35 5B704000 push dword ptr ds:[40705B]
    004035E5 E8 820A0000 call <jmp.&kernel32.GetModuleFileNameA>
    004035EA E8 87070000 call 11.00403D76
    004035EF 6A 00 push 0
    004035F1 68 0B364000 push 11.0040360B
    004035F6 6A 00 push 0
    004035F8 6A 64 push 64
    004035FA FF35 5B704000 push dword ptr ds:[40705B]

    手动脱壳方法

    • 方法1:单步跟踪

    • 方法2:ESP定律法

    • 方法3:2次内存镜像法

    • 方法4:一步直达法

    常用汇编

    1.MOV 传送字或字节.
    2.MOVSX 先符号扩展,再传送.
    3.MOVZX 先零扩展,再传送.
    4.PUSH 把字压入堆栈.
    5.POP 把字弹出堆栈.
    6.PUSHA 把AX,CX,DX,BX,SP,BP,SI,DI依次压入堆栈.
    7.POPA 把DI,SI,BP,SP,BX,DX,CX,AX依次弹出堆栈.
    8.JMP 无条件转移指令
    9.CALL 过程调用
    10.RET/RETF过程返回.
    11.2>条件转移指令 (短转移,-128到+127的距离内)
    ( 当且仅当(SF XOR OF)=1时,OP1<OP2 )
    12.JA/JNBE 不小于或不等于时转移.
    13.JAE/JNB 大于或等于转移.
    14.JB/JNAE 小于转移.
    15.JBE/JNA 小于或等于转移.
    以上四条,测试无符号整数运算的结果(标志C和Z).
    16.JG/JNLE 大于转移.
    17.JGE/JNL 大于或等于转移.
    18.JL/JNGE 小于转移.
    19.JLE/JNG 小于或等于转移.
    以上四条,测试带符号整数运算的结果(标志S,O和Z).
    20.JE/JZ 等于转移.
    21.JNE/JNZ 不等于时转移.
    22.JC 有进位时转移.
    23.JNC 无进位时转移.
    24JNO 不溢出时转移.
    25.JNP/JPO 奇偶性为奇数时转移.
    26.JNS 符号位为 "0" 时转移.
    27.JO 溢出转移.
    28.JP/JPE 奇偶性为偶数时转移.
    29.JS 符号位为 "1" 时转移.
    30.3>循环控制指令(短转移)
    31.LOOP CX不为零时循环.
    32.LOOPE/LOOPZ CX不为零且标志Z=1时循环.
    33.LOOPNE/LOOPNZ CX不为零且标志Z=0时循环.
    34.JCXZ CX为零时转移.
    35.JECXZ ECX为零时转移.

    寄存器相关知识

    • EAX : 是"累加器"(accumulator), 它是很多加法乘法指令的缺省寄存器。

    • ECX : 是计数器(counter), 是重复(REP)前缀指令和LOOP指令的内定计数器。

    • EDX : 总是被用来放整数除法产生的余数。

    • EBX : 是"基地址"(base)寄存器, 在内存寻址时存放基地址。

    • ESP : 专门用作堆栈指针,被形象地称为栈顶指针,堆栈的顶部是地址小的区域,压入堆栈的数据越多,ESP也就越来越小。在32位平台上,ESP每次减少4字节。

    • EBP : 是"基址指针"(BASE POINTER), 它最经常被用作高级语言函数调用的"框架指针"(frame pointer).

    push ebp ;保存当前ebp
    mov ebp,esp ;EBP设为当前堆栈指针
    sub esp, xxx ;预留xxx字节给函数临时变量.
    
    • ESI/EDI:分别叫做"源/目标索引寄存器"(source/destination index),因为在很多字符串操作指令中, DS:ESI指向源串,而ES:EDI指向目标串.

    • EIP: 寄存器存放下一个CPU指令存放的内存地址,当CPU执行完当前的指令后,从EIP寄存器中读取下一条指令的内存地址,然后继续执行。

    • ES:附加段寄存器

    • CS:代码段寄存器

    • SS:堆栈段寄存器

    • DS:数据段寄存器

    • FS:标志段寄存器

    • GS:全局寄存器

  • 相关阅读:
    檢查 cpu 的全部 gpio 狀態及設定
    device tree 負值 property 寫法
    shell script timer and 無限迴圈
    vim 搜尋取代功能
    英国人是这样“造”单词的
    计划时间程序
    程序猿的崛起,一篇文章看懂编程语言
    如何读懂计算机(二进制)
    为什么计算机上能看到动人的图片,精彩的视频和悦耳的音乐?(二进制)
    格式化时间用了YYYY-MM-dd,元旦当天老板喊我回去改Bug!(转载)
  • 原文地址:https://www.cnblogs.com/5315hejialei/p/6938538.html
Copyright © 2011-2022 走看看