Sec Hotspot 首页  排行榜  收藏本站  技术博客  RSS
统计信息
已收录文章数量:12925 篇
已收录公众号数量:89 个
本站文章为爬虫采集,如有侵权请告知
已收录微信公众号
网信中国 区块链大本营 白说区块链 区块链投资家 区块链官微 区块链铅笔Blockchain HACK学习呀 二道情报贩子 合天智汇 小白帽学习之路 小米安全中心 弥天安全实验室 SAINTSEC SecPulse安全脉搏 TideSec安全团队 360安全卫士 游侠安全网 计算机与网络安全 安全祖师爷 安全学习那些事 腾讯安全联合实验室 黑客技术与网络安全 安全圈 腾讯御见威胁情报中心 Python开发者 Python之禅 编程派 Python那些事 Python程序员 安全威胁情报 吾爱破解论坛 行长叠报 安在 i春秋 嘶吼专业版 E安全 MottoIN 网信防务 网安杂谈 数说安全 互联网安全内参 漏洞战争 安全分析与研究 邑安全 ChaMd5安全团队 天融信阿尔法实验室 安全牛 SecWiki 安全学术圈 信安之路 漏洞感知 浅黑科技 Secquan圈子社区 奇安信集团 奇安信 CERT 国舜股份 雷神众测 盘古实验室 美团安全应急响应中心 瓜子安全应急响应中心 顺丰安全应急响应中心 蚂蚁金服安全响应中心 携程安全应急响应中心 滴滴安全应急响应中心 字节跳动安全中心 百度安全应急响应中心 腾讯安全应急响应中心 网易安全应急响应中心 OPPO安全应急响应中心 京东安全应急响应中心 Bypass CNNVD安全动态 安恒应急响应中心 天融信每日安全简报 奇安信威胁情报中心 看雪学院 黑白之道 水滴安全实验室 安全客 木星安全实验室 云鼎实验室 绿盟科技安全预警 白帽汇 深信服千里目安全实验室 腾讯玄武实验室 长亭安全课堂 FreeBuf 绿盟科技 nmask
【二进制安全】某APT样本分析
本文来自公众号:弥天安全实验室   2020.07.06 09:13:13







测试环境及工具

Windows 7 虚拟机

查壳工具: PEID ExeinfoPE

监测工具:火绒剑、 PCHunter

调试工具: OD IDApro
第一阶段
静态分析信息


样本执行枚举当前正在运行的进程和线程

本包含样一个 1431KB 大小的加密资源

Main 函数流程概要

函数在执行 sub_4027f0 后便把自己结束掉,进入 sub_4027F0 的执行流程

先执行 sub_414D70 查找资源,即在 PEStudio 中查看到的较大的异常资源

在 sub_414D70 调用中除了返回值 result,其输出参数 v21,v20 在 sub_401E00 作为输入参数后执行

随后在此过程中又调用几个函数,在 WinMain 函数执行最后

使用 VirtualAlloc 分配空间跳转并执行 shellcode

第二阶段
动态分析信息


OD 定位到 WinMain 入口点 00402A70

单步向下进入 00414D70,获得 FindResourceW、LoadResource、SizeofResource、 LockResource 四个函数地址

判断有效性后,调用

从参数可以得到此时在获取命名 1 的资源

后调用 LoadResource、SizeofResource,并将SizeofResource 的返回结果 165880 传给 arg3,将资源句柄 434EE8 传给 arg4

继续向下执行进入 00401E00->0040B020->0040B305 调用了一个非标准的 memcpy函数,将资源数据拷贝到内存中。 (dst<-B50020,src<-434EE8,size<-165880)

memcpy 执行完后,对照数据,这部分还处于加密状态

继续执行到 00408661,这是属于函数 sub_408570 的部分,这里引用了 00422FA0 的代码

执行到 00416ADC,调用了 00416BEA,它是 malloc 的代码,此时 malloc 返回值为 0xAA28B8

函数 sub_408570 作用为分配一段空间 0xAA28B8,随后在 00401F0C 处调用

memcpy(0xAA28B8,0x429000,0x80)(call 00415D20)


执行到 00401F47,CALL 到 0040AC00,共三个参数([12FE5C](0xAA28B8),0,-1)

在 0040AC00 中又调用了 00408570,分配空间的起始地址为 00AA2950

