《Windows PE》6.4.2 远程注入DLL

实验四十七:远程注入DLL

写一个窗口程序,将一个dll通过远程注入的方法,注入到第三章的示例程序PEHeader.exe中,支持32位和64位PE。

       ●dll.c

/*------------------------------------------------------------------------
 FileName:dll.c
 实验47:远程注入(DLL)
 (c) bcdaren, 2024
-----------------------------------------------------------------------*/
#include <Windows.h>

//入口和退出点
int WINAPI DllMain(HINSTANCE hInstance, DWORD fdwReason, PVOID pvReserved)
{
	switch (fdwReason)
	{
	case DLL_PROCESS_ATTACH:
	{
		MessageBox(NULL, L"Welcome to PE!", L"Hello", MB_OK);
		break;
	}
	case DLL_THREAD_ATTACH:
		break;

	case DLL_THREAD_DETACH:
		break;

	case DLL_PROCESS_DETACH:
		break;
	}
	return TRUE;  
}

resource.h(略)

remoteThread.rc(略)

●remoteThread.c

/*------------------------------------------------------------------------
 FileName:remoteThread.c
 实验46:远程线程注入演示程序
 功能:目标是在进程PEHeader.exe中远程注入一个DLL,运行并显示"Welcome to PE!"对话框。
 测试步骤:当PEHeader.exe运行时,运行remoteThread.exe,文件菜单---插入到PEHeader.exe
 (c) bcdaren, 2024
-----------------------------------------------------------------------*/
#include <windows.h>
#include <strsafe.h>	//StringCchCopy
#include <commctrl.h>
#pragma comment(lib,"comctl32.lib")
#include <Richedit.h>
#include <tchar.h>
#include <string.h>
#include "resource.h"

//使用typedef给函数指针类型一个别名,函数指针存储函数地址
typedef FARPROC(__stdcall *_ApiSuspend)(HANDLE);
typedef HMODULE(__stdcall *_ApiResume)(HANDLE);
_ApiSuspend _suspendProcess;
_ApiResume _resumeProcess;

BOOL CALLBACK ProcDlgMain(HWND, UINT, WPARAM, LPARAM);
BOOL _patchPEInfo();
void _Init();
void ShowErrMsg();

HANDLE hInstance;
HWND hWinMain, hWinEdit;

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int nCmdShow)
{
	const TCHAR	szDllEdit[] = TEXT("RichEd20.dll");
	const TCHAR	szClassEdit[] = TEXT("RichEdit20W");//peinfo.rc中定义
	const TCHAR	szNtdll[] = TEXT("ntdll.dll");
	const CHAR	szSuspend[] = "ZwSuspendProcess";//函数名需要定义为ASCII字符
	const CHAR	szResume[] = "ZwResumeProcess";
	const TCHAR	szErr3[] = TEXT("Error happend when getting address.");
	HMODULE hRichEdit, hNtdll;

	hRichEdit = LoadLibrary((LPCWSTR)&szDllEdit);
	hNtdll = LoadLibrary((LPCWSTR)&szNtdll);
	_suspendProcess = (_ApiSuspend)GetProcAddress(hNtdll, szSuspend);
	if (!_suspendProcess)
		MessageBox(NULL, szErr3, NULL, MB_OK);
	_resumeProcess = (_ApiResume)GetProcAddress(hNtdll, szResume);
	if (!_resumeProcess)
		MessageBox(NULL, szErr3, NULL, MB_OK);

	hInstance = GetModuleHandle(NULL);
	DialogBoxParam(hInstance, MAKEINTRESOURCE(DLG_MAIN), NULL, (DLGPROC)ProcDlgMain, (LPARAM)0);
	FreeLibrary(hRichEdit);
	return 0;
}

