用户层注入:(1)远程线程注入

一、主要思想

  我们知道,进程在加载时,会查看PE文件的导入表,并根据导入表的内容将指定的Dll模块加载到进程地址空间内,因此我们可以使用诸如Kernel32.dll和User32.dll这些动态库的导出函数。
  这些工作在exe文件加载时Windows系统便自动帮我们完成了。那么我们是否可以提出这样一个猜想:我们能否自己写一个Dll文件,然后通过一种方式,让目标进程将我们的Dll文件加载到自己的进程空间内,从而实现我们想要的操作呢?
  那么问题来了,怎样获得操作目标进程的权限呢?获得权限后,怎样让目标进程执行我们的Dll文件呢?目标进程又是如何执行的呢?
  当然,这些问题都是可以解决的。

二、注入过程

  1.通过进程名,使用ToolHelper系列的函数,将系统的所有进程信息进行枚举,通过对进程名的匹配,定位到目标进程的关键信息,从而获得进程ID。
  2.要打开目标进程,就要提高当前自身进程的权限(主要是对Token令牌的操作)。提升权限后,通过进程ID调用OpenProcess函数,获得目标进程的句柄。OpenProcess函数中,有一个重要的参数DesiredAccess,除了传入PROCESS_READ和PROCESS_WRITE等参数,还需要传入PROCESS_CREATE_THREAD,原因下面会提到。
  3.在打开目标进程后,我们就获得了目标进程的一些操作权。这时我们可以调用VirtualAllocEx在目标进程中申请一片内存,用来存放我们的Dll文件路径,因为我们后续需要调用LoadLibrary函数去加载这个Dll。
  4.将动态库的路径写入到目标进程后,我们需要一个线程去执行LoadLibrary这个函数,这时就要用到本文最重要的一个函数CreateRemoteThread,这个函数可以在目标进程中创建一个远程线程,并执行我们想要的操作,这也是上文提到我们为什么要传入一个PROCESS_CREATE_THREAD参数,它表示我们希望在目标进程中执行创建线程的操作。至此,我们的Dll文件就成功地装载到了目标进程的地址空间内。至于Dll文件如何操作,那就是我们自己的事情了。

三、主要函数

1. HANDLE WINAPI CreateToolhelp32Snapshot(
    DWORD dwFlags,       //此处为TH32CS_SNAPPROCESS,表示枚举进程
    DWORD th32ProcessID  //此处为0,表示枚举所有进程
    );

2. LPVOID WINAPI VirtualAllocEx(
    _In_ HANDLE hProcess,        	//目标进程句柄
    _In_opt_ LPVOID lpAddress,		//起始地址
    _In_ SIZE_T dwSize,				//内存大小
    _In_ DWORD flAllocationType,	//内存类型
    _In_ DWORD flProtect		    //内存页属性
    );

3. BOOL WINAPI WriteProcessMemory(
    _In_ HANDLE hProcess,				      //进程句柄
    _In_ LPVOID lpBaseAddress,			    //VirtualAllocEx返回地址
    _In_reads_bytes_(nSize) LPCVOID lpBuffer, //写入数据的缓冲区地址
    _In_ SIZE_T nSize,					      //写入数据大小
    _Out_opt_ SIZE_T* lpNumberOfBytesWritten  //ReturnLength
    );

4. HANDLE WINAPI CreateRemoteThread(
    _In_ HANDLE hProcess,          					   //进程句柄
    _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, //安全描述符
    _In_ SIZE_T dwStackSize,	    				   //线程栈大小
    _In_ LPTHREAD_START_ROUTINE lpStartAddress,        //线程函数地址
    _In_opt_ LPVOID lpParameter,					   //线程函数参数
    _In_ DWORD dwCreationFlags,		                   //是否挂起
    _Out_opt_ LPDWORD lpThreadId
    );


四、参考代码

#include<Windows.h>
#include <iostream>
#include<tchar.h>
using namespace std;
BOOL __EnableDebugPrivilege = TRUE;

void _tmain()
{
	_tprintf(_T("Input Process ImageName\r\n"));
	
	int i = 0;
	TCHAR v1 = _gettchar();
	HANDLE  ProcessHandle = NULL;
	HANDLE  ProcessIdentify = NULL;
	TCHAR   ProcessImageName[260] = { 0 };
	//获得用户输入的进程名
	while (v1 != '\n')
	{
		ProcessImageName[i++] = v1;
		v1 = _gettchar();
	}
	
	//通过进程ProcessImageName获得进程ID
	if (SeGetProcessIdentify(&ProcessIdentify, sizeof(HANDLE),ProcessImageName, sizeof(ProcessImageName)) == FALSE)
	{
		goto Exit;
	}

	BOOL IsOk = TRUE;
	ULONG DllFullPathLength = 0;
	LPVOID VirtualAddress = NULL;
	SIZE_T ReturnLength = 0;

	//获取DLL完整路径
	GetCurrentDirectory(MAX_PATH, DllFullPath);
	_tcscat_s(DllFullPath, _T("\\Dll.dll"));

    //打开目标进程
	ProcessHandle = SeOpenProcess(PROCESS_ALL_ACCESS, FALSE, ProcessIdentify);
				
    //根据在目标进程句柄在目标进程空间中申请内存
	DllFullPathLength = (_tcslen(DllFullPath) + 1) * sizeof(TCHAR);
	VirtualAddress = VirtualAllocEx(ProcessHandle, NULL, DllFullPathLength, MEM_COMMIT, PAGE_READWRITE);
	if (VirtualAddress == NULL)
	{
		goto Exit;
	}
	//在目标进程空间申请的内存中写入动态库的完整路径
	if (WriteProcessMemory(ProcessHandle, VirtualAddress , DllFullPath, DllFullPathLength, NULL) == FALSE)
    {
	    goto Exit;
	}
	//让目标进程执行一个线程去执行LoadLibrary(DllFullPath)
	HANDLE ThreadHandle = CreateRemoteThread(ProcessHandle,NULL, 0, (LPTHREAD_START_ROUTINE)LoadLibrary, VirtualAddress, 0, NULL);
	if (ThreadHandle == NULL)
	{
	    //释放掉曾经申请的DllFullPath所占有的内存
		VirtualFreeEx(ProcessHandle, VirtualAddress, DllFullPathLength, MEM_RELEASE);
		goto Exit;
	}
	WaitForSingleObject(ThreadHandle, INFINITE);
	if (VirtualAddress != NULL)
	{
		VirtualFreeEx(ProcessHandle, VirtualAddress, DllFullPathLength, MEM_RELEASE);
	}
}
Exit:
	if (ProcessHandle != NULL)
	{
		SeCloseHandle(ProcessHandle);
		ProcessHandle = INVALID_HANDLE_VALUE;
	}
}

//通过进程名获得目标进程ID
BOOL SeGetProcessIdentify(_Out_ HANDLE* ProcessIdentify, _In_ ULONG_PTR ProcessIdentifyLength,
	_In_ const TCHAR* ProcessImageName, _In_ ULONG_PTR ProcessImageNameLength)
{
	BOOL IsOk = FALSE;
	HANDLE SnapshotHandle = INVALID_HANDLE_VALUE;
	PROCESSENTRY32 ProcessEntry32;
	ProcessEntry32.dwSize = sizeof(PROCESSENTRY32);
	//快照
	SnapshotHandle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
	if (SnapshotHandle == INVALID_HANDLE_VALUE)
	{
		goto Exit;
	}
	if (!Process32First(SnapshotHandle, &ProcessEntry32))
	{
		goto Exit;
	}
	do
	{
		//进程名匹配
		if (_tcsicmp(ProcessEntry32.szExeFile, ProcessImageName) == 0)
		{
			//获得目标进程ID
			*ProcessIdentify = (HANDLE)ProcessEntry32.th32ProcessID;
			IsOk = TRUE;
			goto Exit;
		}

	} while (Process32Next(SnapshotHandle, &ProcessEntry32));  //继续枚举
	LastError = ERROR_MOD_NOT_FOUND;
Exit:
	if (SnapshotHandle != INVALID_HANDLE_VALUE)
	{
		CloseHandle(SnapshotHandle);
	}
	SnapshotHandle = INVALID_HANDLE_VALUE;
	return IsOk;
}

//打开目标进程
HANDLE SeOpenProcess(DWORD DesiredAccess, BOOL IsInheritHandle, HANDLE ProcessIdentify)
{
	//提高当前进程Privilege
	if (__EnableDebugPrivilege)
	{
		SeEnableSeDebugPrivilege(_T("SeDebugPrivilege"), TRUE);
	}
	//打开目标进程,通过进程ID获得目标进程句柄
	HANDLE ProcessHandle = OpenProcess(DesiredAccess, IsInheritHandle, (DWORD)ProcessIdentify);
	if (__EnableDebugPrivilege)
	{
		SeEnableSeDebugPrivilege(_T("SeDebugPrivilege"), FALSE);
	}
	return ProcessHandle;
}

//提高当前进程权限
BOOL SeEnableSeDebugPrivilege(const TCHAR*  PriviledgeName, BOOL IsEnable)
{
	BOOL IsOk = FALSE;
	HANDLE  ProcessHandle = GetCurrentProcess();     //获取当前进程句柄(伪句柄)-1
	HANDLE  TokenHandle = INVALID_HANDLE_VALUE;
	TOKEN_PRIVILEGES TokenPrivileges = { 0 };

	//通过当前进程句柄获得当前进程中令牌句柄
	if (!OpenProcessToken(ProcessHandle, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &TokenHandle))
	{
		goto Exit;
	}

	//通过LookupPrivilegeValue函数查找PriviledgeName对应的身份码ID并传递给v1
	LUID  v1;
	if (!LookupPrivilegeValue(NULL, PriviledgeName, &v1))	
	{
		goto Exit;
	}

	TokenPrivileges.PrivilegeCount = 1;		// 要提升的权限个数
	TokenPrivileges.Privileges[0].Attributes = IsEnable == TRUE ? SE_PRIVILEGE_ENABLED : 0;
	TokenPrivileges.Privileges[0].Luid = v1;

	if (!AdjustTokenPrivileges(TokenHandle, FALSE, &TokenPrivileges, sizeof(TOKEN_PRIVILEGES), NULL, NULL))
	{
		goto Exit;
	}
	IsOk = TRUE;

Exit:
	if (TokenHandle != INVALID_HANDLE_VALUE)
	{
		CloseHandle(TokenHandle);
		TokenHandle = INVALID_HANDLE_VALUE;
	}         
	return IsOk;
}

五、注入结果

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值