算法难度:⭐⭐⭐⭐
爆破难度:⭐
信息收集
运行情况:
查壳与脱壳:
调试分析
IDA走起~
一开始调用了一个call,跟进去
这个call在是创建窗口的,这里一开始就在填充窗口类,这里有个窗口函数,跟进
老样子,在窗口函数里找nMsg=0x111,wParam=3(通过xspy查的)的分支:
首先是获取Name,判断长度,合法长度是5–0x20字节
紧接着是一个循环,处理前5个字节,生成5个字节填充到字符数组里,这里有一堆跳转就是确保生成的字节满足大小要求
接下来:再次循环前五字节,以类似的方法生成另外5字节数字填充到字符数组的后面
再往下就是获取序列号了:
序列号长度必须满足10字节要求
最后就是比对环节:
取一位序列号,取一位生成字符数组,对生成数组的字符进行处理,处理完成之后,和序列号做对比,相同则判断下一位,全部相同则成功~
注册机
注册码生成算法:
string? name = Console.ReadLine();
char[] nameCheck = new char[11];
if(name!=null && name.Length >= 5 && name.Length<=0x20)
{
// 处理前5字节
byte i = 5;
while (i >0)
{
byte cl = (byte)name[5 - i];
cl ^= 0x29;
cl += i;
if(cl<0x41 || cl > 0x5A)
{
cl = 0x52;
cl += i;
}
nameCheck[5 - i] = (char)cl;
i--;
}
// 处理后五字节
i = 5;
while (i > 0)
{
byte cl = (byte)name[5 - i];
cl ^= 0x27;
cl += i;
cl += 1;
if (cl < 0x41 || cl > 0x5A)
{
cl = 0x4D;
cl += i;
}
nameCheck[10 - i] = (char)cl;
i--;
}
// 生成序列号
char[] serial = new char[11];
i = 0;
while (i < 10)
{
byte dl = (byte)nameCheck[i];
dl += 5;
if (dl > 0x5A) dl -= 0x0d;
dl ^= 0x0c;
if (dl < 0x41)
{
dl = 0x4B;
dl += i;
}
if (dl > 0x5A)
{
dl = 0x4B;
dl -= i;
}
serial[i] = (char)dl;
i++;
}
Console.WriteLine(serial);
}
效果: