سرشماری اطلاعات با تابع 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;
}
این آموزش متعلق به بخش توسعه بدافزار است
برای مشاهده تمام آموزش های توسعه بدافزار وبسایت مسترپایتون به بخش توسعه بدافزار مراجعه کنید
علاقه مند به دنیای کامپیوتر ها ...