Aracılığıyla paylaş


Çekirdek modu sürücülerinde yüksek ayrıcalıklı davranışı kısıtlamak için en iyi yöntemler

Bu konu, Windows çekirdek sürücü kodunuzun istismarına ve suistimaline yol açabilecek güvensiz geliştirme desenlerini özetlemektedir. Bu konu, ayrıcalıklı davranışı kısıtlamaya yardımcı olmak için geliştirme önerileri ve kod örnekleri sağlar. Bu en iyi yöntemlerin takip etmek, Windows çekirdeğinde ayrıcalıklı davranış gerçekleştirmenin güvenliğini artırmaya yardımcı olur.

Güvenli olmayan sürücü davranışına genel bakış

Windows sürücülerinin çekirdek modunda yüksek ayrıcalıklı davranışlar gerçekleştirmesi beklense de, güvenlik denetimleri yapılmaması ve ayrıcalıklı davranışa kısıtlamalar eklenmemesi kabul edilemez. Eski adı WHQL olan Windows Donanım Uyumluluk Programı (WHCP), bu gereksinime uymak için yeni sürücü gönderimleri gerektirir.

Güvenli olmayan ve tehlikeli davranış örnekleri şunlardır ancak bunlarla sınırlı değildir:

MSR'leri okuma ve yazma olanağı sağlama

MSR'lerden okuma güvenliğini geliştirme

Bu ReadMsr örneğinde sürücü, __readmsr modelle özelleştirilmiş kayıt iç kullanarak tüm yazmaçların rastgele okunmasına izin veriyor, bu da güvensiz davranışlara yol açıyor. Bu, kullanıcı modunda kötü amaçlı işlemler tarafından kötüye kullanılmasına neden olabilir.

Func ReadMsr(int dwMsrIdx) 
{
	int value = __readmsr(dwMsrIdx); // Unsafe, can read from any MSR
	return value;
}

Senaryonuz MSR'lerden okuma gerektiriyorsa, sürücünün her zaman okunacak kaydın beklenen dizin veya aralıkla kısıtlanmış olup olmadığını denetlemesi gerekir. Güvenli okuma işleminin nasıl uygulandığına ilişkin iki örnek aşağıda verilmiştir.

Func ConstrainedReadMsr(int dwMsrIdx) 
{
    int value = 0;
    if (dwMsrIdx == expected_index) // Blocks from reading anything
    {
        value = __readmsr(dwMsrIdx); // Can only read the expected MSR
    }
    else
    {
        return error;
    }
    return value;
}

// OR

Func ConstrainedReadMsr(int dwMsrIdx) 
{
    int value = 0;
    if (min_range <= dwMsrIdx <= max_range) // Blocks from reading anything
    {
        value = __readmsr(dwMsrIdx); // Can only from the expected range of MSRs
    }
    else
    {
        return error;
    }
    return value;
}

MSR'lere yazma güvenliğini geliştirme

İlk WriteMsr örneğinde, sürücü herhangi bir ve tüm yazmaçların rastgele yazılmasına izin vererek güvenli olmayan davranışlara izin verir. Bu, kullanıcı modunda ayrıcalığı yükseltmek ve tüm MSR'lere yazmak için kötü amaçlı işlemlerin kötüye kullanılmasına neden olabilir.

Func WriteMsr(int dwMsrIdx) 
{
	int value = __writemsr(dwMsrIdx); // Unsafe, can write to any MSR
	return value;
}

Senaryonuz MSR'lere yazmayı gerektiriyorsa, sürücünün her zaman yazacak kaydın beklenen dizin veya aralıkla kısıtlanmış olup olmadığını denetlemesi gerekir. Güvenli yazma işleminin nasıl uygulandığına ilişkin iki örnek aşağıda verilmiştir.

Func ConstrainedWriteMsr(int dwMsrIdx) 
{
    int value = 0;
    if (dwMsrIdx == expected_index) // Blocks from reading anything
    {
        value = __writemsr(dwMsrIdx); // Can only write to the expected constrained MSR
    }
    else
    {
        return error;
    }
    return value;
}

// OR

Func ConstrainedWriteMSR(int dwMsrIdx) 
{
    int value = 0;
    if (min_range <= dwMsrIdx <= max_range) // Blocks from reading anything
    {
        value = __writemsr(dwMsrIdx); // Can only write to the expected constrained MSR
    }
    else
    {
        return error;
    }
    return value;
}

İşlemleri sonlandırma olanağı sağlama

Sürücünüzde işlemlerin sonlandırılmasına olanak tanıyan işlevler uygulanırken çok dikkatli olunmalıdır. Kötü amaçlı yazılımdan koruma ve virüsten koruma çözümleri tarafından kullanılanlar gibi korumalı işlemler ve korumalı işlem ışığı (PPL) işlemleri sonlandırılmamalıdır. Bu işlevselliğin açığa çıkartılması, saldırganların sistemdeki güvenlik korumalarını sonlandırmasına olanak tanır.

Senaryonuz işlem sonlandırma gerektiriyorsa, PsLookupProcessByProcessId ve kullanılarak rastgele işlem sonlandırmaya karşı koruma sağlamak için aşağıdaki denetimlerin uygulanması gerekir:

Func ConstrainedProcessTermination(DWORD dwProcessId)
{
	// Function to check if a process is a Protected Process Light (PPL)
    NTSTATUS status;
    BOOLEAN isPPL = FALSE;
    PEPROCESS process;
    HANDLE hProcess;

    // Open the process
    status = PsLookupProcessByProcessId(processId, &process);
    if (!NT_SUCCESS(status)) {
        return FALSE;
    }

    // Check if the process is a PPL
    if (PsIsProtectedProcess(process)) {
        isPPL = TRUE;
    }

    // Dereference the process
    ObDereferenceObject(process);
    return isPPL;
}

Bağlantı noktası girişi ve çıkışına okuma ve yazma olanağı sağlama

Port Giriş/Çıkış'tan okuma güvenliğini artırma

Bağlantı noktası giriş/çıkışına (G/Ç) okuma özelliği sağlarken dikkatli olunmalıdır. __indword kullanan bu kod örneği güvenli değildir.

Func ArbitraryInputPort(int inPort) 
{
	dwResult = __indword(inPort); // Unsafe, allows for arbitrary reading from Input Port
	return dwResult; 
}

Sürücünün istismar edilmesini ve sömürülmesini önlemek için, beklenen giriş bağlantı noktası gerekli kullanım sınırına kısıtlanmalıdır.

Func ConstrainedInputPort(int inPort) 
{
	// The expected input port must be constrained to the required usage boundary to prevent abuse
	if(inPort == expected_InPort)
	{
		dwResult = __indword(inPort);
	}
	else
	{
		return error; 
	}
	return dwResult; 
}

Port IO'ya yazma güvenliğini artırma

Bağlantı noktası giriş/çıkışına (G/Ç) yazma imkanı sağlarken dikkatli olunmalıdır. __outword kullanan bu kod örneği güvenli değildir.

Func ArbitraryOutputPort(int outPort, DWORD dwValue) 
{
	__outdword(OutPort, dwValue); // Unsafe, allows for arbitrary writing to Output Port
}

Sürücünün kötüye kullanımını ve istismarını önlemek için, giriş bağlantı noktasının kullanımı gerekli sınırlarla kısıtlanmalıdır.

Func ConstrainedOutputPort(int outPort, DWORD dwValue) 
{
	// The expected output port must be constrained to the required usage boundary to prevent abuse
	if(outPort == expected_OutputPort)
	{
		__outdword(OutPort, dwValue); // checks on InputPort
	}
	else
	{
		return error; 
	}
}

Çekirdek, fiziksel veya cihaz belleği okuma ve yazma olanağı sağlama

