天天看点

软件逆向工程学习(一)前言

前言

本专题学习软件逆向的基本原理、方法,并针对具体案例进行逆向分析,从而学习一套完整、系统的软件逆向的方法并获取相关经验。

什么是逆向工程

逆向工程(又称逆向技术),是一种产品设计技术再现过程,即对一项目标产品进行逆向分析及研究,从而演绎并得出该产品的处理流程、组织结构、功能特性及技术规格等设计要素,以制作出功能相近,但又不完全一样的产品。逆向工程源于商业及军事领域中的硬件分析。其主要目的是在不能轻易获得必要的生产信息的情况下,直接从成品分析,推导出产品的设计原理。

随着计算机技术在各个领域的广泛应用,特别是软件开发技术的迅猛发展,基于某个软件,以反汇编阅读源码的方式去推断其数据结构、体系结构和程序设计信息成为软件逆向工程技术关注的主要对象。软件逆向技术的目的是用来研究和学习先进的技术,特别是当手里没有合适的文档资料,而你又很需要实现某个软件的功能的时候。也正因为这样,很多软件为了垄断技术,在软件安装之前,要求用户同意不去逆向研究。【百度百科】

常用软件

OllyDbg:常用于动态调试程序,无法调试内核,UI功能强大。

SoftICE:工作在ring0态的调试器,常用于调试驱动程序,功能强大的命令行工具。

WinDbg:介于上两者之间的调试器,具有图形界面,调试主要通过命令来进行。

IDA Pro:反汇编软件,用于静态反汇编,带有较弱的动态调试功能。

UltraEdit:16进制编辑器,可用于直接修改可执行文件,也可用于常见语言的变成工作。

虚拟机:防止被调试程序破坏物理机的内核及操作系统。

分析一个简单的程序

为了说明上述软件的作用,我们以一个简单的程序为例,来展示逆向中的反汇编代码并分析。

程序使用vc6.0编译生成,c程序源文件如下:

#include <stdio.h>
#define PASSWORD "1234567"
int verify_password (char *password)
{
    int authenticated;
    authenticated=strcmp(password,PASSWORD);
    return authenticated;
}

main()
{
    int valid_flag=;
    char password[];
    while()
    {
        printf("please input password:       ");
        scanf("%s",password);
        valid_flag = verify_password(password);
        if(valid_flag)
        {
            printf("incorrect password!\n\n");
        }
        else
        {
            printf("Congratulation! You have passed the verification!\n");
            break;
        }
    }
}
           

我们的目标是通过修改程序本身,实现在不知道密码的情况下获得密码正确的提示。

使用IDA Pro对程序进行反汇编,我可以找到编译生成的汇编代码中,main函数的部分如下:

.text: sub_401000      proc near               ; CODE XREF: _main+24p
.text:
.text: arg_0           = dword ptr  
.text:
.text:                 mov     eax, [esp+arg_0]
.text:                 push    ebx
.text:                 push    esi
.text:                 mov     esi, offset a1234567 ; "1234567"
.text:B
.text:B loc_40100B:                             ; CODE XREF: sub_401000+2Dj
.text:B                 mov     dl, [eax]
.text:D                 mov     bl, [esi]
.text:F                 mov     cl, dl
.text:                 cmp     dl, bl
.text:                 jnz     short loc_401034    #if(valid_flag) jump
.text:                 test    cl, cl
.text:                 jz      short loc_40102F
.text:                 mov     dl, [eax+]
.text:C                 mov     bl, [esi+]
.text:F                 mov     cl, dl
.text:                 cmp     dl, bl
.text:                 jnz     short loc_401034
.text:                 add     eax, 
.text:                 add     esi, 
.text:B                 test    cl, cl
.text:D                 jnz     short loc_40100B
.text:F
.text:F loc_40102F:                             ; CODE XREF: sub_401000+17j
.text:F                 pop     esi
.text:                 xor     eax, eax
.text:                 pop     ebx
.text:                 retn
           

我们可以看到,

if(valid_flag)

一句在汇编代码中的位置如标注所示,如果

dl

bl

不相等,则跳转至错误提示。因此,我们只需把

jnz

指令换成

jz

指令,即可达成目的。

最后,我们使用UltraEdit修改可执行程序本身,从而永久保持这种任意密码通过测试的效果。

在后续的学习中,我们还可以用其他方式来突破程序的验证,如缓冲区溢出。本次学习到这里就成功结束了。

继续阅读