Win32API之实现远程线程注入(九)

news2024/9/24 12:28:42

什么是注入

注入是一种在不知情或未经许可的情况下向其他进程中注入模块并试图执行它们的技术

常见的注入方式有:远程线程注入、APC注入、消息钩子注入、注册表注入、导入表注入、输入法注入等等


什么是远程线程注入

远程线程注入是一种技术,可以将一个动态链接库(DLL)注入到另一个进程的地址空间中,并在该进程中创建一个远程线程来执行该 DLL 中的代码。这种技术通常用于恶意软件攻击,也可以用于调试和监视进程。远程线程注入涉及到许多操作系统底层的概念,包括内存映射、线程创建、函数调用等等。为了成功进行远程线程注入,攻击者需要克服许多障碍,例如安全软件、权限限制、代码签名等等


CreateRemoteThreaad

函数描述

CreateRemoteThread函数用于在另一个进程的地址空间中创建一个新线程。CreateRemoteThread函数通常用于远程线程注入和Hook技术等高级应用场景。其原理是通过在目标进程中分配内存,将需要执行的代码和参数写入该内存,然后在该内存中创建新线程并启动执行

其函数原型如下:

HANDLE CreateRemoteThread(
  HANDLE                 hProcess,  //目标进程的句柄
  LPSECURITY_ATTRIBUTES  lpThreadAttributes,  //线程安全描述符
  SIZE_T                 dwStackSize,  //线程的初始堆栈大小,通常为0表示使用默认值
  LPTHREAD_START_ROUTINE lpStartAddress,  //新线程的入口点,即线程执行的第一个函数
  LPVOID                 lpParameter, //传递给线程函数的参数
  DWORD                  dwCreationFlags, //线程创建的标志,例如是否立即运行等
  LPDWORD                lpThreadId //返回新线程的ID
);

注意:lpStartAddress参数表示目标进程所拥有的线程函数,而不是CreateRemoteThread函数所在进程的线程函数


使用实例

如下代码用于表示被远程注入的目标进程,首先通过调试进程获取到线程函数的地址为0x00981f70,然后运行此段代码

include <iostream>
include <windows.h>


DWORD WINAPI ThreadProc(LPVOID lpParameter)
{
	for (int i = 0; i < 5; i++)
	{
		printf("线程正在执行!\n");
	}
	return 0;
}


int main()
{	
	HANDLE hThread = CreateThread(NULL, 0, ThreadProc, 0, 0, NULL);
	getchar();

	CloseHandle(hThread);
	
}

1


如下代码用于实现远程线程注入,运行后会发现目标进程的线程函数会再次执行

include <iostream>
include <windows.h>
include <TlHelp32.h>
include <string>

// 远程线程注入函数
BOOL MyCreateRemoteThread(DWORD ProcessID, DWORD AddrThreadProc) {
	
	HANDLE hProcess;
	HANDLE hThread;
	DWORD ThreadID;

	// 打开目标进程
	hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, ProcessID);
	if (hProcess == NULL)
	{
		OutputDebugString("OpenProcess Error!\n");
		return FALSE;
	}
	
	// 在目标进程中创建新的远程线程
	hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)AddrThreadProc, NULL, 0, &ThreadID);
	if (hThread == NULL)
	{
		OutputDebugString("CreateRemoteThread Error!\n");
		return FALSE;
	}
	// 关闭进程和线程句柄
	CloseHandle(hThread);
	CloseHandle(hProcess);
	return true;
}

// 通过进程名称获取进程ID的函数
DWORD GetProcessIdByName(const std::wstring& name) {
	DWORD pid = 0;
	HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
	if (snap != INVALID_HANDLE_VALUE) {
		PROCESSENTRY32W entry = { sizeof(entry) };
		// 遍历进程快照
		if (Process32FirstW(snap, &entry)) {
			do {
				// 检查进程名称是否匹配
				if (std::wstring(entry.szExeFile) == name) {
					pid = entry.th32ProcessID;
					break;
				}
			} while (Process32NextW(snap, &entry));
		}
		// 关闭快照句柄
		CloseHandle(snap);
	}
	return pid;
}


