المقدمة

في عالم تطوير البرمجيات، وخاصة عند التعامل مع البيانات الحساسة، تعتبر أمان الذاكرة أمرًا بالغ الأهمية. غالبًا ما يواجه المطورون مواقف يحتاجون فيها إلى حماية المعلومات الحساسة مثل مفاتيح الترخيص أو كلمات المرور من الأعين المتطفلة. سؤال يبرز في مثل هذه السياقات هو: كيف يمكننا إنشاء مُخصص ذاكرة آمن في C++ يمنع الترحيل إلى القرص ويصعب الوصول إليه عبر المصححات؟

في هذه التدوينة، سنتناول القضايا المتعلقة بأمان الذاكرة ونستكشف كيفية تنفيذ مُخصص في C++ يلبي هذه المتطلبات.

فهم التحديات

قبل أن نغوص في الحل، من الضروري فهم بعض التحديات التي تأتي مع حماية الذاكرة:

  • منع الترحيل إلى القرص: في الأنظمة التي تستخدم الذاكرة الافتراضية، يمكن أن يتم ترحيل الذاكرة إلى القرص، مما يجعلها عرضة للوصول غير المصرح به. عندما يتم ترحيل الذاكرة، يتم تخزينها في مساحة التبديل، والتي قد تكون متاحة لعمليات أخرى.

  • الوصول عبر المصححات: يمكن أن تصل المصححات إلى الذاكرة وتعدلها، مما يجعل من الضروري العثور على طرق للتقليل من هذا الخطر، خاصةً للمعلومات الحساسة.

  • القيود على مستوى نظام التشغيل: بغض النظر عن نوايانا، يتحكم نظام التشغيل في العمليات ويمكنه قراءة محتويات الذاكرة بشكل محتمل.

مُخصص ذاكرة آمن في C++

على الرغم من هذه التحديات، يمكننا تنفيذ مُخصص مخصص في C++ باستخدام دوال واجهة برمجة تطبيقات ويندوز. دعنا نفكك الحل خطوة بخطوة:

1. استخدام VirtualAlloc

الأداة الرئيسية لتخصيص الذاكرة بشكل آمن هي VirtualAlloc. تتيح لنا هذه الدالة تخصيص الذاكرة بطريقة محددة:

  • يمكننا تعيين مستويات الحماية للسيطرة على كيفية الوصول إلى الذاكرة المخصصة.
LPVOID pMem = ::VirtualAlloc(NULL, allocLen, allocType, allocProtect);

هنا، يتم تعيين allocType إلى MEM_COMMIT، و allocProtect إلى PAGE_READWRITE، مما يتيح الوصول للقراءة والكتابة.

2. قفل الذاكرة

لمنع نظام التشغيل من ترحيل الذاكرة إلى القرص، نستخدم دالة VirtualLock:

if (pMem != NULL) {
    ::VirtualLock(pMem, allocLen);
}

ومع ذلك، يجب أن نضع في اعتبارنا أن VirtualLock تفرض قيودًا على مقدار الذاكرة التي يمكنك تخصيصها، والتي قد تكون قابلة للإدارة حسب احتياجاتك.

3. تحرير الذاكرة بشكل آمن

عند تحرير الذاكرة، من الضروري تصفير المحتويات الحساسة قبل تحريرها. يمكن القيام بذلك باستخدام SecureZeroMemory:

::SecureZeroMemory(_pPtr, allocLen);
::VirtualUnlock(_pPtr, allocLen);
::VirtualFree(_pPtr, 0, MEM_RELEASE);

مثال كامل

إليك التنفيذ الكامل لمخصص الذاكرة الآمنة لدينا:

template<class _Ty>
class LockedVirtualMemAllocator : public std::allocator<_Ty> {
public:
    template<class _Other>
    LockedVirtualMemAllocator<_Ty>& operator=(const LockedVirtualMemAllocator<_Other>&) {
        return (*this);
    }

    template<class Other>
    struct rebind {
        typedef LockedVirtualMemAllocator<Other> other;
    };

    pointer allocate(size_type _n) {
        SIZE_T allocLen = (_n * sizeof(_Ty));
        DWORD allocType = MEM_COMMIT;
        DWORD allocProtect = PAGE_READWRITE;
        LPVOID pMem = ::VirtualAlloc(NULL, allocLen, allocType, allocProtect);
        if (pMem != NULL) {
            ::VirtualLock(pMem, allocLen);
        }
        return reinterpret_cast<pointer>(pMem);
    }

    void deallocate(void* _pPtr, size_type _n) {
        if (_pPtr != NULL) {
            SIZE_T allocLen = (_n * sizeof(_Ty));
            ::SecureZeroMemory(_pPtr, allocLen);
            ::VirtualUnlock(_pPtr, allocLen);
            ::VirtualFree(_pPtr, 0, MEM_RELEASE);
        }
    }
};

// مثال على الاستخدام
typedef std::basic_string<char, std::char_traits<char>, LockedVirtualMemAllocator<char>> modulestring_t;

الخاتمة

إنشاء مُخصص ذاكرة آمن في C++ هو مهمة معقدة تتطلب التنقل بين قيود النظام المختلفة وتحديات الأمان. على الرغم من أنه من المستحيل تحقيق حماية كاملة ضد الوصول إلى الذاكرة، فإن استخدام دوال مثل VirtualAlloc و VirtualLock و SecureZeroMemory يمكن أن يعزز بشكل كبير أمان البيانات الحساسة.

من الضروري أن نضع في اعتبارنا أنه لا يمكن تأمين أي نظام بشكل كامل من مالك الجهاز. لذلك، فإن فهم هذه القيود يسمح للمطورين بإنشاء تطبيقات أكثر قوة ومتانة.

بالنسبة لأي شخص مهتم بالمعرفة الأعمق، يمكن أن توفر موارد مثل علم التشفير العملي لنيال فيرغسون وبروس شناير سياقًا قيمًا في ممارسات التشفير وطرق إدارة الذاكرة الآمنة.