线程注入与DLL加载

什么是线程注入?

线程注入,是通过开启远程线程的方式,将DLL加载到目标宿主进程中的常用方式。

什么是动态链接库?

首先Windows中链接库分为两种:动态链接库DLL、静态链接库LIB。

① 静态链接库:在运行的时候就直接把代码全部加载到程序中,调用方式比如:

#prama comment (lib,"Psapi.lib")

② 动态链接库:在需要的时候加载,加载方式为:

——使用LoadLibrary动态加载DLL

——使用GetProcAddress获取DLL中导出函数的指针

——最后用FreeLibrary卸载指定的DLL

动态链接库设计的目的是为了动态加载功能,动态地释放内存,节约内存,方便每一个程序的4GB内存的管理,4GB有2GB用来放系统内核,即系统大量的DLL。其本质上也是一个可以被加载的程序。同时系统对于DLL只会保存一份。

在Visual Studio编译环境下,DLL又分为三类:

① 非MFC的DLL——使用SDK API进行编程,能被所有语言调用

② MFC规则DLL——使用MFC进行编程,能被所有语言调用

③ MFC扩展DLL——使用MFC进行编程,只能被MFC编写的程序调用

(下面使用第一种)

MFC——Microsoft Foundation Class-Library :微软用C++对API进行的封装,全部封装成了类,方便使

需要注意:

DLL的导出函数使用

extern “C” _declspec(dllexport)

而导入函数使用

extern “C” _declspec(dllimport)

extern “C” 的作用是作为一种编译约定

那么进程是如何调用DLL的呢?

①使用LoadLibrary加载进所需DLL

HMODULE hMod = LoadLibrary(DLL路径)

②定义导入函数指针

typedef int(*ADD_IMPORT) (int a,int b); // 定义一个指向返回值为int类型的函数指针

③使用GetProcAddress获得函数入口点

ADD_IMPORT add_proc = (ADD_IMPORT) GetProcAddress(hMod,“Add”);

④然后就可以使用了:比如 int result = add_proc(1,2);

如下使用VS2019进行编写编译:

1、新建Win32项目,选择DLL

关于DLL入口主函数第二个参数ul_reason_for_call,即DLL四种当前的状态:

2、新建如下头文件

3、在dajiDLL.cpp中

然后同一解决方案下新建MFC项目

这里需要说一下注入的可行性:

①kernel32和user32是两个在大部分程序上都会调用的DLL

②同一个DLL,在不同的进程中,不一定被映射(加载)到同一个内存地址

③但是kernel32和user32除外,他们总是被映射到进程的内存首选地址

④因此在所有使用这两个DLL的进程中,这两个DLL的内存地址是相同的

⑤所以在本进程获取的kernel32.dll中的函数的地址,在目标进程中也是一样的

流程:目标进程-传入DLL地址-开启远程线程-加载DLL-实现DLL注入

具体使用函数如下:

OpenProcess // 获取已知进程的句柄

VirtualAllocEx // 在远程进程中申请内存空间

WriteProcessMemory // 向进程中写入东西

GetProcAddress // 取得函数在DLL中的地址

CreateRemoteThreadEx // 创建远程线程——即在其他进程中创建新的线程

CloseHandle // 关闭句柄

利用以上函数即可完成线程的注入

上面讲了这么多下面开始编写远程线程注入的代码:
① 在资源视图中找到主Dialog文件新建如下组件并命名,其中Inject按钮设为默认按钮,两个Button的ID分别为IDC_INJECT和IDC_OPEN

② 双击Open按钮编写如下代码,需要提前将编辑框1和2的ID分别命名为IDC_DLLPATH、IDC_EXENAME

