热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

[Windows编程]远线程注入

远线程注入是指一个进程在另一个进程中创建线程的技术。函数介绍1.OpenProcess函数打开现有的本地进程对象。HANDLEOpenProcess( DWORDdwDesired

远线程注入是指一个进程在另一个进程中创建线程的技术。


函数介绍


1.OpenProcess函数

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

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

参数

dwDesiredAccess:对进程对象的访问权限,本程序中使用PROCESS_ALL_ACCESS。

bInheritHandle:若此值为TRUE,则此进程创建的进程将继承该句柄。在本程序中设置为FALSE。

dwProcessId:要打开的本地进程的PID。

返回值

若成功,返回值是指定进程的打开句柄。

若失败,返回值为NULL。


2.VirtualAllocEx函数

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

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

参数

hProcess:指定进程的句柄。

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

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

flAllocationType:内存分配类型。MEM_COMMIT:在磁盘的分页文件和整体内存中,为指定的预留内存页分配内存。

flProtect:要分配的页面区域的内存保护。本程序中是PAGE_READWRITE。

返回值

若成功,则返回值是分配页面的基址。

若失败,返回NULL。


3.WriteProcessMemory函数

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

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

参数

hProcess:要修改的进程内存的句柄。

lpBaseAddress:指向指定进程中写入数据的基地址指针。本程序中,就是VirtualAllocEx函数的返回值。

lpBuffer:指向缓冲区的指针,其中包含要写入指定进程的地址空间中的数据。本程序中,是dll文件的绝对路径。

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

lpNumberOfBytesWritten:指向变量的指针,该变量接收传输到指定进程的字节数。可设置为NULL来忽略该参数。

返回值

若成功,则返回值不为0。

若失败,则返回值为0。


4.GetModuleHandle函数

检索指定模块的模块句柄。模块必须已被调用进程加载。

HMODULE GetModuleHandleW(
 LPCWSTR lpModuleName
);

参数

lpModuleName:加载模块的名称(.dll 或 .exe 文件)。

返回值

如果函数成功,则返回值是指定模块的句柄。

如果函数失败,则返回值为 NULL。


5.GetProcAddress函数

从指定的动态链接库 (DLL) 中检索导出函数或变量的地址。

FARPROC GetProcAddress(
 HMODULE hModule,
 LPCSTR  lpProcName
);

参数

hModule:包含函数或变量的 DLL 模块的句柄。LoadLibrary,LoadLibraryEx,LoadPackagedLibrary以及GetModuleHandle函数返回该句柄。

lpProcName:函数或变量名称,或函数的序数值。本程序中为"LoadLibraryA"。

返回值

如果函数成功,则返回值是导出的函数或变量的地址。

如果函数失败,则返回值为 NULL。


6.CreateRemoteThread函数

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

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

参数

hProcess:要创建线程的进程的句柄。

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

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

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

lpParameter:指向要传递给线程函数的变量的指针。本程序中,就是要注入的dll文件的绝对路径,就是VirtualAllocEx函数的返回值(因为WriteProcessMemory函数将dll文件的绝对路径写入了VirtualAllocEx函数开辟的虚拟地址空间)。

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

lpThreadId:指向接收线程标识符的变量的指针。若此参数为NULL,则不返回线程标识符。本程序中为NULL。

返回值

若成功,则返回值是新线程的句柄。

若失败,则返回值为NULL。


实现原理

首先看LoadLibrary函数的声明

HMODULE LoadLibraryW(
 LPCWSTR lpLibFileName
);

可以看到,LoadLibrary函数只有一个参数,就是要加载的dll路径字符串。

然后看CreateRemoteThread函数声明

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

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

所以,若程序能获取目标进程LoadLibrary函数的地址,以及目标进程空间中恶意dll路径字符串的地址,就可以将LoadLibrary函数的地址作为参数lpStartAddress,恶意dll路径字符串作为参数lpParameter,实现远线程注入。

那么,现在的问题有2个:



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



  2. 如何向目标进程空间中写入恶意dll路径字符串数据?



对于第一个问题,只需要知道kernel32.dll的加载基地址在各个进程中都是相同的,因此自己程序空间的LoadLibrary函数地址和其它进程空间的相同。

对于第二个问题,可以调用VirtualAllocEx函数在目标进程中申请一块内存,然后调用WriteProcessMemory函数将恶意dll的绝对路径写入目标进程空间中即可。


编码实现

#include
#include
//定义报错函数
void ShowError(char *pszText)
{
char szErr[MAX_PATH] = { 0 };
::wsprintf(szErr, "%s Error[%d]\n", pszText, ::GetLastError());
::MessageBox(NULL, szErr, "ERROR", MB_OK);
}
// 使用CreateRemoteThread实现远线程注入
BOOL CreateRemoteThreadInjectDll(DWORD dwProcessId, char *pszDllFileName)
{
HANDLE hProcess = NULL; // OpenProcess返回的进程句柄
DWORD dwSize = 0;
LPVOID pDllAddr = NULL; // VirtualAllocEx返回的申请的内存空间地址
FARPROC pFuncProcAddr = NULL; // GetProcAddress返回的函数地址
// 打开注入进程,获取进程句柄
hProcess = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);
if (NULL == hProcess)
{
ShowError("OpenProcess");
return FALSE;
}
// 在注入进程中申请内存
dwSize = 1 + ::lstrlen(pszDllFileName); // 获取dll绝对路径字符串的长度
pDllAddr = ::VirtualAllocEx(hProcess, NULL, dwSize, MEM_COMMIT, PAGE_READWRITE);
if (NULL == pDllAddr)
{
ShowError("VirtualAllocEx");
return FALSE;
}
// 向申请的内存中写入数据
if (FALSE == ::WriteProcessMemory(hProcess, pDllAddr, pszDllFileName, dwSize, NULL))
{
ShowError("WriteProcessMemory");
return FALSE;
}
// 获取LoadLibraryA函数地址
pFuncProcAddr = ::GetProcAddress(::GetModuleHandle("kernel32.dll"), "LoadLibraryA");
if (NULL == pFuncProcAddr)
{
ShowError("GetProcAddress_LoadLibraryA");
return FALSE;
}
// 使用CreateRemoteThread创建远线程,实现DLL注入
HANDLE hRemoteThread = ::CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pFuncProcAddr, pDllAddr, 0, NULL);
if (NULL == hRemoteThread)
{
ShowError("CreateRemoteThread");
return FALSE;
}
// 关闭句柄
::CloseHandle(hProcess);
return TRUE;
}

