以前的记录(加密与解密)

常见的演示版保护技术

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. 算法原理

(1)       数据填充

 填充消息使其长度与448模512同余。也就是说,填充后的消息长度比512的倍数仅小64位的数。

posted on 2011-12-30 18:36  belie8  阅读(492)  评论(0编辑  收藏  举报

导航