کار با Process ها در API

24 12 2008

سلام، شاید براتون پیش اومده باشه که ویروسی Task Manager شما رو غیر فعال کرده باشه و حتی اجازه دسترسی به Registry ویندوز رو هم ازتون گرفته باشه که نتونین از طریق Registry اونو مجدد فعال کنید. ایده ی این نمونه برنامه هم از این نشعت می گیره که، چند روز پیش ویروسی سیستمم رو آلوده کرد و همانطور که بالا بهش اشاره کردم Task Manager مو هم غیر فعال . مجبور شدم از نرم افزار Process Explorer استفاده کنم تا Process ویروس رو KILL کنم. نهایتا تصمیم گرفتم تا خودم برنامه ای مانند این نرم افزار یا حداقل Task Manager ویندوز بنویسم تا در مواقع ضروری بتونم ازش استفاده کنم ( چون اعتقاد دارم هر برنامه نویس باید خودش نیاز های نرم افزاریشو رفع کنه ).

نمونه در �ال اجرا

نمونه در حال اجرا

بریم سر اصل مطلب و به توضیح نحوه کار نرم افزار بپردازیم، روند کار بدین صورته که ابتدا باید ProcessID تمامی process های در حال اجرا بر روی سیستم رو با استفاده از تابع EnumProcesses بدست بیاریم این تابع یک آرایه از نوع DWORD رو گرفته و پس از اجرا ID ی پروسس های در حال اجرا رو درون آرایه قرار میده.

//------/ Buffer
DWORD dwProcessIDs[1024];
//------/ Enumerate all system processes
EnumProcesses(dwProcessIDs, sizeof(dwProcessIDs), &dwNeeded);

خوب پس از استخراج id  ی هر process، باید Handle پروسس رو با استفاده از id اون بدست بیاریم این کار رو با استفاده از تابع OpenProcess انجام میدیم، وظیفه این تابع برگرداندن Handle یک process با استفاده از id اونه.

//-----/ Open process by process id and get the process handle
hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
FALSE, dwProcessIDs[i]);

در ادامه برای اینکه بتونیم نام process مورد نظرمون رو بدست بیاریم به دو تابع دیگه نیاز داریم که یکی برای بدست آوردن Module Handle و دیگری برای گرفتن نام پروسس مورد نظر هستش، که این توابع به ترتیب عبارتند از EnumProcessModules که با گرفتن Process Handle ، میتونه Module Handle رو بر گردونه و دیگری با گرفتن Module Handle نام پروسس رو برمی گردونه.

//-----/ Enumerate each process module
//-----/ then we able to retrieve module name Like EXPLORER.EXE
EnumProcessModules(hProcess, &hModule, sizeof(hModule), &dwCbNeeded);
//-----/ Get module name by process handle and module handle
GetModuleBaseName(hProcess, hModule, szProcessName, sizeof(szProcessName) / sizeof(TCHAR));

خوب در ادامه برای اینکه بتونیم اطلاعاتی در مورد میزان استفاده process از حافظه رو بدست بیاریم باید از تابع GetProcessMemoryInfo این تابع با استفاده از Process Handle ی که در دست داریم یک Struct رو با نام PROCESS_MEMORY_COUNTERS پر می کنه که حاوی اطلاعات مختلفی در رابطه با میزان استفاده process از حافظه است.

//-----/ Process memory information
PROCESS_MEMORY_COUNTERS pmc;
//-----/ Get process memory usage information
//-----/ We need just memory usage by getting PeakWorkingSetSize field of struct
//-----/ ATTENTION : All size fields in the structure calculate as Byte
GetProcessMemoryInfo(hProcess, &pmc, sizeof(pmc));

از اونجایی که ما فقط می خواهیم Memory Usage رو در لیستمون نشون بدیم فقط از فیلد PeakWorkingSetSize این struct استفاده می کنیم.

در پست های بعدی در دارستای تکمیل این نرم افزار نحوه بدست آوردن آدرس یک ماژول و تعداد Handle ها ، Kill و Terminate کردن یک پروسس رو براتون توضیح میدم. پس منتظر پست های بعدی باشید. طبق معمول توضیحات کاملتر همراه با سورس نرم افزار هستش که می تونه بیشتر در یادگیری مطلب کمکتون کنه.

