Windows에서 DLL 이름 해결의 메커니즘 - 검색 순서, Known DLLs, API set, SxS를 실무용으로 정리

· · Windows, DLL, 로더, 보안, Windows 개발

Windows에서 네이티브 DLL을 다루는 이야기가 되면, 꽤 높은 빈도로 다음과 같은 혼란이 일어납니다.

  • LoadLibrary("foo.dll")라고 썼을 때 실제로는 어디를 보러 가는가
  • 실행 파일과 같은 폴더에 두었는데 왜 다른 DLL이 로드되는가
  • System32가 우선인가, 앱 폴더가 우선인가
  • manifest나 API set이나 Known DLLs는 어느 단계에서 효과를 내는가
  • SetDllDirectoryAddDllDirectory를 쓰면 무엇이 달라지는가
  • DLL 심기 공격이나 DLL hijacking은 무엇을 하면 일어나기 쉬운가

이 이야기는 단순히 「검색 순서를 한 줄로 외운다」만으로는 실무에서 도움이 되지 않습니다.
실제로는 Windows의 로더는 파일시스템을 순서대로 훑기 전에, 몇 가지 특별 규칙을 먼저 평가합니다.

이 글에서는 Windows의 DLL 이름 해결을 unpackaged app과 packaged app의 차이, Known DLLs, loaded-module list, API set, side-by-side manifest, LoadLibraryEx 계 API의 영향까지 포함해 실무용으로 정리합니다.
내용은 2026년 3월 시점에 Microsoft Learn의 공개 정보를 전제로 합니다.123456789

1. 먼저 결론

실무용 결론만 먼저 나열하면 다음입니다.

  • Windows의 DLL 이름 해결은 「먼저 파일시스템 검색」이 아닙니다. DLL redirection, API set, SxS manifest, loaded-module list, Known DLLs 같은 요소가 검색 순서의 전단에 들어갑니다.1
  • unpackaged app에서 safe DLL search mode가 유효한 표준 형태에서는 애플리케이션 폴더는 상위에 있지만, 그 앞에 위의 특별 규칙이 평가됩니다.1
  • DLL을 풀패스 지정으로 로드해도 그 DLL의 의존 DLL까지 자동으로 같은 풀패스 고정이 되는 것은 아닙니다. 의존 DLL은 모듈 이름만으로 검색되는 취급이 되므로 다른 장소에서 해결되는 경우가 있습니다.1
  • Known DLLs는 OS가 기지의 특정 DLL을 시스템 쪽 사본에 묶는 구조로, 통상적인 앱 쪽 배치로 덮어쓰는 이야기가 아닙니다.1
  • API set은 「실체 DLL 이름 그 자체」가 아니라 구현 DLL을 은폐하는 가상 에일리어스입니다. api-ms-win-... 같은 이름을 보고 일반 DLL 검색과 같은 감각으로 생각하면 오해하기 쉽습니다.3
  • SetDllDirectory는 검색 순서를 바꿀 뿐만 아니라 safe DLL search mode를 실질적으로 무효화하는 동작을 가지므로, 안일하게 사용하면 보안 면에서 역효과가 될 수 있습니다.1
  • 실무에서는 풀패스 지정, SetDefaultDllDirectories, AddDllDirectory, LoadLibraryExLOAD_LIBRARY_SEARCH_* 플래그를 조합해 검색 범위를 명시적으로 좁히는 것이 안전합니다.4562

요컨대, Windows의 DLL 이름 해결은 「어느 폴더가 몇 번째인가」만이 아니라, 「이름을 무엇으로 해결할지에 대한 전단 규칙이 있는가」와 「API로 검색 공간을 어떻게 바꿨는가」로 정해진다고 생각하는 것이 실무적입니다.

2. DLL의 이름 해결은 「폴더 탐색」 앞에 전단 규칙이 있다

Microsoft Learn의 DLL search order 설명에서는, DLL의 로드 시에 먼저 다음과 같은 요소가 검색 순서의 일부로 다루어집니다.1

  1. DLL redirection
  2. API sets
  3. SxS manifest redirection
  4. loaded-module list
  5. Known DLLs

