前几天在调试物联柜终端上的一个bug时发现 app.config 中的数据库链接串是加密的,由于调试中要切换数据库,我须要将密文放到专门的小工具上解密,改完链接串上的数据库名,还得再加密贴到 app.config 中,烦的要死,内容以下:web
<appSettings> <!-- 数据库链接字符串 --> <add key="OLEDBConnStr" value="XfES27am6Muw48iB1GlMVqvUbq7/Pp9n4XbZJsDu19YDr/Zdb3m7KT6haD7f9HLj/ZEvIiZbmSU4O5L9g03Y5IUB6KLCZI7s3nDLwTIC+bXLf5quu/r8ZAI+rgNnsNZdwoDfquRLQy5Cf2X8/MFDOcMNaZYMpTYeHsZoEERU/TP9t3n5QllJTihrmDFbiGHLqe1kfN3uB3g1kgs0oobIEfNPr09kQ/pFgzZi/kZCrK10PLZZ0pFj1YU5ReFqBsdBlecV3D2Zl3lx1Ibls24t7w==" /> </appSettings>
改完bug以后,我就想这玩意能防的了谁呢? 私觉得搞这么麻烦也就防防君子,像我这样的 晓人
,加不加密都是等于没加密,照样给你脱库。。。😄😄😄算法
要想获得明文的数据库链接串,能够从代码中反推,好比从 DAL
或者 Repository
中找链接串字段 ConnectionString
,我这边的终端程序是用 wpf 写的,采用的是经典的三层架构,因此在 bin
下能够轻松找到,以下图:sql
接下来用 ILSPy
反编译这个 dll。数据库
从上图中能够看出,链接串的明文是存放在: OleDbHelper.ConnectionString
中的,而后能够看到,程序中定义了一个 Decrypt
方法专门用来解密链接串,哈哈,有了这个算法,是否是就能够脱库啦??? 以下代码所示:api
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 ""; } }
不过还好,数据库也是在客户那边独立部署的,不存在走外网的状况,否则就玩大了。。。 接下来咱们来看看如何去防范。架构
如今市面上商业版和免费版都提供了给C#代码进行加密和混淆,不过我没用过,我想最多在反编译代码后阅读性上增长了一些障碍,这也不过是时间问题罢了,毕竟SqlConnection,SqlCommand 这些FCL的类你是无法混淆的,我从这些类上反推能够很轻松的就能找到明文的 ConnectionString ,因此这条路我以为是走不通的。app
既然 解密算法
埋在客户端你都能挖出来,那把它放在 server 端不就能够啦? 在程序启动的时候,调用一下 webapi 进行解密,这样你总没辙了吧 ??? 哈哈,你们能够开动脑子想想,这种方法可行不可行?诚然,解密算法搬走了,再用 ILSpy 去挖已经没有任何意义了,但这里有一个重要突破点,无论是用什么形式解密的,最后的链接串明文都是存放在 OleDbHelper.ConnectionString
这个静态变量中,对吧!接下来的问题就是有没有办法把进程中的这个静态变量给挖出来? 你说的对,就是抓程序的 dump文件 用 windbg 去挖。ide
要想挖出 OleDbHelper.ConnectionString
,其实也很简单,在 CLR via C#
第四章中关于对象类型和类型对象的解读有这么一张图,很经典。工具
从上图中能够看到,静态字段是在 Manager 类型对象
中,实例字段都是在 Manager 对象
中,对照这张图,我只须要经过 windbg 找到 OleDbHelper 类型对象
,也就是所谓的 EEClass
。sqlserver
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
就是方法描述符的地址。
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类型对象 在堆上的内存地址。
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
。
看到没有,上图中的两个紫色框框就是明文的 ConnectionString 哈,怎么样? 🐂不🐂。
当认识到上面的两种脱库方式,你应该就能想到,其实你在程序中链接数据库,这自己就是一种错,操做系统都能给你盗版,况且你这区区一个小软件? 我的以为彻底杜绝的方式那应该就是:灭掉本地的sqlserver,让全部的数据获取都由远端的 webapi 提供,固然这又是在脱离业务聊技术啦!😄😄😄