نکته : همراه سورس برنامه دو فایل در پوشه lib وجود داره در صورت کامپایل اون دو فایل رو با استفاده از Drag & Drop به پروژه تون اضافه کنید

برای دانلود سورس کامل برنامه اینجا را کلیک کنید.





Write Your Own Windows Inspector

14 12 2008

سلام، امروز براتون یه نمونه برنامه ی توپ نوشتم که می خوام براتون توضیح بدم، معمولا هر برنامه ای که می نویسم هر کدومش داستانی برا خودش داره، چرا و از کجا شروع شد، هدف چی بود و چی از آب در اومد، همینقدر بدونین که ایده ی اینم از بحث Code injection به ذهنم رسید که اگه خدا بخواد و مطلب Code injection و تموم کنم براتون یک مقاله در این موردم می ذارم. اکثر دوستان برنامه نویس حتما با نرم افزار های Spy++, Winspector, HwndSpy آشنایی دارن، این نرم افزار ها ابزارهای بسیار نابی برای برنامه نویسان سیستم هستن. چرا که هر رخداد و رویدادی که در ویندوز میفته مانیتور می کنن و کمک زیادی در درک نحوه کار سیستم و نرم افزار به برنامه نویسان ارائه میدن. دیشب داشتم با یکی از این ابزار کار می کردم، با خودم گفتم من که این همه امکانات نیاز ندارم، بنابر این تصمیم گرفتم یک برنامه ی کوچولو برا خودم بنویسم که با حرکت ماوس بر روی Window ها و کنترل ها Handle , Control Id و Class name اون ها رو بر گردونه.

نحوه کار خیلی ساده ست، کلیات کار از این قراره که شما Handle ویندو رو بر اساس موقعیت ماوس بر روی Screen با استقاده از تابع WindowFromPoint بدست میارین و سپس به راحتی مشخصات Window مورد نظرتون رو با استفاده از Handle بدست اومده استخراج می کنید. قلب برنامه متد MouseMovementEvent هستش که وظیفش بدست آوردن Handle ویندو و مشخصات مربوط به ویندویی  رو داره که ماوس بر روی اونه.

تصویر زیر نمایش حالت اجرای نرم افزار رو نشون میده که مکان ماوس بر روی یکی از button های پنجره Run هستش و اطلاعات اون ویندو رو نشون میده :

SaberSoft.BitInspector

برای دانلود سورس کامل برنامه اینجا رو کلیک کنید
void MouseMovementEvent(HWND hwndDialog, POINT pt)
{
//----/ Get window handle from mouse location
HWND hwnd = WindowFromPoint(pt);
DWORD processID, threadID;
//----/ Get process id by handle of window that mouse now on it
threadID = GetWindowThreadProcessId(hwnd, &processID);
//----/ We don't want to inspect our process
if (::GetCurrentProcessId() == processID) return;
if (hwndOld == hwnd) return;
//------------------------------------------
//-----/ Clear border of last detected window
if (hwndOld)
HighLightWindow(hwndOld, false);
//-----/ Highlight selected window
HighLightWindow(hwnd, true);
//-----/ Set old window handle by new
hwndOld = hwnd;
TCHAR chr[128];
//-----/ Set handle EDIT
_stprintf(chr, __TEXT("0x%08X"), hwnd);
::SetDlgItemText(hwndDialog, IDC_HANDLEEDIT, chr);
//-----/ Set Control ID
DWORD id = GetWindowLong(hwnd, GWL_ID);
_stprintf (chr, __TEXT("%d"), id);
::SetDlgItemText (hwndDialog, IDC_CTRLIDEDIT, chr);
//-----/ Set Class name
::GetClassName (hwnd, chr, 128);
::SetDlgItemText (hwndDialog, IDC_CLASSEDIT, chr);
}





استفاده نابجا از توابع رشته ای در حلقه های تکرار

5 11 2008