그 후에 app folder, System32, Windows 폴더, PATH 등의 파일시스템상의 탐색으로 들어갑니다.1

여기를 놓치면, 예를 들어 「앱 폴더보다 먼저 뭔가가 정해지는 것은 이상하다」고 느끼지만, Windows 로더의 설명으로서는 오히려 그쪽이 본류입니다.

flowchart TD
    A["DLL 이름을 해결하고 싶다"] --> B["DLL redirection"]
    B --> C["API set"]
    C --> D["SxS manifest redirection"]
    D --> E["loaded-module list"]
    E --> F["Known DLLs"]
    F --> G["파일시스템상의 검색 순서"]
    G --> H["실제로 로드될 DLL이 정해진다"]

3. unpackaged app의 표준 검색 순서

이른바 일반적인 데스크톱 앱에서 DLL을 풀패스 지정하지 않고 로드할 경우, Microsoft Learn에서는 unpackaged app의 표준 검색 순서가 설명되어 있습니다. safe DLL search mode가 유효한 기정 상태에서는 주로 다음 흐름입니다.1

  1. DLL redirection
  2. API sets
  3. SxS manifest redirection
  4. loaded-module list
  5. Known DLLs
  6. Windows 11 21H2 이후에서는 package dependency graph
  7. 애플리케이션이 로드된 폴더
  8. System32
  9. 16-bit system folder
  10. Windows folder
  11. current folder
  12. PATH

실무에서 특히 중요한 것은 다음입니다.

  • current folder는 기정에서는 꽤 뒤쪽입니다. safe DLL search mode에 의해 current folder를 앞으로 내보내기 어렵게 되어 있습니다.1
  • 다만 뒤에 있다고 안전하다는 뜻은 아닙니다. 공격자가 지배할 수 있는 디렉토리가 검색 대상에 남아 있는 시점에서 DLL preloading의 여지는 남습니다.2
  • Windows 11 21H2 이후에서는 unpackaged app의 검색 설명에도 package dependency graph가 들어가 있습니다. 오래된 설명만 기억하고 있으면 놓치기 쉬운 차이입니다.1

4. packaged app과 unpackaged app은 같지 않다

Microsoft Learn에서는 packaged app에 대해 별도의 검색 순서가 정의되어 있습니다. packaged app에서는 package dependency graph가 더 전단에서 효과를 내, 검색의 사고방식 자체가 조금 다릅니다.1

이 차이를 놓치면 MSIX화나 Windows App SDK 도입 후에 다음과 같은 혼란이 일어납니다.

  • 개발 중인 unpackaged 실행에서는 찾아지는 DLL이, 운영 package에서는 찾을 수 없다
  • package manifest에 의한 의존 관계와 옛날식의 PATH 의존이 섞여 재현 조건이 바뀐다
  • 「Windows의 DLL 검색 순서는 이렇다」고 단일 표만으로 설명해 버려 packaged app의 동작 차이를 놓친다

기사나 설계 리뷰에서는 「packaged app 이야기인가, unpackaged app 이야기인가」를 먼저 나누는 편이 안전합니다.1

5. Known DLLs와 loaded-module list는 무엇을 하고 있는가

DLL의 해결에서 직관에 반하기 쉬운 것이 loaded-module listKnown DLLs입니다.

5.1 loaded-module list

Microsoft Learn에서는 같은 모듈 이름의 DLL이 이미 메모리에 로드되어 있는지를 시스템이 확인할 수 있다고 설명되어 있습니다.1

즉, 파일시스템 검색 앞에

  • 그 DLL 이름은 이미 로드된 적이 없는가
  • 그 결과로서 지금부터 찾으러 갈 필요 자체가 있는가

라는 판정이 들어갑니다.

그래서 조사 중에 「이 프로세스에서는 다른 폴더의 동명 DLL이 먼저 로드되어 있었다」는 사실을 놓치면 재현 조건을 잘못 읽게 됩니다.

5.2 Known DLLs

Known DLLs는 Windows가 그 버전에서 기지로 간주하는 DLL의 목록으로, HKLM\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\KnownDLLs에서 확인할 수 있습니다. 해당하는 DLL이라면 시스템은 그 기지 DLL의 사본을 씁니다.1

