前言
本专题学习软件逆向的基本原理、方法,并针对具体案例进行逆向分析,从而学习一套完整、系统的软件逆向的方法并获取相关经验。
什么是逆向工程
逆向工程(又称逆向技术),是一种产品设计技术再现过程,即对一项目标产品进行逆向分析及研究,从而演绎并得出该产品的处理流程、组织结构、功能特性及技术规格等设计要素,以制作出功能相近,但又不完全一样的产品。逆向工程源于商业及军事领域中的硬件分析。其主要目的是在不能轻易获得必要的生产信息的情况下,直接从成品分析,推导出产品的设计原理。
随着计算机技术在各个领域的广泛应用,特别是软件开发技术的迅猛发展,基于某个软件,以反汇编阅读源码的方式去推断其数据结构、体系结构和程序设计信息成为软件逆向工程技术关注的主要对象。软件逆向技术的目的是用来研究和学习先进的技术,特别是当手里没有合适的文档资料,而你又很需要实现某个软件的功能的时候。也正因为这样,很多软件为了垄断技术,在软件安装之前,要求用户同意不去逆向研究。【百度百科】
常用软件
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修改可执行程序本身,从而永久保持这种任意密码通过测试的效果。
在后续的学习中,我们还可以用其他方式来突破程序的验证,如缓冲区溢出。本次学习到这里就成功结束了。