配置文件中的数据库连接串加密了,你以为我就挖不出来吗?

2023-01-17 数据库SQL编程算法存储

一:背景

1. 讲故事

前几天在调试物联柜终端上的一个bug时发现 app.config 中的数据库连接串是加密的,因为调试中要切换数据库,我需要将密文放到专门的小工具上解密,改完连接串上的数据库名,还得再加密贴到 app.config 中,烦的要死,内容如下:


  <appsettings>
    <!-- 数据库连接字符串 -->
    <add key="oledbconnstr" value="xfes27am6muw48ib1glmvqvubq7/pp9n4xbzjsdu19ydr/zdb3m7kt6had7f9hlj/zeviizbmsu4o5l9g03y5iub6klczi7s3ndlwtic+bxlf5quu/r8zai+rgnnsnzdwodfqurlqy5cf2x8/mfdocmnazymptyehszoeeru/tp9t3n5qlljtihrmdfbighlqe1kfn3ub3g1kgs0oobiefnpr09kq/pfgzzi/kzcrk10plzz0pfj1yu5refqbsdblecv3d2zl3lx1ibls24t7w==" />
  </appsettings>

改完bug之后,我就想这玩意能防的了谁呢?私以为搞这么麻烦也就防防君子,像我这样的 晓人,加不加密都是等于没加密,照样给你脱库。。。

二:使用 ilspy 去脱库

1. 从dal/repository层去反编译代码

要想得到明文的数据库连接串,可以从代码中反推,比如从 dal 或者 repository 中找连接串字段 connectionstring,我这边的终端程序是用 wpf 写的,采用的是经典的三层架构,所以在 bin 下可以轻松找到,如下图:

接下来用 ilspy 反编译这个 dll。

从上图中可以看出,连接串的明文是存放在: oledbhelper.connectionstring 中的,然后可以看到,程序中定义了一个 decrypt 方法专门用来解密连接串,哈哈,有了这个算法,是不是就可以脱库啦???如下代码所示:


    class program
    {
        static void main(string[] args)
        {
            var str = "xfes27am6muw48ib1glmvqvubq7/pp9n4xbzjsdu19ydr/zdb3m7kt6had7f9hlj/zeviizbmsu4o5l9g03y5iub6klczi7s3ndlwtic+bxlf5quu/r8zai+rgnnsnzdwodfqurlqy5cf2x8/mfdocmnazymptyehszoeeru/tp9t3n5qlljtihrmdfbighlqe1kfn3ub3g1kgs0oobiefnpr09kq/pfgzzi/kzcrk10plzz0pfj1yu5refqbsdblecv3d2zl3lx1ibls24t7w==";

            console.writeline(decrypt(str));
        }

        public static string decrypt(string str)
        {
            if (!string.isnullorempty(str))
            {
                descryptoserviceprovider descsp = new descryptoserviceprovider();
                byte[] key = encoding.unicode.getbytes("oyea");
                byte[] data = convert.frombase64string(str);
                memorystream mstream = new memorystream();
                cryptostream cstream = new cryptostream(mstream, descsp.createdecryptor(key, key), cryptostreammode.write);
                cstream.write(data, 0, data.length);
                cstream.flushfinalblock();
                return encoding.unicode.getstring(mstream.toarray());
            }
            return "";
        }
    }

不过还好,数据库也是在客户那边独立部署的,不存在走外网的情况,不然就玩大了。。。接下来我们来看看如何去防范。

2. 加壳/混淆/加密狗

现在市面上商业版和免费版都提供了给c#代码进行加密和混淆,不过我没用过,我想最多在反编译代码后阅读性上增加了一些障碍,这也不过是时间问题罢了,毕竟sqlconnection,sqlcommand 这些fcl的类你是没法混淆的,我从这些类上反推可以很轻松的就能找到明文的 connectionstring ,所以这条路我觉得是走不通的。

3. 将解密算法放在 server 端

既然 解密算法 埋在客户端你都能挖出来,那把它放在 server 端不就可以啦?在程序启动的时候,调用一下 webapi 进行解密,这样你总没辙了吧 ???哈哈,大家可以开动脑子想一想,这种方法可行不可行?诚然,解密算法搬走了,再用 ilspy 去挖已经没有任何意义了,但这里有一个重要突破点,不管是用什么形式解密的,最后的连接串明文都是存放在 oledbhelper.connectionstring 这个静态变量中,对吧!接下来的问题就是有没有办法把进程中的这个静态变量给挖出来?你说的对,就是抓程序的 dump文件 用 windbg 去挖。

三:使用 windbg 去脱库

1. 思路

要想挖出 oledbhelper.connectionstring,其实也很简单,在 clr via c# 第四章中关于对象类型和类型对象的解读有这么一张图,很经典。

从上图中可以看到,静态字段是在 manager 类型对象 中,实例字段都是在 manager 对象 中,对照这张图,我只需要通过 windbg 找到 oledbhelper 类型对象,也就是所谓的 eeclass

2. windbg 挖矿实战

使用 !name2ee 找到 decrypt 方法描述符(methoddesc)

0:000>  !name2ee xxx.utilities.dll xxx.utilities.database.oledbhelper.decrypt
module:      08ed7cdc
assembly:    xxx.utilities.dll
token:       060002aa
methoddesc:  08ed83b0
name:        xxx.utilities.database.oledbhelper.decrypt(system.string)
jitted code address: 048b6af0

上面的 methoddesc: 08ed83b0 就是方法描述符的地址。

使用 !dumpmd 导出方法描述符的详细信息,找到 oledbhelper类型对象 的 eeclass 地址

0:000> !dumpmd 08ed83b0
method name:  xxx.utilities.database.oledbhelper.decrypt(system.string)
class:        08ecab30
methodtable:  08ed8468
mdtoken:      060002aa
module:       08ed7cdc
isjitted:     yes
codeaddr:     048b6af0
transparency: critical

上面的 class: 08ecab30 就是 oledbhelper类型对象 在堆上的内存地址。

使用 !dumpclass 导出 class: 08ecab30 ,从而找到 oledbhelper类的静态字段

0:000> !dumpclass 08ecab30
class name:      xxx.utilities.database.oledbhelper
mdtoken:         02000033
file:            d:\code\a18001\source\main\tunnelclient\bin\debug\xxx.utilities.dll
parent class:    795115b0
module:          08ed7cdc
method table:    08ed8468
vtable slots:    4
total method slots:  6
class attributes:    100081  abstract,
transparency:        critical
numinstancefields:   0
numstaticfields:     2
      mt    field   offset                 type vt     attr    value name
799bfd60  4000152       74        system.string  0   static 04c28270 connectionstring
799bfd60  4000153       78        system.string  0   static 04c299e8 securityconnectionstring

从上面导出信息中可以看到 oledbhelper类中 有两个静态字段: connectionstringsecurityconnectionstring

使用 !do 打印出两个静态字段

看到没有,上图中的两个紫色框框就是明文的 connectionstring 哈,怎么样?不。

四:总结

当认识到上面的两种脱库方式,你应该就能想到,其实你在程序中连接数据库,这本身就是一种错,操作系统都能给你盗版,何况你这区区一个小软件?个人觉得完全杜绝的方式那应该就是:灭掉本地的sqlserver,让所有的数据获取都由远端的 webapi 提供,当然这又是在脱离业务聊技术啦!

上一篇:开源C# WPF控件库强力推荐

下一篇:快速了解 ASP.NET Core Blazor