反射、反射加壳、反射脱壳、反射注册机(下)
反射、反射加壳、反射脱壳、反射注册机(下)
1、反射加壳
我曾经在06年的《黑客防线》上发表过一篇名为《C# 实现从自身资源提取EXE文件》的文章,主要讲的就是如何将EXE文件以资源的形式保存在PE文件中,然后自我释放出来(模仿木马的自我释放功能),当时就用了反射技术。时隔2年,当年的熬夜奋斗的情景我还依稀记得,通过该文章得指引,释放出来后将会得到一个独立的EXE文件。而在反射壳中仅仅将托管程序释放到内存中,并找到其入口点,然后执行入口函数(不释放真实文件),这便是DONET反射壳的原理了。怎么样?貌似很简单吧。
我们今天就拿一个CrackMe来加一层简单的反射壳。
首先新建一个CMD项目,将CrackME拷贝到这个项目文件中,并在解决方案中设置成为这个项目的“嵌入式资源”。
然后我们在代码中将这个资源转换为的字节数组:
然后我们再找到CrackME1.exe的函数入口点并运行就可以了。
最后我们再把这个项目的编译类型强制设置为Windows程序,编译一次,这个最简单的反射壳就完成了。我们可以看到其流程是:读取自身资源->转换资源为Assembly->找到入口点->执行入口函数。
我们用Reflector分别打开加壳和未加壳的程序查看:
未加壳程序如下:
已经加壳程序如下:
经过对比我们发现,加壳后的程序把CrackMe1.exe作为资源文件保存了,而我们的Refletor也不能查看其代码了。起到了简单的加密保护作用。
这就是反射加壳,很简单吧^_^!
2、反射脱壳
能加壳就能脱壳,这当然是天经地义的事情。在Win32时代OllyDbg似乎成了该平台下的宠儿,然而对于反射类的DONET平台壳,这款软件一加载就会将程序跑飞。有一身本领却施展不出来……..。
那么如何对付DONET平台下的反射壳呢?再回顾一下加壳原理,我们仔细看看这句代码:Assembly assembly = Assembly.Load(fileBytes); 这说明不管怎样系统都会将加壳的程序在内存中还原成一个Assembly的对象。那么我们只要获得了这个对象,也就可以获得这个程序相关的信息,结合上一篇文章我们甚至可以获得IL代码。那么如何获得这个对象呢?在程序域中有这样的方法 AppDomain.CurrentDomain.GetAssemblies(),可惜只有在本程序集中才能这样调用,一番思考后,我们发现可以将托管代码注射进入程序中,再利用该方法就可以获得其对象了。
通过上一片文章中我写的这个工具:“通用托管代码注射器”。就可以将托管程序注入到任意进程中。根据上篇文章注入cicireflection到上面的加壳的CiCiPackDemo中可以得到Crackme1.exe的完整信息。
那么我们如何把这个Crackme1.exe程序集完整的Dump下来呢?在介绍原理前先告诉大家一件失望的事情,这种反射脱壳在目前的DONET解密中并不实用了,更多的则是基于JIT层的脱壳,而不是基于软件本身,但是作为一种脱壳思路还是有必要和大家分享的。
其一:分享一下RICK大牛的方法,这是我拜读了RICK大牛的一些文章后自己理解的。(因为牛人写的文章经常只有代码并且点到为止,我等菜鸟可是要消化很久的)。用第三方的Dump软件把这个程序集先DUMP下来,然后根据Assembly对象获得一些数据来修复Dump后的文件,就相当于Win32程序脱壳后需要修复输入输出表的道理是一样的。而DONET反射脱壳则是来修复“方法体、头文件、元数据”之类的。为了不误导大家或者故意标榜自己的嫌疑,我还是请大家来看看Rick大牛的代码:http://bbs.pediy.com/showthread.php?t=47330
其二:说完了RICK大牛的原理,再看看我直接注入进去反射获得数据的办法。当然我们要用到我的通用托管代码注射器,自己写一个插件代码如下:
如果不懂没关系,因为反射脱壳早已经不是主流了,知道是这么回事就行了,以后我会和大家一起分享JIT层的脱壳方法。
3、反射注册机
反射注册机的就是通过反射的方法来运行软件中的注册算法函数,直接获得注册码的一种注册机方式。反射注册机的原理虽然很简单,但是编写者却要对软件的注册流程相当清晰,一旦抓住了软件的注册算法核心,那么写一个反射注册机就会易如反掌了。
下载了“通用托管代码注射器”附件的朋友有兴趣可以看看我是如何编写反射注册机的。
点击此处下载本章附件。
我曾经在06年的《黑客防线》上发表过一篇名为《C# 实现从自身资源提取EXE文件》的文章,主要讲的就是如何将EXE文件以资源的形式保存在PE文件中,然后自我释放出来(模仿木马的自我释放功能),当时就用了反射技术。时隔2年,当年的熬夜奋斗的情景我还依稀记得,通过该文章得指引,释放出来后将会得到一个独立的EXE文件。而在反射壳中仅仅将托管程序释放到内存中,并找到其入口点,然后执行入口函数(不释放真实文件),这便是DONET反射壳的原理了。怎么样?貌似很简单吧。
我们今天就拿一个CrackMe来加一层简单的反射壳。
首先新建一个CMD项目,将CrackME拷贝到这个项目文件中,并在解决方案中设置成为这个项目的“嵌入式资源”。
然后我们在代码中将这个资源转换为的字节数组:
Stream sr = Assembly.GetExecutingAssembly().GetManifestResourceStream("CiCiPackDemo.CrackMe1.exe");
byte[] fileBytes = new byte[sr.Length];
sr.Read(fileBytes, 0, (int)sr.Length -1);
Assembly assembly = Assembly.Load(fileBytes);
MethodInfo mi = assembly.EntryPoint;
mi.Invoke(null, null);
注:这里的“CiCiPackDemo”为该项目的命名空间,而“CrackMe1.exe”为嵌入式资源名。byte[] fileBytes = new byte[sr.Length];
sr.Read(fileBytes, 0, (int)sr.Length -1);
Assembly assembly = Assembly.Load(fileBytes);
MethodInfo mi = assembly.EntryPoint;
mi.Invoke(null, null);
然后我们再找到CrackME1.exe的函数入口点并运行就可以了。
最后我们再把这个项目的编译类型强制设置为Windows程序,编译一次,这个最简单的反射壳就完成了。我们可以看到其流程是:读取自身资源->转换资源为Assembly->找到入口点->执行入口函数。
我们用Reflector分别打开加壳和未加壳的程序查看:
未加壳程序如下:
已经加壳程序如下:
经过对比我们发现,加壳后的程序把CrackMe1.exe作为资源文件保存了,而我们的Refletor也不能查看其代码了。起到了简单的加密保护作用。
这就是反射加壳,很简单吧^_^!
2、反射脱壳
能加壳就能脱壳,这当然是天经地义的事情。在Win32时代OllyDbg似乎成了该平台下的宠儿,然而对于反射类的DONET平台壳,这款软件一加载就会将程序跑飞。有一身本领却施展不出来……..。
那么如何对付DONET平台下的反射壳呢?再回顾一下加壳原理,我们仔细看看这句代码:Assembly assembly = Assembly.Load(fileBytes); 这说明不管怎样系统都会将加壳的程序在内存中还原成一个Assembly的对象。那么我们只要获得了这个对象,也就可以获得这个程序相关的信息,结合上一篇文章我们甚至可以获得IL代码。那么如何获得这个对象呢?在程序域中有这样的方法 AppDomain.CurrentDomain.GetAssemblies(),可惜只有在本程序集中才能这样调用,一番思考后,我们发现可以将托管代码注射进入程序中,再利用该方法就可以获得其对象了。
通过上一片文章中我写的这个工具:“通用托管代码注射器”。就可以将托管程序注入到任意进程中。根据上篇文章注入cicireflection到上面的加壳的CiCiPackDemo中可以得到Crackme1.exe的完整信息。
那么我们如何把这个Crackme1.exe程序集完整的Dump下来呢?在介绍原理前先告诉大家一件失望的事情,这种反射脱壳在目前的DONET解密中并不实用了,更多的则是基于JIT层的脱壳,而不是基于软件本身,但是作为一种脱壳思路还是有必要和大家分享的。
其一:分享一下RICK大牛的方法,这是我拜读了RICK大牛的一些文章后自己理解的。(因为牛人写的文章经常只有代码并且点到为止,我等菜鸟可是要消化很久的)。用第三方的Dump软件把这个程序集先DUMP下来,然后根据Assembly对象获得一些数据来修复Dump后的文件,就相当于Win32程序脱壳后需要修复输入输出表的道理是一样的。而DONET反射脱壳则是来修复“方法体、头文件、元数据”之类的。为了不误导大家或者故意标榜自己的嫌疑,我还是请大家来看看Rick大牛的代码:http://bbs.pediy.com/showthread.php?t=47330
其二:说完了RICK大牛的原理,再看看我直接注入进去反射获得数据的办法。当然我们要用到我的通用托管代码注射器,自己写一个插件代码如下:
if (folderBrowserDialog1.ShowDialog() == DialogResult.OK)
{
try
{
Assembly [] assemblies = AppDomain.CurrentDomain.GetAssemblies();
bool isUnpack = false;
foreach (Assembly assembly in assemblies)
{
if (Path.GetFileName(assembly.Location).ToLower() == "cicipackdemo.exe")
{
using (Stream sr =assembly.GetManifestResourceStream("CiCiPackDemo.CrackMe1.exe"))
{
byte[] fileBytes = new byte[sr.Length];
sr.Read(fileBytes, 0, (int)sr.Length - 1);
File.WriteAllBytes(folderBrowserDialog1.SelectedPath + "\\CrackMe1_UnPack.exe", fileBytes);
}
MessageBox.Show("脱壳成功!", "", MessageBoxButtons.OK, MessageBoxIcon.Information);
isUnpack = true;
break;
}
}
if (!isUnpack)
{
MessageBox.Show("没有找到CiCiPackDemo.exe", "", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
原理很简单吧,找到进程中的程序集,然后直接通过反射读取CrackME1.exe文件,将其写入到具体的文件中。编译后放在“通用托管代码注射器”的Plugin目录下,将这个dll注入到ciciPackDemo.exe中,选择保存的路径,就可以脱壳了。完整代码请参考附件。{
try
{
Assembly [] assemblies = AppDomain.CurrentDomain.GetAssemblies();
bool isUnpack = false;
foreach (Assembly assembly in assemblies)
{
if (Path.GetFileName(assembly.Location).ToLower() == "cicipackdemo.exe")
{
using (Stream sr =assembly.GetManifestResourceStream("CiCiPackDemo.CrackMe1.exe"))
{
byte[] fileBytes = new byte[sr.Length];
sr.Read(fileBytes, 0, (int)sr.Length - 1);
File.WriteAllBytes(folderBrowserDialog1.SelectedPath + "\\CrackMe1_UnPack.exe", fileBytes);
}
MessageBox.Show("脱壳成功!", "", MessageBoxButtons.OK, MessageBoxIcon.Information);
isUnpack = true;
break;
}
}
if (!isUnpack)
{
MessageBox.Show("没有找到CiCiPackDemo.exe", "", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
如果不懂没关系,因为反射脱壳早已经不是主流了,知道是这么回事就行了,以后我会和大家一起分享JIT层的脱壳方法。
3、反射注册机
反射注册机的就是通过反射的方法来运行软件中的注册算法函数,直接获得注册码的一种注册机方式。反射注册机的原理虽然很简单,但是编写者却要对软件的注册流程相当清晰,一旦抓住了软件的注册算法核心,那么写一个反射注册机就会易如反掌了。
下载了“通用托管代码注射器”附件的朋友有兴趣可以看看我是如何编写反射注册机的。
点击此处下载本章附件。