Giriş

Yazılım geliştirme alanında, özellikle hassas verileri ele alırken bellek güvenliği son derece önemlidir. Geliştiriciler sık sık lisans anahtarları veya şifreler gibi hassas bilgileri gözetleyici gözlerden korumaları gereken durumlarla karşılaşırlar. Bu tür bağlamlarda ortaya çıkan bir soru şudur: Diske sayfalamayı engelleyen ve hata ayıklayıcılar aracılığıyla erişilmesi zor bir güvenli bellek ayırıcıyı C++‘da nasıl yaratabiliriz?

Bu blog yazısında, bellek güvenliği etrafındaki sorunları inceleyecek ve bu gereksinimleri karşılayan bir C++ ayırıcıyı nasıl uygulayacağımıza dair bilgilere dalacağız.

Zorlukları Anlamak

Çözümün detaylarına geçmeden önce, belleği korumakla ilgili bazı zorlukları anlamak önemlidir:

  • Diskte Sayfalama Önleme: Sanal bellek kullanan sistemlerde bellek diske sayfalanabilir ve bu durum yetkisiz erişime karşı savunmasız hale gelebilir. Bellek sayfaladığında, diğer süreçler tarafından erişilebilir olan değişim alanında saklanır.

  • Hata Ayıklayıcılar Üzerinden Erişim: Hata ayıklayıcılar belleği erişip manipüle edebilir; bu nedenle, özellikle hassas bilgiler için bu riski en aza indirmek için yollar bulmak kritik öneme sahiptir.

  • İşletim Sistemi Düzeyindeki Kısıtlamalar: Niyetlerimizden bağımsız olarak, işletim sistemi süreçlerin kontrolünü elinde tutar ve potansiyel olarak bellek içeriklerini okuyabilir.

C++‘da Güvenli Bir Bellek Ayırıcı

Bu zorluklara rağmen, Windows API işlevlerini kullanarak C++‘da özel bir ayırıcı uygulayabiliriz. Çözümü adım adım inceleyelim:

1. VirtualAlloc Kullanımı

Belleği güvenli bir şekilde ayırmanın birinci aracı VirtualAlloc‘dur. Bu fonksiyon, belleği belirli bir şekilde ayırmamıza olanak tanır:

  • Ayrılan belleğin nasıl erişileceğini kontrol etmek için koruma seviyelerini ayarlayabiliriz.
LPVOID pMem = ::VirtualAlloc(NULL, allocLen, allocType, allocProtect);

Burada, allocType MEM_COMMIT olarak ayarlanmış ve allocProtect PAGE_READWRITE olarak belirlenmiştir; bu da okuma ve yazma erişimini etkinleştirir.

2. Belleği Kilitlemek

İşletim sisteminin belleği diske sayfalamasını önlemek için VirtualLock işlevini kullanırız:

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

Ancak, VirtualLock‘un ayırabileceğiniz bellek miktarı üzerinde kısıtlamalar getirdiğini aklınızda bulundurmalısınız; bu kısıtlamalar ihtiyaçlarınıza bağlı olarak yönetilebilir olabilir.

3. Belleği Güvenli Bir Şekilde Serbest Bırakmak

Belleği serbest bırakırken, hassas içerikleri sıfırlamak önemlidir. Bu, SecureZeroMemory kullanılarak yapılabilir:

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

Tam Örnek

İşte güvenli bellek ayırıcıyı tam olarak uygulayan kod:

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);
        }
    }
};

// Kullanım Örneği
typedef std::basic_string<char, std::char_traits<char>, LockedVirtualMemAllocator<char>> modulestring_t;

Sonuç

C++‘da güvenli bir bellek ayırıcı oluşturmak, çeşitli sistem düzeyindeki kısıtlamaları ve güvenlik zorluklarını aşmayı gerektiren karmaşık bir iştir. Bellek erişimine karşı tam bir koruma sağlamak imkânsız olsa da, VirtualAlloc, VirtualLock ve SecureZeroMemory gibi fonksiyonların kullanımı, hassas verilerin güvenliğini önemli ölçüde artırabilir.

Ayrıca, hiçbir sistemin cihazın sahibi olan kişiden tamamen güvenli olamayacağını unutmamak önemlidir. Bu kısıtlamaları anlamak, geliştiricilere daha güçlü ve dayanıklı uygulamalar yaratma konusunda yardımcı olabilir.

Daha derinlemesine bilgi arayan herkes için, Neil Ferguson ve Bruce Schneier tarafından yazılan Pratik Kriptografi gibi kaynaklar, kriptografik uygulamalar ve güvenli bellek yönetimi metodolojileri konusunda değerli bağlam sağlayabilir.