用户层注入:(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;
}
五、注入结果
标签:HANDLE,Exit,句柄,ProcessHandle,进程,线程,NULL,远程,注入 来源: https://blog.csdn.net/weixin_43972499/article/details/114640087