여기서 중요한 것은 Known DLLs는 「일반 앱이 동명 DLL을 앱 폴더에 두면 이길 수 있다」 종류의 이야기가 아니라는 점입니다.
System32와의 단순한 선착 다툼으로 이해하면 동작을 오해합니다.

6. API set은 「실체 DLL 이름」이 아니라 계약 이름

api-ms-win-core-... 같은 이름을 보면 무심코 「그 DLL 파일을 어디에서 찾는가」라고 생각하기 쉽습니다. 그러나 Microsoft Learn에서는 API set은 물리 DLL에 대한 가상 에일리어스이며, 구현과 계약을 분리하는 구조라고 설명되어 있습니다.3

즉,

  • API set 이름 = 그대로 물리 DLL 파일 이름
  • API set의 해결 = 일반 DLL과 같은 파일 탐색

으로 생각하는 것은 부정확합니다.

API set의 사고방식을 넣어 두면,

  • Windows의 버전이나 디바이스 종별로 구현 DLL 이름이 달라도 정합된다
  • 호출 측은 「어느 호스트 DLL이 구현하고 있는가」를 고정으로 알지 않아도 된다

라는 설명이 쉬워집니다.3

7. manifest와 side-by-side (SxS)는 DLL versioning 문제에 대한 다른 해법

DLL redirection이나 SxS manifest는 단순한 검색 순서의 소기술이 아니라, DLL versioning의 충돌을 피하기 위한 구조로서 설명되어 있습니다.789

Microsoft Learn에서는,

  • manifest는 side-by-side assembly나 isolated application을 기술하는 XML
  • side-by-side assembly는 명명, binding, versioning, deployment의 단위
  • manifest에 기재된 의존 관계로 어느 버전에 bind할지를 로더가 판단

이라는 정리입니다.89

그래서 실무에서는 다음을 나누어 생각할 필요가 있습니다.

  • 단순히 private DLL을 app folder에 두는 이야기
  • .local 등의 DLL redirection을 쓰는 이야기
  • manifest에 의한 side-by-side binding을 쓰는 이야기

어느 것이나 「DLL의 해결에 영향을 준다」는 점에서는 가깝지만 설계 의도는 같지 않습니다.

8. LoadLibraryEx, SetDllDirectory, AddDllDirectory로 무엇이 바뀌는가

8.1 SetDllDirectory

SetDllDirectory는 검색 순서를 바꾸지만, Microsoft Learn에서는 safe DLL search mode를 실질적으로 무효화한다고 명기되어 있습니다.1

즉, 「앱 전용 폴더를 하나 더하고 싶을 뿐」의 의도로 써도, 결과적으로 current folder의 취급 등을 포함한 검색 공간이 바뀝니다.

나아가 부모 프로세스에서 SetDllDirectory를 호출하면 그 영향이 자식 프로세스 측의 표준 검색 순서에까지 미치는 경우가 있습니다.1

그래서 실무에서는 SetDllDirectory를 대충 상용하기보다,

  • SetDefaultDllDirectories
  • AddDllDirectory
  • LoadLibraryExLOAD_LIBRARY_SEARCH_*

쪽으로 치우치는 것이 안전합니다.456

8.2 AddDllDirectory

AddDllDirectory로 추가한 패스는 LOAD_LIBRARY_SEARCH_USER_DIRS와 조합해 사용합니다.
Microsoft Learn에서는 복수 추가한 경우의 검색 순서는 미규정입니다.15

즉,

  • 복수 디렉토리를 추가했다
  • 그 탐색 순서까지 엄밀하게 기대했다

는 설계는 피하는 편이 좋습니다.

8.3 SetDefaultDllDirectories

SetDefaultDllDirectories는 표준의 DLL search path에서 취약해지기 쉬운 디렉토리를 빼고, 검색 대상을 한정하기 위한 API로 설명되어 있습니다.4

특히 중요한 것은 다음입니다.

  • 프로세스 단위로 효과
  • 호출 후에는 프로세스의 수명 중 지속
  • 한 번 설정한 표준 검색 패스를, 그대로 원래의 표준형으로 되돌릴 수 없다

