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