{samartassembly}4.1.39分析(加解密二)
二、程序集打包功能的分析
{sa}的程序集打包功能分为两种,一种为将几个程序集合成为一个程序集,就如我们编写了一个大的程序集一样,含有不同的命名空间及其一不同的类。第二种方式是将DLL作为加密后的资源嵌入,使用时解压解密释放到内存中。
1、程序集的合并:
准备:依旧采用上面的样例程序AppCllDll.exe,用{sa}将其引用的两个DLL文件打包进来,如下图配置生成。
Reflector打开效果:
分析:
打包后去掉了原来exe对dll的外部引用,并使原引用的DLL成为程序集的一部分。
反向:没有必要再还原回来,如果需要用Reflector+Visual Strdio200X 或ildasm/ilasm手动节选吧。
2、程序集的压缩和内存释放:
准备:依旧采用上面的样例程序AppCllDll.exe,用{sa}将其引用的两个DLL文件打包进来,如下图配置生成。
Reflector打开效果:
分析:能够看出主程序集对两个DLL的引用仍在,增加的那两个以GUID串儿为名的资源就是它们。此外增加了一些解压释放用的类和方法,全为不可见字符命名。一个关键点是:增加了一个全局静态方法(<Module>下的.cctor()),并在其中调用其它类中的方法完成DLL适当时机的内存释放。
释放时机:
// AppDomain.CurrentDomain.AssemblyResolve为对程序集的解析失败时
// rType15.rMethod31就是释放方法了
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(rType15.rMethod31);
//当前程序集从全局缓冲集加载并且主模块名"w3wp.exe"或"aspnet_wp.exe"时(rMethod29()得出)
if (Assembly.GetExecutingAssembly().GlobalAssemblyCache && rMethod29())
{
//释放DLL
}
这就是<Module>下的.cctor()最终调用的内容。
算法分析:
简单调整:为了明确说明问题,此处对上述生成的程序进行了名称反混淆,并导出成C#。如下图:
由于C#中没有全局方法,这里为Form1增加一静态构造类,并把原全局方法放入,达成相同效果。
1、先看解析不成功的释放情况:
x5.rType25.rMethod69()-àrType15.rMethod30()à解析不成时àrType15.rMethod31
以MyDll, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null为例:
当其解析不成时,rType15.rMethod31将其变换成:MyDll, Culture=neutral, PublicKeyToken=null,当其有PK时不变。
然后对其进行Base64编码,结果就是一个串儿” TXlEbGwsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49bnVsbA==”,根据这个串儿从原程序中硬编码的字符串儿集合中找出对应的资源文件名和压缩方式。在上图中已看到了那个硬编码的串儿集合。其格式为:
DLL全名称的Base64编码,[ 压缩方式] ,资源文件名(多个DLL则为多个串儿)
接下来其据压缩方式对资源文件解压放入byte[],然后assembly2 = Assembly.Load(buffer);返回assembly2。
2、当前程序集从全局缓冲集加载时的释放情况:
同上,但把资源文件解压后放入系统临时文件目录,用其创建程序集缓冲后删除。
压缩及解压代码请参见符件,也即调整后的程序代码。
反向:
运行程序后把它们从内存中dump出来就可以了,然后用CFF Explorer看一下它的名字,改为原名。
对于第二种情况,也可以WinDbg或PeBrowseDbg在文件删除前断点,从临时目录中拷出来。再就是利用它的解压代码写出文件来。
最后总结:
其实这种整体加密整体解密的方式用KDD,NETUnpack.exe这类工具在其运行后直接从内存dump就可以了。
当然,我们也可以调用.NET profiling API,Hook mscorjit.dll,或者简单地用进程注入+反射的方法把它dump出来,作为学习我们在下面的文档中动手来一步步完成这样的工作。
这里并没有探讨混淆,一个似乎简单又令人头痛的问题,特别是超大代码块让你的递归溢出后急于借助数据库又不得不嘲笑自己的那种滋味,所以还埋头学习吧。
posted on 2010-05-15 20:46 northstarlight 阅读(734) 评论(0) 编辑 收藏 举报