• 标 题:一种非明码比较程序的注册------NS-SHAFT注册码破解 (9千字)
  • 作 者:幸福的芝麻
  • 时 间:2003-07-20 07:39:09
  • 链 接:http://bbs.pediy.com

NS-SHAFT的两个小游戏一个是向上逃命的,一个是向下逃命的。
暂且叫向上逃命的为“是男人就上100层”,向下逃命的就叫做“是男人就是100层”。
绝对有难度!!鬼子的东西就是变态。
这么简单的程序将然要500日元的注册费(我汉化的把那个汉化掉了,原版上有提示)
向我这些穷人,只能拿它来研究了。
并且对破解“一种非明码比较”程序的思路经验进行总结,以飨读者。

下载地址:http://202.102.229.61/zhima
保护方式:例外,异常
使用工具:OllyDbg1.09C汉化版,VC++6.0(写注册机用)
操作系统:win2000
破解难度:有一定难度

      破解过程

一、解除软件保护。
由于用的是例外,异常来进行保护,所以alt+O打开OllyDbg的“调试选项”,选择“异常”标签
把“忽略”的复选框选项除了最下边的那一个不选其他统统选上。然后就可以放心的加载程序了。
OllyDbg就是强大,没得说,对付鬼子的变态保护很有一套。感谢迎刃兄的指导。

