메모리 무결성 및 VBS와의 드라이버 호환성
메모리 무결성 은 Windows 10, Windows 11 및 Windows Server 2016 이상에서 사용할 수 있는 VBS(가상화 기반 보안) 기능입니다. 메모리 무결성 및 VBS는 Windows의 위협 모델을 개선하고 Windows 커널을 악용하려는 맬웨어에 대해 더 강력한 보호를 제공합니다. VBS는 Windows 하이퍼바이저를 사용하여 커널이 손상될 수 있다고 가정하는 OS의 신뢰 루트가 되는 격리된 가상 환경을 만듭니다. 메모리 무결성은 VBS의 격리된 가상 환경 내에서 커널 모드 코드 무결성을 실행하여 Windows를 보호하고 강화하는 중요한 구성 요소입니다. 또한 메모리 무결성은 시스템을 손상시키는 데 사용할 수 있는 커널 메모리 할당을 제한하므로 보안 런타임 환경 내에서 코드 무결성 검사 전달한 후에만 커널 메모리 페이지가 실행 가능하도록 하고 실행 파일 페이지 자체는 쓰기가 불가능합니다.
참고 항목
메모리 무결성은 HVCI(하이퍼바이저로 보호된 코드 무결성) 또는 하이퍼바이저 적용 코드 무결성이라고도 하며 원래 Device Guard의 일부로 릴리스되었습니다. Device Guard는 그룹 정책 또는 Windows 레지스트리에서 메모리 무결성 및 VBS 설정을 찾는 것 외에는 더 이상 사용되지 않습니다.
메모리 무결성 사용 설정에 설명 된 대로 호환 되는 하드웨어에 S 모드에서 Windows 10 및 Windows 11의 클린 설치에 기본적으로 메모리 무결성이 설정 됩니다. 메모리 무결성 자동 사용 요구 사항을 충족하지 않는 다른 시스템에서 고객은 메모리 무결성을 사용하도록 설정하는 방법에 설명된 방법을 사용하여 옵트인할 수 있습니다.
애플리케이션 호환성
Windows 10 1주년 업데이트(1607) 이후 모든 드라이버에 메모리 무결성과의 호환성이 요구되었지만 일부 애플리케이션 및 하드웨어 디바이스 드라이버는 여전히 호환되지 않을 수 있습니다. 이러한 비호환성으로 인해 디바이스 또는 소프트웨어가 오작동할 수 있으며 드문 경우로 인해 부팅 실패(파란색 화면)가 발생할 수 있습니다. 이러한 문제는 메모리 무결성 보호가 켜진 후 또는 사용 프로세스 자체 중에 발생할 수 있습니다. 애플리케이션 개발자이고 드라이버 및 소프트웨어 패키지가 메모리 무결성과 호환되는지 확인하려는 경우 다음 단계를 수행합니다.
메모리 무결성과의 비호환성을 관찰한 몇 가지 예는 다음과 같습니다.
- 게임 관련 치트 방지 솔루션
- 타사 입력 방법
- 타사 은행 암호 보호
영향을 받은 환경을 완화하기 위해 열심히 노력했기 때문에 부팅에 중요한 드라이버에 대한 비호환성이 있는 경우 자동 사용이 설정된 경우 메모리 무결성 보호가 자동으로 꺼집니다. 다른 앱과 호환되지 않는 경우 메모리 무결성 보호를 해제하기 전에 문제가 발생하는 특정 앱 및 버전에 대한 업데이트를 검사 것이 좋습니다.
호환되는 드라이버를 빌드하는 방법
메모리 페이지와 섹션은 쓰기 가능 및 실행 가능할 수 없으므로 첫 번째 단계는 데이터와 코드를 명확하게 분리하고 코드 페이지를 직접 수정하지 않는 것입니다.
- 기본적으로 NX에 옵트인
- 메모리 할당에 NX API/플래그 사용 - NonPagedPoolNx
- 쓰기 가능하고 실행 가능한 섹션을 사용하지 않음
- 실행 가능한 시스템 메모리를 직접 수정하려고 하지 않음
- 커널에서 동적 코드 사용 안 함
- 데이터 파일을 실행 파일로 로드하지 않음
- 섹션 맞춤은 0x1000(PAGE_SIZE)의 배수여야 합니다. 예: DRIVER_ALIGNMENT=0x1000
기본 설정을 사용할 때 WDK 및 Visual Studio의 최신 버전을 사용하여 호환되는 드라이버를 생성합니다.
드라이버와 메모리 무결성의 호환성을 확인하는 방법
드라이버 호환성을 확인하는 3단계는 다음과 같습니다.
- 코드 무결성 호환성 검사 사용하도록 설정된 드라이버 검증 도구(아래 섹션 참조)를 사용합니다.
- 메모리 무결성을 사용하도록 설정된 시스템에서 드라이버를 테스트합니다.
- Windows HLK에서 하이퍼바이저 코드 무결성 준비 테스트를 실행합니다.
드라이버 검증 도구 호환성 검사
드라이버 검증 도구에는 메모리 무결성 준수의 유효성을 검사하는 추가 검사 사용하도록 설정하는 코드 무결성 옵션 플래그(0x02000000)가 있습니다. 명령줄에서 이를 사용하도록 설정하려면 다음 명령을 사용합니다.
verifier.exe /flags 0x02000000 /driver <driver.sys>
검증 도구 GUI를 사용하는 경우 이 옵션을 선택하려면 사용자 지정 설정 만들기(코드 개발자용)를 선택하고 다음을 선택한 다음, 코드 무결성 검사를 선택합니다.
출력이 없으면 성공한 것입니다. 다음은 오류 출력의 예입니다.
Driver Verifier: Enabled for DvCi.sys, flags 0x2000000, build 16299, key o4Dbg8OVJqaBYlqWQ2QvRH
\*\*\*\*\*\*\*\*\*\*\* Verifier Detected a Code Integrity Issue \*\*\*\*\*\*\*\*\*\*\*\*
\*\* The caller 0xFFFFF8094B9852F0 specified an executable page protection 0x40.
\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
\*\*\* Verifier assertion failed \*\*\*
(B)reak, (I)gnore, (W)arn only, (R)emove assert? B
메모리 무결성을 사용하도록 설정된 드라이버 테스트
Windows는 대부분의 시스템에 대해 기본적으로 메모리 무결성을 설정하지만 이러한 문제가 발생하지 않도록 할 수 있는 몇 가지 이유가 있습니다. 메모리 무결성을 켜려면 메모리 무결성을 켜는 방법을 참조 하세요. 그런 다음 드라이버의 기능을 테스트합니다. 드라이버가 메모리 무결성과 호환되지 않는 작업을 런타임에 수행하지 않도록 드라이버의 모든 코드 경로를 실행해야 합니다.
HLK 테스트(데스크톱 및 서버)
HLK 테스트 하이퍼바이저 코드 무결성 준비 테스트 는 드라이버가 Microsoft 서명에 대한 승인을 받도록 통과해야 합니다. 데스크톱 및 서버 버전 모두에 메모리 무결성 호환 드라이버가 필요합니다. HLK 테스트는 메모리 무결성 호환 드라이버가 OS에서 올바르게 로드되고 실행되는지 확인하기 위해 작성된 기본 테스트입니다.
단순히 HLK 테스트를 통과하는 것만으로도 드라이버에 대한 Microsoft 서명에 충분하지만 메모리 무결성을 사용하도록 설정된 철저한 기능 테스트를 사용하는 것이 좋습니다. 예를 들어 잘못 코딩된 메모리 할당이 NX 보호를 위반하여 테스트에 의해 catch되지 않는 오류가 발생할 수 있습니다. 드라이버 작성자가 메모리 무결성을 사용하도록 유지하면서 드라이버를 철저히 테스트해야 합니다.
드라이버 개발 중 및 HLK 테스트 중에는 드라이버가 로드되지 않도록 방지할 수 있으므로 메모리 무결성을 사용하지 않도록 설정해야 할 수 있습니다.
HLK 하이퍼바이저 코드 무결성 준비 테스트는 Windows Server Assurance AQ의 일부로 필요하며 다른 HLK 테스트 중에 드라이버 검증 도구를 사용하도록 설정하는 동안 코드 무결성 검사 사용하도록 설정하는 플래그도 설정됩니다.
FAQ
기존 드라이버는 어떤가요? Windows 10에서 작동하기 위해 이러한 드라이버를 다시 빌드해야 하나요?
경우에 따라 다릅니다. 많은 드라이버가 이미 호환됩니다. 이전 버전의 WDK 및 Visual Studio에서 표준 설정을 사용하는 경우 알려진 문제는 INIT 섹션이 RWX로 표시된다는 것입니다. 그러나 Windows 10에서 W는 자동으로 제거되므로 이것이 유일한 문제인 경우 드라이버는 호환됩니다.
메모리 무결성이 사용되는지 어떻게 할까요? 확인하시겠습니까?
가장 간단한 방법은 시스템 정보 앱(msinfo32)을 실행하는 것입니다. "가상화 기반 보안 서비스 실행 중"이라는 줄을 찾습니다. "Hypervisor enforced Code Integrity"라고 보고해야 합니다. 관리 도구를 사용하여 검사 WMI 인터페이스도 있습니다. 사용 가능한 VBS 및 메모리 무결성 기능 유효성 검사를 참조하세요.
메모리 무결성은 Windows 보안 앱>에서 설정업데이트 및 보안>Windows 보안Device security>Core 격리 세부 정보>메모리 무결성에> 검사 수 있습니다. 자세한 내용은 KB4096339를 참조하세요.
드라이버 동작을 변경하기 위해 커널에서 프로그래밍 방식으로 메모리 무결성이 사용하도록 설정되어 있는지 확인할 수 있나요?
예, NtQuerySystemInformation을 사용할 수 있습니다. https://msdn.microsoft.com/library/windows/desktop/ms724509(v=vs.85).aspx
SYSTEM_CODEINTEGRITY_INFORMATION 구조체에는 메모리 무결성이 설정되어 있음을 나타내는 0x400 값이 노출됩니다.
호환성 문제를 해결하려면 어떻게 해야 하나요?
위에서 설명한 대로 W+X 페이지가 없고 드라이버 섹션이 올바르게 정렬되었는지 한 번 더 확인하는 것 외에도 메모리 할당이 잘못되었을 가능성을 고려하는 것이 좋습니다. 발급된 메모리 할당과 관련된 Code Analysis 경고에 대한 내용은 다음 페이지의 MSDN에서 확인할 수 있습니다.
다음 MSDN 링크는 몇 가지 예제 수정 사항과 함께 실행 가능한 메모리 할당을 야기하는 일반적인 API의 몇 가지 예를 보여 줍니다.
다음 표를 통해 출력을 해석하여 다양한 유형의 HVCI 비호환성을 해결하는 데 필요한 드라이버 코드 변경을 확인합니다.
Warning | 해결 |
---|---|
실행 풀 유형 | 호출자가 실행 가능한 풀 유형을 지정했습니다. 실행 메모리를 요청하는 메모리 할당 함수를 호출합니다. 모든 풀 유형에 실행 불가능한 NX 플래그가 포함되어 있는지 확인합니다. |
실행 페이지 보호 | 호출자가 실행 가능한 페이지 보호를 지정했습니다. “no execute” 페이지 보호 마스크를 지정합니다. |
실행 페이지 매핑 | 호출자가 실행 가능한 MDL(메모리 설명자 목록) 매핑을 지정했습니다. 사용되는 마스크에 MdlMappingNoExecute가 포함되어 있는지 확인합니다. 자세한 내용은 MmGetSystemAddressForMdlSafe를 참조하세요. |
실행-쓰기 섹션 | 이미지에는 실행 가능 섹션과 쓰기 가능 섹션이 포함되어 있습니다. |
섹션 맞춤 오류 | 이미지에는 페이지가 정렬되지 않은 섹션이 포함되어 있습니다. 섹션 맞춤은 0x1000(PAGE_SIZE)의 배수여야 합니다. 예: DRIVER_ALIGNMENT=0x1000 |
지원되지 않는 Relocs | Windows 10 버전 1507~1607 버전에서는 ASLR(Address Space Layout Randomization)이 사용되기 때문에 주소 정렬 및 메모리 재배치와 관련된 문제가 발생할 수 있습니다. 운영 체제에서 링커가 기본 기준 주소를 ASLR이 할당된 실제 위치로 설정하는 주소의 위치를 다시 지정해야 합니다. 이 재배치는 페이지 경계를 넘어 수행될 수 없습니다. 예를 들어 페이지의 오프셋 0x3FFC에서 시작하는 64비트 주소 값을 고려해 보세요. 주소 값은 오프셋 0x0003에서 다음 페이지와 겹칩니다. 이 유형의 겹치는 relocs는 Windows 10 버전 1703 이전에는 지원되지 않습니다.
이 상황은 전역 구조체 형식 변수 이니셜라이저의 포인터가 다른 전역 구조체로 잘못 정렬되어, 링커가 경계를 넘는 재배치를 방지하도록 변수를 이동할 수 없는 상황이 될 때 발생할 수 있습니다. 링커는 변수를 이동하려고 하지만, 이 작업을 수행할 수 없는 경우가 있습니다. 예를 들어 잘못 정렬된 대규모 구조체 또는 잘못 정렬된 대규모 구조체 배열을 포함하는 경우가 여기에 해당합니다. 적절한 경우 /Gy(COMDAT) 옵션을 사용하여 링커가 모듈 코드를 최대한 많이 정렬할 수 있도록 모듈을 어셈블해야 합니다. #include <pshpack1.h> typedef struct _BAD_STRUCT { USHORT Value; CONST CHAR *String; } BAD_STRUCT, * PBAD_STRUCT; #include <poppack.h> #define BAD_INITIALIZER0 { 0, "BAD_STRING" }, #define BAD_INITIALIZER1 \ BAD_INITIALIZER0 \ BAD_INITIALIZER0 \ BAD_INITIALIZER0 \ BAD_INITIALIZER0 \ BAD_INITIALIZER0 \ BAD_INITIALIZER0 \ BAD_INITIALIZER0 \ BAD_INITIALIZER0 #define BAD_INITIALIZER2 \ BAD_INITIALIZER1 \ BAD_INITIALIZER1 \ BAD_INITIALIZER1 \ BAD_INITIALIZER1 \ BAD_INITIALIZER1 \ BAD_INITIALIZER1 \ BAD_INITIALIZER1 \ BAD_INITIALIZER1 #define BAD_INITIALIZER3 \ BAD_INITIALIZER2 \ BAD_INITIALIZER2 \ BAD_INITIALIZER2 \ BAD_INITIALIZER2 \ BAD_INITIALIZER2 \ BAD_INITIALIZER2 \ BAD_INITIALIZER2 \ BAD_INITIALIZER2 #define BAD_INITIALIZER4 \ BAD_INITIALIZER3 \ BAD_INITIALIZER3 \ BAD_INITIALIZER3 \ BAD_INITIALIZER3 \ BAD_INITIALIZER3 \ BAD_INITIALIZER3 \ BAD_INITIALIZER3 \ BAD_INITIALIZER3 BAD_STRUCT MayHaveStraddleRelocations[4096] = { // as a global variable BAD_INITIALIZER4 }; 이 문제가 발생할 수도 있는 어셈블러 코드 사용과 관련된 다른 상황이 있습니다. |
실행 가능 섹션의 IAT | IAT(가져오기 주소 테이블)는 메모리의 실행 가능한 섹션이 아니어야 합니다.
이 문제는 IAT가 RX(읽기 및 실행) 전용 메모리 섹션에 있을 때 발생합니다. 즉, OS는 참조된 DLL에 대한 올바른 주소를 설정하기 위해 IAT에 쓸 수 없습니다. 이 문제가 발생할 수 있는 한 가지 방식은 코드 연결에서 /MERGE(섹션 결합) 옵션을 사용하는 경우입니다. 예를 들어 .rdata(읽기 전용으로 초기화된 데이터)를 .text 데이터(실행 코드)와 병합하는 경우에는 IAT가 메모리의 실행 가능한 섹션에서 끝날 수 있습니다. |
잠재적으로 어떤 API가 영향을 받나요?
시스템용으로 예약되지 않은 다음 API 목록은 영향을 받을 수 있습니다.