吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 15797|回复: 29
收起左侧

[原创] 新手破解epubtopdf--算法跟踪

  [复制链接]
lknight 发表于 2013-3-23 15:25
本帖最后由 lknight 于 2013-3-23 15:28 编辑

【软件名称】: epubtopdf v2.0.4
【软件大小】: 4.79m
【下载地址】: http://www.epub-to-pdf.com/?soft
【加壳方式】: 无壳
【保护方式】: 序列号
【编写语言】: Microsoft Visual C++ 6.0
【使用工具】: PEiD,OllyDbg
【操作平台】: win8

【详细过程】
      这个软件是本身没啥太大用处,只是为了提高技术找的练习软件,是比较简单的那种,适合新手。废话不多说,下面开始正题了。
      
      这个软件也可以直接用Universal Extractor解包,作为绿色软件使用的,这个软件给用户15次的试用次数,过了15次就变成下图的启动窗口
       试用过期图.jpg
      下面是破解完成后的破解效果图
       破解完成图.jpg
     下面我们就开始了,软件装好后,直接把15次试用全部试用玩,我们运行软件,随便输入用户名和注册码点击注册,会看到下面图中所示内容,再点击确定程序就推出了
      输入假码后的图.jpg
    上面图片中的expired就是关键的内容,我们OD载入程序搜索字符串,如下图
    expired字符串图.jpg
     双击上图的字符串位置,来到下图的位置
      expired在汇编窗口位置图.jpg
     在上图位置可以往上找可以跳过这一提示的跳转,发现上面有这样的跳转,那么我们就拉倒段首下F2断点,F9运行程序,程序断下来了,下图
      第一次断下来图.jpg
      我们一路F8看程序有什么变化,知道走到下图的call位置,程序状态变为run了,下图
      程序运行图.jpg
     我们在程序中随意输入的用户名和注册码,点击注册按钮,程序暂停了,下图
      程序停下来图.jpg
     我们继续往下走F8,看看程序在下面的call中都做了什么,走到下面两个临近的一样的调用call我们看到他们是把用户名和注册码压栈了,下图
      入栈.jpg
     用户名和注册码入栈就说明这些信息可能要进行检测了,后面的call我们全都进去看看,进第一个call,下图
      第一call图.jpg
      上图中我们看到,有两个CALL 0048285A,再次将用户名和注册码入栈了,那么,我们就直接看之后的那个call干了什么吧,跟进CALL 0040EAD0,下图
      第二call图.jpg
     上图中,我们还是F8一步一步分析,CALL 0040ED30什么都没做,我就不截图了,接着的那个call,CALL 0047C6E8,是检测输入的注册码中是否有链接符“-”的,我们可以跟进看一下
       连接符检测call.jpg
     上图中的CALL 0047C6F6,跟进
      连接符检测call1.jpg
     上图中的CALL 0042CB56,跟进
      连接符检测call2.jpg
     上图中对连接符的检测分析完了之后的代码没有什么重要的,我们一直返回到CALL 0047C6E8下一行,继续分析,不重要的call我就不跟进了
      连接符最后分析.jpg
     我这里只分析了跳转实现后的内容,长度不等于16的情况我就不分析了,有兴趣的朋友自己分析吧,下图,是跳转实现后的位置
      注册码计算1.jpg
     上面这段代码就是把输入的注册码分成8组,每组两个字符,并计算每组字符在“N3NANBN4NCNDNHNJNKNMP3PAPBP4PCPDPHPJPKPMA3ANABA4ACADAHAJAKAMH3HAHBH4HCHDHNHJHKHMJ3JAJBJ4JCJDJHJNJKJMK3KAKBK4KCKDKHKJKNKMB3BABNB4”
      这个表中的位置,然后把每组字符的位置数值右移1位,存放在0018A06C地址,程序运行到上图中最后一行0040EBBF位置是,我们可以在命令框中输入db 0018A06C看到下图中读取输入字符在上表中的位置
       字符位置内存图.jpg
       输入的注册码中的所有字符位置都得到后,程序就到了下面的位置,就是最终检验注册码是否正确的位置
       最后.jpg
       上图中的CALL 0040ED70,里面计算过程不复杂,我就不详细说了,其实,可以在程序执行到0040EBFE的位置的时候修改0018A06C出保存的1-4组字符(也就是前八个)位置,让位置的数值等于
     上面两个call算出来的数值,然后运行就可以了,当然你也可以修改后面的跳转,当然这是爆破,下面我详细说下这个软件的注册机制,并给出c语言编写的注册机。

     上面的分析基本分析完了,下面我总结一下这个软件的注册机制:
     首先,由上面的分析可以知道,注册码的内容必须有“N3NANBN4NCNDNHNJNKNMP3PAPBP4PCPDPHPJPKPMA3ANABA4ACADAHAJAKAMH3HAHBH4HCHDHNHJHKHMJ3JAJBJ4JCJDJHJNJKJMK3KAKBK4KCKDKHKJKNKMB3BABNB4”中的内容组成, 当然了,这是注册码长度为16的情况(长度不为16的情况各位看官自己玩玩吧),从分析中我们也可以看出,用户名没有参与注册码运算,同样连接符“-”也是可有可无的,同样,连接符“-”的位置也是可以随意调整的, 最终计算过程没有用到连接符。
      下面就是算法的具体过程了,首先我们假设输入的注册码是:N3NANBN4-NCNDNHNJ(连接符随意加的方便看,不加也行),这样我们会在内存0018A06C的位置看到这样的16进制数据0001020304050607(注意这是07是高位), 接着把5、6组字符的位置信息取出,组成一个16位的数据及0x0504,这个数据为输入调用CALL 0040ED70(本人水平有限,这个函数只能用汇编了,用c没有搞定。。。汗一个。。。),计算得到一个16位数据,假设这个数据为 0xXXYY,那么XX就对应于01,YY就对应于00,如果都像等的话,就说明这部分注册码是正确的;同样取出7、8组字符位置数值组成16位数据0x0706,这个数据为输入,调用CALL 0040ED70,同样得到一个16位数据结果,假设这个 结果是0xZZWW,那么,ZZ对应于07,WW对应于06,如果都像等的话就说明这部分注册码是正确的。这个软件的注册码计算过程就是这样,但是需要注意的是,输入的注册码中有可能某一组字符可能在表中出现了两次,那么就得 注意了,这样可能造成计算得到的位置和读取的位置错位的现象,我的做法是只用没有重复的字符串。。。

      注册机源码(VC 6.0编译通过)keygen.cpp:
      