随后执行到 40AE6F,调用 memcpy(0xAA2950,0xA28B8,0x80),将 0xA28B8 的 0x80 字节拷贝到 0xAA2950,并将 0xAA29D0 置 0

执行到 00401F6A 再次调用 sub_40AC00(0x12FE24(B50020),-1,0),分配空间为 0xCC0020

将 0xB50020 的 165800(整个资源)拷贝到 0xCC0020,继续向下回到 0x401E00 主函 数执行到 00401C80,有两次资源加载操作

第一次分配空间为 0xE30020,其内容为初始资源数据;第二次为 0xAA29E8,将 0xAA2950 的 0x80 字节拷贝,随后执行到 00401D56 代码解密

执行到 00401D86,解密完成起始位置从 00E30020 到 00F95820

向下执行到 00402008,CALL 了 00415ACB,new 了一个 0x16D6C4 的空间,这个大 小是在[00E30020+0x4]处标明,分配空间的起始地址为 0xCC0020(这是一个新的 地址,上面分配的地址已经 delete) 执行到 00402037,这里调用了 sub_4145D0,它是 00412DF0 的包裹函数即为 sub_412DF0(0xCC0020,0x12FE00,0xE3002D,0x12FDD4(0x165873),0xE30028,0x5,0,0 x 12FDE4(0x5),off_0x429138), 其 中 0x5 是 一 个 固 定 参 数 , [0xE30028] 为 0x2000006F,[0x12FE00]为 0x16D6C4,它是 new 的空间大小,0xCC0020 是 new 出 空间的起始地址,0x165873 为[00E30020]-5,[0xE3002D]为 0x0

在 sub_412DF0 中调用第一个函数 412C40(0x12FD28,0xE30028,0x5,off_0x429138)


接着调用 sub_412B80(0x12FCDC(0xAA0608),0xE30028,0x5),0xAA0608 存放的值为 0x164758

在 sub_412B80 中,先对第三个参数进行判断,小于 5 则 result 返回 4,再从 0 xE3002B 取值 0x20 并左移 8 位,与[0xE3002A]=0 异或,再左移 8 位,与 [0xE30029]= 0 异或再左移 8 位,结果为 0x00200000,与 0x1000 比较,若值小于 0x1000 则将结果修改为 4096,保存在[0x12FCDC+3*4]。 再比较[0xE30028](6F)是

否大于 E1,小于则返回 4。 后[0x12FCDC]=0x3,[0x12FCDC+2*4]=0x2,[0x12FCDC+1*4]=0x2

执行到 00412C83,这里 CALL 了两个函数

第一个函数地址是[off_429138+4]=0x40CBF0,共 3 个参数(0x429138,0,0)

它是 CALL 了一个 free() 第二个函数地址是[off_429138]=0x40CBD0,共 2 个参数(0x429138,0xce6c)

即分配了一个大小为 0xce6c 的堆空间,执行后起始地址为 0xFA0048,即 v7

将 FA0048 放 入 0x12FD28+4*4=0x12FD38, 将 v6 的 计 算 结 果 6736 放 到

0x12FD28+21*4=0x12FD7C[0x12FD28]=0x3,[0x12FD28+1*4]=0x2,[0x12FD28+2*4]=0x2,[0x12FD28+3*4]=0x00200000


sub_412C40 执行完毕,返回 result 为 0,进入 if 分支,执行 sub_412440,参数为 ( 0x12FD28(3),0x16D6C4,0xE3002D(0x00),0x12FDD4(0x165873),0,0x12FDE4) 执行进入 sub_411CB0(),检测 ECX 为 0 后直接退出(?)


执行到 00412511,esi=12FD28,对应 IDA 为

执行到 0041256E,用 0x0400 把 00FA0048 开始的空间填充

执行到 004125E0,CALL 到 00411D30,压入参数是0xF9588C(0x187D0992)

这也是 00412440 最后一个 CALL,在 00411D59 处调用了 sub_00410910,压入了 三个参数(0x12FD28,0x16D6C4,0xF9588C),在 IDA 中看出经过一系列复杂的计算, 最终将值保存在以 0x12FD28 开始的位置上, 从 00411C4A 开始会多次计算,下面是第一次的 值:

