WinXp Manager V4.8.8.0算法
首先感谢tankaiha 给的Reflector下载地址,没有Reflector这个超级好的工具,
用ildasm还不知道要研究到何年何月呢,
peid V0.92 检测:Microsoft Visual C# / Basic .NET
它是用Microsoft Visual Basic .NET编写的,这可以从版本信息里看出来
首先当然是把WinXP Manager.exe拖到Reflector里,双击WinXP Manager/WinXP Manager.exe/WinXP_Manager,就可以看到WinXP_Manager名称空间里的各个类了
我想作者的编程风格很好,要不然我怎么一眼就看到了frmRegister类了呢^-^
双击frmRegister类,又会看见一大堆方法,属性,字段等东西,
找到了BtnRegistry_Click,就点它,......恐怖!
Reflector竟然把它的源代码清清楚楚的显示在我们面前,Reflector可以用IL,c#,VB.NET,Delphi四种风格显示代码,
这个软件没用用混淆器,这么好的软件,可惜
private void BtnRegistry_Click(object sender, EventArgs e)
{
if (this.WriteRegisterCode(this.txtSN.Text, this.txtUserName.Text)) //这里调用WriteRegisterCode()方法写注册码
{
MessageBox.Show("\u8bf7\u60a8\u91cd\u65b0\u542f\u52a8\u672c\u8f6f\u4ef6.", "\u5b8c\u6210", MessageBoxButtons.OK, MessageBoxIcon.Asterisk); //这里是用Unicode表示的"请您重新启动本软件"
Application.Exit();
}
else
{
MessageBox.Show("\u6ce8\u518c\u8f6f\u4ef6\u5931\u8d25, \u8bf7\u8054\u7cfb gayxq@tom.com \u6216 gayxq@163.com", "\u9519\u8bef", MessageBoxButtons.OK, MessageBoxIcon.Hand);
}
}
点WriteRegisterCode()方法,跳到这个方法上来,
它是把注册码写入注册表的,没有运算
它是重启效验,所以我进入load/main()里:
[STAThread]
public static void Main()
{
//.....略
Encrypt.MyClsIsRegister register1 = new Encrypt.MyClsIsRegister();
register1.Registered(); //用这个Registered()方法验证
register1 = null;
if (publicVarFun.IsRegistered)
{
Encrypt.MyClsRegister.DelExprie();
frmSplash splash1 = new frmSplash();
splash1.Show();
}
else
{
frmOverdue overdue1 = new frmOverdue();
overdue1.Show();
}
Application.Run();
}
到Registered()方法里看它怎么验证的
public void Registered()
{
string text1 = Encrypt.MyClsRegister.GetRegCodeValue(); //这个方法读取注册表中的注册码
string text2 = Encrypt.MyClsRegister.GetRegCodeWord(); //这个方法读取用户名
if ((StringType.StrCmp(text1, "", false) == 0) | (StringType.StrCmp(text2, "", false) == 0)) //为空就OVER
{
publicVarFun.IsRegistered = false;
}
else if (StringType.StrCmp(text1, this.FromHDSNGetRegisterCode(text2), false) != 0) //注册码和运算结果比较,经典的明码比较
{
publicVarFun.IsRegistered = false;
}
else
{
publicVarFun.IsRegistered = true;
}
}
追到FromHDSNGetRegisterCode方法里
private string FromHDSNGetRegisterCode(string strCodeWord)
{
Encrypt.MyClsEncrypt encrypt1 = new Encrypt.MyClsEncrypt(strCodeWord); // 这个有参数构造器初始化了要用到的数据
return encrypt1.Encrypt(Encrypt.MyClsRegister.GetPySerialNum()); /*用自己写的Encrypt.MyClsEncrypt类里的Encrypt方法计算,用GetPySerialNum()方法获得硬盘ID*/
}
到这个构造器里看看
public MyClsEncrypt(string strCodeWord)
{
this.strCryptMatrix = new string[0x62]; /*先初始化strCryptMatrix的长度,按照作者的目的,长度为62就可以了,不知道为什么长度0x62*/
this.CodeWord = this.EncryptCode("Chinese" + strCodeWord + publicVarFun.ainfo.Version); /*下面看EncryptCode()方法,输入参数是 ("Chinese"+用户名+版本) 的一个字符串*/
this.Matrix = "8x3p5BeabcdfghijklmnoqrstuvwyzACDEFGHIJKLMNOPQRSTUVWXYZ1246790"; //Matrix长度=62
int num1 = 1;
this.LAM = Strings.Len(this.Matrix);
this.strCryptMatrix[1] = this.Matrix;
int num3 = this.LAM;
for (int num2 = 2; num2 <= num3; num2++)
{
this.mov1 = Strings.Left(this.strCryptMatrix[num1], 1);
this.mov2 = Strings.Right(this.strCryptMatrix[num1], this.LAM - 1);
this.strCryptMatrix[num2] = this.mov2 + this.mov1;
num1++;
} //把Matrix变换62次后全放在strCryptMatrix里
}
版本信息
public string Version
{
get
{
string[] textArray1 = new string[6] { "V", StringType.FromInteger(this.myType.Assembly.GetName().Version.Major), ".", StringType.FromInteger(this.myType.Assembly.GetName().Version.Minor), ".", StringType.FromInteger(this.myType.Assembly.GetName().Version.Build) } ;
return string.Concat(textArray1);
}
}
分别是主版本4,次版本8,Build应该是内部版本号8
进入EncryptCode()方法:
private string EncryptCode(string strEncrypted)
{
string text1;
MD5CryptoServiceProvider provider1 = new MD5CryptoServiceProvider(); //用现成的MD5类
UTF8Encoding encoding1 = new UTF8Encoding();
byte[] buffer1 = provider1.ComputeHash(encoding1.GetBytes(strEncrypted)); //MD5加密
byte[] buffer2 = buffer1;
for (int num2 = 0; num2 < buffer2.Length; num2++)
{
byte num1 = buffer2[num2];
text1 = text1 + StringType.FromByte(num1); //转换为字符串
}
return StringType.FromInteger(Math.Abs(text1.GetHashCode())); /*Math.Abs()取正值,GetHashCode()方法,说是得到希哈代码,在.NET里几乎每个实例都有这个方法*/
}
追到Encrypt方法里,算法就在这里:
public string Encrypt(string strEncrypted) //硬盘ID
{
string text2;
try
{
string text3 = strEncrypted;
this.LS2E = strEncrypted.Length; //硬盘ID长度
this.LCW = this.CodeWord.Length;
this.EncryptedLetter = "";
this.EncryptedString = "";
int num2 = 1;
int num5 = this.LS2E - 1;
for (int num1 = 1; num1 <= num5; num1++)
{
string text1 = Strings.Mid(text3, num1, 1); //依次取ID字符
this.MP = Strings.InStr(1, this.Matrix, text1, CompareMethod.Binary); //字符在Matrix里的位置
this.CWL = Strings.Mid(this.CodeWord, num2, 1); //依次取CodeWord的字符
int num4 = this.LAM;
for (int num3 = 1; num3 <= num4; num3++)
{
if (StringType.StrCmp(Strings.Mid(this.strCryptMatrix[num3], this.MP, 1), this.CWL, false) == 0) //ID字符在Matrix中的位置就是strCryptMatrix[num3]的相应位置字符
{
this.EncryptedLetter = Strings.Left(this.strCryptMatrix[num3], 1); //最左端字符
this.EncryptedString = this.EncryptedString + this.EncryptedLetter; //连接上面的字符
break;
}
}
num2++;
if (num2 > this.LCW)
{
num2 = 1;
}
}
text2 = Strings.Trim(this.EncryptedString).ToUpper();
}
catch (Exception exception1)
{
ProjectData.SetProjectError(exception1);
ProjectData.ClearProjectError();
}
return text2;
}
算法总结:
得到MD5("Chinese"+用户名+版本信息)散列,转换为字符串,叫CodeWord吧,
重新组合这个字符串,例如字符串"12345"放在strCryptMatrix[]里
strCryptMatrix[0]="12345"
strCryptMatrix[1]="23451"
strCryptMatrix[2]="34512"
strCryptMatrix[3]="45123"
准备下次用
这时候,记住strEncrypted是硬盘ID,CodeWord是和注册名有关的加密结果,字符串Matrix="8x3p5BeabcdfghijklmnoqrstuvwyzACDEFGHIJKLMNOPQRSTUVWXYZ1246790"
string数组strCryptMatrix[]放着CodeWord变形的结果
LAM是Matrix的长度为62
下面:
依次取ID,查找字符在Matrix的位置,记做MP,
依次取CodeWord,记做CWL
如果CWL在strCryptMatrix[i]中的位置==MP
就在结果上连接strCryptMatrix[i]的第一个字符
循环次数=硬盘ID的长度-1
去空格,大写
到这种地步,应该说编写注册机应该很容易了,还有版本信息,
单击WinXP Manager,就是那个最高级的,就可以看到它的版本信息了:
[assembly: AssemblyVersion("4.8.8.0")]
但这还不是软件计算时用到的字符串,软件计算时的版本信息字符串是"V4.8.8",
我猜它猜了两天!!!!!!!
它的注册信息保存在HKEY_CURRENT_USER\Software\Yanicsoft\WinXP Manager下
写个注册机留念:
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)