以前的记录(加密与解密)
常见的演示版保护技术
5.1序列号保护方式
5.1.1序列号保护机制
软件验证序列号的过程,其实就是验证用户名和序列号之间的数学映射关系。
给定一个用户名,利用穷举法找到一个满足式的序列号,这只适用于穷举难度不大的函数;
给定一个序列号,利用式变换得出一个用户名,从而得到一个正确的用户名/序列号对。
(3)通过对
5.1.2 如何攻击序列号保护
若要找到序列号,或者修改判断序列号之后的跳转指令,最重要的是要利用各种工具来定位判断序列号的代码段。
利用调试器提供的针对API设断点的功能,就有可能找到判断注册码的地方。这些常用的API包括GetWindowTextA(W),
GetDlgItemTextA(W),GetDlgItemInt,Hmemcpyt等。程序判断完注册码之后,一般显示一个对话框,告诉用户注册码是否正确,这也是一个切入点。
常用API:MessageBoxA(W),MessageBoxExA(W),DialogBoxParamA(W),CreateDialogIndirectOaramA(W)...
程序启动时对注册码的判断,API:RegQueryValueExA(W);如果序列号放在ini文件中,可以用GetPrivateProfileStringA(W),GetProfileStringA(W),GetPrivateProfileIntA(W)
GetProfileIntA(W)等函数;如果序列号存放在一般文件中,可以用CreateFileA(W),_lopen()等函数。
1.数据约束性的秘诀
只限于用明文比较注册码的保护方式。
用OllyDbg也可以实现这种查找功能。用OllyDbg加载TraceMe输入假序列号,单击“Check"按钮直到错误提示框。按”Alt+M" 键打开内存窗口,在最上一行,按“Ctrl+B”
键打开搜索框,搜索刚输入序列号,可以在当前进程的整个内存映像里查找数据。
2.Hmemcpy函数(俗称万能断点)
属于Windows 9x系统的内部函数,它的作用是将内存中的一块数据拷贝到另一个地方。
由于Windows9X系统频繁使用该函数处理各种字符串,因此用它作为断点很实用。
3.利用消息断点
许多序列号保护的软件都有一个按钮,当鼠标左键按下和释放时,将发送消息WM_LBUTTONDOWN(0201h)和WM_LBUTTONUP(0202h),因此用这个消息下断很容易找到按键的事件代码。
4.利用提示信息
大多数软件在设计时,都采用了人机对话方式。所谓人机对话,即软件在执行完某一段程序之后,便显示一串提示信息,以反映该程序的运行后的状态。
。可以用反汇编工具查找相应字符串,定位到相关代码处。
5.1.3 字符串比较形式
在序列号分析过程中,字符串处理是一个重点,必须掌握一定的分析技能。加密者为了有效防止解密者修改跳转指令,往往采取一些技巧,迂回比较字符串。
(1)寄存器直接比较
(2)函数比较
call一般是一个BOOL函数,其结果通过eax返回。分析时,关注该call里面返回时对eax处理的代码。
(3)函数比较2
push XXX ;参数1,可能是地址,寄存器
push XXX ;参数2
call XXXXXXX; 比较功能的函数,可以是API的函数,也可以是作者自己的比较函数
test eax,eax
jz(jnz)
(4) 串比较
lea edi[ ] ;edi指向字符串a
lea esi[ ] ;esi指向字符串b
repz cmpsd ;比较字符串a,b
jz(jnz)
5.1.4 注册机制作
软件开发结束后,作者本人很有必要先做攻击测试,找出弱点,避免犯一些低级错误。一般注册算法其实是一些极为简单的算法,基本都是些盟友
或者明码相近的,如查表、异或、换位、移位、累加和等,算法实现比较容易
1.明码比较软件的攻击
运行keymake后,单击菜单“其他/内存注册机”,
具体操作步骤如下:
1.单击“浏览”按钮,打开目标程序TraceMe.exe。
2.“内存方式”选择寄存器,本例是EBP,即序列号保存在EBP所指向的内存地址中。
3.中断地址列表:
中断地址,目标程序明码比较指令地址;
次数,在此地址中断的次数;
指令,此处指令指机器码第一个字节;
2.非明码比较
5.2警告(Nag)窗口
5.3 时间限制
5.3.1 计时器
1.SetTime()函数
UINT SetTimer (HWND hWnd,UINT nIDEvent, UINT uElapse,TIMERPROC lpTimerFunc);
hWnd:窗口句柄,当计时器时间到时,系统瘵向这个窗口发送WM_TIMER消息。
nIDEvent:计时器标识。
uElapse:指定计时器时间间隔,以毫秒为单位。
TIMERPROC:回函数。当计时器超时时,系统将调用这个函数。如果本参数为NULL,当计时器超时时将向相应的窗口发送WM_TIMER消息。
回调用函数原型为:
void CALLBACK TimerProc(HWND hwnd,UINT uMsg,UINT idEvent,DWORD dwTime);
2.使用高精度的多媒体计时器
5.4 菜单功能限制
5.4.1 相关函数
软件将菜单或窗口变灰或变为不可用,一般采用下面的几个函数。
1.EnableMenuItem
允许或禁止指定的菜单条目。原型如下:
BOOL EnableMenuItem(HMENU hMenu,UINT uIDEnableITem,UINT uEnable)
2.EnableWindow
允许或禁止指定窗口。
BOOL EnableWindow(HWND hWnd,BOOL bEnable)
5.4.2拆解菜单限制保护
名称:EnableMenu
5.5 KeyFile保护
5.5.1 相关API函数
由于KeyFile是一个文件,因上所有有关Windows文件操作的API函数都可作为动态跟踪破解的断点。
FindFirstFileA 确定注册文件是否存在
CreateFileA,_lopen 确定文件是否存在;打开文件以获取得其句柄
GetFileSize,GetFileSizeEx 获得注册文件的大小
GetFileAttributesA,GetFileAttributesExA 获得注册文件的属性
SetFilePointer,SetFilePointEx 移动文件指针
ReadFile 读取文件内容
5.5.2 拆解KeyFile保护
1.拆解KeyFile的一般思路
(1)先用FileMon等工具监视软件对文件的操作,以找到KeyFile的文件名。
(2)伪造一个KeyFile文件。用十六进制工具编辑和修改KeyFile,普通的文件编辑工具不太适合。
(3)在调试器里用CreateFileA函数设断查看其打开文件名指针,并记下返回的句柄。
(4)用ReadFile设断,分析传递给ReadFile的文件句柄和缓冲区地址。文件句柄 一般和第(3)步的相同(若不同,则说明不是读该
KeyFile,此外也可用条件断点)。缓冲区地址则是非常重要的,因为读进来的重要数据放在这里。对缓冲区中存放的字节设内存断点,监视读进来的KeyFile的内容。
(5)当然上述步骤只是大概轮廓,有的程序判断KeyFile时还会先判断文件大小和属性,移动文件指针等。
5.6网络验证
5.6.1相关函数
当一个连接建立以后,就可以传传输数据了,常用的传送数据的函数有send和recv两个Socket函数,另外还有微软的扩展函数WSASend和WSARecv.
1.send函数
int send(
SOCKET s,
const char FAR *buf,
int len,
int flags
)
2.recv函数
5.6.2 网络验证破解一般思路
如果网络验证的数据包内容固定,可以将数据包抓取,写个本地服务端模拟服务器;如果验证的数据包内容不固定,则必须分析出其结构,找出相应算法。
实际过程中,服务端是接触不到的,读者必须从客户端入手,并利用一组正确的账号,击破这个网络验证保护。
1.分析发送的数据包
建议用IDA与OD一起来分析,IDA能正确识别出C函数,方便分析OD加载客户端后,用send函数设断,输入正确的账号与口令,单“Register"按钮,中断并回到当前领空
Send 函数将把Data缓冲区中的数据发送到服务端,这里查看Data数据,发现是加密的。在IDA中向前查看代码。再结合OD分析
5.8只运行一个实例
5.8.1 实现方法
1.查找窗口法
在程序运行前,用FindWindow,GetWindowText函数查找具有相同窗口类名和标题的窗口。如果找到了,就说明已经存在一个实例。
HWND FindWindowA(W)(
LPCTSTR lpClassName,//指向窗口类名
LPCTSTR lpWindowName //指向窗口文本
);
返回值;如果未找到相符窗口,则返回零。
2.使用互斥对象
尽管互斥对象通常用于同步连接,但用在这个地方也是非常方便的。一般是用CreateMuteX函数实现,它的作用是创建有名或者无名的互斥对象。
HANDLE CreateMuteXA(W)(
LPSECURITY_ATTRIBUTES lpMutexAttributes, // 安全属性
BOOL bInitialOwner, //指定互斥对象的初始所属身份
LPCTSTR lpName //指向互斥对象名
);
3.使用共享区块
创建一个共享区块,该节拥有读取,写入和共享保护属性,让多个实例共享同一内存。将一个变量放到该区块中作为计数器,该应用程序的所有实例均可以共享该变量,以便通过该变量得知有没有实例在运行。
5.9常用断点设置技巧
设置正确的断点,对调试软件是非常重要的。如果掌握一些Win32编程,对设置合适的断点是非常有帮助的。
第6章 加密算法 131页
RSA、BlowFish、MD5等都是目前比较高级的算法。
6.1 单向散列算法
单向散列函数算法也称Hash(哈希)算法,是一种将任意长度消息压缩到某一个固定长度的函数,该过程是不可逆的。Hash函数可用数字签名、消息的完整性检测、消息起源的认证检测等。常见的散列算法有MD5、SHA、RIPE-MD、HAVAL、N-Hash等。
6.1.1. MD5算法
MD5消息摘要算法。它对输入的任意长度的消息进行运算,产生一个128位的消息摘要。
- 算法原理
(1) 数据填充
填充消息使其长度与448模512同余。也就是说,填充后的消息长度比512的倍数仅小64位的数。