[0x12FD28+0x1C]=[0x12FD44]=0x1DA648C0 -> a[7] last:0x2CD0AA3[0x12FD28+0X18]=[0x12FD40]=0xF9588C -> a[6]  last: 0xF958A0[0x12FD28+0x24]=[0x12FD4C]=0x16D46F -> a[9]  last: 0x16D6C4 Correct0041C5C 处:[0x12FD28+0x48]=[0x12FD70]=0x0 -> a[18] last: 0x0[0x12FD28+0x38]=[0x12FD60]=0x130 -> a[14] last: 0x134[0x12FD28+0x2C]=[0x12FD54]=0x16D46F -> a[11] last: 0x16D6C4 Correct[0x12FD28+0x40]=[0x12FD68]=0xF2 -> a[16]  last: 0x130[0x12FD28+0x20]=[0x12FD48]=0x1964DAF6 -> a[8] last: 0x0[0x12FD28+0x3C]=[0x12FD64]=0x128 -> a[15] last: 0x1[0x12FD28+0x34]=[0x12FD5C]=0x06 -> a[13]  last:0xB[0x12FD28+0x44]=[0x12FD6C]=0x2BA -> a[17] last:0x128


在 sub_412440 里的循环中,其中关键点是[0x12FD28+0x24]=[0x12FD4C](a9),它 赋值处在 00411C5C 处上面调用的代码,当循环执行 18 次后,它的值计算正确 (00411C89 处的执行流程 test ecx,ecx(执行 19 次后跳出)),后继续执行会退 出sub_412440 到代码 00412EBF 处

随后将 off_00429138 压入栈中,调用 sub_0x40CBF0,即 free 掉 0xFA0048 这段空 间,sub_412DF0 函数执行结束,sub_4145D0 函数结束。 至此 sub_401E00 只剩两 个函数,一个是 CopyToMemory(0xCC0020,0x16D6C4)即(sub_40B020,调用处在 0040204B),另外一个是在 00402051 处 CALL 的 sub_416BDF

CopyToMemory 分配的空间为 0x10A0020,调用 copy 函数从 0xCC0020(资源)到 0x10A0020,大小为 0 x16D6C4

上述过程执行完毕后,执行 00416BDF,其压栈了 0xCC0020,其流程就是跳转到 00415D13 执行即 delete 函数,释放 0xCC0020 这段空间

接着释放 0xAA28B8,释放 0xB50020,释放 0xE30020,至此 sub_401E00 执行完毕, 这个函数很长,其总体作用即将资源进行解密后存放在内存 0x10A0020 处,大小 为0x16D6C4,它的返回值即 0x12FEC8(栈地址)中存放的是 0x10A0020 继续向下执行到 0040290C,这里有一个判断,即 Local.7 的值是否小于等于

0x16D6C4,条件成立则 CALL 到 00401B10

把0x12FED4 压栈[0x12FED4]=off_42B090(数据段),在0040291A CALL 到 00401B10, 在 00401B48 将 0x10A0020 放入 EDI,并将[0x10A0020] DWORD =0x16D6C0 取出与

[0x10A0020+0x4]=0x1296AE 比较

继续向下,在 00401C20 准备 CALL 0040A150

随后在 0040A18E CALL sub_406E90,压入 0x1,分配 0x1*4,起始地址为 0xAA2A80, 然后执行一个拷贝函数,这是循环第一次执行,没有拷贝什么实质内容,随后结 束,其返回值为 1,第二次执行分配 0xAA2A90,将从 0xAA2A80 拷贝 4bytes 到 0xAA2A90,随后释放掉 0xAA2A80,接着 0xAA2AA0.........会将结果的指针保存在 ESI

循环结束,返回 0x12FED4,它指向的值为 00AA2AB8

至此 sub_401B10 执行完毕,向下执行到 00402978,它 CALL 函数 0040A880,压栈 两个(0x11C96DA,0x15)


接着在0040A994 CALL到sub_004065B0(0x15,0x0)里面有大量花指令,在00406830 CALL sub_00416AC2 分配一个 0x30 大小内存,起始地址为 0xAA2AD0, sub_406580 执行完毕后,在 0040AAF5 调用 memcpy(0xAA2AD0,0x11C96DA,0x2A),

可以看到 0x11C96DA 是解密后资源包含 FireFox 的安装包

大小是 0x03BFD8,后面就是一个 PE 的 Dos 头(0x11C9708-0x12056DF),带有 Mozilla 签名

在FireFox这个PE结束后,看到有第二个PE,大小为0x8000,起始地址为0x12056E4

