远程线程注入

0x00 前言

远程线程注入是一种经典的DLL注入技术。其实就是指一个新进程中另一个进程中创建线程的技术。

0x01 介绍

1.远程线程注入原理

画了一个图大致理解了下远程线程注入dll的原理。

如果是实现注入dll的话,流程大致就是:

通过OpenProcess获取目标进程句柄。

通过VirtualAllocEx在目标进程空间中申请内存,通过WriteProcessMemory放入需要载入的dll的路径。

通过GetModuleHandleA获取诸如kernel32.dll这类系统dll的模块句柄,进而获取LoadLibraryA这类载入动态链接库的函数地址(固定)

通过CreateRemoteThread的参数传入目标进程对象句柄、写入到目标进程空间的dll路径、LoadLibraryA函数地址,实现中目标中创建多线程加载dll。

2.函数介绍

OpenProcess 函数

打开现有的本地进程对象。

函数声明

HANDLE WINAPI OpenProcess(     _In_ DWORD dwDesiredAccess,     _In_ BOOL  bInheritHandle,     _In_ DWORD dwProcessId);

参数

  • dwDesiredAccess [in]

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

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

    要打开的本地进程的标识符。

    如果指定的进程是系统进程(0x00000000),则该函数失败,最后一个错误代码为ERROR_INVALID_PARAMETER。如果指定的进程是空闲进程或CSRSS进程之一,则此功能将失败,并且最后一个错误代码为ERROR_ACCESS_DENIED,因为它们的访问限制会阻止用户级代码打开它们。

    如果您使用GetCurrentProcessId作为此函数的参数,请考虑使用GetCurrentProcess而不是OpenProcess,以提高性能。

返回值

  • 如果函数成功,则返回值是指定进程的打开句柄。
  • 如果函数失败,返回值为NULL。 要获取扩展错误信息,请调用GetLastError。

VirtualAllocEx 函数

在指定进程的虚拟地址空间内保留,提交或更改内存区域的状态。 该函数初始化其分配给零的内存。

函数声明

LPVOID WINAPI VirtualAllocEx(    _In_     HANDLE hProcess,    _In_opt_ LPVOID lpAddress,    _In_     SIZE_T dwSize,    _In_     DWORD  flAllocationType,    _In_     DWORD  flProtect);

参数

  • hProcess [in]

    过程的句柄。该函数在该进程的虚拟地址空间内分配内存。

    句柄必须具有PROCESS_VM_OPERATION权限。有关更多信息,请参阅流程安全和访问权限。
  • lpAddress [in]

    指定要分配的页面的所需起始地址的指针。

    如果您正在保留内存,则该函数会将该地址舍入到分配粒度的最接近的倍数。

    如果您提交已经保留的内存,该功能会将该地址舍入到最接近的页面边界。要SESSION 0 隔离页面的大小和主机上的分配粒度,请使用GetSystemInfo函数。

    如果lpAddress为NULL,则该函数确定在哪里分配该区域。
  • dwSize [in]

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

    如果lpAddress为NULL,则函数将dwSize循环到下一个页面边界。

    如果lpAddress不为NULL,则该函数将从lpAddress到lpAddress + dwSize的范围内分配包含一个或多个字节的所有页面。这意味着,例如,跨越页面边界的2字节范围会导致功能分配两个页面。
  • flAllocationType [in]

    内存分配类型。此参数必须包含以下值之一:
