刚刚学到了一种可以木马病毒隐藏自身的一种方法,就是通过API:CreateRemoteThreadEx在其他进程中创建一个线程,并且通过LoadlibraryAPI载入自己的Dll文件来实现远程线程注入。
运行在目标进程中,随意访问目标进程的内存空间,最后这个动态链接库里的代码就成为其他进程的一部分来实现了自身的隐藏执行,通过调用“hook”机制,监视用户的输入输出操作,截取有用的资料等操作。这种木马的实际执行体是一个dll文件,由于Windows系统自身就包含着大量的dll文件,谁也无法一眼看出哪个dll文件不是系统自带的,所以这种木马的隐蔽性又提高了一级,而且它的执行方式也更加隐蔽,这是由Windows系统自身特性决定的,Windows自身就是大量使用dll的系统,许多dll文件在启动时便被相关的应用程序加载进内存里执行了,可是有谁在进程里直接看到过某个dll在运行的?因为系统是把dll视为一种模块性质的执行体来调用的,它内部只包含了一堆以函数形式输出的模块,也就是说每个dll都需要由一个用到它的某个函数的exe来加载,当dll里的函数执行完毕后就会返回一个运行结果给调用它的exe,然后dll进程退出内存结束这次执行过程,这就是标准的dll运行周期,而采用了“线程注射”技术的dll则不是这样,它们自身虽然也是导出函数,但是它们的代码是具备执行逻辑的,这种模块就像一个普通exe,只是它不能直接由自身启动,而是需要有一个特殊作用的程序(称为加载者)产生的进程把这个dll的主体函数载入内存中执行,从而让它成为一个运行中的木马程序。
代码实现:
// 远程注入测试代码.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include<windows.h>
#include <TlHelp32.h>
int _tmain(int argc, _TCHAR* argv[])
{
//1 枚举当前系统运行的进程.
//Psapi方式枚举进程与快照方式枚举进程
//创建快照函数调用
HANDLE hProcessSnap;//进程快照句柄
HANDLE hProcess; //进程句柄
PROCESSENTRY32 stcPe32 = { 0 };//进程快照信息
stcPe32.dwSize = sizeof(PROCESSENTRY32);
//1创建一个进程相关的快照句柄
hProcessSnap = CreateToolhelp32Snapshot(
TH32CS_SNAPPROCESS, //快照包含的信息,包含所有进程的信息
0);
//2 通过进程快照句柄获取第一个进程信息
if (!Process32First(hProcessSnap,&stcPe32))
{
CloseHandle(hProcessSnap);
return false;
}
do
{
hProcess = OpenProcess(
PROCESS_QUERY_INFORMATION,
FALSE,
stcPe32.th32ProcessID);
if (hProcess)
{
int nPriority = GetPriorityClass(hProcess);
CloseHandle(hProcess);
}
printf("ID:%4d ", stcPe32.th32ProcessID);
printf("函数名:%s\n", stcPe32.szExeFile);
} while (Process32Next(hProcessSnap,&stcPe32));
CloseHandle(hProcessSnap);
//选择一个进程进行注入
DWORD nId;
scanf_s("%d", &nId);
//1打开一进程
HANDLE hPro=OpenProcess(PROCESS_ALL_ACCESS,//权限
FALSE,//是否可以继承
nId);
if (hPro==NULL)
{
MessageBox(0,"ID错误", 0, 0);
}
//在该进程中远程申请虚拟内存,来存放我们的dll名字
LPVOID p=VirtualAllocEx(hPro, NULL, 1024,
MEM_RESERVE | MEM_COMMIT,//虚拟内存的状态是预定和提交
PAGE_EXECUTE_READWRITE//可读可写可执行
);
DWORD dwSize;
//在该进程中写入
WriteProcessMemory(hPro,
p,//指向了写入内存的地址
"D:\\MyDll.dll",
strlen("D:\\MyDll.dll") + 1,
&dwSize//实际读取的大小
);
//在该进程中创建一个线程来加载我们的dll
CreateRemoteThread(hPro,
NULL,//安全属性
0,//协议栈的大小,如果为0,为默认大小
(LPTHREAD_START_ROUTINE)LoadLibrary, //回调函数的地址,因为LoadLibrary原型与该回调函数原型一致
p,
0, //创建后立即执行
NULL//表示线程表示符不会返回
);
return 0;
}
在MyDll中,在进程启动时,弹窗进行验证:
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
{
MessageBox(0, _T("注入成功"), 0, 0);
}
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
执行效果: