سرشماری اطلاعات با تابع CreateToolhelp32Snapshot

CreateToolhelp32Snapshot

برای پیاده سازی بسیاری از حملات تزریق کد در توسعه بدافزار ها ، نیاز داریم تا Process ها , Thread ها یا ماژول های یک پروسه در سیستم عامل ویندوز را سرشماری کنیم . تابع CreateToolhelp32Snapshot به ما اجازه میدهد تا اینگونه موارد و حافظه های Heap موجود در سیستم ویندوزی را سرشماری کنیم .در این پست چگونگی استفاده از این تابع برای این منظور را یاد خواهیم گرفت و در حملات آینده از آن استفاده خواهیم کرد .

معرفی تابع CreateToolhelp32Snapshot

در زیر تابع CreateToolhelp32Snapshot به همراه ورودی های آن را آورده ایم . 

HANDLE CreateToolhelp32Snapshot(
  [in] DWORD dwFlags,
  [in] DWORD th32ProcessID
);

از آنجایی که این تابع میتواند انواع مختلفی از اطلاعات سیستم را سرشماری کند ،‌ در ورودی اول این تابع (dwFlags) مشخص میکنیم قصد سرشماری کدام یک از نوع اطلاعات را داریم . جهت سرشماری Process های سیستم از مقدار TH32CS_SNAPPROCESS و جهت سرشماری Thread های سیستم از مقدار TH32CS_SNAPTHREAD میتوانیم استفاده کنیم . این دو مورد مرسوم ترین موارد برای حملات تزریق کد هستند که ما استفاده میکنیم وگرنه این تابع سرشماری انواع دیگر اطلاعات را نیز میتواند انجام دهد از جمله ماژول های مختلف یک فایل اجرایی و … که میتوانید اطلاعات دقیق تر را از منابع رسمی مایکروسافت دنبال کنید .

ورودی دوم تابع [th32ProcessID] جهت مشخص کردن PID مربوط به پروسه مورد نظر برای سرشماری است . این ورودی فقط در برخی از حالت های سرشماری کاربرد دارد و در حالات دیگر نادیده گرفته میشود . برای مثال در سرشماری ماژول های یک پروسه ، این ورودی برابر با PID پروسه ای خواهد بود که قرار است ماژول های آن را سرشماری کنیم . 

دقت کنید در سرشماری Thread ها، ورودی دوم تابع نادیده گرفته میشود و در فراخوانی این تابع برای سرشماری thread های سیستم (TH32CS_SNAPTHREAD) تمام thread های سیستم سرشماری خواهد شد و ما به طور دستی از طریق بررسی PID مربوط به پروسه مالک هر thread تشخیص میدهیم آیا thread مورد نظر مربوط به پروسه مورد نظر ما هست یا خیر.

توابع First و Next برای شروع سرشماری

بعد از اینکه تابع CreateToolhelp32Snapshot را برای سرشماری اطلاعات مدنظرمان فراخوانی کردیم تابع یک خروجی از نوع HANDLE به ما برمیگرداند که اصطلاحا این خروجی را یک snapshot از اطلاعات موردنظر مینامیم . حالا باید اطلاعات مدنظر را از این snapshot استخراج کنیم . برای مثال اگر تابع را با ورودی TH32CS_SNAPTHREAD فرخوانی کرده ایم snapshot خروجی حاوی thread های سیستم است و میوانیم اطلاعات thread ها را از این snapshot استخراج کنیم . برای سرشماری پروسه ها نیز به همین شکل …

جهت شروع سرشماری اطلاعات ابتدا باید یکی از توابع First را بسته به اینکه چه نوع اطلاعاتی در snapshot موجود میباشد فراخوانی کنیم . برای مثال اگر snapshot ما حاوی پروسه است از تابع Process32First و اگر حاوی thread است از تابع Thread32First استفاده میکنیم . 

تعریف این دو تابع در زیر آورده شده است :

BOOL Process32First(
  [in]      HANDLE           hSnapshot,
  [in, out] LPPROCESSENTRY32 lppe
);
BOOL Thread32First(
  [in]      HANDLE          hSnapshot,
  [in, out] LPTHREADENTRY32 lpte
);

این دو تابع در ورودی اول snapshot مربوطه که در مراحل قبلی بدست آمده را دریافت میکنند و در ورودی دوم یک اشاره گر به یک ساختار برای نوشتن اطلاعات پروسه یا thread مربوطه در آن میگیرند . اگر قرار است پروسه ها را سرشماری کنیم باید یک اشاره گر به ساختار PROCESSENTRY32 به Process32First بدهیم که حاوی فیلد هایی مثل PID پروسه ، تعداد نخ های آن و … است . تابع Process32First این فیلد ها را برای اولین پروسه موجود در snapshot مقدار دهی میکند . 

