紫雨轩 .Net, DNGuard HVM , .Net VMProtect

DNGuard HVM - Advanced .NET Code Protection Technology

常用链接

统计

积分与排名

友情连接

最新评论

native compile 保护的dotNet本地程序还原成dotNet IL程序集

前面讨论了 .Net 保护中的 native compile 方式 。
提到了 native compile的两种方式 伪编译 和 ngen 编译。仍然没有像C++那样的完全native的编译。

这里要讨论的就是 ngen编译 生成的  ni 文件。
前面讨论时我们提到了fetion框架中的 fetionvm.srm文件。
注意到它是使用了ngen编译保护模式。
Remotesoft在评论中予以了证实,今回就以 fetionvm.srm这个文件为例,尝试ni文件的还原。

首先用reflector直接打开这个 srm文件。
这个文件里面就只有一个
[STAThread]
public static void Main(string[] argv)
{
}

空函数 ,再没有其它内容。很明显这只是一个壳,而且元数据和原始的也肯定不一样。

但是它配合ni文件能够正常运行,显然有一个地方应该会包含原始的元数据。
srm文件只有2k大小,应该没有可能隐藏原始的元数据。

在前面已经确认了原始元数据就隐藏在 ni 文件中。理论上说ni文件应该有个地方记录原始元数据的rva和size,由于对 ni 文件的格式不是完全清楚,所以这里采用暴力搜索的模式确定原始元数据的rva。
用编辑器(如UE)打开文件
\C\WINDOWS\assembly\NativeImages_v2.0.50727_32\FetionVM\6e39d95b1cb7d342a0ad2b892350dc65\FetionVM.ni.exe
搜索 BSJB ,
我们会发现有两个结果,其中一个就是目前cli header中指定的metadata。推测另外一个就是原始的元数据,在文件偏移的0x3000处。
根据元数据结构计算出这个原数据的大小是 0x0970。
把它提取出来查看其结构为:
namespace FetionVM
{
    internal static class Program
    {       
        private static string GetTimeString(DateTime dateTime);
        private static void Log(string message);
        [STAThread]
        private static void Main(params string[] args);
    }
}
看到这样的结构基本上可以肯定它就是原始的元数据了。

元数据有了,只能得到程序的类型结构,还是无法获取到方法体的代码。

前面推测ni 文件也包含了 原始的IL代码,今回就做个测试,
通过强制放法重新Jit编译,然后在Jit层进行捕获,得到了想要的IL代码。
强制方法重新Jit最简单的方式是使用profile api。
这个程序集很简单,经过手动还原,可以得到如下:
internal static class Program
{
    // Methods
    private static string GetTimeString(DateTime dateTime)
    {
        return (dateTime.ToLongTimeString() + ":" + dateTime.Millisecond);
    }

    private static void Log(string message)
    {
        try
        {
            File.AppendAllText(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "VMDotNet.log"), "[" + (DateTime.Now.ToString() + "] " + message + "\r\n"));
        }
        catch
        {
        }
    }

    [STAThread]
    private static void Main(params string[] args)
    {
        if (args.Length != 0)
        {
            string path = args[0];
            if (!File.Exists(path))
            {
                Log("未找到要运行的程序 " + path);
            }
            else
            {
                string assemblyFile = path;
                if (path.IndexOf(@"\") > 0)
                {
                    Environment.CurrentDirectory = Path.GetDirectoryName(path);
                    assemblyFile = Path.GetFileName(path);
                }
                AppDomainSetup info = new AppDomainSetup();
                info.PrivateBinPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "System");
                AppDomain domain = AppDomain.CreateDomain(Path.GetFileNameWithoutExtension(path), AppDomain.CurrentDomain.Evidence, info);
                try
                {
                    string[] destinationArray = new string[args.Length - 1];
                    Array.Copy(args, 1, destinationArray, 0, destinationArray.Length);
                    domain.ExecuteAssembly(assemblyFile, AppDomain.CurrentDomain.Evidence, destinationArray);
                }
                catch (Exception exception)
                {
                    Log("运行程序 " + path + " 出现错误!" + exception.Message);
                }
            }
        }
    }
}

到这里我们可以确定,在ni 文件中包含了原始的元数据和原始的IL代码。所以理论上ni文件是可以被还原的。

不知道除了Jit层捕获,是否还可以使用net2.0中的反射获取方法体代码?
有兴趣可以自己试试。

需要注意的是这些测试需要在那个虚拟框架中进行,另外看Main函数的代码,我们会注意到进程中至少包含两个应用程序域。

posted on 2007-08-27 14:35 紫雨轩 .Net 阅读(2362) 评论(10)  编辑 收藏 所属分类: DNGuard

评论

#1楼  2007-08-27 15:06 Adrian H. [未注册用户]

支持.
不清楚楼主是如何在JIT层捕获IL的, 有一个MS员工写的mdbg插件可以进行IL级别的单步调试:
http://blogs.msdn.com/jmstall/archive/2004/10/03/237137.aspx
http://blogs.msdn.com/jmstall/archive/2005/11/04/mdbg-il-debugging.aspx

我只知道用MethodBuilder emit出来的IL才能用reflection看到, 从程序集反射是否能看到就没试过了.   回复  引用    

#2楼 [楼主] 2007-08-27 15:18 瑞克      

普通net2.0的程序集可以用反射看IL代码。
可看看这个 http://www.cnblogs.com/rick/archive/2007/06/30/801515.html

Jit Hook
http://www.cnblogs.com/rick/archive/2007/07/08/810591.html
http://www.cnblogs.com/rick/archive/2007/08/13/852999.html   回复  引用  查看    

#3楼  2007-08-27 15:32 Adrian H. [未注册用户]

@瑞克
谢啦, 学习学习.   回复  引用    

#4楼  2007-08-27 21:33 没剑      

呵呵,楼主的帖子都非常不错,学习了啦   回复  引用  查看    

#5楼  2007-08-29 13:08 Wisdom-zh      

看来只有混淆难以还原.
为何没有人利用 JIT 编译结果组织成本地代码, 那样就无法还原了(不知道那样还能用否).   回复  引用  查看    

#6楼 [楼主] 2007-08-29 13:14 瑞克      

不太清楚,不过jit编译后的代码会调用到框架的函数。这种本地代码发布时还是需要附带框架环境。   回复  引用  查看    

#7楼  2007-08-30 13:03 .NET面试题 [未注册用户]

不太清楚   回复  引用    

#8楼  2007-09-01 04:44 无所谓 [未注册用户]

其实个人认为,现在强调源码的安全性有点不切实际,老实说技术还是比较透明的,关键是怎么运作,就算是机器语言,高人一样可以看透。还不如多花心思,在业务和运作上,技术不代表一切。
一家之言,不必介怀!   回复  引用    

#9楼 [楼主] 2007-09-01 13:30 瑞克      

@无所谓
国外的软件好像很多都这样,对于加密用得很少。
国内的环境可能还得过几年才行。
  回复  引用  查看    


标题  
姓名  
主页
Email (博主才能看到) 
验证码 *  看不清,换一张 [登录][注册]
内容(请不要发表任何与政治相关的内容)  
  登录  使用高级评论  新用户注册  返回页首  恢复上次提交      
该文被作者在 2008-04-09 20:11 编辑过


相关链接: