拿到程序是找序列号的,查壳没有,vb写的。先运行下,随便输入字符,ok按钮才激活,然后点击后弹出错误的弹窗。
在od中查找字符串,找到了相关信息。
跟进去看了下,找到了跳转的分支。
eax和ecx里面存的什么不知道,往上找。跟了好多次,发现当输入name后,点击ok按钮,会对name的每一位ASSIC码进行一个累加。累加完成后,会和一个0x499602D2的数相乘,计算出的结果转化成十进制后,形成一个字符串,然后在字符串的第四位和第九位替换成‘-’,最后拼接成序列号。
累加部分:我这里输入的123,换成assic后,是31,32,33,三个数累加后,结果为96。
相乘部分:ecx里存放的是累加后的0x96,然后和0x499602D2相乘,计算结果保存在0x0019F114中。因为这里相乘的时候用的是vb的函数,所以找具体相乘的地方,可以在ebp-0xA4的地址下一个硬件访问断点,因为是累加的数乘这个固定的数,然后就能找到相乘的位置。
可以看到乘完以后eax的值,转化成十进制正好的185185183500
拼接序列号:将乘出来的数十进制转成字符串,然后把第四位和第九位替换成‘-’,最后得到序列号
比较部分:最后就是将输入的和正确的序列号进行比较
测试下,输入123,序列号为185-8518-500,弹出正确的对话框。这个注册机写了一下。
#include <iostream>
#include <stdio.h>
#include<windows.h>
//两数相乘超过32位后,eax存不下整个数字,edx存高位,eax存地位,这里取出高位和低位的数
void mult(long op1, long op2, long *prod_hi, long *prod_lo)
{
long op1_hi = (op1 >> 16) & 0xffff;
long op1_lo = op1 & 0xffff;
long op2_hi = (op2 >> 16) & 0xffff;
long op2_lo = op2 & 0xffff;
long cross_prod = op1_lo * op2_hi + op1_hi * op2_lo;
*prod_hi = op1_hi * op2_hi + ((cross_prod >> 16) & 0xffff);
*prod_lo = op1_lo * op2_lo + ((cross_prod << 16) & 0xffff0000);
}
//计算序列号,比较low,没考虑输入汉字什么乱七八遭的情况,就单纯的数字,字母应该都可以
void calcSerial(char *str, char *ret, int len)
{
long Tmp = 0;
long Num = 0x499602D2;
long Hcalc = 0;
long Lcalc = 0;
long long calc = 0;
char strTmp[50] = {};
for (int i = 0; i < len; i++)
{
Tmp += str[i];
}
mult(Tmp, Num, &Hcalc, &Lcalc);
calc |= Hcalc;
long long tmp = calc << 32;
tmp |= (unsigned)Lcalc;
//直接转化成浮点数,来转字符串,然后截掉小数点
sprintf(strTmp, "%lf", (double)tmp);
char *index = strstr(strTmp, ".");
strTmp[index - strTmp] = '\0';
strTmp[3] = '-';
strTmp[8] = '-';
memcpy(ret, strTmp, strlen(strTmp));
}
int main()
{
char str[50] = {};
char aa[50] = {};
int len = 0;
printf("输入name: ");
scanf("%s", str);
len = strlen(str);
if (len == 0)
{
printf("输入name!\n");
}
else
{
calcSerial(str, aa, len);
printf("序列号为%s\n", aa);
}
system("pause");
return 0;
}
测试结果。