继续执行,在 00402985 调用 00402540(0X12FEE4,0x11C9704)即释放 FireFox 文件 执行

先调用 sub_406830 分配内存,起始地址为 0xAA2BDE,随后将 0xAA2B08 开始 的”FireFox Installer.exe” 0x2A字节拷贝,接着执行到00402708,CALL 到004020D0, 这是关键函数,它结束前面准备工作将 Installer 释放并执行,这部分代码作者使

用 JMP 改变正常执行顺序以及花指令,扰乱 IDA 的反汇编结果。

它先 new 0x24 字节的空间,起始地址为 0xAA2D30,在 00402161 调用 00405CC0(“\/”,0x0,0x2)

代码 00402171 到 00402273 循环主要对释放路径进行校验和拼接

代码 004022B8 到 004022F4 循环递归创建上述路径

在 0040232B 处,调用 CreateFileW 创建文件,文件句柄为 0x3C

在 0040263D 调用 WriteFile,向上面文件中将内存0x011C9708(FireFox)写入文件

在 00402793 调用 ShellExecuteW 执行

(由于这个安装包要求环境至少 Win7 以上,更换测试环境)

到此sub_00402540(DropFireFoxAndExecute) 执 行 完 毕 , 接 下 来 调 用 两 次 VirtualAlloc 分配可执行的空间对恶意代码使用

第一次执行分配的内存空间起始地址为 0x00B60000,大小为 0x5

第二次执行分配的内存空间起始地址为 0x00B70000,大小为 0x1296AE

执行到 004029C6-004029C9 向 0x00B60000 填充 0xE9 0x00000FFB,即 JMP 00B70000

接着从[0x10A0020+0x4]中取出 0x1296AE,这是第一部分代码的大小,将恶意代码 拷贝到 0x00B70000- >memcpy(0x00B70000,0x10A028,0x1296AE)

然后 CALL 到 0x00B60000 并 JMP 到 0x00B70000 执行 shellcode。ShellCode 中有大 量花指令,两次执行后停在 00C96C3A

执行到 00C97AD8,将 0x4B(K)、0x45(E)、0x65(e)写[ebp-0x40],[ebp-0x10],[ebp-0x28]

将 0x52(R),0x72(r),0x4E(N),0x6E(n),0x4C(L),0x6C(l),0x44(D),0x64(d),这些字符串恰好 能拼成一个 Kernel dll

开始找 kernel32.dll

保存 Kernel32.dll 的基地址

恶意代码作者采用的是 ASCIItoShellCode 的模式,将函数转换成 shellcode,如

int strLoadLibraryA[4]; // "LoadLibraryA"strLoadLibraryA[0] = 0x64616F4C;strLoadLibraryA[1] = 0x7262694C;strLoadLibraryA[2] = 0x41797261;


nt strGetProcAddress[4]; // "GetProcAddress"strGetProcAddress[0] = 0x50746547;strGetProcAddress[1] = 0x41636F72;strGetProcAddress[2] = 0x65726464;strGetProcAddress[3] = 0x00007373;


结果

在 00C989D9 下断执行

寻找 LoadLibraryA 00C98662 CMP CL,0x4C//0x4C == ‘L’00C9890 JMP 00C9896000C9896F MOV DWORD PTR SS:[EBP-0x50],EAX//EAX->LoadLibararyA 完成赋值寻找 GetProcAddress00C98972 CMP BYTE PTR SS:[EBP-0x29],0X47 //0x47 == ‘G’00C989DC MOV DWORD PTR SS:[EBP-0x1C],EDI//EDI->GetProcAddress 完成赋值


LoadLibraryA 的地址 7C801D7B 放到[ebp-0x50(12FE38)]


GetProcess 地址 7C80AE30 放到[ebp-0x1C],Kernel32.dll 基址在[ebp-0x18]


00C981B0 调用 call edi(GetProcAddress) 获取 VirtualAlloc 函数地址 7C809AE1

VirtualAlloc 的函数地址放到[ebp-0x34] 获取 RtlMoveMemory 函数地址 7C922C94 到[ebp-0x48]


获取 RtlZeroMemory 函数地址 7C922C64 到[ebp-0x14]

并将 0xFEFEFEFE 写入[ebp-0x30],调用RtlZeroMemory(0x12F7D8,0x102),即存储函