int main()
{	
	// 通过进程名获取进程ID,并打印
	std::wstring process_name = L"test2.exe";
	DWORD pid = GetProcessIdByName(process_name);
	if (pid != 0) {
		printf("Process ID of %ls: %lu\n", process_name.c_str(), pid);
	}
	else {
		printf("Failed to get process ID of %ls\n", process_name.c_str());
	}

	// 在获取到的进程ID中执行远程线程注入
	MyCreateRemoteThread(pid, 0x00981f70);
	return 0;
}

1


远程线程注入的思路

通过上述CreateRemoteThread的远程线程实例可知, 若要实现远程线程注入, 只能限制于目标进程的线程函数, 而不能执行自己的代码

若想目标进程执行自己的代码,可以利用Dll注入来实现。首先了解ThreadProc线程函数的语法格式, 此函数需要一个四字节的参数以及四字节的返回值, 也就是说, 只要有符合这种格式的函数,那么它就能代替线程函数并传递给CreateRemoteThread函数调用

DWORD WINAPI ThreadProc(LPVOID lpParameter)
{
    return 0;
}

比如LoadLibrary函数, 此函数与线程函数的格式一样,都是四字节的参数和返回值。只要将CreateRemoteThread函数的线程函数地址替换成LoadLibrary的函数地址, 以及传递dll的路径作为LoadLibrary函数的参数, 在dll中写入我们自己的代码,这样就能实现完整的远程线程注入

HINSTANCE LoadLibrary( 
  LPCTSTR lpLibFileName;
) 

总结以上几点, 远程注入的流程如下所示:

  • 在目标进程分配内存空间, 用于存储dll的路径
  • 获取LoadLibrary函数的地址
  • 创建远程线程, 并执行LoadLibrary函数

远程线程注入实例

代码

如下代码是DLL文件,要注意一点,若目标进程是32位的,那么创建的dll也应该是32位的, 将要执行的代码写在DLL_PROCESS_ATTACH处, 即dll被加载后会自动执行这段代码

//Mydll.dll
include "pch.h"
include <stdio.h>

DWORD WINAPI ThreadProc(LPVOID lpParameter)
{	
	for (int i = 0; i < 5; i++)
	{	
		Sleep(1000);
		printf("远程线程注入成功!\n");
	}
	return 0;
}


<br>

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
		CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL);
		break;
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}	

如下代码是被远程注入的进程B

//进程B

include <iostream>
include <windows.h>

DWORD WINAPI ThreadProc(LPVOID lpParameter)
{
	for (int i = 0; i < 5; i++)
	{
		printf("线程正在执行!\n");
	}
	return 0;
}


int main()
{	
	HANDLE hThread = CreateThread(NULL, 0, ThreadProc, 0, 0, NULL);
	getchar();

	CloseHandle(hThread);
}	

如下代码用于实现远程线程注入的进程A。

关于Dll文件的路径问题, Dll的路径若要使用相对路径, 那么dll文件就必须放在进程B(目标进程)的工作目录下, 而不是进程A的工作目录

//进程A

include <iostream>
include <windows.h>
include <TlHelp32.h>
include <string>

//获取进程ID的函数
DWORD GetProcessIdByName(const std::wstring& name) {
	DWORD pid = 0;
	HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
	if (snap != INVALID_HANDLE_VALUE) {
		PROCESSENTRY32W entry = { sizeof(entry) };
		if (Process32FirstW(snap, &entry)) {
			do {
				if (std::wstring(entry.szExeFile) == name) {
					pid = entry.th32ProcessID;
					break;
				}
			} while (Process32NextW(snap, &entry));
		}
		CloseHandle(snap);
	}
	return pid;
}


BOOL RemoteInject(DWORD pid, char* dllPath)
{
	DWORD DllNameLength = strlen(dllPath);

	//1 获取目的进程句柄
	HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
	
	//2 为目的进程分配内存,用于存放Loadlibrary传入的参数,即dll的路径
	VOID* paraAddr = VirtualAllocEx(hProcess, NULL, DllNameLength + 1, MEM_COMMIT, PAGE_READWRITE);

	//3 将DLL的路径写到目标进程的内存
	if (!WriteProcessMemory(hProcess, paraAddr, dllPath, DllNameLength + 1, NULL))
	{
		printf("写入内存失败!\n");
		return false;
	}
	
	//4 获取loadlibrary函数的地址
	HINSTANCE LibHandle = LoadLibrary("kernel32");
	DWORD ProcAdd = (DWORD)GetProcAddress(LibHandle, "LoadLibraryA");
	if (!ProcAdd)
	{
		printf("获取LoadLibraryA失败!\n");
		return false;
	}

	//5 创建远程线程
	DWORD threadid = 0;
	HANDLE hRemoteThread = INVALID_HANDLE_VALUE;
	hRemoteThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)ProcAdd, paraAddr, 0, &threadid);
	if (NULL == hRemoteThread)
	{
		printf("目标进程中创建线程失败!\n");
		CloseHandle(hProcess);
		return FALSE;
	}
	WaitForSingleObject(hRemoteThread, INFINITE);
	
	//释放句柄
	CloseHandle(hRemoteThread);
	CloseHandle(hProcess);
}