二、对软件注册方式的分析。
这个软件注册时要求输入用户名和注册号,用户名不起任何作用,主要是对注册码进行检验。
两个程序注册码之间的差别只有一条指令。这里我拿“向上100层”举例。那条指令我会特别注释。
打开程序-〉运行。
在反汇编框中,鼠标右键-〉搜索-〉当前模块中的名称(其实也就是当前领空所有被调用的API函数)。
找到GetDlgItemTextA对着它点右键,选择“查找导入参考”。全部设为断点。
前期工作做完了。选择“注册”。输入用户名,输入注册码(7位,后面有解释)。确定。被断下来了。
我们可以看到下面紧接着就是出错的提示框的CALL,能跳过它的只有JNZ 120.0040302F这个。
00402FE1   . 8D85 FCFDFFFF  LEA EAX,DWORD PTR SS:[EBP-204]
00402FE7   . 50             PUSH EAX
00402FE8   . E8 C0010000    CALL 120.004031AD
00402FED   . 83C4 04        ADD ESP,4
00402FF0   . 85C0           TEST EAX,EAX
00402FF2   . 0F85 37000000  JNZ 120.0040302F
所以,比较的核心代码肯定在CALL 120.004031AD这个里面,F7进入。
这里就是比较位数的不能大于7位。
004031BB   . 8A48 07        MOV CL,BYTE PTR DS:[EAX+7]       //取第8个,
004031BE   . 85C9           TEST ECX,ECX      //ECX必须为零所以第8位必须位0x00也就是什么都不能有
004031C0   . 0F84 07000000  JE 120.004031CD
往下看就是比较的核心了。
可以发现比较过程经常调用的一个函数就是CALL 120.00403317。看看里面是什么呢??
00403317  /$ 55             PUSH EBP
00403318  |. 8BEC           MOV EBP,ESP
0040331A  |. 53             PUSH EBX
0040331B  |. 56             PUSH ESI
0040331C  |. 57             PUSH EDI
0040331D  |. 33C0           XOR EAX,EAX
0040331F  |. 8A45 08        MOV AL,BYTE PTR SS:[EBP+8]   //取一个字符
00403322  |. 83F8 61        CMP EAX,61  //是小写字母吗???
00403325  |. 0F8C 0B000000  JL 120.00403336
0040332B  |. 33C0           XOR EAX,EAX
0040332D  |. 8A45 08        MOV AL,BYTE PTR SS:[EBP+8]
00403330  |. 83E8 20        SUB EAX,20  //是转化为大写,
00403333  |. 8845 08        MOV BYTE PTR SS:[EBP+8],AL
00403336  |> 33C0           XOR EAX,EAX
00403338  |. 8A45 08        MOV AL,BYTE PTR SS:[EBP+8]
0040333B  |. 83F8 41        CMP EAX,41 //是大写字母吗???
0040333E  |. 0F8C 0B000000  JL 120.0040334F
00403344  |. 33C0           XOR EAX,EAX
00403346  |. 8A45 08        MOV AL,BYTE PTR SS:[EBP+8]
00403349  |. 83E8 07        SUB EAX,7 //是大写减0x07
0040334C  |. 8845 08        MOV BYTE PTR SS:[EBP+8],AL
0040334F  |> 33C0           XOR EAX,EAX
00403351  |. 8A45 08        MOV AL,BYTE PTR SS:[EBP+8]
00403354  |. 83E8 30        SUB EAX,30  //不管是数字还是字母统统减0x30
00403357  |. E9 00000000    JMP 120.0040335C
0040335C  |> 5F             POP EDI
0040335D  |. 5E             POP ESI
0040335E  |. 5B             POP EBX
0040335F  |. C9             LEAVE
00403360  \. C3             RETN
对这个函数的功能总结:
数字-0x30
小写字母-0x20-0x07-0x30
大写字母-0x07-0x30
好了让我们在分析核心的代码:试炼码:ljylhqn (这个试炼码可是有一定的含义呦)
----------------第一个开始-----------------
00403211   > 8B45 08        MOV EAX,DWORD PTR SS:[EBP+8] //传递给EAX试炼码,这里下断点是个不错的注意
00403214   . 8A40 05        MOV AL,BYTE PTR DS:[EAX+5] //取注册码第6位
00403217   . 50             PUSH EAX
00403218   . E8 FA000000    CALL 120.00403317 //计算得到EAX=1A
0040321D   . 83C4 04        ADD ESP,4
00403220   . 33DB           XOR EBX,EBX
00403222   . 8AD8           MOV BL,AL //EBX=1A
00403224   . 8B45 08        MOV EAX,DWORD PTR SS:[EBP+8] //传递给EAX试炼码
00403227   . 8A40 02        MOV AL,BYTE PTR DS:[EAX+2] //取注册码第3位
0040322A   . 50             PUSH EAX
0040322B   . E8 E7000000    CALL 120.00403317 //计算得到EAX=22
00403230   . 83C4 04        ADD ESP,4
00403233   . 33C9           XOR ECX,ECX
00403235   . 8AC8           MOV CL,AL //ECX=22
00403237   . BE 24000000    MOV ESI,24
0040323C   . 8D4459 1C      LEA EAX,DWORD PTR DS:[ECX+EBX*2+1C] //一个计算,结果EAX=72。下100层的计算是[ECX+EBX*2+1D]
00403240   . 99             CDQ
00403241   . F7FE           IDIV ESI //eax除以24,计算后EAX为商,EDX为余数
00403243   . 8BDA           MOV EBX,EDX
00403245   . 8B45 08        MOV EAX,DWORD PTR SS:[EBP+8]
00403248   . 8A00           MOV AL,BYTE PTR DS:[EAX//取注册码第1位
0040324A   . 50             PUSH EAX
0040324B   . E8 C7000000    CALL 120.00403317 //计算得到EAX=15
00403250   . 83C4 04        ADD ESP,4
00403253   . 33C9           XOR ECX,ECX
00403255   . 8AC8           MOV CL,AL
00403257   . 3BD9           CMP EBX,ECX //一个是6一个是15肯定不一样所以eax应该等于6根据
00403259   . 0F85 AC000000  JNZ 120.0040330B //CALL 120.00403317逆推注册码第一位应该是数字6也就是0x36
----------------第二个开始-----------------//和第一个类似区别,区别在于位置
0040325F   . 8B45 08        MOV EAX,DWORD PTR SS:[EBP+8]
00403262   . 8A40 04        MOV AL,BYTE PTR DS:[EAX+4]
00403265   . 50             PUSH EAX
00403266   . E8 AC000000    CALL 120.00403317
0040326B   . 83C4 04        ADD ESP,4
0040326E   . 33DB           XOR EBX,EBX
00403270   . 8AD8           MOV BL,AL
00403272   . 8B45 08        MOV EAX,DWORD PTR SS:[EBP+8]
00403275   . 8A40 01        MOV AL,BYTE PTR DS:[EAX+1]
00403278   . 50             PUSH EAX
00403279   . E8 99000000    CALL 120.00403317
0040327E   . 83C4 04        ADD ESP,4
00403281   . 33C9           XOR ECX,ECX
00403283   . 8AC8           MOV CL,AL
00403285   . BE 24000000    MOV ESI,24
0040328A   . 8D4459 1C      LEA EAX,DWORD PTR DS:[ECX+EBX*2+1C]
0040328E   . 99             CDQ
0040328F   . F7FE           IDIV ESI
00403291   . 8BDA           MOV EBX,EDX
00403293   . 8B45 08        MOV EAX,DWORD PTR SS:[EBP+8]
00403296   . 8A40 06        MOV AL,BYTE PTR DS:[EAX+6]
00403299   . 50             PUSH EAX
0040329A   . E8 78000000    CALL 120.00403317
0040329F   . 83C4 04        ADD ESP,4
004032A2   . 33C9           XOR ECX,ECX
004032A4   . 8AC8           MOV CL,AL
004032A6   . 3BD9           CMP EBX,ECX
004032A8   . 0F85 5D000000  JNZ 120.0040330B
----------------第三个开始-----------------//差不多一模一样
004032AE   . 8B45 08        MOV EAX,DWORD PTR SS:[EBP+8]
004032B1   . 8A40 06        MOV AL,BYTE PTR DS:[EAX+6]
004032B4   . 50             PUSH EAX
004032B5   . E8 5D000000    CALL 120.00403317
004032BA   . 83C4 04        ADD ESP,4
004032BD   . 33DB           XOR EBX,EBX
004032BF   . 8AD8           MOV BL,AL
004032C1   . 8B45 08        MOV EAX,DWORD PTR SS:[EBP+8]
004032C4   . 8A00           MOV AL,BYTE PTR DS:[EAX]
004032C6   . 50             PUSH EAX
004032C7   . E8 4B000000    CALL 120.00403317
004032CC   . 83C4 04        ADD ESP,4
004032CF   . 33C9           XOR ECX,ECX
004032D1   . 8AC8           MOV CL,AL
004032D3   . BE 24000000    MOV ESI,24
004032D8   . 8D4459 1C      LEA EAX,DWORD PTR DS:[ECX+EBX*2+1C]
004032DC   . 99             CDQ
004032DD   . F7FE           IDIV ESI
004032DF   . 8BDA           MOV EBX,EDX
004032E1   . 8B45 08        MOV EAX,DWORD PTR SS:[EBP+8]
004032E4   . 8A40 03        MOV AL,BYTE PTR DS:[EAX+3]
004032E7   . 50             PUSH EAX
004032E8   . E8 2A000000    CALL 120.00403317
004032ED   . 83C4 04        ADD ESP,4
004032F0   . 33C9           XOR ECX,ECX
004032F2   . 8AC8           MOV CL,AL
004032F4   . 3BD9           CMP EBX,ECX
004032F6   . 0F85 0F000000  JNZ 120.0040330B
----------------结束-----------------
从代码看一共比较3次:
第一次比较:取第六位(ebx)和第三位(ecx)经CALL 120.00403317处理。然后经0040323c计算除0x24取余数存入ebx
再取第一位经CALL 120.00403317处理存入eax。然后比较eax和ebx。相等则以,不等则死

第二次比较:取第五位(ebx)和第二位(ecx)经CALL 120.00403317处理。然后经0040323c计算除0x24取余数存入ebx
再取第七位经CALL 120.00403317处理存入eax。然后比较eax和ebx。相等则以,不等则死

第三次比较:取第七位(ebx)和第一位(ecx)经CALL 120.00403317处理。然后经0040323c计算除0x24取余数存入ebx
再取第四位经CALL 120.00403317处理存入eax。然后比较eax和ebx。相等则以,不等则死

三、制作注册机
通过推理这个软件的注册码可以通过输入任意一个7位字符串猜测出来。下面是我写的注册机的核心代码
void CNS_KGDlg::OnBnGetKey() 
{
// TODO: Add your control notification handler code here
int ctmp1,ctmp2,ctmp3;
LPCSTR testKey1;
char testKey[8];
testKey[7]='\0';
UpdateData();
if(m_strKey.IsEmpty()||m_strKey.GetLength()!=7)//m_strKey是用户输入的任意7位注册码
{
MessageBox("您的输入有误","提示");
return;
}
testKey1=(LPCSTR)m_strKey;
strncpy(testKey,testKey1,7);
ctmp1=changechartoint(testKey[5]);
ctmp2=changechartoint(testKey[2]);
ctmp3=suanfa(ctmp1, ctmp2, m_nChk);
testKey[0]=changeinttochar(ctmp3);

ctmp1=changechartoint(testKey[4]);
ctmp2=changechartoint(testKey[1]);
ctmp3=suanfa(ctmp1, ctmp2, m_nChk);
testKey[6]=changeinttochar(ctmp3);

ctmp1=changechartoint(testKey[6]);
ctmp2=changechartoint(testKey[0]);
ctmp3=suanfa(ctmp1, ctmp2, m_nChk);
testKey[3]=changeinttochar(ctmp3);

m_strKey.Format("%s",testKey); 
m_strNote.Format("幸福的芝麻制作");  //广告
SetWindowText("http://zhimaxp.126.com");   //广告
UpdateData(FALSE);

}

int CNS_KGDlg::changechartoint(char ch)
{
if(ch>=97)
{
ch-=32;
}
if(ch>=65)
{
ch-=7;
}
return ch-48;

}

int CNS_KGDlg::suanfa(char a, char b, int k)
{
int c;
if(k==0)
{
c=b+a*2+28;
return c%36;
}
else
{
c=b+a*2+29;
return c%36;
}
}

char CNS_KGDlg::changeinttochar(int nCh)
{
nCh+=48;
if(nCh>57)
nCh+=7;
if(nCh>90)
nCh+=32;
return nCh;
}
----------
程序下载:http://202.102.229.61/zhima