WannaCry订单处理软件是2017年最热门的订单软件,它应用了微软缺陷在全球提出的攻击,对世界上100多个国家的众多用户产生了巨大影响。就像是全世界的网络平安普及教育。(莎士比亚)。

作为平安行业从业者,我停止了对WannaCry的深入解释。完美的发布可以赞助平安行业从业者了解黑客最新的攻击手腕,为保护领域处理方案提供宝贵信息,进一步测试考试发明软件的缺点,为客户提供有价值的数据恢复业务。(威廉莎士比亚,《北方司法》前情提要)。

以前,我们停止了对热点订购软件(如CryptXXX、Cerber和Locky)的深入说明。Wannacry吸收了以前订单创建软件的计划历史,倒退了,进行了第二阶段的提升。

什么是第二阶段攻击?简而言之,就像Wannacry French自己不做数据加密操作一样,实际上是恶意的法式本身,比如静态释放有进击措施的代码,将数据加密操作隐藏在公开的代码中。注:Wannacry French本人不执行数据加密操作。)听起来好像Locky是一个带shell的单一软件,操作后通过进程shell代码释放恶意代码。但是外壳代码本身也是引人注目的特性。就像加壳的代码一样,被迫停止拆卸,平时信息熵也很高,很多防护软件对这种法式进步危险品级的用户碰撞,也许这种法式Drop到了用户的机器上就能被Detect到达。(威廉莎士比亚,Northern Exposure(美国电视剧),Wannacry)但是,Wannacry在第一阶段的法式完备没有外壳代码,Endpoint不进行任何定制,也没有感觉到任何变化的真迹,也许WANACRY应用微软的漏洞,(阿尔伯特爱因斯坦,美国作家)。

Hack Weapon

在开始之前,我想先谈谈Hack Weapon这个观点。根据很多业余机构的解释,这个炫彩产业链已经成长起来了,非常成熟。(大卫亚设,Northern Exposure(美国电视新闻))在黑暗网络中,可以购买林林的总攻部件,形成有用的攻击实体。例如,如果有缺陷、加载程序、加密模块等,我可能会根据我的需要买适当的模块,然后停止组装到真正激进的恶性法国。(威廉莎士比亚、哈姆雷特、加密、加密、加密、加密、加密、加密、加密)这些模块就是Hack Weapon。我们连接到互联网上的很多Sample是很多模块的组合,通过in-depth的逆向解释,我们可以清楚地知道,当恶意软件有多种进击兵器时,是否可以提取这些进击兵器。永定建立了一个Hack Weapon,并对这个Hack Weapon的静止特性建模。

从技巧的角度来看,机器指示级别的其馀重用相对平等,与源代码级别的其馀重用不同,编译器选项的低迷可能会对最终机器指示产生细微的更改。黑客兵器的供应商没有提供源代码,而是将武器提供给比纳里下游黑客,建立了这种军火库,提供了强大的特性。从兵器的角度来看,婚礼法国有更准确的分辨能力。好像认为隐藏的Peloader模块是恶意软件的一种。那种Weapon停止特性或行为建模可能会更好地应用于应用该Weapon的所有恶意软件。平安防护软件将具有进行更多攻击的才能。(威廉莎士比亚)。

我已经停止了对法式String的加密,抽到了这段时间停止解密的Hack Weapon,那时我没想到恶意软件有模块化这样的计划。直到在其他恶意软件中看到奇怪的行为,并停止提取发明所有function的flow和Instruction。(阿尔伯特爱因斯坦,美国作家)。

在这次解释的过程中,我可以识别两个加载到PE file内存中、不滥用微软API的Hack Weapon: PeLoader和Resource Extractor。内存分配也是VirtualAlloc)的情况下,需要处理Import Table、Base Relocation等繁琐的事情,所以应用Monitor等法国也不能发明有LO(威廉莎士比亚,Northern Exposure(美国电视),记忆名言)后者用于从资源中提取加密攻击用的PE payload。这两个模块都很漂亮。连作者都认为没有再写一遍的动机。这需要停止大量细致的编码和大量的测试。稍有疏忽,就可能导致最后的进击公败(请参阅Payload加载失败)。

这次发布停止后,我将提取这两个Hack Weapon,编写POC代码,重复使用这两个组件。

Phase one

Tasksche

Wannacry的州法律将发生变化,这个名字的目标是让用户困惑。让我们从WinMain函数开始,一起解释这个法式。(威廉莎士比亚、温曼、温曼、温曼、温曼、温曼、温曼)

