您可以捐助,支持我们的公益事业。

1元 10元 50元





认证码:  验证码,看不清楚?请点击刷新验证码 必填



  求知 文章 文库 Lib 视频 iPerson 课程 认证 咨询 工具 讲座 Model Center   Code  
会员   
   
 
     
   
 订阅
  捐助
逆向工程与软件自我保护
 
作者:Erio
  1867  次浏览      15
2020-9-17
 
编辑推荐:
本文介绍了逆向工程与软件自我保护 ,图示较多,阅读下文了解更多。
本文来自于博客园,由火龙果软件Alice编辑、推荐。

第一阶段:软件保护破解

方法一:爆破(至少两种方式)

1.查找显示注册结果相关代码

查找注册码验证相关代码

修改程序跳转

方法二:编写注册机

查找显示注册结果相关代码

查找注册码验证相关代码

根据注册码验证代码编写注册机

第二阶段:软件反动态调试分析

分析CrackMe1.exe是如何通过父进程检测实现反OllyDbg调试的

分析除父进程检测外,该程序用到的反动态调试技术

第三阶段:壳

加壳脱壳深入理解

尝试手动脱壳

第一阶段:软件保护破解

方法一:爆破(至少两种方式)

1.查找显示注册结果相关代码

首先尝试输入Sssss 55555 错误,弹框Bad boy。那么bad boy有关的代码就是注册结果相关代码。

之后用OllyDbg打开crack.exe。

查找所有参考文本子串。

双击 good boy(bad boy 也可)。

就找到了注册结果相关代码。

2. 查找注册码验证相关代码

向上查看代码。

可以看到一段循环后,做cmp,然后jnz,选择是否跳转到Bad boy相关字段。(地址401107)

还是正确,直接good boy。

即为注册码验证相关代码。

3.修改程序跳转

爆破方法一:修改跳转条件

JNZ 改为JZ。

在OllyDbg修改相关代码,汇编,F9运行,查看效果。

F9运行

修改为jz。汇编

爆破完成

修改PE文件。

使用Lordpe 查看crack的文件信息。点击sections。 .text节在V偏移,文件中偏移都为1000,所以节偏移为0。之后下图给出了文件偏移地址的计算公式。

010Editor工具打开crack。 地址10F9 750C (机器指令),与OD一致

改为jz后可见机器码为 740C 。

在pe文件,改为74

运行

爆破成功。

另一种找到地址的方式

在OD

004010F9 右键

在下方数据窗口,右键查看可执行文件,可见地址10F9

爆破方法二:

修改比较方式。

由以上分析可知,crack程序验证时,cmp eax,ecx,若不等(JNZ 401107)

那么我们修改为相等即可。直接cmp eax eax。

爆破成功。

机器码为3BC0

在pe文件的相应位置修改即可。

地址为000010F7.

方法二:编写注册机

查找显示注册结果相关代码

同方法一,不再赘述。

查找注册码验证相关代码

同方法一,不再赘述。

根据注册码验证代码编写注册机

我们在上面找到了验证相关代码,现在通过动态调试分析具体的验证过程。

在XOR(异或) EAX,EAX 处F2下断点,F9运行。

弹窗,此时输入了name abcde,serial 12345.

之后F7单步运行,观察寄存器值和堆栈信息,分析验证过程。

窗口右边有寄存器值。

F7单步运行

单步运行可见ECX值变为abcde,EAX清零,EDX00001908

ECX值变为61,”a”的ascii值

这里cmp eax,ebx ebx=5,是arg1的长度。每次循环eax+1,判断输入的是不是5位

下方堆栈信息

通过单步运行,观察寄存器,汇编和堆栈可以分析出程序的保护方式是根据name计算serial,然后和用户输入的serial比较。

执行完CALL语句就将输入的字符串转化为整型

循环计算对应的注册码,并判断输入的用户名长度是否合法(必须是5位),否则有提示。

Arg3存储输入的name。Arg2(ECX)存储计算得到的注册码

Arg4存储输入的注册码,字符串转换为整型后存到EAX

然后就是CMP EAX ECX

计算过程用C++形式表示如下

#include<iostream>
#include<cstring>
using namespace std;
int main()
{
cout<<"Enter the name"<<endl;
string name;
cin>>name;
string arg3=name;
int arg2=6408;
int ebx=arg3.size();
int ecx;
for(int eax=0;eax<ebx;eax++)
{
arg2+=ebx;
ecx=arg3[eax];
ecx*=arg2;
arg2=ecx;
}
cout<<(arg2^0xA9F9FA)<<endl;

}

编写相关程序,编译运行,输入五位字符,就会计算出相应的注册码。如图所示。

输入name aaaaa,计算出其serial 为978652603.

我们在crack程序验证,确实如此。于是就生成了注册码生成机。

第二阶段:软件反动态调试分析

分析CrackMe1.exe是如何通过父进程检测实现反OllyDbg调试的

OllyDbg打开,查看调用树。

去地址40192C查看。

在这里下断点,开始调试。

Ntdll是获取父进程id,push到edi

获取父进程名字 GetModuleFileNmeExA

这里有关闭句柄操作。

再往下

可以看到ARG2是作为比较的explorer的路径名称,而arg1即为上面获取到的当前打开craackme1的父进程的路径名称。

Push到edx后,call5027FE去进行比较。

5027FE

在第二个cmp处跳转

Jne 502829

Je没有jump。

Jmp 00502705

00502705是大的循环,比较过程。