برای Thread ها نیز به همین شکل است . در ورودی دوم Thread32First یک اشاره گر به ساختار THREADENTRY32 به آن میدهیم تا اطلاعات اولین Thread موجود در snapshot را برای ما در آن بنویسد .

بعد از دریافت اولین اطلاعات از snapshot توسط توابع بالا حالا میتوانیم با توابع next معادل توابع بالا اطلاعات بعدی را نیز استخراج کنیم . برای مثال با استفاده از Process32First اولین پروسه موجود در snapshot را بدست میآوریم و از آن به بعد در یک حلقه دائما با فراخوانی Process32Next اطلاعات پروسه های بعدی موجود در snapshot را میگیریم . 

برای thread ها نیز به همین شکل است . ابتدا اطلاعات اولین thread موجود در snapshot را توسط Thread32First دریافت میکنیم و از آن به بعد در یک حلقه دائما با فراخوانی Thread32Next اطلاعات thread های بعدی را بدست می آوریم . 

تعریف دو تابع Thread32Next و Process32Next نیز دقیقا مثل همان معادل First آن ها میباشد :

BOOL Process32Next(
  [in]  HANDLE           hSnapshot,
  [out] LPPROCESSENTRY32 lppe
);
BOOL Thread32Next(
  [in]  HANDLE          hSnapshot,
  [out] LPTHREADENTRY32 lpte
);

دقت کنید چه در توابع First و چه در توابع Next خروجی تمام توابع در صورت استخراج موفقیت آمیز اطلاعات مقداری غیر صفر خواهد بود و در صورت خطا (تمام شدن اطلاعات موجود در snapshot) مقدار صفر برخواهد گشت .

برای سرشماری انواع دیگر اطلاعات مثل ماژول ها نیز همین روند را طی میکنیم . ابتدا یک snapshot از اطلاعات مدنظر میگیریم ، سپس با تابع First مربوطه اولین اطلاعات را استخراج میکنیم و از آن به بعد با فراخوانی تابع Next مربوطه اطلاعات بعدی را استخراج میکنیم تا زمانی که این توابع خروجی 0 به ما برگردانند .

به عنوان مطلب آخر در زیر ساختار های PROCESSENTRY32 و THREADENTRY32 که به آن ها اشاره شد را نیز میبینیم . برای اطلاعات بیشتر به منابع مایکروسافت مراجعه کنید.

typedef struct tagPROCESSENTRY32 {
  DWORD     dwSize;
  DWORD     cntUsage;
  DWORD     th32ProcessID; // PID
  ULONG_PTR th32DefaultHeapID;
  DWORD     th32ModuleID;
  DWORD     cntThreads;
  DWORD     th32ParentProcessID;
  LONG      pcPriClassBase;
  DWORD     dwFlags;
  CHAR      szExeFile[MAX_PATH]; // name of process
} PROCESSENTRY32;
typedef struct tagTHREADENTRY32 {
  DWORD dwSize;
  DWORD cntUsage;
  DWORD th32ThreadID;       // thread id (TID)
  DWORD th32OwnerProcessID;   // owner process id (pid)
  LONG  tpBasePri;
  LONG  tpDeltaPri;
  DWORD dwFlags;
} THREADENTRY32;

کد سرشماری پروسه های سیستم در C

در برنامه زیر یک تابع به نام getProcesses تعریف میکنیم که به محض فراخوانی نام و PID پروسه های سیستم را برای ما روی صفحه چاپ میکند .

#include <windows.h>
#include <tlhelp32.h>
#include <stdio.h>

void getProcesses(){
	/* this function extracts list of processes 
	   and print their name and pid on the screen */
	
	/* create snapshot of processes in windows */
	HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS , 0);

	/* check if snapshot is valid */
	if (!snapshot){
		printf ("[-] ERROR in getting snapshot\n");
	}	
	
	PROCESSENTRY32 process_entry = { 0 };
	
	/* we must initialize dwSize member to size of structure before using 
		*32First functions */
	process_entry.dwSize = sizeof(PROCESSENTRY32);
	
	int result = Process32First (snapshot ,&process_entry );
	
	while (result){
		/* print name , pid of process */
		printf ("Name : %s , PID : %d\n" , process_entry.szExeFile , process_entry.th32ProcessID);
		
		/* getting next process */
		result = Process32Next(snapshot , &process_entry);	
	}
}