数字符串上面的内存空间,并开始填充,填充完毕后在 00C9701C-00C9702D 开始 使用 00B7000+X 的数据异或解码 0x12FD2C 处 0x28 大小的数据

从 0x12F7D8 开始到 0x12F8D7 填充 0x0 到 0xFF 随后执行到 0xC976AD 解密填充, 在 0xC976D3 把 0xB70032 处的数据填充到 0x12F798 处共 16 字节, 又经过一系列的解密运算后执行到 00C9803C-00C98055(Size 3E)

经过一系列解密执行到 00C97DED,调用 VirtualAlloc(0x0,0x12A000,0x2000,0x1),

始 地 址 为 0x00CA0000, 大 小 为 0x12A000, 接 着 继 续 调 用

VirtualAlloc(0x00CA0000,0x2A0,0x1000,0x4),

返回值为 0x00CA0000,大小为 0x2A0

随后给 00CA0000 从 0x12F798 写入 0x10 字节,这个开头是一个 PE 文件

随后给 00CA0000 从 0x12F798 写入 0x10 字节,这个开头是一个 PE 文件


在 00C96EB9 向 00CA00E0 写入[0x12F6A0]的数据,大小为 0x3E。这是一个 PE 头

从这可以看出,恶意代码作者精巧的构造了一个 PE 文件,而不是采用一次性写 入的方式,继续填充从 00B7020A 读取到 00CA01D8,大小为 0xA

从 00B70232 读取到 00CA0200,大小为 0xA

从 00B7025A 读取到 00CA0228,大小为 0xA

从 00B70282 读取到 00CA0250,大小为 0xA

从 00B702AA 读取到 00CA0278,大小为 0xA

执行到 00C994AF,第二次调用 VirtualAlloc(0xCA1000,0x12EFE,0x1000,0x40),从

0xCA1000 开始,大小为 0x12EFE

清 0

在 00C98C2B 将 0xB70432 开始的 0x12EFE 大小写入 0xCA1000


经过一系列填充修正数据后,第三次调用 VirtualAlloc(0xCB4000,0x3636,0x1000,4),

清零后将 0xB83432 开始的大小为 0x3636 的数据填充到 0xCB4000

第四次调用 VirutalAlloc-RtlMoveMemory 从 0xCB8000 开始,大小 0x1A60。数据拷 贝从 0xB86C32 开始,大小为 0xE00

第五次调用 VirutalAlloc-RtlMoveMemory 从 0xCBA000 开始,大小为 0x10DB50。 数据拷贝从 0xB87A32,大小为 0x10DB50

第六次调用 VirtualAlloc-RtlMoveMemroy 从 0x00DC8000 开始,大小为 0x15F8。 数据拷贝从 0xC95632,大小为 0x15F8

从 00C970CB 开始调用 GetProcAddress 将下列函数地址写入 00CB4044 开始位置

VirtualFree,VirtualAlloc,WriteFile,CloseHandle,CreateDirectoryW,CreateFileW,ExpandEnvironmentStringW,FindResourceW,SizeOfResource,LoadResource,LockResource,CreateProcessW,RaiseException,RtlUnwind,HeapAlloc.....直到 00CB414C,可见是修复


导入表或导出表,从 00C97113 继续执行

在 00C996A3 处执行 LoadLibraryA 加载ADVAPI32.dll(0x77DA0000),从 00CB4000

开始到 00CB4040 调用 GetProcAddress 获取 ADVAPI32 中的函数地址。执行到 00C98F7A,准备修复节表

执行到 00C9887F(偏移 0x12887F),这里的 CALL EAX 即 00CAE709,可以把这段内存 DUMP 出,从 00CA0000 开始这是一个 DLL,而 E709 正好为这个 DLL 的 DllEntry

在这里 CALL 两个函数,第一个即偏移为 0x11059(00CB1059)函数,第二个是偏移 为 E613 的函数(00)

先调用 GetCurrentProcessId,GetCurrentThreadId 和 GetTickCount,这三个值与 ESI 异或 QueryPerformanceCounter 在虚拟机中返回值为 1

回到 DllEntry 部分代码调用 00CAE613



第一个函数是 00CB0D00,设置 SEH,没做其它事情

第二个函数为 00CAE4AF,压入了三个参数(0x00CA0000,0x1,0x0)