// 获取DLL路径名,打开DLL文件
void CdajiInjecterDlg::OnBnClickedOpen()
{
	// 定义一个filedialog对象,通过它来获取dll的路径
	CFileDialog filedialog(TRUE,0,0,6UL,_T("DLL Files|*.dll|"));
	// 如果弹出了对话框并且选择了DLL,那么将获得的路径填充显示到DLLPath
	if (filedialog.DoModal() == IDOK)
	{
		CString DLLpath;
		DLLpath = filedialog.GetPathName();
		// 将路径填充到IDC_DLLPATH的对话框
		SetDlgItemText(IDC_DLLPATH, DLLpath);
	}
}

③ 双击Inject按钮,首先需要在inject按钮函数的前面添加注入功能的函数Inject

// 注入函数,同时返回值为是否注入成功,默认返回成功
BOOL Inject(LPCTSTR DLLPath,DWORD ProcessID) 
{
	// 定义一个句柄获取目标进程的所有权限,包括子进程
	HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, TRUE, ProcessID);
	// 判读是否获取到
	if (!hProcess)
	{
		return FALSE;
	}
	// 计算一下获取到的DLLpath究竟有多长,要在内存空间中申请内存来存放它,注意+1,为\0
	SIZE_T PathSize = (_tcslen(DLLPath) + 1) * sizeof(TCHAR); // 宽字节
	// 在晋城中申请内存存放此DLLpath
	LPVOID StartAddress = VirtualAllocEx(hProcess, NULL, PathSize, MEM_COMMIT, PAGE_READWRITE);
	// 如果未能获取到地址,返回失败
	if (!StartAddress)
	{
		return FALSE;
	}
	// 获取到地址则将DLLPath写入此地址
	if (!WriteProcessMemory(hProcess, StartAddress, DLLPath, PathSize, NULL))
	{
		return FALSE;
	}
	// 获取LoadLibrary的入口点地址,需要进行强制类型转换
	PTHREAD_START_ROUTINE pfnStartAddress = (PTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle(_T("kernel32.dll")), "LoadLibraryW");
	// 在这里获取到的地址,在目标进程中也一样,因此直接传递过去即可
	// 先判断是否获取到
	if (!pfnStartAddress)
	{
		return FALSE;
	}
	// 最重要的一步,创建远程线程,首先获取句柄,createremotethreadex函数只在win7以上系统有
	HANDLE hThread = CreateRemoteThreadEx(hProcess,NULL,NULL,pfnStartAddress,StartAddress,NULL,NULL,NULL);
	// 判断线程是否创建成功
	if (!hThread)
	{
		return FALSE;
	}
	// 最后等待线程结束,然后清理线程和进程
	WaitForSingleObject(hThread, INFINITE);
	CloseHandle(hThread);
	CloseHandle(hProcess);
	return TRUE; 
}

④ 在上面的注入函数之前还需要添加一个进程查找函数,如下

// 获取进程,其参数为进程名——在进程列表中获取我们想要的参数
DWORD ProcessFind(LPCTSTR Exename) 
{
	// 第一个参数只获取进程名
	HANDLE hProcess = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
	// 对获取的进程进行判断
	if(!hProcess)
	{
		return FALSE;
	}
	// 获取成功
	PROCESSENTRY32 info;
	info.dwSize = sizeof(PROCESSENTRY32);
	if (!Process32First(hProcess,&info)) 
	{
		return FALSE;
	}
	while (true) // 遍历进程中的所有项
	{
		// 判断是否与所给进程名相符,就是输入的进程名
		if(_tcscmp(info.szExeFile,Exename)==0)
		{
			// 相符的话返回该进程的PID
			return info.th32ProcessID;
		}
		// 如果遍历了整个进程列表都没有找到,那么返回FALSE
		if (!Process32Next(hProcess, &info))
		{
			return FALSE;
		}
	}
	// 函数默认返回FALSE
	return FALSE;
}

⑤ 最后是注入按钮Inject的函数代码:


