بازم سلام
یه نکته: بابت دیرکرد این قسمت من چون خیلی میخواستم به زبان ساده بنویسمش طول کشید شرمنده ام
پیشنهاد میکنم که اول
با حلقه ها آشنایی کامل پیدا کنین بعد شروع به خوندن این مقاله بکنین هر سوالی که راجع به حلقه ها دارین بپرسین
(شاید یک آموزش کامل هم در این باره در سایت بزارم البته سعی کردم که توضیحات مختصری هم در این باره بدم)
روش های بعدی هم به مراتب سختتر از این روش خواهد بود به همین دلیل
حتما هر قسمت رو متوجه نشدید سوالتون رو راجع به اون قسمت بپرسید
- روش دوم قرار دادن کدمون در یک Dll و اینجکت کد با استفاده از حلقه ها:
اول یک توضیح مختصر راجع به حلقه ها میدم
اولین و اصلی ترین نقشی که حلقه ها بر عهده دارن جاسوسی کردن و به دام انداختن پیغامهایی هست که به یک پروسه خا ص یا قسمتی از اون پروسه فرستاده میشه
در کل ما دو نوع حلقه داریم:
- حلقه های محلی(Local Hooks) که در اون شما یک یا چند ترید(Thread نخ) رو جاسوسی میکنید که به پروسه خودتون تعلق دارند
- حلقه های خارجی(Remote Hooks) که خود به دو دسته تقسیم میشه :
- 2 برای جاسوسی کردن یک Thread که متعلق به یک پروسه دیگه هست
- 2 برای جاسوسی کردن سیستم به صورت گسترده (System-Wide Hooks) که برای جاسوسی تمامی Threadهای فعال در سیستم شما که مطعلق به هر پروسه ای باشه به کار میره
نکته:میتوان
Thread را کلاس هایی که زیر مجموعه پروسه ماست در نظر گرفت و نکته کمکی هم اینکه هر شیئ در ویندوز
(مانند یک TextBox) دارای یک
ThreadID هست.
اگر حلقه مورد نظر
Threadی رو جاسوسی میکرد که مربوط به پروسه دیگری بود
(مورد 1-2 و 2-2) باید آن حلقه را در یک
(dynamic-link library (DLL قرار بدهیم و سپس سیستم آن
Dllی رو که حلقه در اون قرار داره رو در
Threadی که حلقه گزاری شده لود میکنه و پس از اون سیستم کل
Dll رو در
Thread مذکور لود میکنه
(یعنی تمام کد رو نه فقط تابع حلقه) این دلیل اینه که چرا حلقه ها میتونن باعث اینجکت کد در یک پروسه بشن.
خوب بزارید در این راستا چند اشاره و نکته رو داشته باشم :
بعد از ایجاد یک حلقه موفقیت آمیز توسط
SetWindowsHookEx سیستم به صورت اوتوماتیک
Dll رو در
Thread مذکور اینجکت میکنه اما این کار رو بصورت کامل انجام نمیده و د مقابل میدونیم که کارکرد حلقه به گرفتن پیغام هست خوب پس تا زمانی که پیغامی رو به عنوان ورودی نگیره نمیتونه کار خودشو شروع کنه و به طور واقعی در
Thread مذکور
لود(اینجکت) شه
به عبارت دیگر اگه قضیه رو کمی بیشتر باز کنم اینجوری میشه که اگه قبل از اینکه حلقه ما پیغامی رو دریافت کنه ما اون حلقه رو از بین ببریم توسط
UnhookWindowsHookEx به هیچ وجه در اون
Thread اینجکت نمیشه مگه اینکه ما اونو سریعا توسط یک پیغام در پروسه مذکور اینجکت کنیم پس باید بلافاصله پس از ایجاد حلقه یک پیغام به
Thread مورد نظر بفرستیم
و همچنین برای اینکه
Dll رو کاملا از حالت لود شده خارج کنیم باید بلافاصله بعد قبل از فراخوانی
UnhookWindowsHookEx یک پیغام اختصاصی به
Thread مذکور بفرستیم با این کار باعث میشیم که
Dll به طور کامل بسته شود
نکته:استفاده از واژه پروسه برای حلقه ها مناسب نیست چون در
Remote Hook ها ما بیشتر یک
Thread مربوط به یک پروسه سروکار داریم نه با کل پروسس
از اینجا کد نویسی رو شروع میکنیم
اولین کارمون اینه که بیاییم
Dllمون رو ایجاد کنیم و بعد از اون کدمون رو در اون قرار بدیم
همون جور که قبلا هم گفتم ما حول مسیری برای بدست آوردن پسورد تکستباکس ها حرکت میکنیم
پس تمرکزتون رو حول این مبحث در این مقاله جمع کنین
مثلا فرض کنید ما یک همچین تابعی برای
Dll مون درست کردیم و اونو به این طریق فراخونی میکنیم
کد:
Declare Function GetRemoteText Lib "MyDll" (ByVal hWnd As Long, ByVal Pw As String) As Integer
خروجی این تابع
طول رشته دریافتی و
pw خود پسورد هست
البته این
Dll رو باید همونطوری که گفتم طوری طراحی کنیم که موقع بازخونی اون به صورت اوتوماتیک به پروسه مورد نظر اینجکت بشه و بلافاصله از اون حالت اینجکت شده خارج شه و به قولی
Unload شه
این تابعی هست که باید طراحی کنیم
کد:
Public Sub GetRemoteText(chWnd As Long, Strpwd As String)
Dim PID As Long
g = GetWindowThreadProcessId(chWnd, PID)
hHook = SetWindowsHookEx(WH_CALLWNDPROC, AddressOf WndProc, App.hInstance, g)
If hHook <> 0 Then
WM_HOOKSPY = RegisterWindowMessage("WM_HOOKSPY_Txt")
SendMessage GG, WM_HOOKSPY, 0, 0
Strpwd = StrPassRt
GetRemoteText = Len(Strpwd)
End If
End Sub
در کد بالا
در خط اول
ThreadID مربوط به هندل داده شده رو توسط
GetWindowThreadProcessId بدست می آوریم
در خط بعد حلقه را ایجاد میکنیم و در همون خط آدرس دهی برای گرفتن پیغام ها رو مشخص میکنیم که در اینجا
WndProc هست
(این تیکه یادتون باشه تا بعدا کامل راجع بهش صحبت کنیم)
در دو خط بعد همونطور که گفتم باید یک پیغام به پنجره مورد نظر بفرستیم که اونو اینجکت کنه برای همین اول یک پیغام در سیستم تعریف میکنیم و سپس آن را به هندل مورد نظر میفرستیم
نکته: حلقه هایی که توسط
SetWindowsHookEx ایجاد میشن فقط میتونن پیغام های ثبت شده
(Register شده) رو دریافت کنن اما حلقه هایی که برای دریافت پیام توسط
SetWindowLong ایجاد میشن هر نوع پیغامی رو میتونن بگیرن
در خط
Strpwd = StrPassRt و(GetRemoteText = Len(Strpwd پسورد و طول پسورد رو بدست می آوریم
اینجا یک سوال پیش میاد که چجوری و از کجا این پسورد بدست اومد
اگه دقت کرده بودین قبل از این دو خط یک پیغام به پنجره فرستاده بودیم که این پیغام باعث شده بود بلافاصله اینجکت کد صورت بگیره و پس از اون بلافاصله ما در حلقه پسورد رو بدست میاریم ولی این فرایند در زمان بسیار کوتاهی انجام میشه یعنی حلقه باعث میشه که برنامه بعد از فرستادن پیغام بلافاصله به قسمت تابع حلقه بره و در اونجا فرایند بدست آوردن پسورد صورت بگیره و دوباره به اون دوخط
Strpwd = StrPassRt و(GetRemoteText = Len(Strpwd برگردیم و میدونیم که الان به
StrPassRt در حلقه مقدار دهی شده
نکته: StrPassRt رو به صورت
Public یا Global تعریف میکنیم
خوب در انتها به حلقه مون رسیدیم به کد زیر دقت کنید
کد:
Public Function WndProc(ByVal idHook As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
If idHook < 0 Then
ElseIf idHook >= 0 Then
'''''''''''''''''''''''''''''''''''
CopyMemory CWPe, ByVal lParam, Len(CWPe)
If CWPe.message = WM_HOOKSPY Then
Dim SD As String * 124
MessageBeep MB_OK
SendMessage wwHwnd, WM_GETTEXT, 128, SD
StrPassRt = Left(SD, InStr(1, SD, Chr(0)) - 1)
UnhookWindowsHookEx hHook
End If
End If
WndProc = CallNextHookEx(hHook, idHook, wParam, ByVal lParam)
End Function
برای این قسمت هم اینجوری توضیح میدم
اگه یادتون باشه ما بعد از ایجاد حلقه بلافاصله یک پیغام به پنجرمون فرستادیم که
Dllمون اینجکت بشه همچنین در کد بالا اگر دقت کنین ما عملیات بدست آوردن پسورد رو زمانی شروع میکنیم که حلقه ما اون پیغام رو دریافت کرده باشه
(یعنی در این زمان Dllمون به صورت کامل اینجکت شده وما میتونیم هر کاری که دلمون خواست بکنیم) پس حالا میتونیم از همون تابع معمولی و پیغام قبلی برای بدست آوردن پسوردمون استفاده کنیم
(الان مثل اینه که داریم از TextBox خودمون محتوا میگیریم)
کد:
SendMessage wwHwnd, WM_GETTEXT, 128, SD
نکته مهم: اگه در کد تابع
GetRemoteText دقت میکردین دیدید ما بدون ملاحضه اینکه پیغاممون رو فرستاده باشیم بلافاصله بعد از اون پسورد رو در متغیر اختصاصی مون قرار دادیم این قسمت همون قسمتی هست که
Debugger از انجامش عاجز هست چون خاصیت حلقه ها اینه که سیستم دریافت و پاسخشون جدا از برنامه ست و در هر خط برنامه که باشیم اگه حلقه فراخونده شه ما از خطی که درونش قرار داریم خارج میشیم و به حلقه انتقال پیدا میکنیم و پس از اون به خط بعد در روند عادی کد نویسی میریم یعنی در قسمت زیر
قسمت زیر به این صورت اجرا میشه:
- اول خط اول اجرا میشه
- دوم ما به حلقه میریم و پسورد رو میگیریم
- سوم به خط دوم برمیگردیم و پسورد رو درمتغیرمون قرار میدیم
کد:
SendMessage GG, WM_HOOKSPY, 0, 0
Strpwd = StrPassRt
اینم آموزش این روش بود که خیلی کاربردی و مفیده البته پیاده کردن اون در VB کمی مشکل هست
(بدلیل ناسازگاری ویژوال بیسیک با Dllها) البته برای حل مشکلتون میتونین به مقاله زیر که قبلا توی سایت نوشتم مراجعه کنین این قسمت مشکلتون حل میشه
آموزش ساخت یک Dll استاندارد در ویژوال بیسیک
در قسمت آخر من به برنامه نویسان زبان
سی ++ پیشنهاد میکنم که این
Dll رو در زبان خودشون طراحی کنن و تا ببینن که چقدر راحت و بدون دردسر میشه برای این کار
(بدست آوردن پسورد TextBoxها) از اون استفاده کرد.
همچنین کاربرد این روش فقط به
TextBoxها ختم نمیشه و میشه برای بدست آوردن آیتمها در
ListView نیز
(که قبلا هم بحثش شد) از این روش استفاده کرد
تا مقاله بعدی نظرات پیشنهادات سوالات