Windows下DLL注入 - 线程注入及对抗方案

本文讲解如何把一个DLL注入在另一个EXE的进程中(附32bit例子)

方法之一 线程注入

步骤

第一步,要把dll路径字符串写到目标exe的内存中。

这里使用的是 “远程申请内存”和“向进程写内存”;

第二步,开启一个远程线程,远程执行 LoadLibaryA函数,来加载我们要注入的DLL。

test.exe inject.dll这里使用易语言编写。

inject.dll代码截图

 

将"inject.dll"注入“test.exe”,注入成功。

 

DLL注入器流程图

 

注入器代码(C++):


#include <iostream>
#include <string>
#include <thread>
#include <mutex>
#include "windows.h"
#include "tlhelp32.h"

wchar_t* char2wchar(const char* cchar);
char* wchar2char(const wchar_t* wchar);
int process_getIdByName(const char pName[]);

void inject_thread()
{
	std::string filePath = "C:\\Users\\Administrator\\Desktop\\线程注入\\inject.dll";

	HANDLE targetProcessH = OpenProcess(PROCESS_ALL_ACCESS, false, process_getIdByName("test.exe"));
	if (targetProcessH == NULL)
	{
		std::cout << "targetProcessId is null" << std::endl;
		return;
	}

	LPVOID remoteDllPathTextAddr = VirtualAllocEx(targetProcessH, 0, filePath.length() + 1, MEM_COMMIT, PAGE_READWRITE);
	if (remoteDllPathTextAddr == NULL)
	{
		std::cout << "remoteDllPathTextAddr is null" << std::endl;
		return;
	}

	bool isWriteSuccess = WriteProcessMemory(targetProcessH, remoteDllPathTextAddr, filePath.c_str(), filePath.length(), 0);

	if (!isWriteSuccess)
	{
		std::cout << "isWriteSuccess fail" << std::endl;
		return;
	}

	LPTHREAD_START_ROUTINE loadLibraryAAddr = (LPTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandleA("Kernel32.dll"), "LoadLibraryA");
	if (loadLibraryAAddr == NULL)
	{
		std::cout << "loadLibraryAAddr is null" << std::endl;
		return;
	}

	std::cout << "CreateRemoteThread" << std::endl;
	HANDLE targetThreadH = CreateRemoteThread(targetProcessH, 0, 0, loadLibraryAAddr, remoteDllPathTextAddr, 0, 0);
	if (targetThreadH == NULL)
	{
		std::cout << "targetThreadH is null" << std::endl;
		return;
	}

	int result = WaitForSingleObject(targetThreadH, INFINITE);

	std::cout << "WaitForSingleObject result = "<<result << std::endl;

	CloseHandle(targetProcessH);
	CloseHandle(targetThreadH);




}

int main()
{

	inject_thread();

	getchar();
	return 0;
}



wchar_t* char2wchar(const char* cchar)
{
	// 转换函数
	wchar_t* m_wchar;
	int len = MultiByteToWideChar(CP_ACP, 0, cchar, strlen(cchar), NULL, 0);
	m_wchar = new wchar_t[len + 1];
	MultiByteToWideChar(CP_ACP, 0, cchar, strlen(cchar), m_wchar, len);
	m_wchar[len] = '\0';
	return m_wchar;
}
char* wchar2char(const wchar_t* wchar)
{
	// 转换函数
	char* m_char;
	int len = WideCharToMultiByte(CP_ACP, 0, wchar, wcslen(wchar), NULL, 0, NULL, NULL);
	m_char = new char[len + 1];
	WideCharToMultiByte(CP_ACP, 0, wchar, wcslen(wchar), m_char, len, NULL, NULL);
	m_char[len] = '\0';
	return m_char;
}
int process_getIdByName(const char pName[])
{
	// 进程.通过名称获取PID
	PROCESSENTRY32 p;
	PROCESSENTRY32* info = &p;
	// 在使用这个结构之前,先设置它的大小
	info->dwSize = sizeof(PROCESSENTRY32);
	char proName[] = { "devenv.exe" };
	HANDLE handlePro = NULL; //结束进程句柄
	// 给系统内的所有进程拍一个快照
	HANDLE hProcessSnap = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
	if (hProcessSnap == INVALID_HANDLE_VALUE)
	{
		printf(" CreateToolhelp32Snapshot调用失败! \n");
		return -1;
	}
	// 遍历进程快照,轮流显示每个进程的信息
	BOOL bMore = ::Process32First(hProcessSnap, info);
	BOOL terminate = FALSE;
	while (bMore != FALSE)
	{
		//std::cout << pName<<" " <<wchar2char(info->szExeFile) << std::endl;
		if (strcmp(pName, wchar2char(info->szExeFile)) == 0)
		{
			return info->th32ProcessID;
		}


		bMore = Process32Next(hProcessSnap, info);
	}
	::CloseHandle(hProcessSnap);
	return 0;
}

 

对抗DLL注入

方案之一:HOOK LoadLibraryA函数

 附:test.exe的自身HOOK易语言代码

Hook掉LoadLibaryA函数后,我们可以通过判断“lpLibFileName(DLL路径)”,来拦截非白名单DLL。

也可以根据路径找到文件,计算哈希,查询是否在白名单。

Hook掉LoadLibaryA函数,只是对抗方式之一。而且也有绕过方式,比如自己写一个跟LoadLibaryA功能差不多的函数,来加载资源和注册。这个如果有机会,会继续讲。

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值