[AppleScript] 纯文本查看 复制代码
#include "windows.h"
#include "stdio.h"
#include "wchar.h"
#include <time.h>

int GenResult(int input);

int main()
{
        WCHAR table[] = L"N3NANBN4NCNDNHNJNKNMP3PAPBP4PCPDPHPJPKPMA3ANABA4ACADAHAJAKAMH3HAHBH4HCHDHNHJHKHMJ3JAJBJ4JCJDJHJNJKJM";
        int result_tmp = 1,tmp1,tmp2;
        int pos[8]={0};
        int tablelen = wcslen(table);
        WCHAR wstr1[3]=L"";
        WCHAR wstr2[3]=L"";
        WCHAR wstr3[3]=L"";
        WCHAR wstr4[3]=L"";
        WCHAR wstr5[3]=L"";
        WCHAR wstr6[3]=L"";
        WCHAR wstr7[3]=L"";
        WCHAR wstr8[3]=L"";
        srand((unsigned)time(NULL));
        for(int i=4; i<8; i+=2)
        {
                for(;;)
                {
                        pos[i] = rand()%(tablelen-1);
                        pos[i+1] = rand()%(tablelen-1);
                        tmp1 = pos[i]>>1;
                        tmp2 = pos[i+1]>>1;
                        result_tmp = GenResult(tmp1 | (tmp2<<8));
                        if(i==4)
                        {
                                if (tmp1>0x31 || tmp2>0x31)
                                {
                                        continue;
                                } 
                                else
                                {
                                        pos[0] = (result_tmp & 0x0FF)<<1;
                                        pos[1] = ((result_tmp>>8) & 0x0FF)<<1;
                                        wstr1[0]=table[pos[0]];
                                        wstr1[1]=table[pos[0]+1];
                                        wstr2[0]=table[pos[1]];
                                        wstr2[1]=table[pos[1]+1];
                                        wstr5[0]=table[pos[i]];
                                        wstr5[1]=table[pos[i]+1];
                                        wstr6[0]=table[pos[i+1]];
                                        wstr6[1]=table[pos[i+1]+1];
                                        if ((wcsstr(table,wstr1)-&table[pos[0]] <0)  || (wcsstr(table,wstr2) - &table[pos[1]]<0) ||
                                                (wcsstr(table,wstr5)-&table[pos[i]] <0)  || (wcsstr(table,wstr6) - &table[pos[i+1]]<0))
                                        {
                                                continue;
                                        } 
                                        else
                                        {
                                                break;
                                        }
                                }
                        }
                        else
                        {
                                if (tmp1>0x31 || tmp2>0x31)
                                {
                                        continue;
                                } 
                                else
                                {
                                        pos[2] = (result_tmp & 0x0FF)<<1;
                                        pos[3] = ((result_tmp>>8) & 0x0FF)<<1;
                                        wstr3[0]=table[pos[2]];
                                        wstr3[1]=table[pos[2]+1];
                                        wstr4[0]=table[pos[3]];
                                        wstr4[1]=table[pos[3]+1];
                                        wstr7[0]=table[pos[i]];
                                        wstr7[1]=table[pos[i]+1];
                                        wstr8[0]=table[pos[i+1]];
                                        wstr8[1]=table[pos[i+1]+1];
                                        if ((wcsstr(table,wstr3)-&table[pos[2]] <0)  || (wcsstr(table,wstr4) - &table[pos[3]]<0) ||
                                                (wcsstr(table,wstr7)-&table[pos[i]] <0)  || (wcsstr(table,wstr8) - &table[pos[i+1]]<0))
                                        {
                                                continue;
                                        } 
                                        else
                                        {
                                                break;
                                        }
                                }
                        }
                }
        }

        wprintf(L"%s%s%s%s%s%s%s%s\n",wstr1,wstr2,wstr3,wstr4,wstr5,wstr6,wstr7,wstr8);

        return 0;
}

int GenResult(int input)
{
        int re;
        _asm
        {
                pushad
                mov ecx,input
                mov ebx,0x351D
                mov esi,0x5A39
                mov edi,0x1
label1: test bl,0x1
                jnz label3
label2:        mov eax,ecx
                xor edx,edx
                imul eax,ecx
                div esi
                shr ebx,1
                test bl,0x1
                mov ecx,edx
                je label2
label3: mov eax,edi
                xor edx,edx
                imul eax,ecx
                div esi
                dec ebx
                mov edi,edx
                jnz label1
                mov eax,edi
                mov re,eax
                popad
        }
        return re;
}

            第一次写算法跟踪,写的比较乱,高手勿笑。。。
                                                                                   by lknight
--------------------------------------------------------------------------------
【版权声明】: 转载请注明作者并保持文章的完整, 谢谢!

                                                       2013年03月23日 14:55:23

免费评分

参与人数 1热心值 +1 收起 理由
Chief + 1 欢迎分析讨论交流,[吾爱破解论坛]有你更精.

查看全部评分

本帖被以下淘专辑推荐:

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

Chief 发表于 2013-3-23 16:05
写的不错,希望继续发布好破文,
吾爱破解论坛有你更精彩。
taotao 发表于 2013-3-23 16:08
Victory.ms 发表于 2013-3-23 16:09
chenlinhui 发表于 2013-3-23 16:37
看看     学习一下
zhangbaida 发表于 2013-3-23 17:13
高手,学习一下哈
kantal 发表于 2013-3-23 18:07
不错 很详细  值得学习一下  ~~谢谢分享~
RedAngel丶 发表于 2013-3-23 19:40
膜拜,学习下
音美乐纯 发表于 2013-3-23 20:03
看不懂啊,不会编程
silent_grief 发表于 2013-3-23 22:09
  顶下帖子了。  新手来照着一部一部的做,会得到 成就感的。
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2025-1-11 17:08

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表