<
软件逆向入门02
>
上一篇

CTF中由于版本控制导致的文件泄露
下一篇

软件逆向入门01
软件脱壳

0x01 前言

软件逆向工程所涉及知识面较为广泛,本系列文章注重从动手出发,在过程中对知识点查漏补缺,适合各类对软件逆向有兴趣的朋友(这就是传说中的野路子HHH)。如果你有充分的时间去研究学习,那么还是建议从基础一步一步走下去。如果文中存在错误请及时指出,以免误导新人。

在上一节我们简单介绍了逆向中常用的ollydbg(以下简称OD)的使用及相关操作,这一节我们将探讨一下使用该工具对一些简单的加壳软件进行脱壳。

0x02 软件脱壳介绍

软件脱壳前置知识

软件脱壳,顾名思义,就是对软件加壳的逆操作,把软件上存在的壳去掉。在一些计算机软件里也有一段专门负责保护软件不被非法修改或反编译的程序。它们一般都是先于程序运行,拿到控制权,然后完成它们保护软件的任务。由于这段程序和自然界的壳在功能上有很多相同的地方,基于命名的规则,大家就把这样的程序称为“壳”了。 –摘自百度百科

如果我们希望对软件进行汉化,DIY等操作,就必须对加壳的程序进行脱壳后才能编辑。总之在软件逆向中脱壳技术也是需要掌握的基本技术。

常见的壳分为两种,压缩壳和加密壳,压缩的目的是减少程序体积,如ASPack、UPX、PECompact等。保护是为了防止程序被跟踪和调试,如ASProtect、幻影。壳的存在会让我们找不到程序的真实入口点,从而不能正确的分析反汇编程序,也就对程序起到了一定的保护作用。在技术飞速发展的今天,pc端的加壳技术并没有特别的大的发展,大多数厂商现在都集中在移动端的apk加密保护上,在以后我们对移动端进行逆向的过程中难免会与之交锋,学习掌握相关操作技巧还是很有必要的。

工具介绍

查壳工具:Exeinfo PE、peid

文件修复工具:ImportREConstructor、LordPE

0x03 一个简单的实例

程序源码

#include <stdio.h>
#include <stdlib.h>
#define USER_NAME "admin"
#define PASSWORD "admin666666"

int main()
{
    int putin();
    putin();
    return 0;
}
int login(char userName[],char passWord[])
{
   if(strcmp(userName,USER_NAME)!=0||strcmp(passWord,PASSWORD)!=0)
        return 0;
   return 1;
}

int putin(void)
{
    int login(char[],char[]);
    char userName[25],passWord[25];
    printf("用户名:");
    gets(userName);

    printf("密码:");
    gets(passWord);
    if(login(userName,passWord))
        {
        printf("登录成功!\n");

        }
        else{
            printf("登陆失败!\n");
            putin();

        }
    return 0;
}

观察一下特征:

在未加壳的情况下,观察一下程序的入口特征

image-20200914191950255

当然,如果程序加壳后使用OD打开加载就看不到上图内容了。这里我们使用ASPack对程序进行加壳。

在拿到程序后,我们要对程序进行一个简单的判断,我们使用PEID进行检查,当检查不出来也没有关系,也是可以进行手工脱壳的。这里检查只是方便确认是什么壳,是否可以直接使用工具一步解决。

image-20200914192037783

0x04 实例演示简单的手工脱壳操作

单步追踪法

顾名思义就是单步跟踪,直到跟踪到程序OEP地址。

这里需要注意的就是要对常见的编程代码入口地址处有一定的了解,要不可能到达了程序的入口点,往往还继续单步运行程序,导致找不到程序入口。

此方法技巧总结:

F8单步跟踪,向上不能让他跳,有loopd循环也一样(跳转的下一行按F4:运行到选定位置,循环loopd在call下一句F4执行)

只允许向下跳,如单步跟踪CALL处程序运行,则需要重载程序,再CALL处F7跟进(近CALL F7,远CALL F8)

看到popad:出栈就离OEP不远了

过程:

使用OD载入h1.exe,发现程序直接跑飞了。这里跑飞了的意思就是程序直接运行起来了。

我们再其载入的地方下一个断点,防止程序跑飞,进而开始调试

image-20200914192248960

跟踪几步后发现一个向上跳转,红线代表跳转已实现,绿线代表跳转未实现。向上跳我们就在其下一行选中执行F4,继续跟进。

image-20200914192321410

最后我们可以跟进到程序的这个位置,发现是不是和没加壳的程序很像呢,这里就是程序的入口点了,找到程序的OEP地址后,就可以进行脱壳。

image-20200914192355468

这里特别注意一点,程序的oep是在一个函数中,如果不跟进去的话是发现不了的。这里只给出该函数的地址004012E0,感兴趣的同学可以自行下载软件进行尝试。

而后使用od自带的脱壳工具脱壳即可。

image-20200914192458038

这里也可以使用lordpe将程序dump出来,但由于win7环境限制,这里暂不做讲解,感兴趣的同学可以研究一下使用lordpe导出程序。

ESP定律法

原理:

壳代码在一开始会使用PUSHAD指令将所有的寄存器入栈,此时ESP所指向的内存记录着某一个寄存器的值。

然后我们ESP指向的内存处下一个硬件内存访问断点

执行完壳代码后会将所有的寄存器值出栈以平衡堆栈POPAD,CPU需要访问原ESP记录的值,壳代码解压完程序代码后,最后平衡堆栈时必然要从ESP所指向的内存中读取之前存入的某个寄存器的值,所以必定会触发此断点,此时离真正的OEP也不远了。

操作:

入栈后或者关键句的下一句,寄存器窗口ESP显示红色,ESP右键 数据窗口中跟随或命令 dd或hr ,ESP基址来到大跳转->在第一行数值 右键 断点-硬件访问断点 word->F9运行->删除硬件断点

过程:

载入程序后,入栈,单步走,发现esp变红。

image-20200914192644410

在命令输入窗口输入dd 0028FF6C(在数据窗口跟随0028FF6C这个地址),右键设置硬件访问断点,选择word型。当然也可以直接使用命令hr 0028FF8C(在0028FF6C这个地址下硬件断点)

image-20200914192709773

而后F9让程序跑起来,程序会自动断在00412422这个位置,我们往上看一下就能发现已经出栈了。

image-20200914192744406

然后继续单步跟进,就可以到达程序的OEP。

0x05 小结

除了上述讲的两种方法,还有前辈们总结的多种方法,一步直达(搜索popad等出栈关键命令),二次内存镜像法,搜索at getversion,最后一次异常法等等,这里由于篇幅限制就不做讲解了,程序加壳和环境的不同所运用的手段也不同,找到方法将程序成功破壳,那那个方法就是有用的,对你而言也许就是最好的。

Error: Not Found
Top
Foot