BOOL CALLBACK ProcDlgMain(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
{
	switch (wMsg)
	{
	case WM_CLOSE:
		EndDialog(hWnd, 0);
		return TRUE;

	case WM_INITDIALOG:
		hWinMain = hWnd;
		_Init();	//初始化
		return TRUE;

	case WM_COMMAND:
		switch (wParam)
		{
		case IDM_EXIT:
			EndDialog(hWnd, 0);
			return TRUE;

		case IDM_OPEN:		//停止
			_patchPEInfo();
			return TRUE;
		}
	}
	return FALSE;
}

void _Init()
{
	CHARFORMAT stCf;
	static TCHAR szClassEdit[] = TEXT("RichEdit20W");	//UNICODE版本
	//static TCHAR szClassEdit[] = TEXT("RichEdit20A");	//ASCII码版本
	static TCHAR szFont[] = TEXT("宋体");
	//设置编辑控件
	hWinEdit = GetDlgItem(hWinMain, IDC_INFO);
	SendMessage(hWinEdit, EM_SETTEXTMODE, TM_PLAINTEXT, 0);
	RtlZeroMemory(&stCf, sizeof(stCf));
	stCf.cbSize = sizeof(stCf);
	stCf.yHeight = 9 * 20;
	stCf.dwMask = CFM_FACE | CFM_SIZE | CFM_BOLD;
	StringCchCopy((LPTSTR)&stCf.szFaceName, lstrlen(szFont) + 1, (LPCTSTR)&szFont);
	SendMessage(hWinEdit, EM_SETCHARFORMAT, 0, (LPARAM)&stCf);
	SendMessage(hWinEdit, EM_EXLIMITTEXT, 0, -1);
}

/*
;--------------------
; 将远程线程打到进程PEHeader.exe中
; 测试方法:首先运行PEHeader.exe
; 启动该程序,单击第一个菜单的第一项
; 会发现桌面上弹出"Welcome to PE!"对话框
;--------------------
*/
BOOL _patchPEInfo()
{
	HANDLE phwnd, hProcess, hCreate;
	DWORD parent, hProcessID;
	static TCHAR strTitle[256];
	static TCHAR szBuffer[256];
	const TCHAR szTitle[] = TEXT("PE文件头中几个关键地址的定位:");
	const TCHAR szErr1[] = TEXT("Error happend when openning.");
	const TCHAR szErr2[] = TEXT("Error happend when VirtualAllocEx.");

	static int dwProcessID, dwThreadID;
	PVOID lpLoadLibrary, lpDllName;
	static CHAR szMyDllFull[MAX_PATH];//注意:写入内存中的字符都是ANSI字符

	const TCHAR szDllKernel[] = TEXT("Kernel32.dll");
	const CHAR szLoadLibrary[] = "LoadLibraryA";//注意:写入内存中的字符都是ANSI字符
	const CHAR szMyDll[] = "\\DLL.dll";//注意:写入内存中的字符都是ANSI字符

	//准备工作:获取dll的全路径文件名、获取LoadLibrary函数地址等
	GetCurrentDirectoryA(MAX_PATH, szMyDllFull);//获取应用程序的当前工作目录
	strcat_s(szMyDllFull, MAX_PATH, szMyDll);//添加后缀名
	int nLen = sizeof(CHAR)*(strlen(szMyDllFull) + 1);

	//获取Kernel32.dll句柄,LoadLibrary函数地址
	lpLoadLibrary = GetProcAddress(GetModuleHandle(szDllKernel), (LPCSTR)szLoadLibrary);

	//通过标题获得进程的handle
	parent = 0;	//复位标志
	phwnd = GetWindow(GetWindow(GetDesktopWindow(), GW_CHILD), GW_HWNDFIRST);
	if (!GetParent(phwnd))
		parent = 1;

	while (phwnd)
	{
		if (parent)
		{
			parent = 0;	//复位标志
			//得到窗口标题文字
			GetWindowText(phwnd, strTitle, sizeof(strTitle));
			if (!_tcscmp(szTitle, strTitle))
				break;
		}
		//寻找这个窗口的下一个兄弟窗口
		phwnd = GetWindow(phwnd, GW_HWNDNEXT);
		if (!GetParent(phwnd))
		{
			if (IsWindowVisible(phwnd))
				parent = 1;
		}
	}
	//根据窗口句柄获取进程ID
	GetWindowThreadProcessId(phwnd, &hProcessID);

	//1.打开本地进程
	hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, hProcessID);
	if (!hProcess)
	{
		MessageBox(NULL, szErr1, NULL, MB_OK);
		return FALSE;
	}

	//2.分配空间,以页为单位
	lpDllName = VirtualAllocEx(hProcess, NULL, nLen, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
	if (!lpDllName)
	{
		MessageBox(NULL, szErr2, NULL, MB_OK);
		return FALSE;
	}
	//3.写入线程代码,注意:写入内存中的字符都是ANSI字符
	SIZE_T dwWrite = 0;
	if (!WriteProcessMemory(hProcess, lpDllName, szMyDllFull, nLen, &dwWrite))
	{
		MessageBox(NULL, L"写入内存失败!\n", NULL, MB_OK);
		return FALSE;
	}

	//4.创建一个在另一个进程的虚拟地址空间中运行的线程
	hCreate = CreateRemoteThread(hProcess, NULL, 0, lpLoadLibrary, lpDllName, 0, NULL);

	//5.等待线程结束返回,释放资源
	WaitForSingleObject(hCreate, -1);
	CloseHandle(hCreate);
	VirtualFreeEx(hProcess, lpDllName, 0, MEM_FREE);
	CloseHandle(hProcess);
	return TRUE;
}

运行

      

                     图6-5远程注入DLL

  总结

上述示例程序的功能是在进程PEHeader.exe中远程注入一个DLL,运行并显示"Welcome to PE!"对话框。

测试步骤:当PEHeader.exe运行时,运行remoteThread.exe,点击文件菜单”插入到PEHeader.exe”,就可以将DLL远程注入到进程PEHeader.exe中了。

远程注入的步骤:

1.打开本地进程(调用OpenProcess函数)。

2.目标进程分配空间,以页为单位(调用VirtualAllocEx函数)。

3.写入目标进程完整的DLL文件名,(调用WriteProcessMemory函数)。注意:写入内存中的字符都是ANSI字符。

4.创建远程线程(调用CreateRemoteThread函数)。

5.等待线程结束返回,释放资源(调用WaitForSingleObject函数)。

在VS CreateRemoteThread函数调用处下断点,远程注入参数如下所示:

图6-6 远程注入的参数

我们可以使用windbg调试器附加进程PEHeader.exe,查看进程地址0x04dc0000处的数据就是我们已经注入的DLL完整名称。

0:009> db 0x04dc0000

04dc0000  44 3a 5c 63 6f 64 65 5c-77 69 6e 70 65 5c 63 68  D:\code\winpe\ch

04dc0010  30 36 5c 72 65 6d 6f 74-65 54 68 72 65 61 64 5c  06\remoteThread\

04dc0020  44 4c 4c 2e 64 6c 6c 00-00 00 00 00 00 00 00 00  DLL.dll.........

       对比无DLL注入的方法,使用DLL注入的方法不需要对代码和数据进行重定位(由操作系统自动完成),省去了很多不必要的麻烦,因此也是我们常用的方法。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/893460.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【实战案例】JSR303统一校验与SpringBoot项目的整合

前后端分离项目中&#xff0c;当前前端请求后端接口的时候通常需要传输参数&#xff0c;对于参数的校验应该在哪一步进行校验&#xff1f;Controller中还是Service中&#xff1f;答案是都需要校验&#xff0c;只不过负责的板块不一样&#xff0c;Controller中通常校验请求参数的…

OpenCV高级图形用户界面(6)获取指定窗口中图像的矩形区域函数getWindowImageRect()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 提供窗口中图像的矩形区域。 该函数 getWindowImageRect 返回图像渲染区域的客户端屏幕坐标、宽度和高度。 函数原型 Rect cv::getWindowImage…

上海亚商投顾:沪指失守3200点 房地产板块集体下挫

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。 一.市场情绪 市场全天冲高回落&#xff0c;沪指尾盘跌超1%&#xff0c;失守3200点关口。网络安全概念开盘大涨&#xff0c;…

Kaggle竞赛的流程 —— 手把手讲述如何完成一次kaggle比赛

Kaggle竞赛的工作流程&#xff1a; 1、加入竞赛&#xff1a; 看一下竞赛的描述&#xff0c;了解具体任务和数据集的情况之后&#xff0c;如果比较感兴趣这个比赛。点击Join Competition按钮&#xff0c;接受竞赛规则后&#xff0c;就可以访问比赛数据集啦。如下图所示&#xf…

08_实现 reactive

目录 编写 reactive 的函数签名处理对象的其他行为拦截 in 操作符拦截 for...in 循环delete 操作符 处理边界新旧值发生变化时才触发依赖的情况处理从原型上继承属性的情况处理一个对象已经是代理对象的情况处理一个原始对象已经被代理过一次之后的情况 浅响应与深响应代理数组…

Leetcode 跳跃游戏 二

核心任务是找出从数组的起点跳到终点所需的最小跳跃次数。 这段代码解决的是“跳跃游戏 II”&#xff08;Leetcode第45题&#xff09;&#xff0c;其核心任务是找出从数组的起点跳到终点所需的最小跳跃次数。 class Solution {public int jump(int[] nums) {//首先处理特殊情…

LabVIEW提高开发效率技巧----时序分析

一、什么是时序分析&#xff1f; 时序分析是优化LabVIEW程序性能的重要步骤。它通过分析程序各个部分的执行时间&#xff0c;帮助开发者找到程序运行中的瓶颈&#xff0c;并进行有针对性的优化。在LabVIEW中&#xff0c;Profile Performance and Memory工具是进行时序分析的关…

MySQL 免密登录的几种配置方式

文章目录 MySQL 免密登录的几种配置方式使用操作系统用户实现免密登录具体步骤&#xff1a;Step 1: 修改 MySQL 配置文件Step 2: 重启 MySQL 服务Step 3: 使用系统用户登录 MySQL优点&#xff1a;缺点&#xff1a; 使用 mysql_config_editor 配置免密文件具体步骤&#xff1a;S…

晶体与晶振的区别

概述 晶振是有源晶振的简称&#xff0c;又叫振荡器。英文名称是oscillator。 晶体则是无源晶振的简称&#xff0c;也叫谐振器。英文名称是crystal&#xff0c;电路上简称为XTAL。 无源晶振&#xff08;晶体&#xff09;&#xff1a;需要借助时钟电路才能产生振荡信号。 有源…

基于SpringBoot网上超市的设计与实现(论文+源码)_kaic

摘 要 网络技术和计算机技术发展至今&#xff0c;已经拥有了深厚的理论基础&#xff0c;并在现实中进行了充分运用&#xff0c;尤其是基于计算机运行的软件更是受到各界的关注。加上现在人们已经步入信息时代&#xff0c;所以对于信息的宣传和管理就很关键。因此超市商品销售信…

Oracle DECODE 丢失时间精度的原因与解决方案

在Oracle数据库中&#xff0c;DECODE 函数是一个非常实用的条件处理函数&#xff0c;通常用于替代简单的 CASE WHEN 语句。它根据给定的值列表进行匹配&#xff0c;如果匹配成功则返回相应的值。如果不匹配&#xff0c;返回一个默认值。 问题描述 SELECT DECODE(-21, -1, NU…

Python酷库之旅-第三方库Pandas(157)

目录 一、用法精讲 716、pandas.Timedelta.view方法 716-1、语法 716-2、参数 716-3、功能 716-4、返回值 716-5、说明 716-6、用法 716-6-1、数据准备 716-6-2、代码示例 716-6-3、结果输出 717、pandas.Timedelta.as_unit方法 717-1、语法 717-2、参数 717-3、…

MyBatis 框架搭建时依赖包引入异常

MyBatis 框架搭建时依赖包引入异常 问题&#xff1a;原因&#xff1a;解决办法&#xff1a; 问题&#xff1a; 在基于idea环境中学习搭建mybatis框架时&#xff0c;在maven工程的pom.xml文件中引入的 junit及mysql依赖包后&#xff0c;出现驼色阴影&#xff0c;提示信息如下图&…

白平衡之基于 Green 通道的白平衡算法

免责声明&#xff1a;本文所提供的信息和内容仅供参考。作者对本文内容的准确性、完整性、及时性或适用性不作任何明示或暗示的保证。在任何情况下&#xff0c;作者不对因使用本文内容而导致的任何直接或间接损失承担责任&#xff0c;包括但不限于数据丢失、业务中断或其他经济…

IP报文格式、IPv6概述

IPv4报文格式 IPv4报文首部长度至少为20字节(没有可选字段和填充的情况下)&#xff0c;下面来逐一介绍首部各个字段的含义 Version版本&#xff1a;表示采用哪一种具体的IP协议&#xff0c;对于IPv4来说该字段就填充4以表示&#xff0c;如果是IPv6就填充6IHL首部长度&#xff…

HTML5实现古典音乐网站源码模板2

文章目录 1.设计来源1.1 主界面1.2 古典音乐界面1.3 著名人物界面1.4 古典乐器界面1.5 历史起源界面1.6 联系我们界面 2.效果和源码2.1 动态效果2.2 源代码 源码下载万套模板&#xff0c;程序开发&#xff0c;在线开发&#xff0c;在线沟通 作者&#xff1a;xcLeigh 文章地址&a…

3D Gaussian Splatting前向渲染代码解读

文章目录 3D Gaussian Splatting前向渲染简介3DGS前向渲染流程伪代码 代码解读栅格化主流程初始化常量和变量预处理生成Idx为排序做准备查找最高有效位device级别的并行基数排序排序后处理渲染 预处理获取3D高斯点的id&#xff0c;变量初始化检查3D高斯点是否在视锥体范围内计算…

(十九)、使用 minikube 运行k8s 集群

文章目录 1、机器信息2、官方文档3、启动本机 docker4、安装 minikube5、启动 minikube5.1、报错重试应该做什么&#xff1f; 6、启动后7、安装 Vs Code & k8s extensions8、在 VS Code 查看运行起来的 k8s 集群9、基本命令10、虚拟化不支持 Mac Os 14.3.1 1、机器信息 Ma…

LabVIEW提高开发效率技巧----事件触发模式

事件触发模式在LabVIEW开发中是一种常见且有效的编程方法&#xff0c;适用于需要动态响应外部或内部信号的场景。通过事件结构&#xff08;Event Structure&#xff09;和用户自定义事件&#xff08;User Events&#xff09;&#xff0c;开发者可以设计出高效的事件驱动程序&am…

Linux的kafka安装部署

1.kafka是一个分布式的,去中心化的,高吞吐低延迟,订阅模式的消息队列系统 确保要有jdk与zookeeper安装配置 2.下载kafka安装包 http://archive.apache.org/dist/kafka/2.4.1/kafka_2.12-2.4.1.tgz 此时可以wget http://archive.apache.org/dist/kafka/2.4.1/kafka_2.12-2.4.…