RemoteThread 远程线程 线程注入
基本原理是将dll的绝对路径使用VirtualAllocEx在目标进程中获取一块内存,然后将dll的绝对路径注入到这个新申请的区域,作为远程函数的参数。获取目标进程的kernel32.dll的模块地址,获取kernel32中LoadLibraryA函数的地址。然后使用CreateRemoteThread函数调用LoadLibraryA去加载我们自己想要注入的dll。至此完成了dll注入。
之所以选择使用dll注入自己想要允许的代码,是因为CreateRemoteThread这个远程函数只能调用,目标进程内所含有的函数,一般来说,是没有故意留出的接口的,并且所有进程都会加载kernel32这个模块,故此有了这种dll注入方法。
代码:
function.h
function.cpp
RemThreadInjector.h
RemThreadInjector.cpp
RemoteThread.cpp
function.h:
#pragma once
#include <string>
#include <string.h>
#include <Windows.h>
using namespace std;
char* wchar2char(WCHAR* data);
WCHAR* char2wchar(char* data);
wstring string2wstring(string str);
string wstring2string(wstring wstr);
function.cpp:
#include "function.h"
char* wchar2char(WCHAR* data)
{
//获取缓冲区大小,并申请空间,缓冲区大小事按字节计算的
unsigned int char_len = WideCharToMultiByte(CP_ACP, 0, data, -1, NULL, 0, NULL, NULL);
char* buffer = (char*)malloc(char_len + 1);
//宽字节编码转换成多字节编码
WideCharToMultiByte(CP_ACP, 0, data, -1, buffer, char_len, NULL, NULL);
buffer[char_len] = '\0';
return buffer;
}
WCHAR* char2wchar(char* data)
{
//获取缓冲区大小,并申请空间,缓冲区大小按字符计算
unsigned int wchar_len = MultiByteToWideChar(CP_ACP, 0, data, strlen(data), NULL, 0);
unsigned int malloc_size = (wchar_len + 1) * 2;
char* buffer = (char*)malloc(malloc_size);
//多字节编码转换成宽字节编码
MultiByteToWideChar(CP_ACP, 0, data, -1, (WCHAR*)buffer, wchar_len);
//添加字符串结尾 WCHAR 占用两个字节,所以最后的两个字节都要填充\0
buffer[malloc_size - 2] = '\0';
buffer[malloc_size - 1] = '\0';
return (WCHAR*)buffer;
}
//将string转换成wstring
wstring string2wstring(string str)
{
wstring result;
//获取缓冲区大小,并申请空间,缓冲区大小按字符计算
unsigned int wchar_len = MultiByteToWideChar(CP_ACP, 0, str.c_str(), str.size(), NULL, 0);
TCHAR* buffer = new TCHAR[wchar_len + 1];
//多字节编码转换成宽字节编码
MultiByteToWideChar(CP_ACP, 0, str.c_str(), str.size(), buffer, wchar_len);
//添加字符串结尾 由于上边直接申请的TCHAR,就是WCHAR,直接是两个字节为单位的,所以直接将最后一位置为\0其实是将两个字节都置为了\0
buffer[wchar_len] = '\0';
//删除缓冲区并返回值
result.append(buffer);
delete[] buffer;
return result;
}
//将wstring转换成string
string wstring2string(wstring wstr)
{
string result;
//获取缓冲区大小,并申请空间,缓冲区大小事按字节计算的
int len = WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), wstr.size(), NULL, 0, NULL, NULL);
char* buffer = new char[len + 1];
//宽字节编码转换成多字节编码
WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), wstr.size(), buffer, len, NULL, NULL);
buffer[len] = '\0';
//删除缓冲区并返回值
result.append(buffer);
delete[] buffer;
return result;
}
RemThreadInjector.h:
#pragma once
#include <iostream>
#include <Windows.h>
#include <TlHelp32.h>
#include <string>
#include "function.h"
class CRemThreadInjector
{
public:
CRemThreadInjector(const WCHAR * InjectDllPath);
~CRemThreadInjector();
// 注入DLL到指定的进程空间
BOOL InjectModuleInto(DWORD dwProcessId);
// 从指定的进程空间卸载DLL
BOOL EjectModuleFrom(DWORD dwProcessId);
protected:
WCHAR wchar_DllName[MAX_PATH];
char char_DllName[MAX_PATH];
// 调整特权级别
static BOOL EnableDebubgPrivilege(BOOL bEnable);
static BOOL is_same_dll(const WCHAR* dll1_path, const WCHAR* dll2_path);
};
RemThreadInjector.cpp
#include "RemThreadInjector.h"
CRemThreadInjector::CRemThreadInjector(const WCHAR* InjectDllPath)
{
memset(wchar_DllName, '\0', sizeof(WCHAR) * MAX_PATH);
memset(char_DllName, '\0', sizeof(char) * MAX_PATH);
wcsncpy_s(wchar_DllName, InjectDllPath, MAX_PATH);
char* t_char = wchar2char(wchar_DllName);
strncpy_s(char_DllName, t_char, MAX_PATH);
free(t_char);
EnableDebubgPrivilege(TRUE);
}
CRemThreadInjector::~CRemThreadInjector()
{
EnableDebubgPrivilege(FALSE);
}
BOOL CRemThreadInjector::EnableDebubgPrivilege(BOOL bEnable)
{
// 附给本进程特权,以便访问系统进程
BOOL bOk = FALSE;
HANDLE hToken;
// 打开一个进程的访问令牌
if (::OpenProcessToken(::GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))
{
// 取得特权名称为 “SetDebugPrivilege”的LUID
LUID uID;
::LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &uID);
// 调整特权级别
TOKEN_PRIVILEGES tp;
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = uID;
tp.Privileges[0].Attributes = bEnable ? SE_PRIVILEGE_ENABLED : 0;
::AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), NULL, NULL);
bOk = (::GetLastError() == ERROR_SUCCESS);
// 关闭访问令牌句柄
::CloseHandle(hToken);
}
return bOk;
}
BOOL CRemThreadInjector::InjectModuleInto(DWORD dwProcessId)
{
if (::GetCurrentProcessId() == dwProcessId)
return FALSE;
// 首先查看目标进程是否加载了这个模块
BOOL bFound = FALSE;
MODULEENTRY32 me32 = { 0 };
HANDLE hModuleSnap = ::CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwProcessId);
me32.dwSize = sizeof(MODULEENTRY32);
if (::Module32First(hModuleSnap, &me32))
{
do
{
if (is_same_dll(me32.szExePath, wchar_DllName))
{
bFound = TRUE;
break;
}
} while (::Module32Next(hModuleSnap, &me32));
}
::CloseHandle(hModuleSnap);
// 如果能够找到,就不重复加载了(因为重复加载没有用,Windows只将使用计数加1.其他什么也不做)
if (bFound)
return FALSE;
// 试图打开目标进程
HANDLE hProcess = ::OpenProcess(PROCESS_VM_WRITE | PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION, FALSE, dwProcessId);
if (hProcess == NULL)
return FALSE;
// 在目标进程中申请空间,存放字符串m_szDllName,作为远程线程的参数
int cbSize = (strlen(char_DllName) + 1);
LPVOID lpRemoteDllName = ::VirtualAllocEx(hProcess, NULL, cbSize, MEM_COMMIT, PAGE_READWRITE);
if (lpRemoteDllName == NULL)
return FALSE;
::WriteProcessMemory(hProcess, lpRemoteDllName, char_DllName, cbSize, NULL);
// 取得LoadLibraryA 函数的地址,我们将以它作为远程线程函数启动
HMODULE hModule = ::GetModuleHandle(LPCWSTR(TEXT("kernel32.dll")));
if (hModule == NULL)
return FALSE;
LPTHREAD_START_ROUTINE pfnStartRoutine = (LPTHREAD_START_ROUTINE)::GetProcAddress(hModule, "LoadLibraryA");
// 启动远程线程
HANDLE hRemoteThread = ::CreateRemoteThread(hProcess, NULL, 0, pfnStartRoutine, lpRemoteDllName, 0, NULL);
if (hRemoteThread == NULL)
{
::CloseHandle(hProcess);
return FALSE;
}
// 等待目标线程运行结束,即LoadLibraryA函数返回
::WaitForSingleObject(hRemoteThread, INFINITE);
::CloseHandle(hRemoteThread);
::CloseHandle(hProcess);
return TRUE;
}
BOOL CRemThreadInjector::EjectModuleFrom(DWORD dwProcessId)
{
if (::GetCurrentProcessId() == dwProcessId)
return FALSE;
// 首先查看目标进程是否加载了这个模块
BOOL bFound = FALSE;
MODULEENTRY32 me32 = { 0 };
HANDLE hModuleSnap = ::CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwProcessId);
me32.dwSize = sizeof(MODULEENTRY32);
if (::Module32First(hModuleSnap, &me32))
{
do
{
if (is_same_dll(me32.szExePath, wchar_DllName))
{
bFound = TRUE;
break;
}
} while (::Module32Next(hModuleSnap, &me32));
}
::CloseHandle(hModuleSnap);
// 如果找不到就返回出错
if (!bFound)
return FALSE;
// 试图打开目标进程
HANDLE hProcess = ::OpenProcess(PROCESS_VM_WRITE | PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION, FALSE, dwProcessId);
if (hProcess == NULL)
return FALSE;
// 取得FreeLibrary 函数的地址,我们将以它作为远程线程函数启动
HMODULE hModule = ::GetModuleHandle(LPCWSTR(TEXT("kernel32.dll")));
if (hModule == NULL)
return FALSE;
LPTHREAD_START_ROUTINE pfnStartRoutine = (LPTHREAD_START_ROUTINE)::GetProcAddress(hModule, "FreeLibrary");
// 启动远程线程
HANDLE hRemoteThread = ::CreateRemoteThread(hProcess, NULL, 0, pfnStartRoutine, me32.hModule, 0, NULL);
if (hRemoteThread == NULL)
{
::CloseHandle(hProcess);
return FALSE;
}
// 等待目标线程运行结束,即LoadLibraryA函数返回
::WaitForSingleObject(hRemoteThread, INFINITE);
::CloseHandle(hRemoteThread);
::CloseHandle(hProcess);
return TRUE;
}
BOOL CRemThreadInjector::is_same_dll(const WCHAR* dll1_path, const WCHAR* dll2_path)
{
WCHAR dll1_path_copy[MAX_PATH], dll2_path_copy[MAX_PATH];
wcsncpy_s(dll1_path_copy, dll1_path, MAX_PATH);
wcsncpy_s(dll2_path_copy, dll2_path, MAX_PATH);
int flag = 1;
int i = 0;
while (i < MAX_PATH && dll1_path_copy[i] != WCHAR('\0') && dll2_path_copy[i] != WCHAR('\0'))
{
if (dll1_path_copy[i] != dll2_path_copy[i] && ((dll1_path_copy[i] != '\\' && dll1_path_copy[i] != '/') || (dll2_path_copy[i] != '\\' && dll2_path_copy[i] != '/')))
{
flag = 0;
break;
}
i++;
}
return flag;
}
RemoteThread.cpp
// RemoteThread.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include "RemThreadInjector.h"
#include <iostream>
#include <string>
using namespace std;
int FindPID(string ProcessName);
int FindPID(string ProcessName)
{
int pid = -1;
PROCESSENTRY32 pe32;
pe32.dwSize = sizeof(pe32);
HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hProcessSnap == INVALID_HANDLE_VALUE) {
cout << "CreateToolhelp32Snapshot Error!" << endl;;
return false;
}
BOOL bResult = Process32First(hProcessSnap, &pe32);
int num(0);
while (bResult)
{
if (wstring2string(wstring(pe32.szExeFile)) == ProcessName)
{
pid = pe32.th32ProcessID;
break;
}
bResult = Process32Next(hProcessSnap, &pe32);
}
CloseHandle(hProcessSnap);
return pid;
}
LPCWSTR stringToLPCWSTR(const std::string& s) {
size_t convertedChars = 0;
std::string curLocale = setlocale(LC_ALL, NULL); //curLocale="C"
setlocale(LC_ALL, "chs");
const char* source = s.c_str();
size_t charNum = sizeof(char) * s.size() + 1;
wchar_t* dest = new wchar_t[charNum];
mbstowcs_s(&convertedChars, dest, charNum, source, _TRUNCATE);
setlocale(LC_ALL, curLocale.c_str());
return dest;
}
int main()
{
wstring injectDllPath = TEXT("D:/c++/vs_data/create_ce_dll/x64/Release/create_ce_dll.dll");
CRemThreadInjector thread_injector(injectDllPath.c_str());
string inject_process_name = "YuanShen.exe";
//string inject_process_name = "notepad.exe";
int pid = FindPID(inject_process_name);
bool inject_flag = FALSE;
string info = "";
inject_flag = thread_injector.InjectModuleInto(pid);
info = "inject " + inject_process_name + " " + to_string(pid) + " " + to_string(inject_flag) + "\n";
printf("%s", info.c_str());
getchar();
inject_flag = thread_injector.EjectModuleFrom(pid);
info = "eject " + inject_process_name + " " + to_string(pid) + " " + to_string(inject_flag) + "\n";
printf("%s", info.c_str());
return 0;
}