循环可以分为三个段。

前两个做大小写转换,第三个做比较

cmp19 判断是大写还是小写,是大写+20转化为小写

test eax,eax判断循环是否结束。结束跳转到502738

JE 相同的话跳转到2712继续循环比较后续字符

注意看右侧的寄存器值

一开始edx为c:xxxx

一次比较后

c比较过了,就去掉。

比较不等,返回到call5027FE的下一条,进行后续操作。(这时已经判断出有问题了,父进程不是explorer)

2. 分析除父进程检测外,该程序用到的反动态调试技术

该程序用到的关键函数还有

作用分别为:

1.GetCurrentProcessId

GetCurrentProcessId(

VOID

);

说明:

获取当前进程的标示符(PID)

返回值:

返回一个标示符(PID)

库文件:kernel32.dll

2.OpenProcess

库文件:Kernel32.dll

OpenProcess 函数用来打开一个已存在的进程对象,并返回进程的句柄。

函数原型

HANDLE OpenProcess(

DWORD dwDesiredAccess,

BOOL bInheritHandle,

DWORD dwProcessId

);

3.GetModuleFileNameExA 通过进程句柄获取进程文件名

DWORD GetModuleFileNameExA(

HANDLE hProcess,

HMODULE hModule,

LPTSTR lpstrFileName,

DWORD nsize

);

库文件:Kernel32.dll

4.CreateToolhelp32Snapshot

可以获取系统中正在运行的进程信息,线程信息

HANDLE WINAPI CreateToolhelp32Snapshot(

DWORD dwFlags, //用来指定“快照”中需要返回的对象,可以是TH32CS_SNAPPROCESS等

DWORD th32ProcessID //一个进程ID号,用来指定要获取哪一个进程的快照,当获取系统进程列表或获取 当前进程快照时可以设为0

);

库文件:Kernel32.dll

5.Process32Next

是一个进程获取函数,当我们利用函数CreateToolhelp32Snapshot()获得当前运行进程的快照后,我们可以利用Process32Next函数来获得下一个进程的句柄。

BOOLWINAPIProcess32Next(

__inHANDLEhSnapshot,

__outLPPROCESSENTRY32lppe

);

库文件:Kernel32.dll

6.EnumWindows()

函数原型:

BOOL WINAPI EnumWindows(

_In_ WNDENUMPROC lpEnumFunc,

_In_ LPARAM lParam

);

lpEnumFunc: 应用程序定义的回调函数的指针

lParam: 传递给回调函数的应用程序定义的值

即:

枚举屏幕上的所有的顶层窗口,轮流地将这些窗口的句柄传递给一个应用程序定义的回调函数。EnumWindows会一直进行下去,直到枚举完所有的顶层窗口,或者回调函数返回了FALSE.

库文件:user32.dll

7.GetWindowTextA

GetWindowTextA将指定窗口的标题栏(如果有的话)的文字拷贝到缓冲区内。如果指定的窗口是一个控件(control),那么该控件的text属性将被拷贝(到缓冲区)。但是,GetWindowText 不能取回其他程序中控件的text。

int WINAPI GetWindowText(

_In_ HWND hWnd,

_Out_ LPTSTR lpString,

_In_ int nMaxCount

);

库文件:User32.dll

对该程序反动态调试技术的理解:

该程序被打开后,通过windows api函数获取父进程的路径,存储到寄存器中,然后与explorer.exe(预期的父进程名)的路径作比较,比较时先转换为小写。之后比较相同,则认为没有被动态调试,否则认为是调试器。之后进行操作阻止调试。

第三阶段:壳

加壳脱壳深入理解

用PEid检测CrackmeUPX,可以发现该程序是UPX方法加壳的。

用OllyDbg打开运行,查看壳的加载过程。

409BF0pushad保存现场环境。

单步运行查看右下角堆栈信息。

将信息保存到12FFA4开始的位置,当壳加载完成退出后,在弹出保存好的信息。

F7单步运行查看加载壳的具体过程

完成后Popad弹出保存好的信息。

   
1867 次浏览       15
 
相关文章

iOS应用安全开发,你不知道的那些事术
Web安全之SQL注入攻击
移动APP安全在渗透测试中的应用
从Google备份互联网看“数据安全”
 
相关文档

web安全设计与防护
互联网海量内容安全处理技术
黑客攻击与防范技术
WEB黑盒安全检测
 
相关课程

WEB网站与应用安全原理与实践
web应用安全架构设计
创建安全的J2EE Web应用代码
信息安全问题与防范
最新课程计划
信息架构建模(基于UML+EA)3-21[北京]
软件架构设计师 3-21[北京]
图数据库与知识图谱 3-25[北京]
业务架构设计 4-11[北京]
SysML和EA系统设计与建模 4-22[北京]
DoDAF规范、模型与实例 5-23[北京]
 
最新文章
物联网安全概述
史上最详细的区块链技术架构分析
一文读懂区块链整体架构及应用案例
区块链技术架构
安全架构评审实战
最新课程
Web应用安全架构、入侵检测与防护
物联网关键技术、安全与边缘计算
区块链安全技术实践指南
云服务与安全架构
互联网安全开发方法与实践
更多...   
成功案例
中国银行 信息安全技术及深度防御
北京 Web应用安全架构、入侵检测与防护
某财税领域知名IT服务商 Web安全测试
普瑞克斯 web安全设计、测试与优化
北京和利时 性能和安全性测试
更多...