보안 면을 생각하면 「기동 직후에 안전 쪽의 검색 공간으로 치우친다」라는 설계가 취하기 쉬운 API입니다.4

8.4 LoadLibraryEx

LoadLibraryExLOAD_WITH_ALTERED_SEARCH_PATHLOAD_LIBRARY_SEARCH_* 플래그로 검색 동작을 바꿀 수 있습니다.61

실무적으로는,

  • 의존 DLL을 포함해, 로드 원 DLL의 폴더도 탐색 대상으로 하고 싶다
  • 앱 폴더, System32, 명시 추가한 사용자 디렉토리만으로 좁히고 싶다

같은 요구에 대응하기 쉬운 API입니다.

9. 풀패스 지정해도 의존 DLL까지는 고정되지 않는다

이 주제에서 실무상 꽤 중요한데 놓치기 쉬운 것이 이것입니다.
Microsoft Learn에서는 처음 DLL을 풀패스 지정으로 로드해도, 그 DLL의 의존 DLL은 모듈 이름만으로 검색된다고 설명되어 있습니다.14

즉,

  • C:\\MyApp\\plugins\\foo.dll을 명시 로드했다
  • 그래서 foo.dll이 의존하는 bar.dll도 같은 폴더에서 반드시 취해진다

고는 할 수 없습니다.

이 오해가 있으면,

  • 개발 환경에서는 동작한다
  • 배포 대상에서는 다른 bar.dll이 해결된다
  • 의존 DLL의 충돌이 재현 환경 의존이 된다

는 조금 까다로운 장애가 됩니다.

10. DLL preloading / hijacking을 피하려면

Microsoft Learn의 DLL security에서는 풀패스 없는 동적 로드와, 공격자가 지배할 수 있는 검색 대상 디렉토리의 조합이 DLL preloading attack이나 binary planting attack으로 이어진다고 설명되어 있습니다.2

실무에서는 다음을 기본으로 하면 정리하기 쉽습니다.

  • LoadLibrary("foo.dll") 같은 맨 이름 로드를 줄인다
  • 필요하다면 풀패스 지정을 쓴다
  • 프로세스 기정의 검색 패스를 SetDefaultDllDirectories로 좁힌다
  • 명시적으로 허가한 디렉토리만 AddDllDirectory로 추가한다
  • LOAD_LIBRARY_SEARCH_SYSTEM32, LOAD_LIBRARY_SEARCH_APPLICATION_DIR, LOAD_LIBRARY_SEARCH_USER_DIRS 등을 써서 탐색 범위를 명시한다
  • current folder나 부주의한 PATH 의존을 피한다

특히 관리자 권한으로 도는 프로세스가 애매한 검색 패스를 가지는 상황은 위험합니다. Microsoft Learn에서도 악의 있는 DLL이 로드되면 그 DLL은 그 프로세스의 권한으로 실행된다고 설명되어 있습니다.2

11. 실무에서의 판단 체크리스트

Windows에서 DLL 로드 설계를 리뷰할 때는 최소한 다음을 확인하면 사고가 줄어듭니다.

  1. 그 앱은 packaged app인가 unpackaged app인가
  2. 어느 DLL이 정적 링크 유래이고, 어느 것이 동적 로드인가
  3. 풀패스 지정인가, 모듈 이름만인가
  4. SetDllDirectory를 쓰고 있지 않은가
  5. SetDefaultDllDirectoriesLOAD_LIBRARY_SEARCH_*를 쓸 수 있는 구성인가
  6. AddDllDirectory를 복수 사용하며 순서 의존을 암묵적으로 기대하고 있지 않은가
  7. manifest / SxS / private DLL / redirection 중 어느 것으로 의존 관계를 관리하고 있는가
  8. current folder나 PATH에 보안상 약한 전제가 없는가
  9. 의존 DLL이 다른 환경에서 다른 장소에서 해결되지 않는가

이 9점을 나누어 확인하면, 「DLL이 찾아지지 않는다」 「다른 DLL이 읽혔다」 「운영에서만 기동되지 않는다」 「취약점 리뷰에서 멈춘다」 같은 문제를 꽤 전단에서 미리 없앨 수 있습니다.