VALUE MEANING
MEM_COMMIT 为指定的预留内存页分配内存费用(从磁盘上的内存和分页文件的总体大小)。 该函数还保证当调用者稍后初次访问存储器时,内容将为零。 除非/直到虚拟地址被实际访问,实际的物理页面才被分配
MEM_RESERVE 保留进程的虚拟地址空间的范围,而不会在内存或磁盘上的分页文件中分配任何实际物理存储
MEM_RESET 表示由lpAddress和dwSize指定的内存范围内的数据不再受关注。 页面不应从页面文件中读取或写入页面文件。 然而,内存块将在以后再次被使用,所以不应该被分解。 该值不能与任何其他值一起使用
MEM_RESET_UNDO 只能在早期成功应用了MEM_RESET的地址范围上调用MEM_RESET_UNDO。 它指示由lpAddress和dwSize指定的指定内存范围内的数据对呼叫者感兴趣,并尝试反转MEM_RESET的影响。 如果功能成功,则表示指定地址范围内的所有数据都是完整的。 如果功能失败,地址范围中的至少一些数据已被替换为零
  • flProtect [in]

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

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

    PAGE_NOACCESS

    PAGE_GUARD

    PAGE_NOCACHE

    PAGE_WRITECOMBINE

返回值

  • 如果函数成功,则返回值是分配的页面区域的基址。
  • 如果函数失败,返回值为NULL。 要获取扩展错误信息,请调用GetLastError。

WriteProcessMemory 函数

在指定的进程中将数据写入内存区域。 要写入的整个区域必须可访问或操作失败。

函数声明

BOOL WINAPI WriteProcessMemory(     _In_  HANDLE  hProcess,     _In_  LPVOID  lpBaseAddress,     _In_  LPCVOID lpBuffer,     _In_  SIZE_T  nSize,     _Out_ SIZE_T  *lpNumberOfBytesWritten);

参数

  • hProcess [in]

    要修改的进程内存的句柄。 句柄必须具有PROCESS_VM_WRITE和PROCESS_VM_OPERATION访问进程。
  • lpBaseAddress [in]

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

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

    要写入指定进程的字节数。
  • lpNumberOfBytesWritten [out]

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

返回值

  • 如果函数成功,则返回值不为零。
  • 如果函数失败,返回值为0(零)。 要获取扩展错误信息,请调用GetLastError。

CreateRemoteThread 函数

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

使用CreateRemoteThreadEx函数创建在另一个进程的虚拟地址空间中运行的线程,并可选地指定扩展属性。

函数声明

HANDLE WINAPI CreateRemoteThread(   _In_  HANDLE                 hProcess,   _In_  LPSECURITY_ATTRIBUTES  lpThreadAttributes,   _In_  SIZE_T                 dwStackSize,   _In_  LPTHREAD_START_ROUTINE lpStartAddress,   _In_  LPVOID                 lpParameter,   _In_  DWORD                  dwCreationFlags,   _Out_ LPDWORD                lpThreadId);

参数

  • hProcess [in]

    要创建线程的进程的句柄。 句柄必须具有PROCESS_CREATE_THREAD,PROCESS_QUERY_INFORMATION,PROCESS_VM_OPERATION,PROCESS_VM_WRITE和PROCESS_VM_READ访问权限,如果某些平台上没有这些权限,可能会失败。 有关更多信息,请参阅流程安全和访问权限。
  • lpThreadAttributes [in]

    指向SECURITY_ATTRIBUTES结构的指针,该结构指定新线程的安全描述符,并确定子进程是否可以继承返回的句柄。 如果lpThreadAttributes为NULL,则线程将获得默认安全描述符,并且该句柄不能被继承。 线程的默认安全描述符中的访问控制列表(ACL)来自创建者的主令牌。dwStackSize [in]

    堆栈的初始大小,以字节为单位。 系统将此值循环到最近的页面。 如果此参数为0(零),则新线程使用可执行文件的默认大小。 有关更多信息,请参阅线程堆栈大小。
  • lpStartAddress [in]

    指向由线程执行的类型为LPTHREAD_START_ROUTINE的应用程序定义函数的指针,并表示远程进程中线程的起始地址。 该功能必须存在于远程进程中。 有关更多信息,请参阅ThreadProc。
  • lpParameter [in]

    指向要传递给线程函数的变量的指针。
  • dwCreationFlags [in]

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

    指向接收线程标识符的变量的指针。

    如果此参数为NULL,则不返回线程标识符。

