吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 33758|回复: 65
收起左侧

[原创] QQLite的奇葩破解之法——DNS+WebServer

  [复制链接]
maozhenyu 发表于 2017-5-12 13:52
本帖最后由 maozhenyu 于 2017-5-12 14:08 编辑

最近回国了,有点空。于是再来一篇,是我之前完成的QQLite的破解

不得不说这个东西确实做的很好,几乎实现了QQ协议所有的功能:包括不限于正常的发消息、图片、表情,甚至包括发红包等等。

程序的基本原理是QQLite 调用QQLite.Framework.dll。核心在QQLite.Framework.dll。因此我的目标是自己制作一个“外壳”,调用QQLite.Framework.dll 来实现我的功能。

如果你准备直接引用dll,使用命名空间,………………,然后……   哦,你想得美!
03.png
说明里面有联网认证

首先用抓包软件抓取这个QQLite在验证时的网络请求。发现这样的请求:POST http://auth.qqlite.cn/Authorize.php

01.png
02.png

请求返回了一堆16进制小写字母,怀疑是被AES加密。那么我们着手分析程序。


可惜这东西是用最新的DNGuard HVM 的企业版加的壳,破解起来十分的有难度——至少我没这个时间和耐心去破。好在52pojie有提供过DNGuard HVM Unpacker for 3.71 trial 的版本,虽然无法完全脱开QQLite的壳,但是可以去掉很大一部分。通过搜索,我们发现了在这里。


