동적 링크 라이브러리 리디렉션

DLL 로더는 DLL에 대한 참조를 확인하고, 로드하고, 연결하는 운영 체제(OS)의 일부입니다. DLL(동적 연결 라이브러리) 리디렉션은 DLL 로더동작에 영향을 미치고 실제로 로드되는 여러 후보 DLL 중 하나를 제어할 수 있는 기술 중 하나입니다.

이 기능의 다른 이름으로는 .local, Dot Local, DotLocalDot Local 디버깅이 있습니다.

DLL 버전 관리 문제

애플리케이션이 공유 DLL의 특정 버전에 따라 달라지고 다른 애플리케이션이 해당 DLL의 최신 또는 이전 버전과 함께 설치되는 경우 호환성 문제와 불안정성이 발생할 수 있습니다. 앱이 실패하기 시작할 수 있습니다.

DLL 로더는 호출 프로세스가 다른 파일 시스템 위치를 보기 전에 실행 파일의 폴더에서 로드된 폴더를 찾습니다. 따라서 한 가지 해결 방법은 앱에 필요한 DLL을 실행 파일의 폴더에 설치하는 것입니다. 이는 DLL을 효과적으로 비공개로 만듭니다.

그러나 COM의 문제는 해결되지 않습니다. 호환되지 않는 두 버전의 COM 서버를 설치하고 등록할 수 있지만(다른 파일 시스템 위치에서도) COM 서버를 등록할 수 있는 곳은 하나뿐입니다. 따라서 등록된 최신 COM 서버만 활성화됩니다.

리디렉션을 사용하여 이러한 문제를 해결할 수 있습니다.

프라이빗 이진 파일 로드 및 테스트

DLL 로더가 따르는 규칙은 시스템 DLL이 Windows 시스템 위치(예: 시스템 폴더)%SystemRoot%\system32에서 로드되도록 합니다. 이러한 규칙은 악의적 사용자가 작성할 수 있는 위치에 작성한 코드를 배치한 다음 일부 프로세스를 로드하고 실행하도록 설득하는 등 공격을 심지 않습니다. 그러나 로더의 규칙을 실행하려면 시스템을 업데이트해야 하므로 OS 구성 요소에서 작업하기가 더 어려워집니다. 그리고 그것은 매우 영향력 있는 변화입니다.

그러나 리디렉션을 사용하여 DLL의 프라이빗 복사본을 로드할 수 있습니다(예: 테스트 또는 코드 변경의 성능 영향 측정).

공용 WindowsAppSDK GitHub 리포지토리의 소스 코드에 기여하려면 변경 내용을 테스트해야 합니다. 또한 리디렉션을 사용하여 Windows 앱 SDK 함께 제공되는 버전 대신 DLL의 프라이빗 복사본을 로드할 수 있는 시나리오입니다.

옵션

실제로 앱에서 원하는 DLL 버전을 사용하도록 하는 두 가지 방법이 있습니다.

  • DLL 리디렉션. 자세한 내용은 이 항목을 계속 읽어보세요.
  • 병렬 구성 요소입니다. 격리된 애플리케이션 및 병렬 어셈블리 항목 에 설명되어 있습니다.

개발자 또는 관리자인 경우 기존 애플리케이션에 대해 DLL 리디렉션을 사용해야 합니다. 앱 자체를 변경할 필요가 없기 때문입니다. 그러나 새 앱을 만들거나 기존 앱을 업데이트하는 경우 잠재적인 문제로부터 앱을 격리하려면 나란히 구성 요소를 만듭니다.

선택 사항: 레지스트리 구성

컴퓨터 전체에서 DLL 리디렉션을 사용하도록 설정하려면 새 레지스트리 값을 만들어야 합니다. 키 HKLM\Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options아래에 DevOverrideEnable이라는 이름의 DWORD 값을 만듭니다. 값을 1로 설정하고 컴퓨터를 다시 시작합니다. 또는 아래 명령을 사용하고 컴퓨터를 다시 시작합니다.

reg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options" /v DevOverrideEnable /t REG_DWORD /d 1

해당 레지스트리 값을 설정하면 앱에 애플리케이션 매니페스트가 있더라도 DotLocal DLL 리디렉션이 적용됩니다.

리디렉션 파일 또는 폴더 만들기