为了便于阐明法国式的行为,下面的代码片段都用C来表达。除非碰C表白,否则可能因为编译器优化等原因,C不得不表白,我会接受编辑话详细说明。(大卫亚设)。

int _ _ stdcallwinmain(hinstance hinstance、hinstance hprevinstance、lpstr lpcm dl)

ine, int nShowCmd){ char **argv; void *lpPEFile; CPeBuilder *pPeBuilder; void (__stdcall *fpTaskStart)(_DWORD, _DWORD); CProgram Program; char szModuleFileName[520]; int nFileSize; szModuleFileName[0] = szSelfName; memset(&szModuleFileName[1], 0, 516u); *&szModuleFileName[517] = 0; szModuleFileName[519] = 0; GetModuleFileNameA(0, szModuleFileName, 520u); CreateRandomSequence(szServiceName); if ( *_p___argc() != 2 || (argv = _p___argv(), strcmp(*(*argv + 1), aI)) || !CreateHiddenData(0) || (CopyFileA(szModuleFileName, FileName, 0), GetFileAttributesA(FileName) == INVALID_FILE_ATTRIBUTES) || !StartMalware() ) { if ( strrchr(szModuleFileName, '\\') ) *strrchr(szModuleFileName, '\\') = 0; SetCurrentDirectoryA(szModuleFileName); WriteRegistery(1); ExtractFromResource(0, WNcry); ModifyOneByte(); StartProcess(CommandLine, 0, 0); // attrib +h : Sets the hidden file attribute. StartProcess(aIcacls_GrantEv, 0, 0); if ( InitKernel32Funcs() ) { CProgram::ctor(&Program); if ( CProgram::Initialize(&Program, 0, 0, 0) ) { nFileSize = 0; lpPEFile = CProgram::GetPeFile(&Program, aT_wnry, &nFileSize); if ( lpPEFile ) { pPeBuilder = WncryLoadPE(lpPEFile, nFileSize); if ( pPeBuilder ) { fpTaskStart = WncrySeek2TaskStart(pPeBuilder, szTaskStart); if ( fpTaskStart ) fpTaskStart(0, 0); } } } CProgram::dtor_0(&Program); } } return 0; }

WinMain的代码很轻易理解,声清楚明了几个变量,此中CProgram对象,CPeBuilder指针,和fpTaskStart是全体WinMain运转的症结,WinMain的目标是静态加载一个Pe dll到内存中并运转起来,全体过程做的相称的隐藏。 WinMain函数在栈上声清楚明了一个520 byte的数组,用来获得以后过程的完备门路,法式会应用这个门路将文件复制一份并命名为,并挪用StartMalware启动自己。

在这里Malware已经经由过程破绽进入Endpoint中而且被launch起来了,我觉得这里存在一个common的阶段,我把这个阶段界说为暗藏阶段。作甚暗藏阶段,换句话说在这个阶段Malware起首要做的不是履行进击代码,而是在实行进击以前起首藏匿自己的行迹,假装自己为一个看起来失常的法式,并在日后的日记查询拜访中困惑阐发职员。

if ( *_p___argc() != 2|| (argv = _p___argv(), strcmp(*(*argv + 1), aI))

细心看一下这段代码,Wannacry启动后的第一时间停止了几个症结操纵:

反省启动参数

创立暗藏数据(folder)

重命名为

再次启动自己

反省启动参数与重命名可以或许间接从表白式中断定出来,不复杂。

创立暗藏数据

int __cdecl CreateHiddenData(wchar_t *p){ int result;

上面的函数终极创立了**%WinDir%\ProgramData,%WinDir%\Intel**两个folder并将其属性设置为Hidden。

int __cdecl CreateFolder(LPCWSTR lpPathName, LPCWSTR lpFileName, wchar_t *String){ int result;

上面是CreateFolder的代码,很轻易理解,重要是对经由过程此函数创立的Folder设置Hidden属性。

再次启动自己

BOOL StartMalware(){ char szFullPath[520];

留意末了一行的代码,Wannacry会用2中种方法再次启动自己,起首测验考试将自己假装成办事法式,假如失败了,在测验考试通用的过程方法。

办事方法

在应用办事方法启动的时候,Wannacry起首会应用在WinMain中初始化的一个随机序列作为办事称号。 上面是天生随机序列的代码:

int __cdecl CreateRandomSequence(char *displayname)

这段代码应用了用户的计算机称号,经由过程对计算机称号的每个自己停止乘法溢出运算,会获得一个初始化随机产生器的种子值,并应用随机数产生器来天生随机的办事称号。 这个随机的办事称号由’a-z”0-9′构成。

signed int __cdecl StartService(char *pFullpath){ signed int result;

Wannacry应用StartService函数将自己作为一个带有随机办事称号的办事停止启动,这是最轻易掩人耳目标隐藏手腕。 然则假如没有权限操纵办事管理器,或许不测失败了,Wannacry另有惯例启动办法作为备选。

int __cdecl StartProcess(LPSTR lpCommandLine, DWORD dwMilliseconds, LPDWORD lpExitCode){ int result;

StartProcess函数作为备选应用惯例方法启动一个过程,这里被传入的CommandLine便是已经被悛改称号为的法式门路了,至多用这个称号这也有一些困惑感化,而且一个小细节,设置了非窗口形式。

signed int __cdecl WaitMutex4Times(int param){ int nCount;

不管应用哪一种方法再次启动了自己,法式都邑挪用上面的函数去期待Global\MsWinZonesCacheCounterMutexA0这个体系Mutex,而且在接下来测验考试期待60次,每次1秒,合计60秒。 这么看来这个Named的Mutex对象应当在真正提议合计的模块中,这是惯例的假定。

固然假如上面的办法都失败了,Wannacry也不会废弃这独一的一次机遇加密用户的数据,既然暗藏不可,那就间接干吧。 而间接干这部分代码与暗藏后再来干的代码是同样的,恰好归并阐发。 在开端以前另有一些工作要做:

WriteRegistry(1); ExtractFromResource(0, WNcry); SetBitcoinAddress(); StartProcess(CommandLine, 0, 0); // attrib +h : Sets the hidden file attribute. StartProcess(aIcacls_GrantEv, 0, 0); // icacls . /grant Everyone:F /T /C /Qif ( InitKernel32Funcs() )

写注册表

提取Payload

将Bitcoin钱包地点写入c.wnry

将以后工作目次暗藏

将以后目次受权一切人完备拜访权限

初始化体系挪用

这表面暗藏工作目次,提权,和初始化体系挪用都没有甚么好说的,剩下的几个操纵中,最难的是ExtractFromResource,它从资本段中开释Payload。

写注册表

signed int __cdecl WriteRegistry(int flag){ size_t nlen;

Wannacry应用WriteRegistryFunc将在”HKLM\Software\WanaCrypt0r”和”HKCU\Software\WanaCrypt0r”上面创立一个wd的键并写入以后的工作目次,咱们先假定它这么做是为了避免把自己也加密了吧。

WINDBG>du 0012f71c0012f71c "Software\WanaCrypt0r"

提取Payload

以前提到的法式逻辑都很简略,从这里开端今后就开端有意思了,阐发这些代码照样很难的,同时也异常有意思。 起首来看看 Payload Extractor的完成。

Wannacry在自己的res segment中存放了许多加密过的Data,这表面有许多有歹意的法式,要想懂得它们都是做甚么的,咱们必要先懂得它的内存结构。

提取函数起首将资本数据加载到内存中:

hRes = FindResourceA(hModule, (LPCSTR)'\b\n', aXIA);if ( hRes

以后挪用StartVersion函数初始化一个CResource对象,这个对象会将load出来的Resource数据加载出来,之以是用这个函数称号,是认为它另有别的版本的加载办法,此中一个版本是经由过程一个文件句柄来加载Payload,也便是说这个Payload Extractor同时也支撑从文件中提取Payload。

struct CResource{

CResource如上面结构所示,有一些数据至今我还不清楚是做甚么用的,然则最紧张的数据结构是一个名为CWnBigResData的数据结构,这个数据结构的前0×20是CWnResData它包括了Payload的一些紧张信息。 别的pSignture是这个对象的一个特性在这里是表面传入的数据“WNcry@20l7”。

CWnResult *__cdecl StartVersion3(HANDLE hRes, int nSize, int version, char *WNcry@2ol7){

StartVersion3是被StartVersion挪用的,而且传入了3给version这个参数,由于这个参数的感化,法式会从Memory中读取Payload而不是文件句柄。 这个函数创立了CResource对象并挪用了它的Initialize办法停止初始化。 初始化Payload的成果会记载在全局变量g_StatusCode中,假如初始化失败,会析构并加入,同时法式将无奈胜利。假如胜利会创立一个CResult对象,这个对象备两个数据成员,bLoadSuccess用来表现初始化胜利,pResource指针指向CResource对象。

pWnResData->bIsFile = 0;

上面的代码片断是当version参数即是3时候的行动,有两个紧张的数据pWnResData->lpResourceData被赋值为指向资本段的指针,pWnResData->nResourceSize是资本段的巨细值。

最紧张的一个函数,来自于GetDataFromResource,这个办法真正的从Resource中加载数据到内存数据结构中。

struct CWnResData{ char bIsFile;

这里的风趣的是,针对ResourceData的load是从后往前读的,这与惯例的数据加载从Memory低往高读取的方法是反的,可以或许看出作者这么做真是用心良苦。

34:961Fh: 50 4B 05 06 00 00 00 00 24 00 24 00 D8 0D 00 00 PK......$.$.Ø...

上面的数据是我从Resource中提取出来的原始数据的末了22字节,经由过程对末了22个字节的阐发,我将展现法式若何说明这类自界说协定的数据格局。

signed int __cdecl FindPkSignPosition(CWnResData *pResData){

FindPkSignPosition函数的感化是将pResourceBuffer指向末了一个PK0506的标志,上面的函数中有两个ResetCurrentOffset函数,两次挪用中末了一个参数一次是2一次是0, 2代表指针以后地位是Buffer的末端,0代表指针的值是一个绝为地位。以是第一挪历时,将指针的地位移动了Buffer的末端,第二次挪历时指针已经指向了Buffer末端,Offset的偏移即是一个Block的巨细1028个自己。 以是这两次操纵后,指针实际上即是从Buffer末端往前偏移了1028字节,以是指针的以后地位即是Buffer总巨细减去一个Block的巨细。

pBuffer = pBuffer + nTotalSize - nBlock

定位完指针后,法式读取了一个Block巨细的数据进了BlockBuffer中。

if ( pBuffer[index] == 'P' && pBuffer[index + 1] == 'K' && pBuffer[index + 2] == 5 && pBuffer[index + 3] == 6 )

留意这个代码片断,法式开端从这个Block的末了一个字节反向搜刮‘PK56’这个特别的标志值。 它会不停读取直到读到我在上面贴出来的数据片断为止。

察看上面的数据,法式会继承读取,将这些数据写入内存数据结构中,读取办法有2种,一次读取2个字节和一次读取4个字节。就我列出的数据,数据结构如下:

Magic: 504B0506Reserved1: 0Reserved2: 0Unknown1: 24Unknown1: 24Current segment offset: 00000dd8

此中前一个段的相对地位加上以后端的偏移即是以后段的相对地位,假如测验考试将这两个值相加,会发明即是我上面贴出的数据的以后地位,是以经由过程这个办法咱们就能够或许赓续的定位到前一个段,不停遍历到Memory的开首。

由于Payload Extractor的代码异常多,它必要将一切段中的数据都提取出来,而且经由过程写文件的办法开释出来,以是就不在这里继承阐发了,假如感兴趣,经由过程我上面的启迪应当可以或许自己测验考试的阐发代码将一切的数据提取出来。

PS. 咱们在法式运转过程当中看到过的 c.wnry u.wnry 等都是在这个阶段开释出来的。

DropFileCategoryUsageData
c.wnryTextC&C Server; Bitcoin addressgx7ekbenv2riucmf.onion;
r.wnryTextQ & AQ: What’s wrong with my files?
s.wnryPK FormatNone
t.wnryEncryptFileAttack PayloadNone
u.wnryPEUI InterfaceWana Decrypt0r 2.0

写Bitcoin钱包地点

这个过程比拟简略,起首有3个bitcoin的钱包地点,随机抉择一个,写到buffer的第178字节开端的后35字节中,而后把buffer写到c.wnry中。

int SetBitcoinAddress(){ int result; int iRandom;

PeLoader

到这里Payload也已经胜利的提取出来了,那咱们以前说过Wannacry是分两阶段进击的,第一阶段另有一个最紧张的义务便是将加密法式悄无声息的加载起来。 如今到了激动人心的时候,经由过程接下来的阐发,咱们可以或许控制PeLoader的运转道理。 作为第二阶段进击的最紧张的Weapon,Peloader将忽略微软API,来完成Pe dll的静态加载。

假如不想翻到最上面看的话,这里有一个代码片断:

CProgram::ctor(&Program);if ( CProgram::Initialize(&Program, 0, 0, 0) )

这表面有两个数据结构比拟紧张CProgram和CPeBuilder,先来看一下CProgram:

class CProgram{ void *vtable;struct CWnCryptContext{ void *vtable;

法式起首结构一个CProgram对象,并初始化外部的CWnCryptContext与CWnAES成员,此中微软的CWnCryptContext应用的CSP是“Microsoft Enhanced RSA and AES Cryptographic Provider”算法是RSA,RSA秘钥是从法式的数据段中读出来的。

void *__thiscall CProgram::GetPeFile(CProgram *this, LPCSTR lpFileName, int *nRet)

上面的CProgram::GetPeFile函数应用法式数据段中的PublicKey对t.wnry中的一段数据停止解密,这段数据解密出来后是AES初始化向量,而后用它去初始化AES加密Key,以后继承读取将用这个AESKey加密的PE文件读取到内存中,并用初始化后的AESKey停止解密,这个函数前往一个在内存中的PE文件,接下来就轮到PeBuilder上场了。

经由过程这部分,咱们可以或许懂得一个被加密的文件的加密结构,经由过程前面没有提到的二阶段进击阐发,我发明纵然是用户被加密的文件的加密后格局也与这个文件同等。

OffsetSummaryData
0×0000:0×0007MagicCode“WANACRY!”
0×0008:0x000BSize of Encrypt AES Vector
0x000C:0x010BBody of Encrypt AES Vector
0x010C:0x011FBlank 4 bytes
0×0110:0×0117File Size
0×0118:Numble of sizeFile Content

PeBuilder

适才Wannacry已经将在ResourceData中的t.wnry开释出来,并经由过程上面的解密举措胜利在内存中搁置了一个PE File,如今可以或许应用PeBuilder停止静态加载了。 PeBuilder异常的精美,也很繁琐。

CPeBuilder *__cdecl BuildPEExecutable(DOS_Header *fileBuffer, size_t nFileSize, LPVOID (__cdecl *VirtualAlloc)(LPVOID, SIZE_T, DWORD, DWORD, int), int (__cdecl *VirtualFree)(LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType, int), HMODULE (__cdecl *LoadLibraryA)(LPCSTR lpLibFileName), int (__cdecl *GetProcAddress)(HMODULE, LPCSTR, DWORD), BOOL (__cdecl *FreeLibrary)(HMODULE hLibModule), int zero)

我信任纵然是翻译成C++代码,看到上面的大篇幅代码也没有读下去的能源了,况且我看的是汇编级其余代码。 那我简略讲一下好了,这个函数会前往一个PeBuilder对象,它会办理加载这个pe对象的一切体系级其余工作。

!WncryBuildPESection(fileBuffer, nFileSize, pPEHead, pPeBuilder))

上面是一些紧张的片断,假如你没有细心读上面大片的代码,那末看看这个也是可以或许的。

这个PeBuilder凶猛的地方在于,只应用了如下5个体系API,是以纵然应用Monitor对象也无奈发明有一个Loaddll的举措在表面。

VirtualAlloc

VirtualFree

LoadLibraryA

GetProcAddress

FreeLibrary

固然有LoadLibrary在然则貌似没有应用。

CPeBuilder的数据结构如下:

struct CPeBuilder{

此中ImageBase指向一块内存中的Buffer,它是一个被加载起来的Dll模块的基地点。

获得了CPeBuilder对象后,Wannacry应用Seek2TaskStart办法来定位到Dll中导出的TaskStart函数,并挪用这个函数,真正开端第二阶段的进击。

int __cdecl Seek2TaskStart(CPeBuilder *pPeBuilder, char *szTaskStart)

上面这个函数接收CPeBuilder和一个Func Name作为参数,法式在PE的Export中搜刮名为FuncName的导出函数,并前往这个导出函数。

while ( stricmp(szTaskStart, ImageBase + *AddressOfNames) )

这部分代码便是在搜刮导出函数表。

fpTaskStart = Seek2TaskStart(pPeBuilder, szTaskStart); if ( fpTaskStart ) fpTaskStart(0, 0);

挪用导出函数,进击开端。

至此,tasksche悄无声息的将一个PE dll加载并运转,全体过程无奈经由过程Proc monitor等软件发明。本日阐发的是Wannacry中的进击主体,它是已经落到用户机械上的payload,下次我会给人人带来Peloader的阐发,和详细加密行动的详细阐发。

1.《【奔驰cls320同价位车型aq】Wannacry深度分析:第一阶段tasksche》援引自互联网,旨在传递更多网络信息知识,仅代表作者本人观点,与本网站无关,侵删请联系页脚下方联系方式。

2.《【奔驰cls320同价位车型aq】Wannacry深度分析:第一阶段tasksche》仅供读者参考,本网站未对该内容进行证实,对其原创性、真实性、完整性、及时性不作任何保证。

3.文章转载时请保留本站内容来源地址,https://www.lu-xu.com/auto/2889606.html