新CrackMe160之106 - crackme_0018
OD载入程序, 搜索界面定位到成功关键词00401099, 向上看到关键算法00401081 call 00401130, 进入方法可看到GetDlgItemTextA, 0040118A处,下好断点开始单步调试
获取用户名和系列号后都调用了call 00401270这个方法,进入调试发现是需要输入都为大写字母才能通(内存地址004060BE ~ 004061DD里有一组固定数据, 只有单数 00406160 ~ 00406192才能与0x103与以后得1, 由004060DE + x * 2 = 00406160 ~ 00406192 可得 x = A ~ Z)
004011D7处可知用户名和系列号的长度要一样, 00401199处调试可得长度得是4位以上偶数位
00401200 ~ 0040124F 就是真正的用户名系列号校验算法了
for(i=0;i<len/2;i++){
c1 = code[i*2+1] - 0x41;
c0 = code[i*2+0] - 0x41;
eax = c0 * 9 + c1 * 2;
eax % 26 ?== user[i*2+0] - 0x41;
eax = c0 + c1 * 15;
eax % 26 ?== user[i*2+1] - 0x41;
}
由上面算法可知,要从用户名算出系列号有点难, 从系列号反算用户倒是简单,所以,我们就反着来
#include <stdio.h>
#include <string.h>
int main() {
char user[33] = {0};
char code[33] = {0};
printf("系列号: ");
scanf("%s", code); getchar(); //消耗掉多输入的\n
int i,len = strlen(code), c0,c1;
if(len<4 || (len % 2 == 1)){
printf("输入的位数不对,需要4位以上偶数位");
getchar(); return;
}
for(i=0; i<len/2; i++){
c1 = code[i * 2 + 1] - 0x41;
c0 = code[i * 2 + 0] - 0x41;
user[i * 2 + 0] = (c0 * 9 + c1 * 2) % 0x1A + 0x41;
user[i * 2 + 1] = (c0 + c1 * 15) % 0x1A + 0x41;
}
printf("用户名: %s\n", user);
getchar(); return 0;
}
运行示例:
系列号: CRACKMEE
用户名: AXEEKISM
如果一定要正着来, 那就变得复杂多了
#include <stdio.h>
#include <string.h>
int main() {
char user[33] = {0};
char code[33] = {0};
printf("用户名: ");
scanf("%s", user); getchar(); //消耗掉多输入的\n
int i,len = strlen(user), c0,c1, s=0, v0, v1;
if(len<4 || (len % 2 == 1)){
printf("输入的位数不对,需要4位以上偶数位");
getchar(); return;
}
for(i=0; i<len/2; i++){
s = 0;
for(c0=0; c0<0x1A; c0++){
for(c1=0; c1<0x1A; c1++){
v0 = (c0 * 9 + c1 * 2) % 0x1A + 0x41;
v1 = (c0 + c1 * 15) % 0x1A + 0x41;
if ((v0 == user[i * 2 + 0]) &&
(v1 == user[i * 2 + 1])){
s = 1; break;
}
}
if(s == 1) break;
}
if(s == 0) {
printf("无解,请重新输入");
getchar(); return;
}
code[i * 2 + 0] = c0 + 0x41;
code[i * 2 + 1] = c1 + 0x41;
}
printf("系列号: %s\n", code);
getchar(); return 0;
}
运行示例:
用户名: CRACKMEE
系列号: QHQGQYAC
使用的工具连接(工具有点多有点大,可以先下OD,其它的后面慢慢下) 点击前往下载
下面是我的OD的界面布局,我觉得这4个是最常用的界面,其它的我基本上没用到~


浙公网安备 33010602011771号