吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 510|回复: 16
上一主题 下一主题
收起左侧

[.NET逆向] 逆向分析某排八字软件的过程

  [复制链接]
跳转到指定楼层
楼主
GDExecW 发表于 2026-6-23 18:48 回帖奖励
本帖最后由 GDExecW 于 2026-6-23 18:50 编辑

逆向排八字程序过程

信息

  • 网:aHR0cDovL25mYmF6aS5jb20vcWl0YS9Eb3dubG9hZC5odG0=
  • 文件名:排八字.exe
  • 大小:3,249,664 字节

初步分析

看到了这个东西要安装 .NET 运行时,最近想找 .NET 练手,正好来了兴趣(

这个软件如果需要使用功能的话,就要注册,否则无法使用功能。

使用 EXE Info PE 初步分析,该程序为 .NET 程序集,并且没有壳。

点 "执行" 的时候,提示未注册……

破解过程

使用 dnSpy 打开过后,搜索字符串 "您还没有注册本软件",如图所示。

发现在 frmMain 类中有个字符串,和我们在程序中看到的字符串是相同的,因此查找引用。

最终在一个按钮的回调中找到了,一个巨大的 if 里边儿,如果 if 中的条件语句为 false,就跳转到了 else 分支,此时程序的就会显示未注册的提示。

一直往上找,找到 if 的条件语句处,这个 if 判断了布尔型变量 regInfoFlag2 是否为 true,如果不是 true 则跳转进 else 分支,显示未注册的消息,如图所示。

if 内就是 "执行" 按钮中的关键逻辑,爆破的话就是把 regInfoFlag2 想办法赋值为 true 即可,但是不想爆破(

(前面我试着去爆破,结果编译错误了,估计是因为 VB.NET 被反编译成 C# 的问题,又或者是程序混淆了?)

所以就去翻了一下 RegData 类,这个类主要管用户的注册。

在注册窗口中随便输入一个数据,返回 "注册码不对!",在 dnSpy 中搜索这个字符串,发现该字符串位于方法 cmdOK_Click 中,所以呢,该函数应该为确定按钮的回调。

以下为 cmdOK_Click 方法的反编译:

private void cmdOK_Click(object eventSender, EventArgs eventArgs)
{
        int num;
        int num7;
        object obj;
        try
        {
                IL_0002:
                ProjectData.ClearProjectError();
                num = -2;
                IL_000B:
                int num2 = 2;
                this.getTapTimes();
                IL_0014:
                num2 = 3;
                bool flag = this.count >= 7;
                if (!flag)
                {
                        goto IL_0037;
                }
                IL_0028:
                num2 = 4;
                this.count = 1;
                IL_0031:
                goto IL_0CF5;
                IL_0037:
                IL_0038:
                num2 = 7;
                bool flag2 = Strings.Len(ModPCAndRegcode.gstrPCNumber) == 0;
                if (!flag2)
                {
                        goto IL_0062;
                }
                IL_004D:
                num2 = 8;
                Interaction.MsgBox("机器码不能为空,如不能解决,请与南方联系。", MsgBoxStyle.OkOnly, null);
                IL_005C:
                goto IL_0CF5;
                IL_0062:
                IL_0063:
                num2 = 11;
                string text = Conversions.ToString(MyProject.Computer.Registry.GetValue("HKEY_CURRENT_USER\\Software\\NanfangSoft .net\\PaiBazi737", "PCNB", ""));
                IL_008B:
                num2 = 12;
                string text2 = Strings.Trim(this.txtPcNum.Text);
                IL_009F:
                num2 = 13;
                string text3 = "";
                IL_00A9:
                num2 = 14;
                string text4 = Strings.Trim(this.txtRegNum.Text);
                IL_00BE:
                num2 = 15;
                bool flag3 = Operators.CompareString(text4, "25096102", true) == 0;
                if (!flag3)
                {
                        goto IL_0188;
                }
                IL_00DA:
                num2 = 16;
                Module1.Passflag = false;
                IL_00E3:
                num2 = 17;
                RegData.RegInfoFlag = false;
                IL_00EC:
                num2 = 18;
                this.txtRegNum.ReadOnly = false;
                IL_00FC:
                num2 = 19;
                this.txtRegNum.BackColor = Color.White;
                IL_0110:
                num2 = 20;
                string text5 = Strings.UCase("12345678");
                string text6 = "2020";
                string text7 = "10";
                string text8 = "10";
                RegData.FuncWriteRegFile(ref ModPCAndRegcode.gstrPCNumber, ref text5, ref text6, ref text7, ref text8);
                IL_0147:
                num2 = 21;
                File.WriteAllText(RegData.gStrSystemDir + "\\token.dll", "asmdhfkahfkas");
                IL_0164:
                num2 = 22;
                this.txtOk.Text = "输入的数子正确";
                IL_0178:
                num2 = 23;
                this.IntRegOk = 0;
                IL_0182:
                goto IL_0CF5;
                IL_0188:
                IL_0189:
                num2 = 26;
                bool flag4 = Operators.CompareString(text4, "34771385", true) == 0;
                if (!flag4)
                {
                        goto IL_01F1;
                }
                IL_01A2:
                num2 = 27;
                bool flag5 = File.Exists(RegData.gStrSystemDir + "\\token.dll");
                if (!flag5)
                {
                        goto IL_01D7;
                }
                IL_01BF:
                num2 = 28;
                File.Delete(RegData.gStrSystemDir + "\\token.dll");
                IL_01D7:
                num2 = 29;
                this.txtOk.Text = "删除34771385,再输入注册码,点击确定。";
                IL_01EB:
                goto IL_0CF5;
                IL_01F1:
                IL_01F2:
                num2 = 32;
                bool flag6 = File.Exists(RegData.gStrSystemDir + "\\token.dll");
                if (!flag6)
                {
                        goto IL_0229;
                }
                IL_020F:
                num2 = 33;
                this.txtOk.Text = "输入的注册码不对......";
                IL_0223:
                goto IL_0CF5;
                IL_0229:
                IL_022A:
                num2 = 36;
                bool passflag = Module1.Passflag;
                if (!passflag)
                {
                        goto IL_023E;
                }
                IL_0238:
                goto IL_0CF5;
                IL_023E:
                IL_023F:
                num2 = 39;
                bool flag7 = (text4.Length < 14) | (text4.Length > 15);
                if (!flag7)
                {
                        goto IL_0279;
                }
                IL_025F:
                num2 = 40;
                this.txtOk.Text = "注册码不对!";
                IL_0273:
                goto IL_0CF5;
                IL_0279:
                IL_027A:
                num2 = 43;
                string text9 = Strings.Mid(text4, 1, 4) + Strings.Mid(text4, 9, 4);
                IL_0297:
                num2 = 44;
                string text10 = Strings.Mid(text4, 5, 1);
                IL_02A5:
                num2 = 45;
                string text11 = Strings.Mid(text4, 6, 1);
                IL_02B3:
                num2 = 46;
                string text12 = Strings.Mid(text4, 7, 1);
                IL_02C1:
                num2 = 47;
                string text13 = Strings.Mid(text4, 8, 1);
                IL_02CF:
                num2 = 48;
                string text14 = Strings.Mid(text4, 13, 1);
                IL_02DE:
                num2 = 49;
                string text15 = Strings.Mid(text4, 14, 1);
                IL_02ED:
                num2 = 50;
                bool flag8 = (Operators.CompareString(text10, "6", true) == 0) | (Operators.CompareString(text10, "7", true) == 0) | (Operators.CompareString(text10, "B", true) == 0) | (Operators.CompareString(text10, "b", true) == 0);
                if (!flag8)
                {
                        goto IL_0343;
                }
                IL_0339:
                num2 = 51;
                text10 = "1";
                IL_0343:
                num2 = 52;
                bool flag9 = (Operators.CompareString(text10, "8", true) == 0) | (Operators.CompareString(text10, "9", true) == 0) | (Operators.CompareString(text10, "C", true) == 0) | (Operators.CompareString(text10, "c", true) == 0);
                if (!flag9)
                {
                        goto IL_0399;
                }
                IL_038F:
                num2 = 53;
                text10 = "2";
                IL_0399:
                num2 = 54;
                bool flag10 = (Operators.CompareString(text10, "D", true) == 0) | (Operators.CompareString(text10, "d", true) == 0);
                if (!flag10)
                {
                        goto IL_03CD;
                }
                IL_03C3:
                num2 = 55;
                text10 = "3";
                IL_03CD:
                num2 = 56;
                bool flag11 = (Operators.CompareString(text11, "A", true) == 0) | (Operators.CompareString(text11, "a", true) == 0);
                if (!flag11)
                {
                        goto IL_0401;
                }
                IL_03F7:
                num2 = 57;
                text11 = "0";
                IL_0401:
                num2 = 58;
                bool flag12 = (Operators.CompareString(text11, "B", true) == 0) | (Operators.CompareString(text11, "b", true) == 0);
                if (!flag12)
                {
                        goto IL_0435;
                }
                IL_042B:
                num2 = 59;
                text11 = "1";
                IL_0435:
                num2 = 60;
                bool flag13 = (Operators.CompareString(text11, "C", true) == 0) | (Operators.CompareString(text11, "c", true) == 0);
                if (!flag13)
                {
                        goto IL_0469;
                }
                IL_045F:
                num2 = 61;
                text11 = "2";
                IL_0469:
                num2 = 62;
                bool flag14 = (Operators.CompareString(text11, "D", true) == 0) | (Operators.CompareString(text11, "d", true) == 0);
                if (!flag14)
                {
                        goto IL_049D;
                }
                IL_0493:
                num2 = 63;
                text11 = "3";
                IL_049D:
                num2 = 64;
                bool flag15 = (Operators.CompareString(text11, "E", true) == 0) | (Operators.CompareString(text11, "e", true) == 0);
                if (!flag15)
                {
                        goto IL_04D1;
                }
                IL_04C7:
                num2 = 65;
                text11 = "4";
                IL_04D1:
                num2 = 66;
                bool flag16 = (Operators.CompareString(text11, "F", true) == 0) | (Operators.CompareString(text11, "f", true) == 0);
                if (!flag16)
                {
                        goto IL_0505;
                }
                IL_04FB:
                num2 = 67;
                text11 = "5";
                IL_0505:
                num2 = 68;
                bool flag17 = (Operators.CompareString(text11, "G", true) == 0) | (Operators.CompareString(text11, "g", true) == 0);
                if (!flag17)
                {
                        goto IL_0539;
                }
                IL_052F:
                num2 = 69;
                text11 = "6";
                IL_0539:
                num2 = 70;
                bool flag18 = (Operators.CompareString(text11, "H", true) == 0) | (Operators.CompareString(text11, "h", true) == 0);
                if (!flag18)
                {
                        goto IL_056D;
                }
                IL_0563:
                num2 = 71;
                text11 = "7";
                IL_056D:
                num2 = 72;
                bool flag19 = (Operators.CompareString(text11, "J", true) == 0) | (Operators.CompareString(text11, "j", true) == 0);
                if (!flag19)
                {
                        goto IL_05A1;
                }
                IL_0597:
                num2 = 73;
                text11 = "8";
                IL_05A1:
                num2 = 74;
                bool flag20 = (Operators.CompareString(text11, "K", true) == 0) | (Operators.CompareString(text11, "k", true) == 0);
                if (!flag20)
                {
                        goto IL_05D5;
                }
                IL_05CB:
                num2 = 75;
                text11 = "9";
                IL_05D5:
                num2 = 76;
                string text16 = "20" + text10 + text11;
                IL_05E8:
                num2 = 77;
                bool flag21 = (Operators.CompareString(text12, "6", true) == 0) | (Operators.CompareString(text12, "7", true) == 0) | (Operators.CompareString(text12, "B", true) == 0) | (Operators.CompareString(text12, "b", true) == 0);
                if (!flag21)
                {
                        goto IL_063E;
                }
                IL_0634:
                num2 = 78;
                text12 = "1";
                IL_063E:
                num2 = 79;
                bool flag22 = (Operators.CompareString(text12, "4", true) == 0) | (Operators.CompareString(text12, "5", true) == 0) | (Operators.CompareString(text12, "A", true) == 0) | (Operators.CompareString(text12, "a", true) == 0);
                if (!flag22)
                {
                        goto IL_0694;
                }
                IL_068A:
                num2 = 80;
                text12 = "0";
                IL_0694:
                num2 = 81;
                bool flag23 = (Operators.CompareString(text13, "A", true) == 0) | (Operators.CompareString(text13, "a", true) == 0);
                if (!flag23)
                {
                        goto IL_06C8;
                }
                IL_06BE:
                num2 = 82;
                text13 = "0";
                IL_06C8:
                num2 = 83;
                bool flag24 = (Operators.CompareString(text13, "B", true) == 0) | (Operators.CompareString(text13, "b", true) == 0);
                if (!flag24)
                {
                        goto IL_06FC;
                }
                IL_06F2:
                num2 = 84;
                text13 = "1";
                IL_06FC:
                num2 = 85;
                bool flag25 = (Operators.CompareString(text13, "C", true) == 0) | (Operators.CompareString(text13, "c", true) == 0);
                if (!flag25)
                {
                        goto IL_0730;
                }
                IL_0726:
                num2 = 86;
                text13 = "2";
                IL_0730:
                num2 = 87;
                bool flag26 = (Operators.CompareString(text13, "D", true) == 0) | (Operators.CompareString(text13, "d", true) == 0);
                if (!flag26)
                {
                        goto IL_0764;
                }
                IL_075A:
                num2 = 88;
                text13 = "3";
                IL_0764:
                num2 = 89;
                bool flag27 = (Operators.CompareString(text13, "E", true) == 0) | (Operators.CompareString(text13, "e", true) == 0);
                if (!flag27)
                {
                        goto IL_0798;
                }
                IL_078E:
                num2 = 90;
                text13 = "4";
                IL_0798:
                num2 = 91;
                bool flag28 = (Operators.CompareString(text13, "F", true) == 0) | (Operators.CompareString(text13, "f", true) == 0);
                if (!flag28)
                {
                        goto IL_07CC;
                }
                IL_07C2:
                num2 = 92;
                text13 = "5";
                IL_07CC:
                num2 = 93;
                bool flag29 = (Operators.CompareString(text13, "G", true) == 0) | (Operators.CompareString(text13, "g", true) == 0);
                if (!flag29)
                {
                        goto IL_0800;
                }
                IL_07F6:
                num2 = 94;
                text13 = "6";
                IL_0800:
                num2 = 95;
                bool flag30 = (Operators.CompareString(text13, "H", true) == 0) | (Operators.CompareString(text13, "h", true) == 0);
                if (!flag30)
                {
                        goto IL_0834;
                }
                IL_082A:
                num2 = 96;
                text13 = "7";
                IL_0834:
                num2 = 97;
                bool flag31 = (Operators.CompareString(text13, "J", true) == 0) | (Operators.CompareString(text13, "j", true) == 0);
                if (!flag31)
                {
                        goto IL_0868;
                }
                IL_085E:
                num2 = 98;
                text13 = "8";
                IL_0868:
                num2 = 99;
                bool flag32 = (Operators.CompareString(text13, "K", true) == 0) | (Operators.CompareString(text13, "k", true) == 0);
                if (!flag32)
                {
                        goto IL_089C;
                }
                IL_0892:
                num2 = 100;
                text13 = "9";
                IL_089C:
                num2 = 101;
                string text17 = text12 + text13;
                IL_08AA:
                num2 = 102;
                bool flag33 = (Operators.CompareString(text14, "A", true) == 0) | (Operators.CompareString(text14, "a", true) == 0) | (Operators.CompareString(text14, "4", true) == 0) | (Operators.CompareString(text14, "5", true) == 0);
                if (!flag33)
                {
                        goto IL_0900;
                }
                IL_08F6:
                num2 = 103;
                text14 = "0";
                IL_0900:
                num2 = 104;
                bool flag34 = (Operators.CompareString(text14, "B", true) == 0) | (Operators.CompareString(text14, "b", true) == 0) | (Operators.CompareString(text14, "6", true) == 0) | (Operators.CompareString(text14, "7", true) == 0);
                if (!flag34)
                {
                        goto IL_0956;
                }
                IL_094C:
                num2 = 105;
                text14 = "1";
                IL_0956:
                num2 = 106;
                bool flag35 = (Operators.CompareString(text14, "C", true) == 0) | (Operators.CompareString(text14, "c", true) == 0) | (Operators.CompareString(text14, "8", true) == 0) | (Operators.CompareString(text14, "9", true) == 0);
                if (!flag35)
                {
                        goto IL_09AC;
                }
                IL_09A2:
                num2 = 107;
                text14 = "2";
                IL_09AC:
                num2 = 108;
                string text18 = text14 + text15;
                IL_09BA:
                num2 = 109;
                bool flag36 = (text4.Length == 15) & (Operators.CompareString(Strings.Mid(text4, 15, 1), "1", true) != 0) & (Operators.CompareString(Strings.Mid(text4, 15, 1), "2", true) != 0) & (Operators.CompareString(Strings.Mid(text4, 15, 1), "3", true) != 0);
                if (!flag36)
                {
                        goto IL_0A33;
                }
                IL_0A19:
                num2 = 110;
                this.txtOk.Text = "注册码不对!";
                IL_0A2D:
                goto IL_0CF5;
                IL_0A33:
                IL_0A34:
                num2 = 113;
                bool flag37 = (text4.Length == 15) & ((Operators.CompareString(Strings.Mid(text4, 15, 1), "1", true) == 0) | (Operators.CompareString(Strings.Mid(text4, 15, 1), "2", true) == 0) | (Operators.CompareString(Strings.Mid(text4, 15, 1), "3", true) == 0));
                if (!flag37)
                {
                        goto IL_0ADF;
                }
                IL_0A93:
                num2 = 114;
                bool flag38 = MyProject.Computer.FileSystem.FileExists(RegData.gStrSystemDir + "\\syspbaz737.dll");
                if (!flag38)
                {
                        goto IL_0ADD;
                }
                IL_0ABA:
                num2 = 115;
                MyProject.Computer.FileSystem.DeleteFile(RegData.gStrSystemDir + "\\syspbaz737.dll");
                IL_0ADC:
                IL_0ADD:
                IL_0ADE:
                IL_0ADF:
                IL_0AE0:
                num2 = 118;
                int num3 = Conversions.ToInteger(text16);
                IL_0AEC:
                num2 = 119;
                int num4 = Conversions.ToInteger(text17);
                IL_0AF8:
                num2 = 120;
                int num5 = Conversions.ToInteger(text18);
                IL_0B04:
                num2 = 121;
                bool flag39 = (num5 < 1) | (num5 > 31) | (num3 < 2021) | (num3 > 2036) | (num4 < 1) | (num4 > 12) | (num3 < DateAndTime.Now.Year) | ((num3 == DateAndTime.Now.Year) & (num4 < DateAndTime.Now.Month));
                if (!flag39)
                {
                        goto IL_0B8D;
                }
                IL_0B73:
                num2 = 122;
                this.txtOk.Text = "注册码不对!";
                IL_0B87:
                goto IL_0CF5;
                IL_0B8D:
                IL_0B8E:
                num2 = 125;
                bool flag40 = this.IntRegOk == 1;
                if (!flag40)
                {
                        goto IL_0BBA;
                }
                IL_0BA0:
                num2 = 126;
                this.cmdExit_Click(this.cmdExit, new EventArgs());
                IL_0BB5:
                goto IL_0CF5;
                IL_0BBA:
                num2 = 128;
                bool flag41 = Operators.CompareString(this.txtName.Text, "", true) == 0;
                if (!flag41)
                {
                        goto IL_0BFC;
                }
                IL_0BDF:
                num2 = 129;
                this.txtOk.Text = "您没有输入姓名。";
                IL_0BF6:
                goto IL_0CF5;
                IL_0BFC:
                IL_0BFD:
                num2 = 132;
                bool flag42 = Strings.Len(text9) == 0;
                if (!flag42)
                {
                        IL_0C36:
                        num2 = 136;
                        bool flag43 = Module1.yanzheng(ref text2, ref text9) & !File.Exists(RegData.gStrSystemDir + "\\syspbaz737.dll");
                        if (!flag43)
                        {
                                IL_0CDB:
                                num2 = 142;
                                this.txtOk.Text = "注册码不对!";
                                IL_0CF2:
                                goto IL_0CF3;
                        }
                        IL_0C63:
                        num2 = 137;
                        MyProject.Computer.Registry.SetValue("HKEY_CURRENT_USER\\Software\\NanfangSoft .net\\PaiBazi737", "Name", this.txtName.Text);
                        IL_0C8E:
                        num2 = 138;
                        text8 = Strings.UCase(text9);
                        RegData.FuncWriteRegFile(ref text2, ref text8, ref text16, ref text17, ref text18);
                        IL_0CAD:
                        num2 = 139;
                        RegData.RegInfoFlag = true;
                        IL_0CB9:
                        num2 = 140;
                        this.txtOk.Text = "注册成功!点击'退出'。" + text3;
                        IL_0CD7:
                        IL_0CF3:
                        IL_0CF4:
                        goto IL_0CF5;
                }
                IL_0C13:
                num2 = 133;
                this.txtOk.Text = "您没有输入注册码。";
                IL_0C2A:
                IL_0CF5:
                goto IL_0F93;
                IL_0036:
                goto IL_0037;
                IL_0061:
                goto IL_0062;
                IL_0187:
                goto IL_0188;
                IL_01F0:
                goto IL_01F1;
                IL_0228:
                goto IL_0229;
                IL_023D:
                goto IL_023E;
                IL_0278:
                goto IL_0279;
                IL_0A32:
                goto IL_0A33;
                IL_0B8C:
                goto IL_0B8D;
                IL_0BFB:
                goto IL_0BFC;
                IL_0C2F:
                goto IL_0CF4;
                IL_0CFA:
                int num6 = num7 + 1;
                num7 = 0;
                @switch(ICSharpCode.Decompiler.ILAst.ILLabel[], num6);
                IL_0F4C:
                goto IL_0F88;
                IL_0F4E:
                num7 = num2;
                @switch(ICSharpCode.Decompiler.ILAst.ILLabel[], (num > -2) ? num : 1);
                IL_0F66:;
        }
        catch when (endfilter((obj is Exception) & (num != 0) & (num7 == 0)))
        {
                Exception ex = (Exception)obj2;
                goto IL_0F4E;
        }
        IL_0F88:
        throw ProjectData.CreateProjectError(-2146828237);
        IL_0F93:
        if (num7 != 0)
        {
                ProjectData.ClearProjectError();
        }
}

各种标签和跳转,不知道是混淆了,还是 VB 反汇编就是这样……

反正关键的有一句:

yanzheng(ref text2, ref text9)

调用了 yanzheng 方法来校验注册码,该方法代码如下:

(话说,这个名字取得好随便啊……

public static bool yanzheng(ref string pcn, ref string psw)
{
    bool flag = (Operators.CompareString(pcn, "", true) == 0) | (Operators.CompareString(psw, "", true) == 0);
    bool flag2;
    if (flag)
    {
        flag2 = false;
    }
    else
    {
        ModPCAndRegcode.funcGetZhucema(ref pcn);
        bool flag3 = Operators.CompareString(Strings.UCase(ModPCAndRegcode.gstrZhucema), Strings.UCase(psw), true) == 0;
        if (flag3)
        {
            ModPCAndRegcode.gstrZhucema = "a@^*(^*ga$(&%io";
            flag2 = true;
        }
        else
        {
            flag2 = false;
        }
    }
    return flag2;
}

以下为一些辅助函数:

public static void funcGetZhucema(ref string PCcode)
{
    string text = Strings.Replace(PCcode, " ", "", 1, -1, CompareMethod.Text);
    text = Strings.Replace(text, "-", "", 1, -1, CompareMethod.Text);
    text = Strings.Replace(text, "-", "", 1, -1, CompareMethod.Text);
    text = Strings.Replace(text, ",", "", 1, -1, CompareMethod.Text);
    text = Strings.Replace(text, "\u3000", "", 1, -1, CompareMethod.Text);
    bool flag = text.Length > 10;
    if (flag)
    {
        text = Strings.Left(text, 10) + Strings.Right(text, 5);
    }
    string falseMd = ModPCAndRegcode.getFalseMd5(text);
    string text2 = modMD5.md5(ref falseMd);
    ModPCAndRegcode.gstrZhucema = ModPCAndRegcode.funcGetNumber_20100601(ref text2);
}

public static string funcGetNumber_20100601(ref string tstr)
{
    bool flag = Strings.Len(tstr) < 30;
    checked
    {
        string text;
        if (flag)
        {
            Interaction.MsgBox("本程序在您的电脑上无法注册,请与南方联系。", MsgBoxStyle.OkOnly, null);
            text = "";
        }
        else
        {
            string text2 = "";
            string text3 = "";
            text2 = string.Concat(new string[]
            {
                text2,
                Strings.Mid(tstr, 6, 2),
                Strings.Mid(tstr, 17, 2),
                Strings.Mid(tstr, 5, 2),
                Strings.Mid(tstr, 1, 2),
                Strings.Mid(tstr, 9, 2),
                Strings.Mid(tstr, 13, 2)
            });
            int num = 1;
            do
            {
                bool flag2 = Versioned.IsNumeric(Strings.Mid(text2, num, 1));
                if (flag2)
                {
                    text3 += Conversions.ToString(Conversions.ToInteger(Strings.Mid(text2, num, 1)) ^ 4);
                }
                else
                {
                    string text4 = Conversions.ToString(Strings.Chr(Strings.Asc(Strings.Mid(text2, num, 1)) + 20 - num));
                    bool flag3 = Operators.CompareString(text4, "O", true) == 0;
                    if (flag3)
                    {
                        text3 += "0";
                    }
                    else
                    {
                        text3 += text4;
                    }
                }
                num++;
            }
            while (num <= 12);
            text3 = Strings.Replace(text3, "0", "3", 1, -1, CompareMethod.Text);
            text = Strings.Mid(text3, 2, 2) + Strings.Mid(text3, 6, 2) + Strings.Mid(text3, 5, 2) + Strings.Mid(text3, 9, 2);
        }
        return text;
    }
}

public static string getFalseMd5(string strCode)
{
    int length = strCode.Length;
    long num = 0L;
    bool flag = length > 0;
    checked
    {
        string text2;
        if (flag)
        {
            int num2 = length - 1;
            for (int i = 0; i <= num2; i++)
            {
                int num3 = Strings.Asc(strCode.Substring(i, 1));
                int num4 = num3 + 7;
                int num5 = num3 * 5;
                num += unchecked((long)ModPCAndRegcode.md5_a(num3, num4, num5));
                num += unchecked((long)ModPCAndRegcode.md5_b(num3, num4, num5));
                num += unchecked((long)ModPCAndRegcode.md5_c(num3, num4, num5));
                num *= unchecked((long)ModPCAndRegcode.md5_d(num3, num4, num5)) + 12L;
                bool flag2 = num > 100000000L;
                if (flag2)
                {
                    num = Conversions.ToLong(Strings.Right(num.ToString(), 7));
                }
            }
            string text = num.ToString();
            bool flag3 = text.Length >= 6;
            if (flag3)
            {
                text2 = Strings.Right(text, 6);
            }
            else
            {
                text2 = (num + 523109L).ToString();
            }
        }
        return text2;
    }
}

那些 md5_ 好像是自定义的校验,混淆用的吧?

根据以上的代码,我们就可以逆向注册码验证的所有逻辑了。

机器码生成逻辑

程序运行时,会从 %SystemDir%\mspcnumfirst.dll 读取加密的机器码。如果文件不存在或读取失败,则重新生成:

  1. 获取硬件信息(下面是生成的优先级):

    • 优先读取主板序列号,提取其中的数字部分
    • 如果主板序列号无效,则读取硬盘物理序列号,提取数字部分
    • 如果硬盘序列号无效,则读取磁盘驱动器型号,提取数字部分
    • 如果以上都无效,则使用CPU ID的后5位
  2. 生成5位硬件码

    • 从提取的数字中取后5位
    • 如果不足5位,在前面补数字(9、98、987、9876)直到满5位
    • 如果最终仍为空,则使用默认值 "55895"
    • 根据硬件来源,在末尾添加标识位:硬盘→1,主板→2,磁盘驱动器→3,CPU→4
  3. 组装完整机器码

    • 格式:{硬件码}-{CPU后5位}-{OS版本前5位}-40738
    • 示例:55895-33133-55225-40738
  4. 保存机器码

    • 使用简单加密(每个字符ASCII码减15)后保存到 mspcnumfirst.dll
    • 设置文件属性为隐藏和系统文件

注册码核心提取逻辑

当用户点击"确定"按钮验证注册码时,程序会使用当前机器码生成正确的注册码:

  1. 清理机器码

    • 移除所有空格、短横线(-)、全角短横线(-)、逗号(,)、全角空格( )
    • 示例:55895-33133-55225-40738 - 55895331335522540738
  2. 截取处理

    • 如果清理后的机器码长度超过10位,则取前10位 + 后5位
    • 示例:55895331335522540738 - 5589533133 + 40738 = 558953313340738
  3. 自定义混淆(getFalseMd5)

    • 遍历截取后的字符串的每一个字符
    • 对每个字符的ASCII码进行一系列位运算:
      • 计算 a = ascii + 7
      • 计算 b = ascii * 5
      • 累加四个自定义函数的结果:
      • 函数A:(ascii << 2) | (a & b)
      • 函数B:ascii & a & ((b << 3) | a)
      • 函数C:(ascii & (a << 2)) | ((b << 3) & a)
      • 函数D:((ascii << 4) & (a << 2) & ((b << 2) | a)) + 12
      • 将累加结果乘以函数D的结果
      • 如果累加值超过1亿,只保留后7位
    • 最终结果转为字符串:
      • 如果长度≥6位,取后6位
      • 如果长度<6位,加上523109后作为结果
  4. 标准MD5加密

    • 对混淆结果进行标准MD5哈希,得到32位十六进制字符串
  5. 转换为8位注册码(funcGetNumber_20100601)

    • 从MD5字符串的特定位置提取字符,组成12位临时字符串:
      • 第6-7位 + 第17-18位 + 第5-6位 + 第1-2位 + 第9-10位 + 第13-14位
    • 逐字符转换这12位:
      • 如果是数字:将该数字与4进行异或运算
      • 如果是字母:将ASCII码加20再减当前位置,然后转为字符;如果结果是"O"则改为"0"
    • 将结果中的所有"0"替换为"3"
    • 从转换后的字符串中提取4组2位字符,组成最终8位注册码:
      • 第2-3位 + 第6-7位 + 第5-6位 + 第9-10位

最终得到8位注册码核心,例如:3151Q546

注册码组装逻辑

用户需要输入的完整注册码为 14位或15位,由三部分组成:

1. 8位核心码

就是上面生成的8位注册码,但需要拆分成两部分:

  • 第1-4位:核心码的前4位
  • 第9-12位:核心码的后4位

2. 6位日期编码

用于设置软件有效期,需要将年月日编码成6位字符。注意:第6、8、14位直接使用数字,不需要映射为字母。

年份编码(第5-6位)

  • 取年份的后两位(如2026年取"26")
  • 第5位(十位)映射规则:
    • 6、7、B、b - 对应数字 1
    • 8、9、C、c - 对应数字 2
    • D、d - 对应数字 3
  • 第6位(个位):直接使用数字(0-9)

月份编码(第7-8位)

  • 第7位(十位)映射规则:
    • 6、7、B、b - 对应数字 1
    • 4、5、A、a - 对应数字 0
  • 第8位(个位):直接使用数字(0-9)

日期编码(第13-14位)

  • 第13位(十位)映射规则:
    • A、a、4、5 - 对应数字 0
    • B、b、6、7 - 对应数字 1
    • C、c、8、9 - 对应数字 2
  • 第14位(个位):直接使用数字(0-9)

重要:第13-14位解码后必须都是纯数字(0-9),因为程序会执行 Conversions.ToInteger(text18),其中 text18 = text14 + text15。如果包含字母,转换会抛出异常导致注册失败。

3. 可选版本位(第15位)

可以是 123,表示版本标识。

注册码验证逻辑

当用户输入完整注册码后,程序会:

  1. 检查特殊注册码

    • 25096102(作为8位核心码):无限期注册,写入 token.dll
    • 34771385(作为8位核心码):删除 token.dll,重置注册状态
  2. 检查 token.dll:如果存在,直接拒绝所有注册码

  3. 检查 Passflag:如果为 true,跳过验证

  4. 检查注册码长度:必须为14或15位

  5. 提取8位核心码:取第1-4位 + 第9-12位

  6. 解码日期

    • 从第5-8位解码出年份和月份
    • 从第13-14位解码出日期
    • 第13-14位必须都是数字
  7. 验证核心码:使用当前机器码重新生成8位核心码,与用户输入的对比(不区分大小写)

  8. 验证日期有效性

    • 年份:2021-2036
    • 月份:1-12
    • 日期:1-31
    • 不能早于当前日期
  9. 全部通过:保存注册信息到注册表,注册成功

Keygen 编写

根据以上逻辑,可以编写 Keygen 生成正确的注册码。

Keygen 代码

我的电脑上暂时还没有安装 C# 的环境,因此我就用 C++ 写吧(

#include <iostream>
#include <string>
#include <sstream>
#include <iomanip>
#include <vector>
#include <algorithm>
#include <cctype>
#include <windows.h>
#include <wincrypt.h>

#pragma comment(lib, "advapi32.lib")

using namespace std; // std:: 太麻烦了(

string MD5Hash(const string& input)
{
    HCRYPTPROV hProv = 0;
    HCRYPTHASH hHash = 0;
    BYTE rgbHash[16];
    DWORD cbHash = 16;
    string result;

    if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
        return "";

    if (!CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash))
    {
        CryptReleaseContext(hProv, 0);
        return "";
    }

    if (!CryptHashData(hHash, (const BYTE*)input.c_str(), (DWORD)input.length(), 0))
    {
        CryptDestroyHash(hHash);
        CryptReleaseContext(hProv, 0);
        return "";
    }

    if (!CryptGetHashParam(hHash, HP_HASHVAL, rgbHash, &cbHash, 0))
    {
        CryptDestroyHash(hHash);
        CryptReleaseContext(hProv, 0);
        return "";
    }

    stringstream ss;
    for (DWORD i = 0; i < cbHash; i++)
        ss << hex << setw(2) << setfill('0') << (int)rgbHash[i];

    CryptDestroyHash(hHash);
    CryptReleaseContext(hProv, 0);
    return ss.str();
}

int md5_a(int a, int b, int c)
{
    return (a << 2) | (b & c);
}

int md5_b(int a, int b, int c)
{
    return a & c & ((b << 3) | c);
}

int md5_c(int a, int b, int c)
{
    return (a & (c << 2)) | ((b << 3) & c);
}

int md5_d(int a, int b, int c)
{
    return (a << 4) & (c << 2) & ((b << 2) | c);
}

string getFalseMd5(const string& strCode)
{
    long long num = 0;

    for (size_t i = 0; i < strCode.length(); i++)
    {
        int ascii = (int)strCode[i];
        int a = ascii + 7;
        int b = ascii * 5;

        num += md5_a(ascii, a, b);
        num += md5_b(ascii, a, b);
        num += md5_c(ascii, a, b);
        num *= (md5_d(ascii, a, b) + 12);

        if (num > 100000000)
        {
            string numStr = to_string(num);
            num = stoll(numStr.substr(numStr.length() - 7));
        }
    }

    string result = to_string(num);
    if (result.length() >= 6)
        return result.substr(result.length() - 6);
    else
        return to_string(num + 523109);
}

string funcGetNumber_20100601(const string& md5str)
{
    if (md5str.length() < 30)
        return "";

    string temp = "";
    temp += md5str.substr(5, 2);
    temp += md5str.substr(16, 2);
    temp += md5str.substr(4, 2);
    temp += md5str.substr(0, 2);
    temp += md5str.substr(8, 2);
    temp += md5str.substr(12, 2);

    string result = "";
    for (size_t i = 0; i < temp.length(); i++)
    {
        char c = temp[i];
        if (isdigit(c))
        {
            // xor with 4
            int val = (c - '0') ^ 4;
            result += to_string(val);
        }
        else
        {
            int ascii = (int)c + 20 - (int)(i + 1);
            char converted = (char)ascii;
            if (converted == 'O' || converted == 'o')
                result += "0";
            else
                result += (char)toupper(converted);
        }
    }

    replace(result.begin(), result.end(), '0', '3');

    // get 8 core code..
    return result.substr(1, 2) +
        result.substr(5, 2) +
        result.substr(4, 2) +
        result.substr(8, 2);
}

string GenerateCoreCode(const string& machineCode)
{
    // clean up machine code...
    string cleaned = machineCode;
    cleaned.erase(remove(cleaned.begin(), cleaned.end(), ' '), cleaned.end());
    cleaned.erase(remove(cleaned.begin(), cleaned.end(), '-'), cleaned.end());
    cleaned.erase(remove(cleaned.begin(), cleaned.end(), '-'), cleaned.end());
    cleaned.erase(remove(cleaned.begin(), cleaned.end(), ','), cleaned.end());
    cleaned.erase(remove(cleaned.begin(), cleaned.end(), ' '), cleaned.end());

    if (cleaned.length() > 10)
        cleaned = cleaned.substr(0, 10) + cleaned.substr(cleaned.length() - 5);

    // obfuscation??
    string falseMd5 = getFalseMd5(cleaned);

    // md5 hash calculation
    string md5Hash = MD5Hash(falseMd5);

    // 2 reg code
    return funcGetNumber_20100601(md5Hash);
}

char EncodeDigitToLetter(int digit)
{
    switch (digit)
    {
    case 0: return 'A';
    case 1: return 'B';
    case 2: return 'C';
    case 3: return 'D';
    case 4: return 'E';
    case 5: return 'F';
    case 6: return 'G';
    case 7: return 'H';
    case 8: return 'J';
    case 9: return 'K';
    default: return (char)('0' + digit);
    }
}

string EncodeDate(int year, int month, int day)
{
    int yearLastTwo = year % 100;
    int yearTen = yearLastTwo / 10;
    int yearOne = yearLastTwo % 10;
    int monthTen = month / 10;
    int monthOne = month % 10;
    int dayTen = day / 10;
    int dayOne = day % 10;

    char c1;
    switch (yearTen)
    {
    case 1: c1 = '6'; break;
    case 2: c1 = '8'; break;
    case 3: c1 = 'D'; break;
    default: c1 = (char)('0' + yearTen); break;
    }

    char c2 = (char)('0' + yearOne);

    char c3;
    switch (monthTen)
    {
    case 0: c3 = '4'; break;
    case 1: c3 = '6'; break;
    default: c3 = (char)('0' + monthTen); break;
    }

    // 8 idx
    char c4 = (char)('0' + monthOne);

    // 13 idx
    char c5;
    switch (dayTen)
    {
    case 0: c5 = '4'; break;
    case 1: c5 = '6'; break;
    case 2: c5 = '8'; break;
    default: c5 = (char)('0' + dayTen); break;
    }

    // 14 idx.
    char c6 = (char)('0' + dayOne);

    string result;
    result += c1;
    result += c2;
    result += c3;
    result += c4;
    result += c5;
    result += c6;
    return result;
}

// gen reg code.
string GenerateFullRegCode(const string& machineCode, int year, int month, int day, int version = 1)
{
    string coreCode = GenerateCoreCode(machineCode);
    if (coreCode.empty())
        return "";

    string dateCode = EncodeDate(year, month, day);

    string fullRegCode = coreCode.substr(0, 4) +          // core code (4)
        dateCode.substr(0, 4) +  // 日期编码前4位 (年月)
        coreCode.substr(4, 4) +  // 核心码后4位
        dateCode.substr(4, 2) +  // 日期编码后2位 (日)
        to_string(version); // I didnot know what is it, so I will call it "version"??.

    return fullRegCode;
}

int DecodeChar(char c)
{
    if (isdigit(c))
        return c - '0';

    char upper = toupper(c);
    switch (upper)
    {
    case 'A': return 0;
    case 'B': return 1;
    case 'C': return 2;
    case 'D': return 3;
    case 'E': return 4;
    case 'F': return 5;
    case 'G': return 6;
    case 'H': return 7;
    case 'J': return 8;
    case 'K': return 9;
    default: return -1;
    }
}

int DecodeYear(const string& code)
{
    if (code.length() != 2) return -1;

    int ten = DecodeChar(code[0]);
    int one = DecodeChar(code[1]);
    if (ten < 0 || one < 0) return -1;
    return 2000 + ten * 10 + one;
}

int DecodeMonth(const string& code)
{
    if (code.length() != 2) return -1;

    int ten = DecodeChar(code[0]);
    int one = DecodeChar(code[1]);
    if (ten < 0 || one < 0) return -1;
    return ten * 10 + one;
}

int DecodeDay(const string& code)
{
    if (code.length() != 2) return -1;

    int ten = DecodeChar(code[0]);
    int one = DecodeChar(code[1]);
    if (ten < 0 || one < 0) return -1;
    return ten * 10 + one;
}

// self-verify registeration code generated.
bool VerifyRegCode(const string& machineCode, const string& regCode)
{
    if (regCode.length() < 14 || regCode.length() > 15)
        return false;

    // core code  (4)
    string userCore = regCode.substr(0, 4) + regCode.substr(8, 4);

    // generate core code
    string correctCore = GenerateCoreCode(machineCode);

    // compare
    transform(userCore.begin(), userCore.end(), userCore.begin(), ::toupper);
    transform(correctCore.begin(), correctCore.end(), correctCore.begin(), ::toupper);

    return userCore == correctCore;
}

int main(int argc, char* argv[])
{
    cout << "# PaiBazi Registration Keygen\r\nBy GDExecW [LCG]" << endl;

    string defaultMachineCode = "05872-79994-62920-40738";
    string machineCode;

    cout << "Enter machine code (press Enter to use default): ";
    getline(cin, machineCode);
    if (machineCode.empty())
        machineCode = defaultMachineCode;

    cout << endl;
    cout << "Machine Code: " << machineCode << endl;
    cout << endl;

    //  generate 8 core code
    string coreCode = GenerateCoreCode(machineCode);
    cout << "8-digit Core Registration Code: " << coreCode << endl;
    cout << endl;

    // expiration
    SYSTEMTIME st;
    GetLocalTime(&st);

    int year = st.wYear + 1;
    int month = st.wMonth;
    int day = st.wDay;

    cout << "Current Date: " << st.wYear << "-"
        << setw(2) << setfill('0') << st.wMonth << "-"
        << setw(2) << setfill('0') << st.wDay << endl;
    cout << "Default Expiration: " << year << "-"
        << setw(2) << setfill('0') << month << "-"
        << setw(2) << setfill('0') << day << " (one year from now)" << endl;
    cout << endl;

    string input;
    cout << "Enter expiration year (press Enter to use " << year << "): ";
    getline(cin, input);
    if (!input.empty()) year = stoi(input);

    cout << "Enter expiration month (press Enter to use " << month << "): ";
    getline(cin, input);
    if (!input.empty()) month = stoi(input);

    cout << "Enter expiration day (press Enter to use " << day << "): ";
    getline(cin, input);
    if (!input.empty()) day = stoi(input);

    cout << endl;

    // gen full reg code
    string fullRegCode = GenerateFullRegCode(machineCode, year, month, day);

    if (fullRegCode.empty())
    {
        cout << "Failed to generate registration code!" << endl;
        system("pause");
        return 1;
    }

    cout << "# Registration Info" << endl;
    cout << endl;
    cout << "Machine Code:   " << machineCode << endl;
    cout << "Expiration:     " << year << "-"
        << setw(2) << setfill('0') << month << "-"
        << setw(2) << setfill('0') << day << endl;
    cout << endl;
    cout << "Full Reg Code:  " << fullRegCode << endl;
    cout << endl;

    // Parse registration code structure
    cout << "# Registration Code Structure:" << endl;
    cout << "    Digits 1-4 (Core Code prefix):   " << fullRegCode.substr(0, 4) << endl;
    cout << "    Digits 5-6 (Year encoding):      " << fullRegCode.substr(4, 2) << endl;
    cout << "    Digits 7-8 (Month encoding):     " << fullRegCode.substr(6, 2) << endl;
    cout << "    Digits 9-12 (Core Code suffix):  " << fullRegCode.substr(8, 4) << endl;
    cout << "    Digits 13-14 (Day encoding):     " << fullRegCode.substr(12, 2) << endl;
    cout << "    Digit 15 (Version flag):         " << fullRegCode[14] << endl;
    cout << endl;

    // decode then verify
    cout << "# Verification:" << endl;
    string yearCode = fullRegCode.substr(4, 2);
    string monthCode = fullRegCode.substr(6, 2);
    string dayCode = fullRegCode.substr(12, 2);

    int decodedYear = DecodeYear(yearCode);
    int decodedMonth = DecodeMonth(monthCode);
    int decodedDay = DecodeDay(dayCode);

    cout << "    Year encoding:  " << yearCode << " - " << decodedYear << endl;
    cout << "    Month encoding: " << monthCode << " - " << decodedMonth << endl;
    cout << "    Day encoding:   " << dayCode << " - " << decodedDay << endl;
    cout << "    Decoded date:   " << decodedYear << "-"
        << setw(2) << setfill('0') << decodedMonth << "-"
        << setw(2) << setfill('0') << decodedDay << endl;
    cout << endl;

    bool isValid = VerifyRegCode(machineCode, fullRegCode);
    cout << "Registration Code Verification: " << (isValid ? "VALID" : "INVALID") << endl;
    cout << endl;
    system("pause");
    return 0;
}

Keygen 核心算法要点

  1. 核心码生成:严格按照 funcGetNumber_20100601 的逻辑实现,注意数字异或 4 后可能产生两位数(如 9^4=13),直接作为字符串追加

  2. 日期编码

    • 第5位(年份十位):1→6/7/B/b2→8/9/C/c3→D/d
    • 第6位(年份个位):直接数字
    • 第7位(月份十位):0→4/5/A/a1→6/7/B/b
    • 第8位(月份个位):直接数字
    • 第13位(日期十位):0→4/5/A/a1→6/7/B/b2→8/9/C/c
    • 第14位(日期个位):直接数字
  3. 日期限制:由于第13位只能映射为 0、1、2,日期只能为 01-29

  4. 大小写:核心码中的字母自动转为大写

Keygen 示例输出

Machine Code: 05872-79994-62920-40738
8-digit Core Code: 3151Q546
Expiration: 2030-12-20
Full Reg Code: 3151D0626102801

结果

免费评分

参与人数 2吾爱币 +1 热心值 +2 收起 理由
爱我666 + 1 + 1 我很赞同!
obtio + 1 我很赞同!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

推荐
爱我666 发表于 2026-6-25 10:11
其实一直蛮期待八字软件,称骨算命,八字合婚,万年历和生物钟(七种生物钟版本,平时多是4种的)合并的软件被开发出来。
沙发
bernardnoone 发表于 2026-6-24 14:46
谢谢博主分享,非常详细的流程,适合新手直接复现。
3#
ynahdyl 发表于 2026-6-24 19:39
4#
cbkxh 发表于 2026-6-24 20:20
厉害啊。来学习的。
5#
博爵 发表于 2026-6-24 22:33
感谢分享,很强
6#
做自己 发表于 2026-6-25 02:48
网盘分享不了,自动屏蔽,昨天 到今天,您超出了24小时内发短消息数量的上限,怎么弄
7#
XTDR12 发表于 2026-6-25 08:34
大佬分析的细致入微,赞,Keygen 代码可以直接使用,方便新手使用
8#
hsanren 发表于 2026-6-25 09:43
来个软件啊
9#
 楼主| GDExecW 发表于 2026-6-25 10:08 |楼主

在文章里面了,dnSpy 使用的是 GitHub 中的 dnSpyEx/dnSpy,建议使用 32 位方便调试
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - 52pojie.cn ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2026-6-26 03:57

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表