返回值

  • 如果函数成功,则返回值是新线程的句柄。
  • 如果函数失败,返回值为NULL。 要获取扩展错误信息,请调用GetLastError。

0x02 编码实现

测试demo,指定进程pid和dll位置。

TestCreatePId.cpp

// TestCreatePId.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
// #include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <iostream> void InjectDLL(DWORD PID, char* Path)
{
DWORD dwSize;
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, false, PID);
dwSize = strlen(Path) + 1; LPVOID lpParamAddress = VirtualAllocEx(hProcess, 0, dwSize, PARITY_SPACE, PAGE_EXECUTE_READWRITE);
WriteProcessMemory(hProcess, lpParamAddress, (PVOID)Path, dwSize, NULL); HMODULE hModule = GetModuleHandleA("kernel32.dll");
LPTHREAD_START_ROUTINE lpStartAddress = (LPTHREAD_START_ROUTINE)GetProcAddress(hModule, "LoadLibraryA");
HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, lpStartAddress, lpParamAddress, 0, NULL);
WaitForSingleObject(hThread, 1000);
CloseHandle(hThread);
} int main(int argc,char *argv[])
{
char* a = argv[2];
//std::cout << atoi(argv[1]) << a <<std::endl;
InjectDLL(int(argv[1]),a);
//InjectDLL(atoi(argv[1]), "c:\\test\\TestDll.dll");
return 0;
}

0x03 实测

经测试对应位数的dll可以加载到对应位数的进程中。

不过遇到个问题,这里也记录下,当想在同一进程载入两个dll,如果先载入的dll有dllmain中,里面的函数没有走完逻辑,那么第二个dll会在线程挂起结束之后载入到进程。比如我载入到第一个dll里面DLL_PROCESS_ATTACH有个MessageBox,我没给他结束窗口,第二个dll没有加载到进程中,而结束了MessageBox窗口才注入到了进程。

0x04 总结

部分进程需要以管理员权限才可注入到进程,具体原因是OpenProcess打开高权限进程会因权限不足无法打开,其实就是权限继承到原因,这里如果以powershell默认启动就会获得SE_DEBUG权限,而进程令牌权限提升准备再挑一篇文章单独总结学习。

另一个问题就是,不能成功注入到一些系统服务的进程,因为系统存在 SESSION 0 隔离。如果想向系统服务进程中注入,需要突破SESSION 0 隔离,这个也准备另启一篇文章做记录。

0x05 参考

https://www.write-bug.com/article/2011.html

https://www.cnblogs.com/LyShark/p/11066063.html