执行到 00CB04E0 CALL HeapCreate(0x0,0x1000,0x0),返回值为 00DD0000,存到 [0xCB9628] 执行到 00CAE4D3 CALL 到 00CAFDA1,sub_FDA1 函数比较复杂 首先调用 GetModuleHandleW,获取 Kernel32.dll 的模块基址,通过 GetProcAddress 获取 FlsAlloc,FlsSetValue,FlsFree 三个函数地址并执行(由于用到的函数均需要在 Win7以上版本才能执行,因此需要切换环境) 补充 在进入 PE 之前在偏移+0x0001649A 函数处获得当前执行环境



随后在偏移 0x10061 处调用 RtlEncodePointer,返回的加密指针保存在

[+0x18FAC],[+0x19740],[+0x19908],[+0x19904],[+0x198F0],[+0x198F4][+0x198F8][+0x198Fc]



在 sub_FFA0 再次调用 RtlEncodePointer,压入偏移为 0xFF1C 处(0x6068086A),将返 回值存入[+0x18FC8] sub_FE78 开始分 别用 RtlEncodePointer 对 FlsAlloc,FlsSetValue,FlsGetValue 编码

继续在偏移+0xFEA6 处调用 sub_ 112C9 其主要是临界区加锁


接着执行 sub_105AC->sub_12937,调用RtlAllocateHeap([+0x19628],ZERO,0x214), 则 sub_105AC 完毕



调用 sub_FABD(HeapAllocate 返回值,0x0),对临界区和 Fiber 一些操作,最后在 0xFF01 处调用 GetCurrentThreadId()并返回 sub_E4AF, 在偏移 E4E8 处调用 GetCommandLineA,并将返回结果存入[+0x19A5C],随后调

sub_10C0F->GetEnvironmentStringW->WideCharToMultiByte->RtlAllocateHeap(0x1CE0000,0x487)(sub_E3B9)sub_10646->GetStartUpInfo->RtlAllocateHeap->GetStdHandle->SetHandleCount


在偏移+E50D 处有这样三处调用,有大量花指令和循环代码


单步 F7,随后 F8 步过后执行 sub_E4AF 最后一个函数 sub_10D45 清理堆栈返回 第三个函数为 sub_1000,给 eax 置 1 后返回,最后加载 DLL 的流程结束 回到 ShellCode 的内存空间


在偏移+0x129592 处 CALL EAX 到偏移+0x1389B0 处

在 偏 移 +0x139615 CALL 了 AllocateAndInitializeSid , +0x139685 CALL 了 ChekTokenMembership 作用是用来判断是否有管理员权限

在偏移+0x(13)96A7 CALL 偏移+0x(13)3980 代码,随后执行到偏移+0x(13)3C81 执 行FindResourceW hModule 为 DLL 基址,Name 为 0x1

资源位置在偏移 0x1A080 处

大小为 0x10D850

加载资源并 Lock(0x1A0A0)

跳转到 PE 内存基址处执行到偏移+0x3B6B 处,调用偏移+1F40 处代码

首先调用 sub_DE20,进入后调用 sub_E3B9 RtlAllocateHeap 结束

在偏移+0x3A02 处压入 4 个参数,其中 0x17C0020 是分配的空间,0x1BFA0A0 是 资源的地址,0x10D850 是资源大小

从偏移+0xE83B 处开始到偏移+0xE884 将资源写入堆空间

至此+0x3980 代码执行完毕, 随后再次执行到+0x4D5B 调用+0xD740,拷贝 8 个字节到刚分配的空间

执行到偏移 0x417D 调用 CryptAcquireContextW(0x12F48C,0,0,0x18,0xF0000000)


在+0x3E59 处调用 CryptImportKey(0x2E8DB0,0x12F4CC,0x2C,0,0,0x12F4C8)

在+0x4007 处调用 CryptSetKeyParam(0x2EA758,0x1,0x1451F88(0xAAABD1B2),0)

执行到+0xE83B,将 0x17C0020 资源文件前 0x70 大小的资源写入 0x1D10020 - 0x1E1D860

在+0x4134 处执行 CryptDecrypt(0x2EA758,0,0x1,0,0x1D10020,[0x12F4C4]=10D850)

CALL 到+0x3440 即 RtlAllocateHeap(0x1450000,0,0x1D850) 返回 0x1E20020

将 01D10020 的内容拷贝到 01E20020-01F2D860

执行