// 点击按钮执行注入
void CdajiInjecterDlg::OnBnClickedInject()
{
	CString Dllpath;
	CString Exename;
	GetDlgItemText(IDC_EXENAME, Exename);
	GetDlgItemText(IDC_DLLPATH, Dllpath);

	// 如果用户什么进程名都没输入,那么提示
	if (Exename.GetLength() == 0)
	{
		MessageBox(_T("请输入进程名!"));
		return;  // 未填写进程名,直接返回,不让此函数继续执行
	}
	// DWORD类型变量用于存储PID
	DWORD ProcessID = ProcessFind(Exename);
	// 如果在进程列表中没找到此程序,提示
	if (!ProcessID)
	{
		MessageBox(_T("未找到该程序!"));
		return;  // 不再执行下面的
	}
	// 执行注入,并且对注入结果进行获取
	BOOL IsInjected = Inject(Dllpath, ProcessID);
	// 注入成功与失败,提示
	if (IsInjected)
	{
		MessageBox(_T("注入成功!"));
	}
	else
	{
		MessageBox(_T("注入失败!"));
	}
}

最后在dllmain.cpp中添加一个清楚的注入成功提醒标识:

// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "pch.h"

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
	// 进程连接时进程提示
    case DLL_PROCESS_ATTACH:
		MessageBox(NULL,L"Hello daji!",L"Welcome!",NULL);
		break;
	// 注意到此只能注入32位的进程,如果想要注入64位的进程
	// 需要在配置管理器中进行修改


    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}

如下进行测试,选择x64版本DLL(注意编译的时候选择编译的版本):

目标进程为Everything.exe

可以在任务栏的Evething中发现DLL的线程,二者此时属于同一个进程。

网络安全学习资源分享:

给大家分享一份全套的网络安全学习资料,给那些想学习 网络安全的小伙伴们一点帮助!

对于从来没有接触过网络安全的同学,我们帮你准备了详细的学习成长路线图。可以说是最科学最系统的学习路线,大家跟着这个大的方向学习准没问题。

因篇幅有限,仅展示部分资料,朋友们如果有需要全套《网络安全入门+进阶学习资源包》,请看下方扫描即可前往获取

👉1.成长路线图&学习规划👈

要学习一门新的技术,作为新手一定要先学习成长路线图,方向不对,努力白费

对于从来没有接触过网络安全的同学,我们帮你准备了详细的学习成长路线图&学习规划。可以说是最科学最系统的学习路线,大家跟着这个大的方向学习准没问题。

在这里插入图片描述
在这里插入图片描述

👉2.网安入门到进阶视频教程👈

很多朋友都不喜欢晦涩的文字,我也为大家准备了视频教程,其中一共有21个章节,每个章节都是当前板块的精华浓缩。(全套教程扫描领取哈)
在这里插入图片描述
在这里插入图片描述

👉3.SRC&黑客文档👈

大家最喜欢也是最关心的SRC技术文籍&黑客技术也有收录

SRC技术文籍:
在这里插入图片描述
黑客资料由于是敏感资源,这里不能直接展示哦! (全套教程扫描领取哈)

👉4.护网行动资料👈

其中关于HW护网行动,也准备了对应的资料,这些内容可相当于比赛的金手指!
在这里插入图片描述

👉5.黑客必读书单👈

在这里插入图片描述

👉6.网络安全岗面试题合集👈

当你自学到这里,你就要开始思考找工作的事情了,而工作绕不开的就是真题和面试题。
在这里插入图片描述

所有资料共282G,朋友们如果有需要全套《网络安全入门+进阶学习资源包》,可以扫描下方二维码或链接免费领取~

本文转自 https://blog.youkuaiyun.com/Cody_Ren/article/details/100041660?ops_request_misc=%257B%2522request%255Fid%2522%253A%25227787dc5ddbd47092ad7c75db342e7470%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=7787dc5ddbd47092ad7c75db342e7470&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allfirst_rank_ecpm_v1~rank_v31_ecpm-20-100041660-null-null.142v101pc_search_result_base6&utm_term=%E7%BA%BF%E7%A8%8Bjincheng&spm=1018.2226.3001.4187,如有侵权,请联系删除。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值