DLL 리디렉션을 사용하려면 이 항목의 이후 섹션에서 볼 수 있듯이 리디렉션 파일 또는 리디렉션 폴더(있는 앱의 종류에 따라 다름)를 만듭니다.

패키지된 앱에 대한 DLL을 리디렉션하는 방법

패키지된 앱에는 DLL 리디렉션을 위한 특별한 폴더 구조가 필요합니다. 다음 경로는 리디렉션을 사용할 때 로더가 표시되는 위치입니다.

<Drive>:\<path_to_package>\microsoft.system.package.metadata\application.local\

파일을 편집 .vcxproj 할 수 있는 경우 패키지와 함께 특수 폴더를 만들고 배포하는 편리한 방법은 다음의 빌드에 몇 가지 추가 단계를 추가하는 것입니다 .vcxproj.

<ItemDefinitionGroup>
    <PreBuildEvent>
        <Command>
            del $(FinalAppxManifestName) 2&gt;nul
            <!-- [[Using_.local_(DotLocal)_with_a_packaged_app]] This makes the extra DLL deployed via F5 get loaded instead of the system one. -->
            if NOT EXIST $(IntDir)\microsoft.system.package.metadata\application.local MKDIR $(IntDir)\microsoft.system.package.metadata\application.local
            if EXIST "&lt;A.dll&gt;" copy /y "&lt;A.dll&gt;" $(IntDir)\microsoft.system.package.metadata\application.local 2&gt;nul
            if EXIST "&lt;B.dll&gt;" copy /y "&lt;B.dll&gt;" $(IntDir)\microsoft.system.package.metadata\application.local 2&gt;nul
        </Command>
    </PreBuildEvent>
</ItemDefinitionGroup>
<ItemGroup>
    <!-- Include any locally built system experience -->
    <Media Include="$(IntDir)\microsoft.system.package.metadata\application.local\**">
        <Link>microsoft.system.package.metadata\application.local</Link>
    </Media>
</ItemGroup>

해당 구성이 수행하는 몇 가지 작업을 살펴보겠습니다.

  1. 디버깅하지 않고 Visual Studio 시작(또는 디버깅 시작) 환경을 설정합니다PreBuildEvent.

    <ItemDefinitionGroup>
      <PreBuildEvent>
    
  2. 중간 디렉터리에 올바른 폴더 구조가 있는지 확인합니다.

    <!-- [[Using_.local_(DotLocal)_with_modern_apps]] This makes the extra DLL deployed via Start get loaded instead of the system one. -->
    if NOT EXIST $(IntDir)\microsoft.system.package.metadata\application.local MKDIR $(IntDir)\microsoft.system.package.metadata\application.local
    
  3. 로컬로 빌드한 DLL을 디렉터리에 복사합니다(시스템 배포 DLL을 기본 설정으로 application.local 사용하려는 경우). 어디서나 DLL을 선택할 수 있습니다(사용 가능한 매크로를 .vcxproj사용하는 것이 좋습니다). 이 프로젝트가 수행되기 전에 해당 DLL이 빌드되는지 확인합니다. 그렇지 않으면 누락됩니다. 여기에 두 개의 템플릿 복사 명령이 표시됩니다. 필요한 만큼 사용하고 자리 표시자를 편집 <path-to-local-dll> 합니다.

      if EXIST "<path-to-local-dll>" copy /y "<path-to-local-dll>" $(IntDir)\microsoft.system.package.metadata\application.local 2&gt;nul
      if EXIST "<path-to-local-dll>" copy /y "<path-to-local-dll>" $(IntDir)\microsoft.system.package.metadata\application.local 2&gt;nul
      </Command>
    </PreBuildEvent>
    
  4. 마지막으로 배포된 패키지에 특수 디렉터리 및 해당 콘텐츠를 포함하도록 지정합니다.

    <ItemGroup>
      <!-- Include any locally built system experience -->
      <Media Include="$(IntDir)\microsoft.system.package.metadata\application.local\**">
        <Link>microsoft.system.package.metadata\application.local</Link>
      </Media>
    </ItemGroup>
    

여기에 설명된 접근 방식(중간 디렉터리 사용)은 소스 코드 제어 인리스트먼트 클린 유지하고 컴파일된 이진 파일을 실수로 커밋할 가능성을 줄입니다.

다음으로, 프로젝트를 (다시) 배포하기만 하면 됩니다. 클린 전체(다시) 배포를 얻으려면 대상 디바이스에서 기존 배포를 제거/클린 해야 할 수도 있습니다.