int main(int argc , char ** argv){
	getProcesses();
	return 0;
}

کد سرشماری Thread های یک پروسه در C

در کد زیر تابعی تعریف کرده ایم به نام getProcessThreads که PID مربوط به یک پروسه را از ما گرفته و TID تمام نخ های آن پروسه را روی صفحه برای ما چاپ میکند

#include <windows.h>
#include <tlhelp32.h>
#include <stdio.h>
    
void getProcessThreads(DWORD pid){
	/* this function extracts list of threads of a process
	   that its PID is specified by pid parameter*/
	
	/* create snapshot of all threads in system */
	HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD , 0);

	/* check if snapshot is valid */
	if (!snapshot){
		printf ("[-] ERROR in getting snapshot\n");
	}	
	
	THREADENTRY32 thread_entry = { 0 };
	
	/* we must initialize dwSize member to size of structure before using 
		*32First functions */
	thread_entry.dwSize = sizeof(THREADENTRY32);
	
	int result = Thread32First (snapshot ,&thread_entry );
	
	while (result){
		
		/* check if this thread belongs to our process */
		if (thread_entry.th32OwnerProcessID == pid){
			
			/* print tid of thread */
			printf ("Thread : %d\n" , thread_entry.th32ThreadID);
		}
		
		
		/* getting next thread */
		result = Thread32Next(snapshot , &thread_entry);	
	}
}


int main(int argc , char ** argv){
	DWORD notepad_pid = 256;
	
	/* getting notepad.exe threads */
	getProcessThreads(notepad_pid);
	return 0;
}    

این آموزش متعلق به بخش توسعه بدافزار است

برای مشاهده تمام آموزش های توسعه بدافزار وبسایت مسترپایتون به بخش توسعه بدافزار مراجعه کنید

پست های مرتبط

مطالعه این پست ها رو از دست ندین!
Thread Hijacking in windows

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

نخ ها واحد های اجرایی در پروسه ها و در هر پروسه در حال اجرا ، حداقل یک نخ (Thread) اجرایی وجود دارد . یکی از روش های مرسوم تزریق کد به نام Thread Hijacking به این روش عمل میکند که بدافزار یکی از نخ های در حال اجرا در پروسه هدف را وادار به اجرای کد دلخواه میکند . این روش با تغییر مقدار ثبات EIP یا RIP در نخ مربوطه انجام میشود . همانطور که میدانید ثبات EIP (در معماری x86) یا RIP (در معماری x86-64) یک ثبات ۳۲ یا ۶۴ بیتی است که حاوی آدرس دستورالعمل بعدی در حافظه است که پردازنده اجرا خواهد کرد حال اگر ما مقدار این ثبات را طوری تغییر دهیم که به کد دلخواه ما اشاره کند در نتیجه دستورالعمل های بعدی که پردازنده اجرا خواهد کرد ، کد ما خواهد بود . 

بیشتر بخوانید
C Socket Programming

برنامه نویسی سوکت در زبان C

برنامه نویسی سوکت یا با اصطلاح سوکت نویسی (Socket Programming) در هر زبان برنامه نویسی به شما اجازه میدهد تا کار های شبکه ای مثل ارسال و دریافت داده در شبکه را انجام بدهید . از این رو در پروژه هایی که نیاز به ارتباطات شبکه ای دارید (ساخت یک سرور ، دانلود یک فایل ، ارسال اطلاعات به یک سرور و …) سوکت ها یار و یاور شما هستند .

در این مجموعه قصد داریم تا سوکت نویسی در زبان C را به صورت ویدیویی به شما آموزش بدهیم . این مجموعه به دو بخش تقسیم شده است . در بخش اول سوکت نویسی زبان C در سیستم عامل لینوکس و در بخش دوم در سیستم عامل ویندوز را بررسی میکنیم .

بیشتر بخوانید

ساخت KeyLogger ویندوزی با استفاده از Hooking

در این قسمت به بررسی یکی دیگر از روش های مرسوم ساخت کیلاگر های ویندوزی خواهیم پرداخت . اگر مشاهده کرده باشید در یکی از ویدیو های قبلی بررسی کردیم یکی از روش های ساخت کیلاگر استفاده از تابع GetAsyncKeyState بود . در این روش از مکانیزم Hooking ویندوز برای ساخت کیلاگر استفاده میکنیم .

بیشتر بخوانید

نظرات

سوالات و نظراتتون رو با ما به اشتراک بذارید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *