.NET P****** CMS 逆向工程

  (应一些园友建议,我把敏感字段去掉)

  其实当初我的目的是很纯洁的,只是想找一个简单的网站生成模板,由于对.net更熟悉一点,就去搜索了.net框架的CMS,看它的介绍挺强大的,符合最初的目的,但是下下来之后发现最新版本是要钱的,低一级的版本免费,但是免费的生成出来的东西会有他们公司的版权,这就让我不能忍了,免费就免费啊,搞个纯净点的不行啊,GOOGLE是强大的,所以我尝试的去搜索看有没有破解的版本,发现搜出来的一律都是免费版的去掉版权的版本,擦,去个版权就叫破解了么,而且还是低一级的版本,略微坑爹。.NET的东西理论上没有什么不可以破解的,之前由于项目需要,偶尔也会去破解一些商业的.NET软件,学习学习嘛,破解也不是什么罪大恶极的事,只要你不破坏别人的利益就行,所以我就抱着学习的心态去看了一下P*****的源代码,罪过罪过。只是学习。

  本人声明,下面的内容只是个人研究所用,不作为任何商业目的,如果有人看了本篇文章做出任何违法之事,本人不负任何责任责任。by Zengg

 

  破解所需软件:Reflector,ILSpy,de4dot

 

  Reflector和ILSpy其实是一个性质的,都是用来查看别人的源代码,由于有时我发现Reflector查看方法的时候会出现一些错误,所以就用ILSPY配合着用。

  de4dot,脱壳和反混搅的利器,一般商业软件都会加壳或者用了混搅代码,让一些人就算看到代码也不明白写的是什么,有了这个神器,妈妈再也不用担心我看到乱码了。。。当然有时也不是万能的,90%都能还原吧。

 

P******版本:V3.0

 

 

这是V3.0的基本样貌

 

 按照官网的说法,只要把域名和对应的注册码填到web.config里面就可以了。

 

Web.config

 

 

 

  可以看到Url是域名,License就是填写注册码的地方,由于域名是唯一的,我们不难想象出Url肯定是作为生成注册码的主要参照物,说个题外话,破解嘛,看你是要暴力破解还是文艺破解,暴力破解就是把代码注入他的DLL,从而绕过他的验证达到注册的目的,文艺嘛,就是大家有话好好说,不改动他的DLL,但是需要根据他提供的一些信息去推测软件作者的加密思想,只要你明白了加密核心思想,就能从源码中找出蛛丝马迹,由于软件里的源码肯定只存在解密的步骤,加密的步骤就需要大家反推出来了,有木有一种当侦探的赶脚。。。。。当然,本人只是业余人士,大牛们看到心里鄙视就好,不用说出来。。会打击人的.by Zengg

 

  言归正传,我们已经知道了URL是生成注册码的参照物,以后就按着这个线索去查找,其实上面还有一个重要的线索,”License”,由于注册码肯定是要从配置文件读取,读取之后就是验证的步骤,这验证的步骤就是我们需要去的地方,读取License的值,大家会想一下.NET的做法,是不是ConfigurationManager.AppSettings["License"],现在由于程序员的水平高低不齐,一般来说都会像上述那样去写,这样就暴露了获取验证码的地方,我们就可以定位到所有有”License”内容的代码段去,所以说,以后大家写核心解密代码的时候多留一个心眼,把敏感字段写入资源里面,至少给破解的人增加一点难度。

 

  Bin目录下有很多的DLL,其中一个肯定就是藏有解密的地方

   

  当然由于我已经破解过了,筛选DLL的过程就不描述了,P*******.web.dll,就是解密的地方,用de4dot先给DLL脱壳。

然后我们用ILSPY打开这个DLL

   

  会看到。。尼玛还是这么坑爹,所有东西基本都是乱码,让人不能直视,具体为什么我也没研究过,由于我们也不需要去明白这些乱码写的是神马,按照上面的思路我们要查找所有含有License字段的代码段,这步骤可以用软件实现。

 

 

  利用ILSPY,在SEARCH里填上License,就可以看到出来很多方法,当初很疑惑为什么有这么多地方用到验证注册码,验证的算法都是一样的,难道作者以为你各个角落都验证一遍就不能破解了么。。

 

仔细看了搜索出来的结果,他是一些重要的表操作时就会去验证一遍,挺谨慎的嘛,上面标蓝的地方就是登陆的时候主页验证,我们从这里开始。

点击进入该方法

  从上面代码可以看出,其实注册码分为两个部分,以’g’字符隔开,前面一部分是由MD5加密,后面一部分暂时不清楚,前面我们推论注册码是由URL来的,我们有理由怀疑

this.j3G1XJp4Xe, this.EsQ1WjnrPD肯定有一个是URL字段,至于另一个是什么得去寻找,一般来说我们初始化的时候会在类的构造函数初始化,相信在构造函数里面,我们会知道这两个字段的意思,忘记了这是web,我们应该从Page_load页面加载里面去寻找:

protected void Page_Load(object sender, EventArgs e)
{
    string connectionString;
    int[] num;
    while (true)
    {
        IL_24F:
        this.Qi911iK25u = ":" + master_login.tDhwcmhvMr4nRqlEc9G(base.Request)["SERVER_PORT"];
        while (true)
        {
            IL_232:
            if (this.Qi911iK25u == ":80")
            {
                this.Qi911iK25u = "";
            }
            this.EsQ1WjnrPD = this.Jbr136aAXj(master_login.MpkoQbh7EvS0PEFh1B3(master_login.rEXTLBh8uXG8glkV91p(ConfigurationManager.AppSettings, "Url").ToString()));
            master_login.xncn9GhN2hVekNKKcgK();
            if (!master_login.DMFvcGhZ55jZPl06Jhl())
            {
                goto IL_FA;
            }
            goto IL_215;
            IL_1CA:
            bool flag;
            while (!(flag = (base.Request.Form["username"] == null)))
            {
                this.NTR1li2VG4();
                this.Yqx1ac8tvS = new Conn();
                connectionString = master_login.lPkTddhObfF6vvZs9Ta(this.Yqx1ac8tvS);
                num = new int[]
                {
                    41,
                    0,
                    6,
                    4,
                    26,
                    3,
                    12,
                    8,
                    13,
                    93,
                    28,
                    38,
                    44
                };
                while (true)
                {
                    this.j3G1XJp4Xe = this.Yqx1ac8tvS.GetString(num);
                    num = new int[]
                    {
                        87,
                        4,
                        17,
                        17,
                        14,
                        17,
                        76,
                        34,
                        13,
                        21,
                        0,
                        11,
                        8,
                        3,
                        73,
                        37,
                        8,
                        2,
                        4,
                        13,
                        18,
                        4
                    };
                    this.DDU1A3AUYe = this.Yqx1ac8tvS.GetString(num);
                    int expr_AA = 7;
                    if (master_login.xncn9GhN2hVekNKKcgK())
                    {
                        switch (expr_AA)
                        {
                        case 0:
                            goto IL_232;
                        case 2:
                        case 4:
                            goto IL_FA;
                        case 3:
                        case 8:
                            goto IL_215;
                        case 5:
                            goto IL_176;
                        case 6:
                            continue;
                        case 7:
                            goto IL_276;
                        case 9:
                            goto IL_2AE;
                        case 10:
                            goto IL_1CA;
                        case 11:
                            goto IL_24F;
                        case 12:
                            goto IL_2F5;
                        case 13:
                            return;
                        }
                        break;
                    }
                    break;
                }
                goto IL_187;
            }
            return;
            IL_FA:
            this.KpC1B5ZX4p = this.Jbr136aAXj(master_login.tDhwcmhvMr4nRqlEc9G(master_login.rnmK14hAjv0aZay85lt(this))["SERVER_NAME"].ToLower());
            if (!master_login.MAaokyhM2irc0iduDgg(this.KpC1B5ZX4p, "localhost"))
            {
                goto IL_1CA;
            }
            int num2 = this.KpC1B5ZX4p.IndexOf(this.EsQ1WjnrPD);
            string a;
            if (num2 >= 0)
            {
                a = this.KpC1B5ZX4p.Substring(num2, this.KpC1B5ZX4p.Length - num2);
                goto IL_176;
            }
            master_login.a6dZyFh3MrLLslJyyx5(this).Write("<script>location.href='http://" + this.EsQ1WjnrPD + this.Qi911iK25u + "/e/master/login.aspx';</script>");
            goto IL_215;
            IL_187:
            if (!flag)
            {
                this.KpC1B5ZX4p = this.EsQ1WjnrPD;
                goto IL_1CA;
            }
            master_login.a6dZyFh3MrLLslJyyx5(this).Write("<script>location.href='http://" + this.EsQ1WjnrPD + this.Qi911iK25u + "/e/master/login.aspx';</script>");
            base.Response.End();
            goto IL_1CA;
            IL_215:
            master_login.a6dZyFh3MrLLslJyyx5(this).End();
            goto IL_1CA;
            IL_176:
            flag = !(a == this.EsQ1WjnrPD);
            goto IL_187;
        }
    }
    IL_276:
    num = new int[]
    {
        87,
        4,
        17,
        17,
        14,
        17,
        76,
        34,
        13,
        21,
        0,
        11,
        8,
        3,
        73,
        28,
        14,
        15,
        24,
        17,
        8,
        6,
        7,
        19
    };
    this.wht18BDAPc = this.Yqx1ac8tvS.GetString(num);
    num = new int[]
    {
        75,
        41,
        14,
        22,
        4,
        17,
        4,
        3,
        93,
        1,
        24,
        93,
        41,
        0,
        6,
        4,
        26,
        3,
        12,
        8,
        13,
        93,
        28,
        38,
        44
    };
    IL_2AE:
    this.eA41Kphpj9 = this.Yqx1ac8tvS.GetString(num);
    this.kwo1i4CnR3 = this.ne91erSgMV();
    this.GqT1YHkWWq = new OleDbConnection(connectionString);
    master_login.qOyjNXhFe7tECUDuWP7(this.GqT1YHkWWq);
    this.gII1QQxT9S();
    this.aK41NqyDHj();
    this.Tov1vquSFP();
    IL_2F5:
    this.GqT1YHkWWq.Close();
}
Load

   仔细看上面的代码,我们会发现,this.EsQ1WjnrPD就是URL,但是经过了一些处理,即去掉了域名前面的“WWW.”,this.j3G1XJp4Xe是经过特殊算法得出字符串。by Zengg

算法源码:

  {
  int[] num = new int[]{
                             41,
                            0,
                            6,
                            4,
                            26,
                            3,
                            12,
                            8,
                            13,
                            93,
                            28,
                            38,
                            44
                              };
  this.j3G1XJp4Xe = GetString(num);
}

 public string GetString(int[] num)
        {
            string text = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789~!@#$%^&*()_+-={}[]:\";'<>?,./\\| ";
            StringBuilder stringBuilder = new StringBuilder();
            string result;
            if (num.Length > 0)
            {
                for (int i = 0; i < num.Length; i++)
                {
                    stringBuilder.Append(text[num[i]]);
                }
                result = stringBuilder.ToString();
            }
            else
            {
                result = "";
            }
            return result;
        }
j3G1XJp4Xe

MD5算法:

public class Md5
        {
            public string Get_Md5(string s)
            {
                MD5 mD = new MD5CryptoServiceProvider();
                Encoding encoding = Encoding.GetEncoding("UTF-8");
                string s2 = "pageadmin cms";
                byte[] array = mD.ComputeHash(encoding.GetBytes(s));
                byte[] array2 = mD.ComputeHash(encoding.GetBytes(s2));
                StringBuilder stringBuilder = new StringBuilder(32);
                for (int i = 0; i < array.Length; i++)
                {
                    stringBuilder.Append(((int)(array[i] + array2[i])).ToString("x").PadLeft(2, '0'));
                }
                return stringBuilder.ToString();
            }
            public string Md5_Num(string s)
            {
                string text = "";
                for (int i = 0; i < s.Length; i++)
                {
                    if (i == s.Length - 1)
                    {
                        text += this.GetNum(s[i].ToString()).ToString();
                    }
                    else
                    {
                        text = text + this.GetNum(s[i].ToString()).ToString() + ",";
                    }
                }
                return text;
            }
            private int GetNum(string C)
            {
                string text = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789~!@#$%^&*()_+-={}[]:\";'<>?,./\\| ";
                int num = text.IndexOf(C);
                int result;
                if (num < 0)
                {
                    result = -1;
                }
                else
                {
                    result = num;
                }
                return result;
            }
        }
MD5

  第一部分的注册码其实已经得出来的,即this.j3G1XJp4Xe+this.EsQ1WjnrPD的字符串经过MD5加密就是第一部分的注册码,下面我们去寻找第二部分的线索,重新回到上次搜索"License"的列表,经过一个个的排查,发现了重要线索。

 

  进入这个方法

 

  从上面的代码可以推出,后部分注册码,其实就是URL的长度乘以2,到这里其实注册码差不多已经出来了,基本格式

    MD5(this.j3G1XJp4Xe+this.EsQ1WjnrPD)+“g”+URL.Length*2+?....注册码例子:ef12a131357bb3e67396e01061141385da5149g143

剩余核心算法:

 private static bool g031FKBmaF(string A_1)
        {
            string[] array = new string[5];
            array[0] = "^127[.]0[.]0[.]1$";
            array[1] = "^localhost$";
            array[2] = "^10[.]\\d{1,3}[.]\\d{1,3}[.]\\d{1,3}$";
            array[3] = "^172[.]((1[6-9])|(2\\d)|(3[01]))[.]\\d{1,3}[.]\\d{1,3}$";
            array[4] = "^192[.]168[.]\\d{1,3}[.]\\d{1,3}$";
            string[] array2 = array;
            int num = 0;
        IL_45:
            if (num >= array2.Length)
            {
                bool result = false;
                return result;
            }
            if (A_1 != null)
            {
                goto IL_64;
            }
            string arg_58_0 = "";
        IL_55:
            if (Regex.IsMatch(arg_58_0, array2[num]))
            {
                bool result = true;
                return result;
            }
            num++;
            goto IL_45;
        IL_64:
            arg_58_0 = A_1;
            goto IL_55;
        }
        private static string Jbr136aAXj(string A_1)
        {
            bool arg_27_0;

            if (g031FKBmaF(A_1))
            {
                arg_27_0 = false;
                goto IL_27;
            }
            arg_27_0 = (A_1.IndexOf(".") >= 0);
        IL_27:
            string result;
            if (!arg_27_0)
            {
                result = "localhost";
            }
            else
            {
                result = A_1.Replace("www.", "");
            }
            return result;
        }

 

  写了这么多也够了,最后一个数字3代表的是.net后缀的域名,这里就不提供完整的程序源码,可能会涉及一些侵权,我写的其实也够详细了,

核心算法也贴出来,大家自己去写一个注册机吧,如果有想要域名对应的注册码的,请邮电我说明正当理由,我会考虑是否给你。

 

如果您看了本篇博客,觉得对您有所收获,请点击右下角的 [推荐]

如果您想转载本博客,请注明出处

如果您对本文有意见或者建议,欢迎留言

感谢您的阅读,请关注我的后续博客 Zengg

作者:Zengg
出处:http://www.cnblogs.com/01codeworld/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

 

posted on 2013-09-12 11:06  Zengg  阅读(8571)  评论(64编辑  收藏  举报