수동으로 이진 파일 복사

위에 표시된 방식으로 사용할 .vcxproj 수 없는 경우 몇 가지 간단한 단계를 통해 대상 디바이스에서 직접 동일한 끝을 달성할 수 있습니다.

  1. 패키지의 설치 폴더를 확인합니다. PowerShell에서 이 작업을 수행하려면 명령을 Get-AppxPackage실행하고 반환되는 InstallLocation찾습니다.

  2. 해당 InstallLocation 을 사용하여 폴더를 만들거나 파일을 복사할 수 있도록 ACL을 변경합니다. 이 스크립트에서 <InstallLocation> 자리 표시자를 편집하고 스크립트를 실행합니다.

    cd <InstallLocation>\Microsoft.system.package.metadata
    takeown /F . /A
    icacls  . /grant Administrators:F
    md <InstallLocation>\Microsoft.system.package.metadata\application.local
    
  3. 마지막으로 로컬로 빌드한 DLL을 수동으로 복사하고(시스템 배포 DLL을 기본 설정으로 사용하려는) application.local 디렉터리에 앱을 다시 시작합니다.

모든 항목이 작동했는지 확인

런타임에 올바른 DLL이 로드되고 있는지 확인하려면 디버거가 연결된 Visual Studio를 사용할 수 있습니다.

  1. 모듈 창을 엽니다(Windows>모듈 디버그>).
  2. DLL을 찾아서 경로시스템 배포 버전이 아니라 리디렉션된 복사본을 나타내는지 확인합니다.
  3. 지정된 DLL의 복사본 하나만 로드되어 있는지 확인합니다.

패키지되지 않은 앱에 대한 DLL을 리디렉션하는 방법

리디렉션 파일의 이름을 <your_app_name>.local지정해야 합니다. 따라서 앱 이름이 이 Editor.exe면 리디렉션 파일 Editor.exe.local의 이름을 지정합니다. 리디렉션 파일을 실행 파일의 폴더에 설치해야 합니다. 또한 실행 파일의 폴더에 DLL을 설치해야 합니다.

리디렉션 파일의 내용은 무시됩니다. 이 파일만 있으면 DLL 로더가 DLL을 로드할 때마다 먼저 실행 파일의 폴더를 검사. COM 문제를 완화하기 위해 해당 리디렉션은 전체 경로 및 부분 이름 로드에 모두 적용됩니다. 따라서 리디렉션은 COM 사례에서 발생하며 LoadLibrary 또는 LoadLibraryEx지정된 경로에 관계없이 발생합니다. 실행 파일의 폴더에서 DLL을 찾을 수 없는 경우 로드는 일반적인 검색 순서를 따릅니다. 예를 들어 앱 C:\myapp\myapp.exe 이 다음 경로를 사용하여 LoadLibrary를 호출하는 경우:

C:\Program Files\Common Files\System\mydll.dll

그리고 둘 다 C:\myapp\myapp.exe.localC:\myapp\mydll.dll 존재 하면 LoadLibrary 가 로드됩니다 C:\myapp\mydll.dll. 그렇지 않으면 LoadLibrary 가 로드됩니다 C:\Program Files\Common Files\System\mydll.dll.

또는 이름이 지정된 C:\myapp\myapp.exe.local 폴더가 있고 폴더가 mydll.dll포함된 경우 LoadLibrary가 로드됩니다.C:\myapp\myapp.exe.local\mydll.dll

DLL 리디렉션을 사용하고 있고 앱이 검색 순서의 모든 드라이브 및 디렉터리에 액세스할 수 없는 경우 액세스 가 거부되는 즉시 LoadLibrary 가 검색을 중지합니다. DLL 리디렉션을 사용하지 않는 경우 LoadLibrary는 액세스할 수 없는 디렉터리를 건너뛰고 검색을 계속합니다.

앱이 포함된 동일한 폴더에 앱 DLL을 설치하는 것이 좋습니다. DLL 리디렉션을 사용하지 않는 경우에도 해당합니다. 따라서 앱을 설치해도 DLL의 다른 복사본을 덮어쓰지 않으므로 다른 앱이 실패하게 됩니다. 또한 이 모범 사례를 따르는 경우 다른 앱은 DLL 복사본을 덮어쓰지 않으며 앱이 실패하지 않도록 합니다.