LoadLibraryEx 함수는 플래그 인자를 통해 여러 형태로 모듈을 메모리로 로드할 수 있다.

그 중에 LOAD_LIBRARY_AS_DATAFILE 플래그를 사용하면 파일 형태로 메모리에 모듈을 로드시킬 수 있다.


오늘 저 함수를 사용해 특정 코드를 작성 중 원치 않은 결과가 나와 당황을 하였다.

리버싱을 하면서도 저 플래그를 사용해 작업하는걸 많이 봐왔고 다른 오픈소스에서도 많이 사용하는 것을 봐왔는데 왜 이제서야 이 문제가 인식이 되었는지 이해가 되질 않는다.


아무튼 내가 겪은 문제는 다음과 같다.



함수 호출은 성공하였는데 리턴 값이 이상하다. MZ로 시작하는 메모리 위치를 리턴(0x30000)해줘야하는데 0x30001 이 리턴된 것이다. 음? 저 1은 뭐지?


난 아무것도 하지 않았는데 리턴 값이 저런다는건 MS 버그인가? 하지만 저런 문제가 모든 사람들한테 발생을 했으면 MS는 진작에 고쳤을 것이다. 하지만 내 코드 상에도 저 리턴 결과에 따른 황당함을 해결해줄 만한 부분은 없다... -_-;


일단 크게 시간 걸릴 것 같지 않아 그냥 LoadLibraryEx 내부를 살펴보았다.


Windows 7 x64 환경에서 wow64를 탄 환경에서 분석하였다. (windows 7 x86과 같은 환경..)


LoadLibraryEx를 함수에 LOAD_LIBRARY_AS_DATAFILE 플래그를 주고 호출하면


kernelbase!BasepLoadLibraryAsDataFile 를 내부적으로 호출한다. 그 다음엔

kernelbase!BasepLoadLibraryAsDataFileInternal 함수 호출이 된다.


BasepLoadLibraryAsDataFileInternal 함수 내부에서는

CreateFileW로 디스크 상에 있는 모듈의 파일 핸들을 얻고

CreateFileMappingW와 NtMapViewOfSection 함수를 사용해 메모리로 해당 내용을 맵핑시킨다.

그리고 이 때 NtMapViewOfSection 함수가 리턴한 값은 0x30000 이다! 여기까진 정상이다.


그리고 그 아래 코드는 다음과 같다.



NtMapViewOfSection 다음 코드이다.

빨간색 네모 친 부분을 보면 BaseAddress(0x30000)에 "or 1"을 하고 있다.

저 부분 때문에 0x30000 값이 0x30001로 변경이 되고 저 값이 변화 없이 리턴이 되버린다.

저 코드 후에 값 변화는 없지만 ntdll에서 관리하는 LoadAsDataTable 이라는 공간에 데이터가 추가 된다. 

이 때 호출되는 함수는 ntdll의 LdrAddLoadAsDataTable이다.


일단 다시 살펴보면 "or" 연산을 한다는 것은 뭔가 플래그를 셋팅하는 동작으로 보인다.

만약 카운터 값을 나타내고 이를 증가하는 동작이었다면 add나 inc 명령어가 사용되었을 것이다.

근데 NtMapViewOfSection 에서 리턴하는 값은 MZ를 가리키는 메모리라는 것을 뻔히 알면서 왜 그 값에 플래그를 셋팅하는 걸까? 어디서 사용하려고? 근데 왜 플래그를 셋팅했으면 반환할 땐 다시 0x30000으로 만들어 줘야지 왜 그대로 리턴을 하는 것일까? 궁금하다.... 진짜로 MS 버그라고 생각하지는 않는다. 하지만 내 쪽 버그도 아니다.


구글링 결과 한국 블로그에는 나와 같은 현상을 겪은 내용을 포스팅한 사람이 없다.

이것저것 찾아본 결과 설명이 나와있는 글이 있었다.


일반적인 HINSTANCE의 하위 16bit는 항상 0이다. 하지만 다른 구성요소는 다른 목적을 위해 하위 16bit를 사용해야했다. 커널은 하나의 큰 블럭으로 맵핑된 섹션을 메모리에 맵핑되어 로드된 모듈을 구별하기 위해 하위 비트를 사용한다(datafile로서 로드된 경우). 이는 다양한 리소스 관리 함수들(FindResource 함수와 같은)이 어떻게 해당 리소스를 찾기위해 데이터를 해석할지 알기 위해 필요하다. 비록 HINSTANCE가 DLL의 기준 주소라는 것을 알고 있지만, 원칙적으론, 이는 알지못하는 값이다. (16bit 세계에서는 실제로 이 값은 알수가 없다)


이 설명을 보면 해당 값은 플래그가 맞는거 같고 해당 플래그는 리소스 관련 함수들을 사용할 때 커널에서 로드된 모듈들이 어떤 속성으로 로드되었는지 구분하기 위해 사용되는 것 같다.


..... 음.. 그래도 왜 MS가 LoadLibraryEx에서 플래그가 셋팅된 값을 리턴해주는지 모르겠다. 진짜로..

그냥 VirtualAlloc + CreateFile + ReadFile 조합을 사용해야겠다.


왜 저런 결과가 나오는지 아시는 분은 한 수 가르쳐 주십시요. ( _ _ )

Posted by Ezbeat