首页 > 系统相关 >Windows编程系列:远线程注入

Windows编程系列:远线程注入

时间:2024-03-13 12:11:41浏览次数:33  
标签:函数 Windows 编程 MEM 线程 PAGE 页面

远线程注入

远线程(RemoteThread)注入是指一个进程在另一个进程中创建线程的技术,这是一种很经典的DLL注入技术。

虽然比较古老,但是很实用。通过远线程注入,再配合api函数的hook技术,可以实现很多有意思的功能。

 

 

实现远线程注入的关键函数

OpenProcess

打开现有的本地进程,函数声明如下:

1 WINAPI
2 OpenProcess(
3     _In_ DWORD dwDesiredAccess,
4     _In_ BOOL bInheritHandle,
5     _In_ DWORD dwProcessId
6     );

参数:

dwDesiredAccess:

访问进程对象。此访问权限为针对进程的安全描述符进行检查,此参数可以是一个或多个进程访问权限。如果调用该函数的进程启用了SeDebugPrivilege权限,则无论安全描述符的内容是什么,它都会授予所请求的访问权限。

bInheritHandle:

若此值为TRUE,则此进程创建的进程将继承该句柄。否则,进程不会继承此句柄。

dwProcessId:

要打开的本地进程的PID

返回值:

成功,返回进程的句柄

失败,返回NULL,要获取错误信息,调用GetLastError

 

VirtualAllocEx

在指定进程的虚拟地址空间内保留、提交或更改内存的状态。声明如下:

1 WINAPI
2 VirtualAllocEx(
3     _In_ HANDLE hProcess,
4     _In_opt_ LPVOID lpAddress,
5     _In_ SIZE_T dwSize,
6     _In_ DWORD flAllocationType,
7     _In_ DWORD flProtect
8     );

hProcess

进程的句柄。VirtualAllocEx函数在该进程的虚拟地址空间内分配内存,句柄必有具有PROCESS_VM_OPERATION权限。

 

lpAddress

指定要分配页面所需起始地址的指针。如果lpAddress为NULL,则该函数自动分配内存。

 

dwSize

要分配的内存大小,以字节为单位。

 

flAllocationType

内存分配类型。此参数必须为以下值之一

含义
MEM_COMMIT
0x00001000
从指定保留内存页的磁盘) 的总内存大小和分页文件 (分配内存费用。 函数还保证当调用方稍后最初访问内存时,内容将为零。 除非实际访问虚拟地址,否则不会分配实际物理页面。

尝试通过指定 MEM_COMMIT 而不指定 MEM_RESERVE 和非 NULLlpAddress 来提交特定地址范围,除非已保留整个范围。 生成的错误代码ERROR_INVALID_ADDRESS。

尝试提交已提交的页面不会导致函数失败。 这意味着,无需先确定每个页面的当前承诺状态即可提交页面。

如果 lpAddress 指定 enclave 中的地址,则必须MEM_COMMITflAllocationType

MEM_RESERVE
0x00002000
保留进程的虚拟地址空间范围,而无需在内存或磁盘上的分页文件中分配任何实际物理存储。

使用 MEM_COMMIT 再次调用 VirtualAllocEx 来提交保留页。 若要在一个步骤中保留和提交页面,请使用 MEM_COMMIT | MEM_RESERVE调用 VirtualAllocEx。

其他内存分配函数(如 malloc 和 LocalAlloc)在释放内存之前不能使用预留内存。

MEM_RESET
0x00080000
指示 lpAddress 和 dwSize 指定的内存范围中的数据不再感兴趣。 不应从分页文件读取或写入页面。 但是,内存块稍后将再次使用,因此不应取消提交。 此值不能与任何其他值一起使用。

使用此值并不能保证使用 MEM_RESET 操作的范围将包含零。 如果希望范围包含零,请取消提交内存,然后重新提交。

使用 MEM_RESET 时, VirtualAllocEx 函数会忽略 fProtect 的值。 但是,仍必须将 fProtect 设置为有效的保护值,例如 PAGE_NOACCESS。

如果使用 MEM_RESET并且内存范围映射到文件,VirtualAllocEx 将返回错误。 仅当共享视图映射到分页文件时,才可接受该视图。

MEM_RESET_UNDO
0x1000000
应 仅对之前成功应用MEM_RESET的地址范围调用 MEM_RESET_UNDO 。 它指示调用方对 lpAddress 和 dwSize 指定的指定内存范围中的数据感兴趣,并尝试反转 MEM_RESET的影响。 如果该函数成功,则表示指定地址范围中的所有数据都保持不变。 如果函数失败,则至少将地址范围中的某些数据替换为零。

此值不能与任何其他值一起使用。 如果在之前未MEM_RESET的地址范围上调用MEM_RESET_UNDO,则行为未定义。 指定 MEM_RESET时, VirtualAllocEx 函数将忽略 flProtect 的值。 但是,仍必须将 flProtect 设置为有效的保护值,例如 PAGE_NOACCESS。

Windows Server 2008 R2、Windows 7、Windows Server 2008、Windows Vista、Windows Server 2003 和 Windows XP: 在 Windows 8 和 Windows Server 2012 之前,不支持 MEM_RESET_UNDO 标志。

此参数还可以按指示指定以下值。

MEM_LARGE_PAGES
0x20000000
使用 大页支持分配内存。

如果指定此值,还必须指定 MEM_RESERVE 和 MEM_COMMIT。

MEM_PHYSICAL
0x00400000
保留可用于将 地址窗口扩展 (AWE) 页映射的地址范围。

此值必须与 MEM_RESERVE 一起使用,不能与其他值一起使用。

MEM_TOP_DOWN
0x00100000
在可能的最高地址分配内存。 这可能比常规分配慢,尤其是在有许多分配时。

flProtect

要分配的页面区域的内存保护。如果页面已提交,则可以指定任何一个如下内存保护常量。

常量/值说明
PAGE_EXECUTE
0x10
启用对页面已提交区域的执行访问。 尝试写入已提交区域会导致访问冲突。
CreateFileMapping 函数不支持此标志。
PAGE_EXECUTE_READ
0x20
启用对页面已提交区域的执行或只读访问。 尝试写入已提交区域会导致访问冲突。
Windows Server 2003 和 Windows XP: 在 Windows XP SP2 和 Windows Server 2003 SP1 之前, CreateFileMapping 函数不支持此属性。
PAGE_EXECUTE_READWRITE
0x40
启用对已提交页面区域的执行、只读或读/写访问权限。
Windows Server 2003 和 Windows XP: 在 Windows XP SP2 和 Windows Server 2003 SP1 之前, CreateFileMapping 函数不支持此属性。
PAGE_EXECUTE_WRITECOPY
0x80
启用对文件映射对象的映射视图的执行、只读或写入时复制访问权限。 尝试写入已提交的写入时复制页会导致为进程创建页面的专用副本。 专用页面标记为 PAGE_EXECUTE_READWRITE,更改将写入新页面。
VirtualAlloc 或 VirtualAllocEx 函数不支持此标志。 Windows Vista、Windows Server 2003 和 Windows XP: 在具有 SP1 和 Windows Server 2008 的 Windows Vista 之前, CreateFileMapping 函数不支持此属性。

PAGE_NOACCESS
0x01
禁用对已提交页面区域的所有访问。 尝试从提交区域读取、写入或执行区域会导致访问冲突。
CreateFileMapping 函数不支持此标志。
PAGE_READONLY
0x02
启用对已提交页面区域的只读访问。 尝试写入已提交区域会导致访问冲突。 如果启用了 数据执行防护 ,则尝试在已提交的区域中执行代码会导致访问冲突。
PAGE_READWRITE
0x04
启用对已提交页面区域的只读或读/写访问。 如果启用了 数据执行保护 ,则尝试在提交的区域中执行代码会导致访问冲突。
PAGE_WRITECOPY
0x08
启用对文件映射对象的映射视图的只读或写入时复制访问权限。 尝试写入已提交的写入时复制页会导致为进程创建页面的专用副本。 专用页面标记为 PAGE_READWRITE,更改将写入新页面。 如果启用了 数据执行保护 ,则尝试在提交的区域中执行代码会导致访问冲突。
VirtualAlloc 或 VirtualAllocEx 函数不支持此标志。
PAGE_TARGETS_INVALID
0x40000000
将页面中的所有位置设置为 CFG 的无效目标。 与任何执行页保护(如 PAGE_EXECUTE、 PAGE_EXECUTE_READ、 PAGE_EXECUTE_READWRITE 和 PAGE_EXECUTE_WRITECOPY)一起使用。 对这些页面中的位置的任何间接调用都将失败 CFG 检查,并且进程将终止。 分配的可执行页面的默认行为是标记为 CFG 的有效调用目标。
VirtualProtect 或 CreateFileMapping 函数不支持此标志。
PAGE_TARGETS_NO_UPDATE
0x40000000
当 VirtualProtect 的保护发生更改时,区域中的页面将不会更新其 CFG 信息。 例如,如果区域中的页面是使用 PAGE_TARGETS_INVALID 分配的,则在页面保护更改时将保留无效信息。 仅当保护更改为可执行类型(如 PAGE_EXECUTE、PAGE_EXECUTE_READ、PAGE_EXECUTE_READWRITE 和 PAGE_EXECUTE_WRITECOPY)时,此标志才有效。 VirtualProtect 保护更改为可执行文件的默认行为是将所有位置标记为 CFG 的有效调用目标。

 

如果lpAddress指定了一个地址,则flProtect不能是以下值之一:

PAGE_NOACCESS
PAGE_GUARD
PAGE_NOCACHE
PAGE_WRITECOMBINE

 

返回值:

成功,返回分配页面的基址

失败,返回NULL,要获得更多的错误信息,请调用 GetLastError。

 

WriteProcessMemory

在指定的进程中将数据写入内存区域,要写入的整个区域必须可访问,否则操作失败。函数声明如下:

1 BOOL
2 WINAPI
3 WriteProcessMemory(
4     _In_ HANDLE hProcess,
5     _In_ LPVOID lpBaseAddress,
6     _In_reads_bytes_(nSize) LPCVOID lpBuffer,
7     _In_ SIZE_T nSize,
8     _Out_opt_ SIZE_T* lpNumberOfBytesWritten
9     );

hProcess

要修改的进程内存的句柄,句柄必有具有 PROCESS_VM_WRITE和PROCESS_VM_OPERATION访问权限

 

lpBaseAddress

指向指定进程中写入数据的基地址指针。在数据传输发生之前,系统会验证指定大小的基地址和内存中的所有数据是否可以进行写入访问,如果不可以访问,则该函数将失败。

 

lpBuffer

指向缓冲区的指针,其中包含要写入指定进程的地址空间中的数据。

 

nSize

要写入指定进程的字节数。

 

lpNumberOfBytesWritten

指向变量的指针,该变量接收传输到指定进程的字节数。如果lpNumberOfBytes Written为NULL,则忽略该参数。

 

返回值:

成功,返回值不为0,

失败,返回值为0

 

CreateRemoteThread

在另一个进程的虚拟地址空间中创建运行的线程。声明如下:

 1 HANDLE
 2 WINAPI
 3 CreateRemoteThread(
 4     _In_ HANDLE hProcess,
 5     _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
 6     _In_ SIZE_T dwStackSize,
 7     _In_ LPTHREAD_START_ROUTINE lpStartAddress,
 8     _In_opt_ LPVOID lpParameter,
 9     _In_ DWORD dwCreationFlags,
10     _Out_opt_ LPDWORD lpThreadId
11     );

参数说明:

hProcess

要创建线程的进程的句柄。句柄必须具有

PROCESS_CREATE_THREAD、

PROCESS_QUERY_INFORMATION、

PROCESS_VM_OPERATION、

PROCESS_VM_WRITE

PROCESS_VM_READ

访问权限

 

lpThreadAttributes

指向SECURITY_ATTRIBUTES结构的指针,该结构指定新线程的安全描述符,并确定子进程是否可以继承返回的句柄。如果lpThreadAttributes为NULL,则线程将获得默认的安全描述符,并且不能继承该句柄。

 

dwStackSize

堆栈的初始大小,以字节为单位。如果此参数为o,则新线程使用可执行文件的默认大小。

 

lpStartAddress

指向由线程执﹐行类型为LPTHREAD_START_ROUTINE的应用程序定义的函数指针,并表示远程进程中线程的起始地址,该函数必须存在于远程进程中。

 

lpParameter

指向要传递给线程函数的变量的指针。

 

dwCreationFlags

控制线程创建的标志。若是0,则表示线程在创建后立即运行。

 

lpThreadId

指向接收线程标识符的变量的指针。如果此参数为NULL,则不返回线程标识符。

 

返回值:

成功,返回新线程的句柄,

失败,返回NULL,如果要获取错误信息,请调用GetLastError

 

远线程注入实现原理

程序在加载DLL时,通常调用LoadLibrary函数来实现DLL的动态加载。LoadLibrary函数的声明如下:

1 HMODULE WINAPI LoadLibrary(LPCTSTR lpFileName);

LoadLibrary函数只有一个参数,传递的是要加载的DLL路径字符串。

而CreateRemoteThread需要传递的是目标进程空间中的多线程函数地址,以及多线程参数。

如果程序能够获取目标进程LoadLibrary函数的地址,而且还能够获取目标进程空间中某个DLL路径字符串的地址,那么,可将LoadLibrary函数的地址作为多线程函数的地址,某个DLL路径字符串作为多线程函数的参数,并传递给CreateRemoteThread函数在目标进程空间中创建一个多线程,这样能不能成功呢?答案是可以的。这样就可以在目标进程空间中创建一个多线程,这个多线程就是LoadLibrary函数加载DLL。

 

远线程注入的原理就大致清晰了。那么要想实现远线程注入DLL,还需要解决以下两个问题:

1、是目标进程空间中LoadLibrary函数的地址是多少

2、是如何向目标进程空间中写入DLL路径字符串函数

 

标签:函数,Windows,编程,MEM,线程,PAGE,页面
From: https://www.cnblogs.com/zhaotianff/p/18070259

相关文章

  • 实验案例:使用Windows 10桌面系统
    1、实验环境      BDON公司刚刚招聘了一位新入职员工小张。部门经理要求系统管理员带小张快速地熟悉公司环境以尽快上手工作,系统管理员为小张的计算机安装了Windows1o操作系统以后,需要小张进一步熟悉公司的Windows10桌面环境及使用系统的基本操作,以便更好地实......
  • 第15届蓝桥杯青少组STEMA考试C++中高级真题试卷(2024年3月)编程题部分
    编程题第6题   问答题编程实现:寒假期间小明需要做完n张试卷,但他每天最多能做完m张,请计算出小明做完n张试卷最少需要多少天?输入描述一行输入两个整数n和m(1≤n≤100,1≤m≤10),分别表示要完成的试卷张数,及每天最多能做完的试卷张数,整数之间以一个空格隔开输出描述输出......
  • Qt 安装与环境变量的设置(Windows 10)
    Qt安装与环境变量的设置(Windows10)Qt下载Qt下载地址我下载的是windowQt5.13.1下载后安装,安装过程很简单,中间需要注册一个qt的账户,按步骤来即可组件选择了MinGW73_32、MinGW73_64、MSVC2017_32和MSVC2017_64环境变量设置打开此电脑的属性选择高级系统设置打开环境......
  • Windows右键菜单管理程序:ContextMenuManager
    前言ContextMenuManager是一款由中国人开发免安装的纯粹的Windows右键菜单管理开源程序,可以非常方便的管理Windows电脑的右键菜单,轻松去除不必要的或者是流氓的菜单选项,使你的电脑更加的干净、清爽。程序使用非常简单,没有任何门槛,我感觉非常棒,极力推荐道友们下载使用。Github......
  • windows 配置 docker
    安装dockerdesktop安装后修改路径在Microsoftstore安装Linux的任意版本安装后需要将Linux迁移到其他盘,避免减少c盘空间。开发时,项目放在Linux子系统目录下,避免文件系统不一致导致文件修改时不会触发监听事件。docker中将安装的Linux选为默认系统VScode安......
  • Windows启动项管理
    windows图形化界面的自动启动机制感觉有点混乱。网上的管理教程五花八门,最多的就是推荐你下载"电脑管家",特总结了下windows的自启动项目管理模式。常规的自启动项目在windows的任务栏中右键点击可以看到当前系统的自动启动软件。我们可以看到在这个窗口中,可以设置软件的“......
  • 多线程系列(十八) -AQS原理浅析
    一、摘要在之前的文章中,我们介绍了ReentrantLock、ReadWriteLock、CountDownLatch、CyclicBarrier、Semaphore、ThreadPoolExecutor等并发工具类的使用方式,它们在请求共享资源的时候,都能实现线程同步的效果。在使用方式上稍有不同,有的是独占式,多个线程竞争时只有一个线程能执......
  • 12-多线程
    进程和线程多线程是Java语言的重要特性,大量应用于网络编程、服务器端程序的开发,最常见的UI界面底层原理、操作系统底层原理都大量使用了多线程。我们可以流畅的点击软件或者游戏中的各种按钮,其实,底层就是多线程的应用。UI界面的主线程绘制界面,如果有一个耗时的操作发生则启动新......
  • 13-网络编程
    在网络通信协议下,不同计算机上运行的程序进行数据的传输;封装在java.net包下网络编程三要素:IP:设备在网络中的地址,是唯一的标识端口号:应用程序在设备中的唯一标识协议:数据在网络中传输的规则TCP、UDP、http、https、ftpIP:InternetProtocol互联网协议地址,常见的IP分为IPV4......
  • Linux软件高级编程-网络--TCP通信--day14
    TCP包头:1.序号:发送端发送数据包的编号2.确认号:已经确认接收到的数据的编号(只有当ACK为1时,确认号才有用)TCP为什么安全可靠:1.在通信前建立三次握手连接  SYN    SYN+ACK    ACK 2.在通信过程中通过序列号和确认号保障数据传输的完整性  本次......