int main()
{
BOOL bRet = CreateRemoteThreadInjectDll(9372, "C:\\Users\\Administrator\\Desktop\\artifact.dll");
if (FALSE == bRet)
{
printf("Inject Dll Error.\n");
}
printf("Inject Dll OK.\n");
system("pause");
return 0;
}

测试

 

 


小结

此方法无法成功注入到一些系统服务进程,这是由于从Windows Vista 开始,微软为了增强系统的安全性,对系统服务和登录用户进行了会话(Session)隔离,系统服务属于会话0,登录的第一个用户属于会话1,之前系统服务和第一个登录用户都属于会话0。此方法并不能突破SESSION 0隔离。原因是在 CreateRemoteThread 函数中对此进行了检查,如果不在同一会话中,调用 CsrClientCallServer 为新进程进行登记的操作就会失败,这就直接导致了线程创建的失败。



推荐阅读
  • Linux环境变量函数getenv、putenv、setenv和unsetenv详解
    本文详细解释了Linux中的环境变量函数getenv、putenv、setenv和unsetenv的用法和功能。通过使用这些函数,可以获取、设置和删除环境变量的值。同时给出了相应的函数原型、参数说明和返回值。通过示例代码演示了如何使用getenv函数获取环境变量的值,并打印出来。 ... [详细]
  • CF:3D City Model(小思维)问题解析和代码实现
    本文通过解析CF:3D City Model问题,介绍了问题的背景和要求,并给出了相应的代码实现。该问题涉及到在一个矩形的网格上建造城市的情景,每个网格单元可以作为建筑的基础,建筑由多个立方体叠加而成。文章详细讲解了问题的解决思路,并给出了相应的代码实现供读者参考。 ... [详细]
  • 预备知识可参考我整理的博客Windows编程之线程:https:www.cnblogs.comZhuSenlinp16662075.htmlWindows编程之线程同步:https ... [详细]
  • 李逍遥寻找仙药的迷阵之旅
    本文讲述了少年李逍遥为了救治婶婶的病情,前往仙灵岛寻找仙药的故事。他需要穿越一个由M×N个方格组成的迷阵,有些方格内有怪物,有些方格是安全的。李逍遥需要避开有怪物的方格,并经过最少的方格,找到仙药。在寻找的过程中,他还会遇到神秘人物。本文提供了一个迷阵样例及李逍遥找到仙药的路线。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • Java序列化对象传给PHP的方法及原理解析
    本文介绍了Java序列化对象传给PHP的方法及原理,包括Java对象传递的方式、序列化的方式、PHP中的序列化用法介绍、Java是否能反序列化PHP的数据、Java序列化的原理以及解决Java序列化中的问题。同时还解释了序列化的概念和作用,以及代码执行序列化所需要的权限。最后指出,序列化会将对象实例的所有字段都进行序列化,使得数据能够被表示为实例的序列化数据,但只有能够解释该格式的代码才能够确定数据的内容。 ... [详细]
  • 本文主要解析了Open judge C16H问题中涉及到的Magical Balls的快速幂和逆元算法,并给出了问题的解析和解决方法。详细介绍了问题的背景和规则,并给出了相应的算法解析和实现步骤。通过本文的解析,读者可以更好地理解和解决Open judge C16H问题中的Magical Balls部分。 ... [详细]
  • c语言\n不换行,c语言printf不换行
    本文目录一览:1、C语言不换行输入2、c语言的 ... [详细]
  • http:my.oschina.netleejun2005blog136820刚看到群里又有同学在说HTTP协议下的Get请求参数长度是有大小限制的,最大不能超过XX ... [详细]
  • 本文介绍了解决二叉树层序创建问题的方法。通过使用队列结构体和二叉树结构体,实现了入队和出队操作,并提供了判断队列是否为空的函数。详细介绍了解决该问题的步骤和流程。 ... [详细]
  • 自动轮播,反转播放的ViewPagerAdapter的使用方法和效果展示
    本文介绍了如何使用自动轮播、反转播放的ViewPagerAdapter,并展示了其效果。该ViewPagerAdapter支持无限循环、触摸暂停、切换缩放等功能。同时提供了使用GIF.gif的示例和github地址。通过LoopFragmentPagerAdapter类的getActualCount、getActualItem和getActualPagerTitle方法可以实现自定义的循环效果和标题展示。 ... [详细]
  • 本文介绍了一个题目的解法,通过二分答案来解决问题,但困难在于如何进行检查。文章提供了一种逃逸方式,通过移动最慢的宿管来锁门时跑到更居中的位置,从而使所有合格的寝室都居中。文章还提到可以分开判断两边的情况,并使用前缀和的方式来求出在任意时刻能够到达宿管即将锁门的寝室的人数。最后,文章提到可以改成O(n)的直接枚举来解决问题。 ... [详细]
  • C++字符字符串处理及字符集编码方案
    本文介绍了C++中字符字符串处理的问题,并详细解释了字符集编码方案,包括UNICODE、Windows apps采用的UTF-16编码、ASCII、SBCS和DBCS编码方案。同时说明了ANSI C标准和Windows中的字符/字符串数据类型实现。文章还提到了在编译时需要定义UNICODE宏以支持unicode编码,否则将使用windows code page编译。最后,给出了相关的头文件和数据类型定义。 ... [详细]
  • 本文介绍了深入浅出Linux设备驱动编程的重要性,以及两种加载和删除Linux内核模块的方法。通过一个内核模块的例子,展示了模块的编译和加载过程,并讨论了模块对内核大小的控制。深入理解Linux设备驱动编程对于开发者来说非常重要。 ... [详细]
  • 本文介绍了在处理不规则数据时如何使用Python自动提取文本中的时间日期,包括使用dateutil.parser模块统一日期字符串格式和使用datefinder模块提取日期。同时,还介绍了一段使用正则表达式的代码,可以支持中文日期和一些特殊的时间识别,例如'2012年12月12日'、'3小时前'、'在2012/12/13哈哈'等。 ... [详细]
author-avatar
王佳秋承男
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有