12. 정리

Windows에서의 DLL 이름 해결은 단순한 「폴더의 탐색 순서」가 아닙니다.
실제로는 DLL redirection, API set, SxS manifest, loaded-module list, Known DLLs, 그리고 API 호출로 변경되는 검색 공간이 겹쳐 정해집니다.134

실무에서 가장 중요한 것은 다음입니다.

  • 검색 순서를 한 장의 표로 암기하지 않는다
  • packaged / unpackaged를 나눈다
  • 풀패스 지정이어도 의존 DLL은 별도 취급이 될 수 있다는 것을 이해한다
  • SetDllDirectory를 안일하게 쓰지 않는다
  • 안전 쪽으로 치우친다면 SetDefaultDllDirectoriesLoadLibraryEx의 검색 플래그를 쓴다

DLL 이름의 해결은 기동 장애, 환경 차이, 보안 문제가 한꺼번에 표면화되기 쉬운 장소입니다.
그래서야말로 「Windows가 어느 순서로 찾는가」뿐만 아니라, 「Windows가 애초에 무엇을 이름 해결의 전제로 다루고 있는가」까지 이해해 둘 가치가 있습니다.

References

  1. Microsoft Learn: Dynamic-link library search order
  2. Microsoft Learn: Dynamic-Link Library Security
  3. Microsoft Learn: Windows API sets
  4. Microsoft Learn: SetDefaultDllDirectories function
  5. Microsoft Learn: AddDllDirectory function
  6. Microsoft Learn: LoadLibraryEx function
  7. Microsoft Learn: Dynamic-link library redirection
  8. Microsoft Learn: Manifests
  9. Microsoft Learn: About Side-by-Side Assemblies
  1. Microsoft Learn, “Dynamic-link library search order”, accessed March 24, 2026, https://learn.microsoft.com/en-us/windows/win32/dlls/dynamic-link-library-search-order  2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21

  2. Microsoft Learn, “Dynamic-Link Library Security”, accessed March 24, 2026, https://learn.microsoft.com/en-us/windows/win32/dlls/dynamic-link-library-security  2 3 4 5

  3. Microsoft Learn, “Windows API sets”, accessed March 24, 2026, https://learn.microsoft.com/en-us/windows/win32/apiindex/windows-apisets  2 3 4 5

  4. Microsoft Learn, “SetDefaultDllDirectories function”, accessed March 24, 2026, https://learn.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-setdefaultdlldirectories  2 3 4 5 6 7

  5. Microsoft Learn, “AddDllDirectory function”, accessed March 24, 2026, https://learn.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-adddlldirectory  2 3 4

  6. Microsoft Learn, “LoadLibraryEx function”, accessed March 24, 2026, https://learn.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexa  2 3 4

  7. Microsoft Learn, “Dynamic-link library redirection”, accessed March 24, 2026, https://learn.microsoft.com/en-us/windows/win32/dlls/dynamic-link-library-redirection  2

  8. Microsoft Learn, “Manifests”, accessed March 24, 2026, https://learn.microsoft.com/en-us/windows/win32/sbscs/manifests  2 3

  9. Microsoft Learn, “About Side-by-Side Assemblies”, accessed March 24, 2026, https://learn.microsoft.com/en-us/windows/win32/sbscs/about-side-by-side-assemblies-  2 3

같은 태그를 공유하는 최신 기사입니다. 더 가까운 주제로 지식을 넓힐 수 있습니다.

이 기사와 가까운 토픽 페이지입니다. 기사를 출발점 삼아 관련 서비스와 다른 기사로 이어집니다.

이 기사는 다음 서비스 페이지로 이어집니다. 가까운 입구부터 확인해 주세요.

저자 프로필

기사 저자의 프로필 페이지입니다.

Go Komura

합동회사 코무라소프트 대표

Windows 소프트웨어 개발, 기술 상담, 장애 조사를 중심으로 재현이 어려운 장애 조사와 기존 자산이 남아 있는 프로젝트에 강점이 있습니다.

블로그 목록으로 돌아가기