背景信息
“透明部落”是一个南亚(可能是巴基斯坦)来源具有政府背景的APT组织,其长期针对周边国家和地区的军队和政府机构实施定向攻击,其和南亚“响尾蛇”APT组织属于两个相互 “敌对”的APT组织。
样本信息
由于没有找到docx的md5所以也无法获取到样本只能从宏样本释放的payload进行分析。
• 档案名称:TrayIcos.exe
• 文件类型:适用于MS Windows(GUI)Intel 80386 32位的PE32可执行文件
• 档案大小:2.4 MB(2519552位元组)
• MD5:18ACD5EBED316061F885F54F82F00017
• 签名:Microsoft Visual C ++ 8
静态分析
初步先使用ida打开观看下大体的内容,下图展示的大概就是获取资源然后进行解密等操作
下面这张图如果有经验的话可以发现这是利用了CLR进行内存中加载.NET程序,没有经验也没有关系后面也都会提到。
下面就是实现C++运行donet的代码
#include <windows.h>
#include <oleauto.h>
#include <mscoree.h>
#include <comdef.h>
#include <cstdio>
#include <cstdint>
#include <cstring>
#include <cstdlib>
#include <sys/stat.h>
#import "mscorlib.tlb" raw_interfaces_only
void rundotnet(void *code, size_t len) {
HRESULT hr;
ICorRuntimeHost *icrh;
IUnknownPtr iu;
mscorlib::_AppDomainPtr ad;
mscorlib::_AssemblyPtr as;
mscorlib::_MethodInfoPtr mi;
VARIANT v1, v2;
SAFEARRAY *sa;
SAFEARRAYBOUND sab;
printf("CoCreateInstance(ICorRuntimeHost).n");
hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
hr = CoCreateInstance(
CLSID_CorRuntimeHost,
NULL,
CLSCTX_ALL,
IID_ICorRuntimeHost,
(LPVOID*)&icrh);
if(FAILED(hr)) return;
printf("ICorRuntimeHost::Start()n");
hr = icrh->Start();
if(SUCCEEDED(hr)) {
printf("ICorRuntimeHost::GetDefaultDomain()n");
hr = icrh->GetDefaultDomain(&iu);
if(SUCCEEDED(hr)) {
printf("IUnknown::QueryInterface()n");
hr = iu->QueryInterface(IID_PPV_ARGS(&ad));
if(SUCCEEDED(hr)) {
sab.lLbound = 0;
sab.cElements = len;
printf("SafeArrayCreate()n");
sa = SafeArrayCreate(VT_UI1, 1, &sab);
if(sa != NULL) {
CopyMemory(sa->pvData, code, len);
printf("AppDomain::Load_3()n");
hr = ad->Load_3(sa, &as);
if(SUCCEEDED(hr)) {
printf("Assembly::get_EntryPoint()n");
hr = as->get_EntryPoint(&mi);
if(SUCCEEDED(hr)) {
v1.vt = VT_NULL;
v1.plVal = NULL;
printf("MethodInfo::Invoke_3()n");
hr = mi->Invoke_3(v1, NULL, &v2);
mi->Release();
}
as->Release();
}
SafeArrayDestroy(sa);
}
ad->Release();
}
iu->Release();
}
icrh->Stop();
}
icrh->Release();
}
int main(int argc, char *argv[])
{
void *mem;
struct stat fs;
FILE *fd;
if(argc != 2) {
printf("usage: rundotnet <.NET assembly>n");
return 0;
}
// 1. get the size of file
stat(argv[1], &fs);
if(fs.st_size == 0) {
printf("file is empty.n");
return 0;
}
// 2. try open assembly
fd = fopen(argv[1], "rb");
if(fd == NULL) {
printf("unable to open "%s".n", argv[1]);
return 0;
}
// 3. allocate memory
mem = malloc(fs.st_size);
if(mem != NULL) {
// 4. read file into memory
fread(mem, 1, fs.st_size, fd);
// 5. run the program from memory
rundotnet(mem, fs.st_size);
// 6. free memory
free(mem);
}
// 7. close assembly
fclose(fd);
return 0;
}
动态调试
有了大体的认识之后我们可以开始用OD调试看看里面具体的细节,首先我们可以来到程序的入口点,不是VC的入口点,而是进入main函数里面的代码。发现调用了OleInitialize这个函数,这个函数的作用是初始化COM库。所以后面肯定使用到了COM库。
下面是这种操作mov了一大堆的指令然后再调用了一个call
进入这个call里面观看,这个函数就是取到了之前mov的数组进行解密了
那么我们直接来到return 看看返回值,可以很明显发现这解密出了字符串
所以我把这个函数命名为DecString
下面是获取环境变量Cor_Enable_Profiling
的值如果和0x41B2A0做比较如果不等于则会继续走下面,等于则跳转走另一分支,另一分支就是直接结束程序。所以我们走遍历模块的。
下面的api就是在创建快照
遍历模块和解密字符串
解密出来mscorjit.dll,这个dll是donet的,所以遍历模块应该是为了找到这个dll
这一段汇编就是strcmp,不熟悉的可以多看看
如果找到一样的则关闭句柄,并且return
然后下面又在找这个dll clrjit.dll
下面的代码就是一直循环在找那两个dll
当最后没有找到的话就会来到后面的解析资源的操作
遍历模块没看懂的话可以看看MSDN遍历模块
这里是在找资源了
然后先malloc一个资源大小 然后又new了一个0x40022的大小
很明显下面是个if else 就是下面这样的汇编格式,到这里内存空间就申请完了,下面就是拷贝资源了吧
cmp
jxx
ELSE_BEGIN:
…
jmp ELSE_END
….
ELSE_END:
这个函数主要做的就是把资源拷贝到new出来的空间
这个是按照1024个字节拷贝到malloc这个内存中
这里在取模sizeofRes也就是拷贝不足1024个字节的资源到malloc申请的空间中
释放资源后,malloc了一个空间,这个空间就是放解密后的资源数据
看看下面解密函数栈,第一个是刚刚malloc的空间,也就是解密数据要放的空间。第二个是之前malloc的大小。第三个是之前mallco空间的地址(加密的数据),最后一个是资源的大小。
解密后的资源不难看出有一个PE
再后面也没啥看的大概就是准备donet的环境,把该有的dll加载起来然后用C++调用这个PE文件,有兴趣的可以看看
现在我把那个PE给dump出来看看
使用PE解析工具看看发现资源里面还藏了个PE
既然这样这个dll就没啥必要看了大概功能就是释放执行里面的PE还是个Loader,用dnspy把资源保存出来
一看就是被混淆了的使用工具de4dot.exe去除试试
去完混淆后基本能很好的看懂了
这里就是远控的的代码地方了 donet的感兴趣的自己可以看看还是比较简单的
VT查了下最里层的Payload还没有被查
发表评论
您还未登录,请先登录。
登录