远程线程注入DLL的更多相关文章

  1. 远程线程注入DLL突破session 0 隔离

    远程线程注入DLL突破session 0 隔离 0x00 前言 补充上篇的远程线程注入,突破系统SESSION 0 隔离,向系统服务进程中注入DLL. 0x01 介绍 通过CreateRemoteTh ...

  2. 详细解读:远程线程注入DLL到PC版微信

    一.远程线程注入的原理 1.其基础是在 Windows 系统中,每个 .exe 文件在双击打开时都会加载 kernel32.dll 这个系统模块,该模块中有一个 LoadLibrary() 函数,可以 ...

  3. 远程线程注入dll,突破session 0

    前言 之前已经提到过,远线程注入和内存写入隐藏模块,今天介绍突破session 0的dll注入 其实今天写这个的主要原因就是看到倾旋大佬有篇文章提到:有些反病毒引擎限制从lsass中dump出缓存,可 ...

  4. CreateRemoteThread远程线程注入Dll与Hook

    CreateRemoteThread虽然很容易被检测到,但是在有些场合还是挺有用的.每次想用的时候总想着去找以前的代码,现在在这里记录一下. CreateRemoteThread远程注入 DWORD ...

  5. 【windows核心编程】使用远程线程注入DLL

    前言 该技术是指通过在[目标进程]中创建一个[远程线程]来达到注入的目的. 创建的[远程线程]函数为LoadLibrary, 线程函数的参数为DLL名字, 想要做的工作在DLL中编写.  示意图如下: ...

  6. 微信 电脑版 HOOK(WeChat PC Hook)- 远程线程注入dll原理

    Windows加载dll的特性 1.Windows系统中,每个exe软件运行的时候,会加载系统模块kernel32.dll 2.所有加载进exe软件的系统模块kernel32.dll,内存地址都是一样 ...

  7. 安全之路 —— 借助DLL进行远程线程注入实现穿墙与隐藏进程

    简介        大多数后门或病毒要想初步实现隐藏进程,即不被像任务管理器这样典型的RING3级进程管理器找到过于明显的不明进程,其中比较著名的方法就是通过远程线程注入的方法注入将恶意进程的DLL文 ...

  8. 安全之路 —— 无DLL文件实现远程线程注入

    简介         在之前的章节中,笔者曾介绍过有关于远程线程注入的知识,将后门.dll文件注入explorer.exe中实现绕过防火墙反弹后门.但一个.exe文件总要在注入时捎上一个.dll文件着 ...

  9. Dll注入技术之远程线程注入

    DLL注入技术之远线程注入 DLL注入技术指的是将一个DLL文件强行加载到EXE文件中,并成为EXE文件中的一部分,这样做的目的在于方便我们通过这个DLL读写EXE文件内存数据,(例如 HOOK EX ...

随机推荐

  1. RHCSA_DAY08

    locate与find查找 locate:/var/lib/mlocate/mlocate.db getfacl 目录 chmod权限管理 chmod(英文全拼:change mode)设置用户对文件 ...

  2. CVE-2021-3156 复现

    测试环境 OS: Ubuntu 18.04.5 LTS GCC: gcc version 7.5.0 (Ubuntu 7.5.0-3ubuntu1~18.04) Make: GNU Make 4.1 ...

  3. 安装CDH6.2 agent报错

    界面报错信息提示如下: file /opt/cloudera/parcels/.flood/CDH-6.2.0-1.cdh6.2.0.p0.967373-el7.parcel...does not e ...

  4. for循环中++i和i++的区别

    语法 for (语句1; 语句2; 语句3) { 被执行的代码块 } 语句 1 在循环(代码块)开始前执行 语句 2 定义运行循环(代码块)的条件 语句 3 在循环(代码块)已被执行之后执行(这就是循 ...

  5. SpringBoot-技术专区-用正确的姿势如何用外置tomcat配置及运行(Tomcat优化分析)

    前提概要 在特别特殊的时候,我们可能需要外置tomcat去运行程序,例如alitomcat等特殊场景,方便我们去定时化开发项目或者其他特殊场景. 外置tomcat执行 pom.xml文件首先更改打包方 ...

  6. excel的导入与导出---通用版

    excel的导入与导出---通用版 web项目关于导入导出的业务场景很常见,最近我就又遇到了这个业务场景.这次将最近半个月做的导入导出总结一下 使用的pom如下,主要还是阿里巴巴的easyexcel依 ...

  7. 跟我一起写 Makefile(三)

    Makefile 总述 ------- 一.Makefile里有什么? Makefile里主要包含了五个东西:显式规则.隐晦规则.变量定义.文件指示和注释. 1.显式规则.显式规则说明了,如何生成一个 ...

  8. Install Redmine Server with Bitnami Installer

    Download bitnami installer: bitnami-redmine-2.4.1-1-linux-installer.run $ chmod 755 bitnami...instal ...

  9. python数据统计之禅道bug统计

    背景 通过定期输出 每条产品的 BUG 情况,以此来反馈开发解决问题.测试跟进问题的情况:钉钉群推送提醒开发及时解决 以此我这边开始着手准备编写一个小工具,最终达到目的:自动定期发送统计报告,报告维度 ...

  10. Java之Cookie与Session

    Cookie.Session Cookie:服务端生成Cookie发给客户端用于认证 Session:服务端进行进行登记,每人有不同的Session session与cookie的区别 Cookie: ...