Memcpy'nin güvenliğini geliştirme

Bu örnek kod, fiziksel belleğin güvenli kullanımının kısıtlanmamış ve güvenli olmayan kullanımını gösterir.

Func ArbitraryMemoryCopy(src, dst, length) 
{
	memcpy(dst, src, length); // Unsafe, can read and write anything from physical memory
}

Senaryonuz çekirdek, fiziksel veya cihaz belleği okuma ve yazma gerektiriyorsa, sürücünün her zaman kaynak ve hedeflerin beklenen dizinlerle veya aralıklarla kısıtlanıp kısıtlandığını denetlemesi gerekir.

Func ConstrainedMemoryCopy(src, dst, length) 
{
	// valid_src and valid_dst must be constrained to required usage boundary to prevent abuse
	if(src == valid_Src && dst == valid_Dst)
	{
		memcpy(dst, src, length); 
	}
	else
	{
		return error;
	}
}

ZwMapViewOfSection güvenliğini geliştirme

Aşağıdaki örnekte, ZwOpenSection ve ZwMapViewOfSection API'lerini kullanarak kullanıcı modundan fiziksel belleği okumak ve yazmak için güvenli olmayan ve yanlış yöntem gösterilmektedir.

Func ArbitraryMap(PHYSICAL_ADDRESS Address)
{
	ZwOpenSection(&hSection, ... ,"\Device\PhysicalMemory");
	ZwMapViewOfSection(hSection, -1, 0, 0, 0, Address, ...);
}

Kötü amaçlı kullanıcı modu işlemleri tarafından sürücünün okuma/yazma davranışının kötüye kullanılmasını ve kötüye kullanılmasını önlemek için, sürücünün giriş adresini doğrulaması ve bellek eşlemesini yalnızca senaryo için gerekli kullanım sınırıyla sınırlaması gerekir.

Func ConstrainedMap(PHYSICAL_ADDRESS paAddress)
{
	// expected_Address must be constrained to required usage boundary to prevent abuse
	if(paAddress == expected_Address)
	{
		ZwOpenSection(&hSection, ... ,"\Device\PhysicalMemory");
		ZwMapViewOfSection(hSection, -1, 0, 0, 0, paAddress, ...);
	}
	else
	{
		return error;
	}
}

MmMapLockedPagesSpecifyCache güvenliğini geliştirme

Aşağıdaki örnekte, MmMapIoSpace, IoAllocateMdl ve MmMapLockedPagesSpecifyCache API'lerini kullanarak kullanıcı modundan fiziksel belleği okumak ve yazmak için güvenli olmayan ve yanlış yöntem gösterilmektedir.

Func ArbitraryMap(PHYSICAL_ADDRESS paAddress)
{
	lpAddress = MmMapIoSpace(paAddress, qwSize, ...);
	pMdl = IoAllocateMdl( lpAddress, ...);
	MmMapLockedPagesSpecifyCache(pMdl, UserMode, ... );
}

Kötü amaçlı kullanıcı modu işlemleri tarafından sürücünün okuma/yazma davranışının kötüye kullanılmasını ve kötüye kullanılmasını önlemek için, sürücünün giriş adresini doğrulaması ve bellek eşlemesini yalnızca senaryo için gerekli kullanım sınırıyla sınırlaması gerekir.

Func ConstrainedMap(PHYSICAL_ADDRESS paAddress)
{
	// expected_Address must be constrained to required usage boundary to prevent abuse
	if(paAddress == expected_Address && qwSize == valid_Size) 
	{
		lpAddress = MmMapIoSpace(paAddress, qwSize, ...);
		pMdl = IoAllocateMdl( lpAddress, ...);
		MmMapLockedPagesSpecifyCache(pMdl, UserMode, ... );
	}
	else
	{
		return error;
	}
}

Ayrıca Bkz.

sürücü güvenlik denetim listesi