int main(int argc, char*argv[])
{	
	//获取进程ID
	std::wstring process_name = L"test2.exe";
	DWORD ProcessID = GetProcessIdByName(process_name);
	
	//远程线程注入
	RemoteInject(ProcessID, (char*)"E:\\Mydll.dll");
	
	return 0;
}

执行结果

将生成的dll文件(MyDll.dll)放到E盘目录, 先运行进程B的代码, 随后运行进程A的代码, 可以发现dll文件的线程代码在进程A执行了

动画

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

前端vue之根据内容生成二维码

1.实现这功能需要借助第三方插件,首先下载安装插件: 我在终端直接下载 npm install vue-qr --save2.在需要的.vue文件中引入并注册组件 import VueQr from vue-qr; export default {components: {VueQr,},3.在需要用的位置使用该二维码标签 <vue-qr :logo-src"logoS…

自动控制原理模拟卷6

自动控制原理模拟题六 Question1 已知控制系统的信号流图如下图所示: 求控制系统传递函数 C ( s ) / R ( s ) C(s)/R(s) C(s)

[mars3d] 学习

今天整体说下mars3d&#xff0c;集成问题之后在说&#xff0c;先说下概念性的东西&#xff1b; 一、设置地球的参数 下载他们的示例&#xff0c;如果不是特别的要求&#xff0c;可以直接使用他们的 confign 进行加载&#xff1b; 如果有什么特别的设置的&#xff0c;可以通过…

Chapter6-可靠性优先的使用场景

6.1 顺序消息 顺序消息是指消息的消费顺序和产生顺序相同&#xff0c;在有些业务逻辑下&#xff0c;必须保证顺序 。 比如订单的生成 、付款、发货&#xff0c;这 3 个消息必须按顺序处理才行。顺序消息分为全局顺序消息和部分顺序消息&#xff0c;全局顺序消息指某个 Topic 下…

centos7.6部署ELK集群(一)之elasticsearch7.7.0集群部署

32.3. 部署es7.7.0 32.3.1. 下载es&#xff08;各节点都做&#xff09; wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-7.7.0-linux-x86_64.tar.gz 32.3.2. 解压至安装目录&#xff08;各节点都做&#xff09; tar -xvf elasticsearch-7.7.0-li…

你的宝典,软件测试项目实战,金融项目测试点详全(超详细)

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 测试要点 软件测试…

Locust 压力测试helloworld

1. 什么是Locust Locust 是一种易于使用、可直接使用pyhton编写脚本运行且可扩展的性能测试工具。 2. 安装Locust Python 3.9.16 pip install locust2.15.1 3. 一个简单的示例 3.1. 编写下面代码&#xff0c;文件命名为locustfile_test.py from locust import HttpUser,…

Python实现哈里斯鹰优化算法(HHO)优化卷积神经网络回归模型(CNN回归算法)项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档视频讲解&#xff09;&#xff0c;如需数据代码文档视频讲解可以直接到文章最后获取。 1.项目背景 2019年Heidari等人提出哈里斯鹰优化算法(Harris Hawk Optimization, HHO)&#xff0c;该算法有较强的全…

Linux多线程-3

在之前的两篇博客当中&#xff0c;我们讲述了线程概念、线程控制和线程安全三部分内容。紧随其后本篇博客内容&#xff1a;我们首先来讲述生产者和消费者模型&#xff0c;来了解一种多线程的设计模式&#xff0c;然后在此基础上讲述上一篇博客剩余的内容&#xff1a;信号量的相…

跨平台开发 uni-app

目录&#xff1a; 1 邂逅跨平台开发 2 初体验uni-app 3 uni-app全局文件 4 内置组件和样式 5 扩展组件 uni-ui 6 跨端兼容实现 7 路由和生命周期 8、扩展组件 uni-ui 9、跨端兼容实现 10、页面路由和传参 11、其它常用API 12、自定义组件 13、状态管理Pinia 创建的…

归并排序的非递归实现

其实想法和递归实现的类似&#xff0c;只不过是通过其他变量分组&#xff0c;而不是mid&#xff0c;我们可以将数组先分为两 两一组&#xff0c;再合并成四四一组&#xff0c;以此类推&#xff0c;最后一次合并排序后&#xff0c;得到的数组就为有序数组了&#xff0c;所以 递…

Docker容器数据卷详解

文章目录 一、数据卷使用二、数据卷容器三、数据卷备份与恢复 数据卷特点&#xff1a; 数据卷会一直在&#xff0c;即使容器销毁可以对数据卷内容直接修改 一、数据卷使用 1、为容器添加数据卷 docker run -itd --name nginx -v /data:/usr/share/nginx/html qinzt/nginx:v1…

15、虚拟内存LLDB高级调试

一、虚拟内存 早期的操作系统 早期的操作系统,并没有虚拟内存的概念.系统由进程直接访问内存中的物理地址,这种方式存在严重的安全隐患.内存中的不同进程,可以计算出他们的物理地址,可以跨进程访问,可以随意进行数据的篡改.早期的程序也比较小,在运行时,会将整个程序全部加载到…

SQL——关于bjpowernode.sql的33道经典例题之18-33

目录 18 列出所有“CLERK”&#xff08;办事员&#xff09;的姓名和部门名称、部门人数 19 列出最低薪水大于1500的各种工作和此工作的全部雇员人数 20 列出在部门“SALES”<销售部>工作的员工姓名 21 列出薪资高于公司平均薪资的所有员工&#xff0c;所在部门、上级…

windows python 安装 mathutils库出现问题解决

项目场景&#xff1a; 在windows11上python安装mathutils库时报错。分如下两种情况安装&#xff0c;都报的是同样的错误&#xff1a; &#xff08;1&#xff09;直接在使用pip安装 python -m pip install mathutils # 或者 pip install mathutils &#xff08;2&#xff09;…

2023年第二届服务机器人国际会议(ICoSR 2023) | IEEE-CPS独立出版

会议简介 Brief Introduction 2023年第二届服务机器人国际会议(ICoSR 2023) 会议时间&#xff1a;2023年7月21日-23日 召开地点&#xff1a;中国上海 大会官网&#xff1a;www.iwosr.org ICoSR 2023将围绕“服务机器人”的最新研究领域而展开&#xff0c;为研究人员、工程师、专…

版本升级|Co-Project V3.1智能项目管理平台——新增三大调整板块 提高自动估算精准度

大家好&#xff0c;CoCode开发云旗下Co-Project V3.1智能项目管理平台正式发布&#xff0c;需求分析工具全新升级&#xff0c;新增功能点调整类型、工作量调整因子和费用调整因子三大板块&#xff0c;全面提高自动估算项目精准度。 一、调整功能点数 要提高项目估算精准度&…

stable diffusion webui 使用

参考各文章以及个人操作后的记录文章&#xff0c;也希望能帮助有需要的人~ 首先进去大概是这样的&#xff0c;介绍下下图几个区域&#xff08;主要是文生图&#xff09;。 一、模型区域 Stable Diffusion checkpoint下拉选择框是用来切换ckpt模型&#xff0c;不清楚的可以看…

快速入门 Python 内置模块 argparse

目录 一、argparse 简介二、The add_argument() method 一、argparse 简介 argparse 模块是 Python 内置的用于命令项选项与参数解析的模块&#xff0c;argparse 模块可以让人轻松编写用户友好的命令行接口&#xff0c;能够帮助程序员为模型定义参数。 使用 argparse 模块的四个…

C++string类详解

C语言中&#xff0c;字符串是以\0结尾的一些字符的集合&#xff0c;为了操作方便&#xff0c;C标准库中提供了一些str系列的库函数&#xff0c;但是这些库函数与字符串是分离开的&#xff0c;不太符合OOP的思想&#xff0c;而且底层空间需要用户自己管理&#xff0c;稍不留神可…