پروسه ی محاسبه طول رشته یک عمل بسیار سنگینیه، حالا شما فرض کنید که در هر بار اجرای حلقه، باید این تابع کلی محاسبات برروی رشته ی ورودی انجام بده تا به null terminated برسه تا برای یک بار تونسته باشه مقدار طول رشته رو برگردونه .شما حالا فرض کنید که رشته ی شما 1000 تا کاراکتر داشته باشه، تابع محاسبه ی طول رشته 1001 بار و حلقه ی شما 1000بار اجرا خواهد شد. آیا این عاقلانه است که یک تکه کد اینقدر بار زمانی و محاسباتی برای سیستم تحمیل کنه ؟!!!

کد پایین یک استفاده نادرست از تابع strlen هستش :

for ( int ix = 0; ix < strlen(a_str); ix++)
{
a_str[ix] = tolower( (unsigned char) a_str[ix] );
}

توابع زیر بهترین شرایط استفاده از این تابع در حلقه ی تکرار می تونه باشه :

for ( int ix = 0; a_str[ix] != ''; ix++)
{
a_str[ix] = tolower( (unsigned char) a_str[ix] );
}
یا

int len = strlen(a_str);
for ( int ix = 0; ix < len; ix++)
{
a_str[ix] = tolower( (unsigned char) a_str[ix] );
}




اجرای اپلتهای کنترل پنل از طریق برنامه

5 11 2008

این تکه کدی که امروز می خوام براتون توضیح بدم، در مورد نحوه اجرای اپلت های کنترل پنل از طریق نرم افزار، فایل دسته ای و خط فرمان. امیدوارم بتونین بهره برداری کامل و لازمه رو ببرین :-). شما می تونین به راحتی هر یک از اپلت هایی رو که می خواهید رو اجرا کنین.

با اجرای کد زیر می تونین به راحتی اپلت مورد نظر رو اجرا کنین. CPL نام اپلتی هست که قراره اجرا بشه. حتما به خاطر داشته باشید که پس از تایپ نام اپلت پسوند cpl. رو بهش اضافه کنید چون در غیر اینصورت اپلت اجرا نخواهد شد.

شکل کلی دستور :

rundll32.exe shell32.dll,Control_RunDLL CPL

برای مثال برای اجرای اپلت Date and Time از خط فرمان یا فایل دسته ای می تونین از کد زیر استفاده کنین:

rundll32.exe shell32.dll,Control_RunDLL timedate.cpl

اجازه بدین این تکه کد رو همراه با یک تابع ++c براتون توضیح بدم، شما می تونین به راحتی با استفاده از این تابع که براتون گذاشتم اپلت مورد نظرتون رو اجرا کنین، من نام تابعم رو RunControlPanelApplet می گذارم.


#include <stdio.h>
#include <windows.h>
int RunControlPanelApplet(char* sAppletFileName)
{
char s[1024];
sprintf(s, "rundll32.exe shell32.dll," "Control_RunDLL %s", sAppletFileName);
return WinExec(s, SW_SHOWNORMAL);
}

تایع فوق یک ورودی اشاره گر از نوع char می گیره که همون نام اپلتی که قرار توسط کد های داخل تابع اجرا بشن، تابع نام رو میگیره و درون کد با استفاده از تابع ()sprintf اونو طبق شکل کلی دستور فرمت می کنه و در نهایت با استفاده از تابع ()WinExe رشته ای که در قالب دستور هستش رو اجرا می کنه.

تابع ()WinExec : این تابع با گرفتن پارامتر اولش به عنوان ورودی و در صورت اجرایی بودن اون فایل فایل مورد نظر رو اجرا می کنه ، برای دریافت اطلاعات بیشتر و نحوه عملکرد دقیق این تابع  اینجا را کلیک کنید.

لیستی از اپلت های کنترل پنل :

access.cpl: Accessibility Properties
appwiz.cpl: Add/Remove Programs Properties
desk.cpl: Display Properties
intl.cpl: Regional Settings Properties
joy.cpl: Joystick Properties
main.cpl: Mouse Properties
mmsys.cpl: Multimedia Properties
modem.cpl: Modems Properties
sysdm.cpl: System Properties
timedate.cpl: Time/Date Properties

شما می تونید لیست کامل نام فایل های اپلت های کنترل پنل را از c:\windows\system32، با پسوند cpl. پیدا کنید.