[C#] 纯文本查看 复制代码
private readonly string[] ABIONX4Oko = new string[] { "http://qqlite.94qing.com/Authorize.php", "http://auth.94qing.com/Authorize.php", "http://www.qqlite.cn/Authorize.php" };
 string str = "无法访问服务器,请确定联网状态";
//注意 为了可读性 我对这里的变量名和方法名进行了一些修改
private bool [b]AuthHosts[/b]() //这里读取hosts文件,看看有没有对qqlite域名劫持(常规题,改127.0.0.1然后伪造认证服务器)
        {
            string path = string.Format(@"{0}\drivers\etc\hosts", Environment.GetFolderPath(Environment.SpecialFolder.System));
            if (System.IO.File.Exists(path))
            {
                StreamReader reader = new StreamReader(path, Encoding.Default);
                string str2 = reader.ReadToEnd();
                reader.Close();
                if (((str2.IndexOf("qqlite", StringComparison.CurrentCultureIgnoreCase) > -1) || (str2.IndexOf("94qing", StringComparison.CurrentCultureIgnoreCase) > -1)) || (str2.IndexOf("authorize", StringComparison.CurrentCultureIgnoreCase) > -1))
                {
                    return false;
                }
            }
            return true;
        }

public void MainAuth(){
            if (!this.[b]AuthHosts[/b]()) 
            {
                if (this.DtaOyWwSSY() == null)
                {
                    this.WIxO7NaA7k(new AuthorizeJson());
                }
                this.DtaOyWwSSY().result = false;
                this.DtaOyWwSSY().message = str;
//如果hosts验证不通过,Boom!
            }
            else if (Utility.Md5((License.AgentQQ + License.SoftWareQQ) + License.SoftWareName + License.SoftWareAuthor) != License.LdffLjAU3r()) //这里是读取License检验程序防止篡改的
            {
                str = "非法篡改";
                if (this.DtaOyWwSSY() == null)
                {
                    this.WIxO7NaA7k(new AuthorizeJson());
                }
                this.DtaOyWwSSY().result = false;
                this.DtaOyWwSSY().message = str;
            }
            else //这里开始向服务器发送请求
            {
                byte[] buffer = Utility.Md5File(Splash.GetType().Assembly.Location); //先获得当前dll的md5
                string str3 = string.Empty;
                string str4 = string.Empty;
                foreach (byte num2 in buffer)
                {
                    str3 = str3 + num2.ToString("X2");  //先获得当前dll的md5
                }
                foreach (byte num4 in Utility.Md5File(Application.ExecutablePath)) //获得当前宿主exe的md5
                {
                    str4 = str4 + num4.ToString("X2");
                }
                object[] args = new object[] { str3, License.FrameworkVersion, str4, License.Version, this.Jw5OeqK15o().QQ, (this.Jw5OeqK15o().LoginStatus == LoginStatus.Login) ? "1" : "0", bool_0 ? "1" : "0", License.SoftWareQQ, License.AgentQQ, License.FrameworkType };
                string str5 = string.Format("FrameworkMd5={0}&FrameworkVersion={1}&ExeMd5={2}&ExeVersion={3}&RobotQQ={4}&IsLogin={5}&IsReStart={6}&BuildQQ={7}&AgentQQ={8}&FrameworkType={9}", args); //传参
                string str6 = QIDOLuDhqR();
                if (!string.IsNullOrEmpty(str6))
                {
                    str5 = str5 + "&AuthKey=" + str6;
                }
                DateTime now = DateTime.Now;
                int num5 = now.Minute + 10;
                string str7 = num5.ToString(CultureInfo.InvariantCulture);
                string str8 = (now.Second + 10).ToString(CultureInfo.InvariantCulture);
                string str9 = str7 + str8;
                string key = Utility.Md5(string.Concat(new object[] { this.Jw5OeqK15o().QQ, "00-01-6C-06-A6-29", License.FrameworkVersion.Replace(".", ""), str9 }));
                object[] objArray3 = new object[] { this.Jw5OeqK15o().QQ, License.FrameworkVersion.Replace(".", ""), "00-01-6C-06-A6-29", str9 };
                string str11 = Utility.Md5(string.Concat(objArray3)).Substring(5, 0x10);
                str5 = PHP.authcode_en(str5, key);
//这里计算authcode 
                object[] objArray4 = new object[] { jb9BOoatwNaPbmWQJN.FCsPZSC4Oe(now) / 0x3e8L, License.FrameworkVersion, this.Jw5OeqK15o().QQ, HttpUtility.UrlEncode(str5) };
                string str12 = string.Format("Do=CheckAuthorize&AuthVersion=2.3&Time={0}&Version={1}&RobotQQ={2}&Data={3}", objArray4);
                HttpHelper helper = new HttpHelper();
                HttpItem item = new HttpItem {
                    URL = this.ABIONX4Oko[int_0],
                    Method = "POST",
                    UserAgent = "QQLite_Framework_" + License.FrameworkVersion,
                    Postdata = str12
                };
                HttpResult html = helper.GetHtml(item);
//发出HTTP请求,并获得返回
                if (((html.StatusCode == HttpStatusCode.OK) && !string.IsNullOrEmpty(html.Html)) && (html.Html.Length >= 5))
                {
                    string str13 = MdTXO0IDbFmn8RvdCTm.vdTweSWh6L(html.Html, str11);、、
//这里验证返回值
                    if (!string.IsNullOrEmpty(str13) && (str13.Length >= 5))
                    {
                        string str14 = PHP.authcode_de(str13, key);
                        if (!string.IsNullOrEmpty(str14) && (str14.Length >= 5))
                        {
                            AuthorizeJson json = Json.Deserialize<AuthorizeJson>(str14);
                            if (json == null)
                            {
                                if (this.DtaOyWwSSY() == null)
                                {
                                    this.WIxO7NaA7k(new AuthorizeJson());
                                }
                                this.DtaOyWwSSY().result = false;
                                this.DtaOyWwSSY().message = str;
                            }
                            else
                            {
                                this.WIxO7NaA7k(json);
                                if (this.DtaOyWwSSY().authkey != null)
                                {
                                    object[] objArray5 = new object[] { this.Jw5OeqK15o().QQ, License.Version.Replace(".", ""), str9, "00-01-6C-06-A6-29" };
                                    if (this.DtaOyWwSSY().authkey == Utility.Md5(string.Concat(objArray5)))
                                    {
                                        if (!string.IsNullOrEmpty(this.DtaOyWwSSY().message))
                                        {
                                            this.DtaOyWwSSY().message = HttpUtility.UrlDecode(this.DtaOyWwSSY().message);
                                        }
                                        this.DtaOyWwSSY().authkey = null;
                                        return;
                                    }
                                }
                                if (!string.IsNullOrEmpty(this.DtaOyWwSSY().message))
                                {
                                    this.DtaOyWwSSY().message = HttpUtility.UrlDecode(this.DtaOyWwSSY().message);
                                }
                            }
                        }
                        else if (int_0 == 0)
                        {
                            this.fE8OvhvTfu(bool_0, int_0 + 1);
                        }
                        else
                        {
                            if (this.DtaOyWwSSY() == null)
                            {
                                this.WIxO7NaA7k(new AuthorizeJson());
                            }
                            this.DtaOyWwSSY().result = false;
                            this.DtaOyWwSSY().message = str;
                        }
                    }
                    else if (int_0 == 0)
                    {
                        this.fE8OvhvTfu(bool_0, int_0 + 1);
                    }
                    else
                    {
                        if (this.DtaOyWwSSY() == null)
                        {
                            this.WIxO7NaA7k(new AuthorizeJson());
                        }
                        this.DtaOyWwSSY().result = false;
                        this.DtaOyWwSSY().message = str;
                    }
                }
                else if (html.StatusCode != HttpStatusCode.NotFound)
                {
                    this.fE8OvhvTfu(bool_0, int_0 + 1);
                }
                else
                {
                    if (this.DtaOyWwSSY() == null)
                    {
                        this.WIxO7NaA7k(new AuthorizeJson());
                    }
                    this.DtaOyWwSSY().result = false;
                    this.DtaOyWwSSY().message = str;
                }
            }

这里就是认证的核心代码了,我在上面打了注释。

对于这种问题的通常解决方法是根据代码做一个Emulator,伪造的认证服务器。然后通过hosts把向原本认证服务器的请求转移到伪造的服务器上。

可惜,他做了hosts检查,没法用hosts了。

好啊,你不让我用hosts,我用DNS还不行么?立刻动手本地搭一个DNS服务器,C#处理,代码如下:

[C#] 纯文本查看 复制代码
//这里我使用了ARSoft.Tools的库(http://arsofttoolsnet.codeplex.com/ )
public MyDNSServer()
        {
            DnsServer dnsServer = new DnsServer(IPAddress.Parse("0.0.0.0"), 1, 1); //监听本地DNS
            dnsServer.QueryReceived += DnsServer_QueryReceived;
            dnsServer.Start();//this.ProcessQuery
        }

        private async System.Threading.Tasks.Task DnsServer_QueryReceived(object sender, QueryReceivedEventArgs e) //Handle 请求
        {
            DnsMessage query = e.Query as DnsMessage;

            if (query == null)
                return;

            DnsMessage response = query.CreateResponseInstance();
            string add = query.Questions[0].Name.ToString();

            // check for valid query
            if ((query.Questions.Count == 1)
                && (query.Questions[0].RecordType == RecordType.A)
               )
            {
                if (add== "auth.qqlite.cn.") //如果是对auth.qqlite.cn域名的DNS请求
                {
                    response.AnswerRecords.Add(new ARecord(query.Questions[0].Name, 36000, IPAddress.Parse("127.0.0.1"))); //给他返回A记录 127.0.0.1,也就是本机
                    response.ReturnCode = ReturnCode.NoError;
                }
            }

            // set the response
            e.Response = response;
        }


修改主用DNS为127.0.0.1,备用DNS为你的上级DNS。

那我同时就用这个程序搭建Emulator了,代码截图:
04.png

QQLite请求时,我的Emulator的显示:
05.png

QQLite主程序能工作了:
1.png

主要问题解决了,是不是呢

点评

这样破的话,是不是太容易就被作者和谐了呢,用不了几天吧  发表于 2017-5-14 16:35

免费评分

参与人数 16吾爱币 +25 热心值 +14 收起 理由
hlf5201314 + 1 我很赞同!
Hmily + 10 + 1 用心讨论,共获提升!
CH_2014 + 1 + 1 多谢提醒,已经提交给作者,坐等修复
ClearLover + 1 + 1 求那个本地搭建DNS的工具,最好能后面自己添加删除DNS值就好了
茫然唔错 + 1 + 1 该作者的东西从来就没出过真正的破解版,可惜啊
zhminxp + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
詠恒ぃ☆吣 + 1 + 1 已经失效了~
wmsuper + 1 + 1 我很赞同!
610100 + 2 感谢发布原创作品,吾爱破解论坛因你更精彩!
MwYa + 1 热心回复!
gogogo2000 + 1 + 1 用心讨论,共获提升!
55555555 + 2 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
czzy + 1 用心讨论,共获提升!
韩文 + 1 + 1 我很赞同!
述说过去 + 2 + 1 谢谢@Thanks!
william2568 + 1 谢谢@Thanks!

查看全部评分

本帖被以下淘专辑推荐:

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

56766876 发表于 2017-10-26 23:00
你好 ,咨询下 “ QQLite请求返回了一堆16进制小写字母,怀疑是被AES加密”,这里的AES我解密结果这么只有部分,还有个尾巴 消失了
他是用的是aes哪种填充方式加密的呢?

aes_key=f81c0a4a5d6b43b9
密文=6cda8ef7094bbd60a3f39564f3c8c6b750234511d6272f372d5ef4899a21ec1f720c0d0a4cfc725a15d6bc6bd8b255311acc92f68cfecd9925009a0299c2c67195e8436b3020dade5c4a5412bc41183c9c32d3c7f3278ec621fe6440cca9fddac96d6751e15881afb388c3afe8a2f9bb2a3671d822a51d90b8a8f4c7a220b5dc00eb274aa5475266a3d7facddf23cf13a50fde56224a1fd6da3b9e82713a91813e8357610af9d75aa911e9c838e2aac3ccef435ad0dd73f7804a9e3022b8d93c5f71bab666ed7195b7c1ed074c31c714a911211185c2ed91950e420fc834fed74cf59e7240c0bcffea83df515b77563049b66c50fe44f2d1274e875be1a4f2cca0f7b79ba0d04cb872fe5dbc161bc663d66106222602f12b2534dc5554d316b8a0f1594da6ecd1de5a5ff2ceb36826693e5f48684995f155cc111b632e2f67caae052ee7be5782fc068f6bd882fec0a9551c7c884d2582ec16b731533ebf66485f2bcb0eeef2d72277a9165843fd344d4ae4fa56f2027ba4846f9a089b2cbc762ae463baa9ea2542627e94783e4ea08ec11313a8f74c1b4ea3adcfa6ef76dec70af9817135d0c28dd163cf130e34161c23396ff8eeb1aa0b2f8676e77019d14a9ca0cdc8e38c0f4cb9d54471d7a5b8b29e9551004f798e1943ab9c1628fcf66ab4c427ea1246791480a748736f576a902983214bb44eebf824534c5ecd766d0fd739566ace91cd077152bc9ce387b3eb72a7eb0cb804926122d31b1a03bf38119ad4e3c91db1ed1b2f17a7c0847ab98f4879a3c931e510027dfae4ff6fb5afd6ccb97b926d085877a25fd7985dd769bf5fbc5e34d6a218f2a68c217301fdb5ecec6c62439e91034dea45f1c0628988401b47992eaa70a4216aabb6c019503ef404a62208c13f3587c3d7c7f3164fc52e

我aes解密的结果是 2a34BQPe5ORETeurQeeeL/Sftw7POvvRpZnxYyYrwdWHb3bLUcliYAlMUoF8b5oi++9QCAV6mUxFAbnDuAFGbUSSFT4MFNCIZQSPLsTP/pJMlU+H4FNV+GT0k9Yxvn7NKHDqGxUZon0lEQGTVOSHSaQAXUwe6XSs/02uI1lD34+YCtpUapKJE8jyIj7rovh7r6OER0/N0Yjj+2D9EkeZs3jlE5Bbmg+t3mYvQJzj8ocZKj4c47Nq+gKpQDH/Lm5JXFV9Bmm5LIJMTEFg0FXVSyDtGRpz6dDs5u35Bhxwy2Rxd3R4wWaFcU2niiJynGCdytLQIdCWuebicCud7f0NXsngYEH7JqHvfxF+kgHX3hy03YHw0JZIxouas/YbzXO0Fe4kYRa6uBxBVpieurqvzu/+UJilW+EaVyE3W8km2zUpVoWuKQrTybVcPTXsou2+O7YoeL2WLMt7w/DVU3Q6vk/FHVATVKNw75uyDPPDoyGYDQMDwZHWhPBqtVzkFgTMpMGeuoJ8m91XvO6aVv5hMkUQiME9hhjcsDZ1HjGaZTz5GnXashZ6wEWKilg+MTqigdgYSNCiQHPhdtTmNd7B//mFVfWOLTO72A7yJoCiZJOHCn5Y

正确的结果是 2a34BQPe5ORETeurQeeeL/Sftw7POvvRpZnxYyYrwdWHb3bLUcliYAlMUoF8b5oi++9QCAV6mUxFAbnDuAFGbUSSFT4MFNCIZQSPLsTP/pJMlU+H4FNV+GT0k9Yxvn7NKHDqGxUZon0lEQGTVOSHSaQAXUwe6XSs/02uI1lD34+YCtpUapKJE8jyIj7rovh7r6OER0/N0Yjj+2D9EkeZs3jlE5Bbmg+t3mYvQJzj8ocZKj4c47Nq+gKpQDH/Lm5JXFV9Bmm5LIJMTEFg0FXVSyDtGRpz6dDs5u35Bhxwy2Rxd3R4wWaFcU2niiJynGCdytLQIdCWuebicCud7f0NXsngYEH7JqHvfxF+kgHX3hy03YHw0JZIxouas/YbzXO0Fe4kYRa6uBxBVpieurqvzu/+UJilW+EaVyE3W8km2zUpVoWuKQrTybVcPTXsou2+O7YoeL2WLMt7w/DVU3Q6vk/FHVATVKNw75uyDPPDoyGYDQMDwZHWhPBqtVzkFgTMpMGeuoJ8m91XvO6aVv5hMkUQiME9hhjcsDZ1HjGaZTz5GnXashZ6wEWKilg+MTqigdgYSNCiQHPhdtTmNd7B//mFVfWOLTO72A7yJoCiZJOHCn5YmombKZ+FdYg8evHMcQ/AAUQQ

多了mombKZ+FdYg8evHMcQ/AAUQQ这尾巴
就这搞不定了。谢谢
wtuaixk 发表于 2017-5-12 13:59
抹不掉 发表于 2017-5-12 14:12
wt7758521888 发表于 2017-5-12 14:14
大佬厉害!
头像被屏蔽
大象无形 发表于 2017-5-12 14:27
提示: 作者被禁止或删除 内容自动屏蔽
zhminxp 发表于 2017-5-12 14:38
贴代码啊。老大。学习一下
mayl8822 发表于 2017-5-12 14:41
厉害了哥, 感谢分享
chinaboy008 发表于 2017-5-12 15:02
厉害!支持你!!
师法自然 发表于 2017-5-12 15:20
厉害厉害,这个思路可以啊
maoxuechuen 发表于 2017-5-12 15:22 来自手机
完全看不明白!还是支持楼主分享
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 警告:本版块禁止灌水或回复与主题无关内容,违者重罚!

快速回复 收藏帖子 返回列表 搜索

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

GMT+8, 2024-5-5 12:48

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

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