->+0xCEE1 CALL EDX(+9840) (0x1BF8068(0x01BE96D0),0),第一个参数是一个函数指针->RtlHeapAllocate 标记 1->+0xCB73 CALL +BAA0 步过->+0xC804 初始化上两步分配的空间->+0xC883 CALL +0xBC70->+0xA234 +0xAF18 +0xAF9D +0xAFF6 向标记 1 写入解密数据



->+0xB579 出循环->+0xA327,+0xA332 下断执行,开始向内存写入要 Drop 文件%appdata%\SymantecEndpoint Protection\12.1.671.4971.104a\



可以看到这里拼接了三个文件

在%programfiles%\Symantec\Symantec Endpoint Protection\12.1.671.4971.104a\... 释放同样三个文件, 第一块从偏移+0x04A0 开始,是一个 PE 文件

第二块从这块内存偏移+0x14A0 开始,到+0xC643 结束,是一段 ShellCode

第三块从这块内存偏移+0xD4A0 开始,存一些字符串和函数名,像是编译信息


第四块从偏移+0x1D4A0 开始,是一些签名信息等

还要类似这样,+01242CA

直接 F9 后发现%programs%多了三个文件

向 CreateFile WriteFile 下断,F9 执行

->+0x78B5 CALL WriteFile (CALL +0xD5F7 ->HeapFree)

第一个是 rastls.exe,大小为 0x1A548

第二个是 SyLog.bin,大小为 0xF6010

第三个是 rastls.dll 大小为 0x13800

随后继续执行,发现样本创建进程 rastls.exe 并注册了一个服务,并且 rastls.exe 具有自保护的功能,在删除后会重新启动,创建服务名称为 dmwappushservic e, 并且加载了释放出的 dll 文件,由此猜测 rastlsc.exe->rastls.dll->SyLog.bin 这样的调 用方式来进一步加载恶意代码。 这个进程是属于 System 组

与远程地址 xx.xxx.xxx.xxx:25123 建立连接,本地端口开启是 51034

其服务对应的注册表项

向与进程或服务相关函数下断点

OpenSCManagerW,CreateService,ChangeServiceConfig2W,StartServiceW,StartServiceCtrlDispatcher,RegisterServiceCtrlHandlerW在+0x5D6B 处调用 OpenSCManagerW->+0x5C06 CALL CreateServiceW->+0x5D8D CALL ChangeServiceConfig2W->+0x5E36 CALL StartServiceW 启动服务

解密资源后的加载执行的 PE 代码结束,即作者继续释放了一个白样本 rastls.exe 具有赛门铁克的签名,其加载同名 DLL,在同名 DLL 中又调用了 VirtualAlloc 来分 配空间 SyLog.bin 的代码执行,用 WireShark 抓包后发现可能有类似远控功能

根据流程还有一个函数 sub_401700 在 sub_402540 执行返回 0 时执行,但在调试 程中此处代码并没 有进入


函数说明:

sub_0x11443 Ignoresub_0xFB5F LeaveCriticalSectionsub_0xFB68 LeaveCriticalSectionsub_0x10D45  Deal SEH & Leavesub_0x14088  GetCurrentThreadIdsub_0x14090  GetCommandLineAsub_0x140AC  RtlEncodePointersub_0x1408C  RtlDecodePointersub_0x140D0 GetProcAddresssub_0x140F0  InitializeCriticalSectionAndSpinCountsub_0x140F8  GetStartupInfosub_0x1407C  RtlAllocateHeapsub_0x1410C  GetEnvironmentStringW[+0x18FB8] FlsAlloc[+0x18FBC] FlsGetValuePE DLL offset:0x12887FOrigin:Dst1: Size:Dst2:  Size:


第三阶段
总结


恶意文件被执行后,首先获得当前运行环境,执行一个 FireFox 的安装包并解密 加载资源,资源解密后是一个 DLL 文件,这个 DLL 文件还包含着一个同名的加密资源,再次解密后获得了三个文件,其中一个具有赛门铁克的签名,将其执行后会加载其释放的另外两个文件,这部分代码会创建一个服务用来与 C&C 通信。作者在构思执行rastls.exe 有一份双保险,若是%Programs%目录下执行失败,那么文件会释放到%appdata%目录,而 Dropper 在执行到最后调用 TerminateProcess结束自己。


往期精彩回顾
【web安全】文件上传漏洞
【web安全】简单XSS演练
【二进制安全】熊猫烧香病毒分析




END