一:背景
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 类中 有两个动态字段:ConnectionString
和 SecurityConnectionString
。
- 应用 !do 打印出两个动态字段
看到没有,上图中的两个紫色框框就是明文的 ConnectionString 哈,怎么样????? 不????。
四:总结
当意识到下面的两种脱库形式,你应该就能想到,其实你在程序中连贯数据库,这自身就是一种错,操作系统都能给你盗版,何况你这区区一个小软件?集体感觉齐全杜绝的形式那应该就是:灭掉本地的 sqlserver,让所有的数据获取都由远端的 webapi 提供,当然这又是在脱离业务聊技术啦!????????????