뭉근 : 느긋하게 타는 불

1. vmware를 이용한 드라이버 디버깅 방법

데브구루의 기술 칼럼을 따라했는데 잘 되지 않았다.

프로젝트 생성한 후, 호스트가 윈도우 7 x64이고 타겟이 가상머신 윈도우 7 x86인 환경에서

디버깅 환경 설정을 진행하였는데 드라이버 컴파일 후 가상 머신으로 전송하고 Driver Install 하는 부분에서 막혔다.

이후 타겟을 윈도우 8.1 x64로 변경하였는데 잘되었다.

컴파일 설정은 당연히 바꾸고 했는데 이상했다... 

아무튼 디버깅을 해보니 타겟으로 Driver Install 하는데 시간도 오래 걸리고 디버깅하는데도 버벅 거렸다.

간단한 제작에는 DbgPrint 등으로 디버깅하는게 더 빠르겠다.


참고
http://devguru.co.kr/blog/6619/

https://msdn.microsoft.com/en-us/library/windows/hardware/hh439654(v=vs.85).aspx



2. WinDbg에 DbgPrint 출력하기

DbgPrint 출력 전에 WinDbg 커맨드 라인에 아래와 같이 해주면 된다.

kd> ed Kd_DEFAULT_MASK 8


3. 커널 페이지 메모리 보호 해제

MDL을 사용하여 페이지 메모리 보호 해제를 하려다 

예전에 공부한 CR0 레지스터 변경을 찾아서 적용했더니 바로 되었다.

짬내어 MDL 공부도 해놓아야겠다.


참고 

http://resources.infosecinstitute.com/hooking-system-service-dispatch-table-ssdt/


4. 드라이버 로드 & 언로드 1

윈도우 서비스 메니저(SCM)을 이용하여 로드까진 진행이 잘 되었는데

드라이버를 언로드하려 할 때 아래 코드에서 자꾸 에러가 났다.

ControlService(service, SERVICE_CONTROL_STOP, &ss)

알고보니 드라이버 언로드 루틴이 없어서 그런거였다.

또는 MJ_IRP_CLOSE 루틴인가? .. 사실 언로드 루틴과 클로즈 루틴을 다 넣어놨다.

뭐 때문인지는 테스트해봐야겠지만 일단 그냥 둔다.


참고

https://msdn.microsoft.com/en-us/library/windows/desktop/ms682571(v=vs.85).aspx


5. 드라이버 로드 & 언로드 2

이번엔 드라이버가 처음에는 잘 로드되는데

처음 로드한 드라이버를 언로드 후 다시 로드하면 시스템 에러 0x02가 났다.

확인해보니 디바이스 생성 후 삭제를 안해서 

커널에 똑같은 이름의 디바이스가 남아있었다.

드라이버 언로드 루틴에 디바이스 오브젝트 삭제 코드를 추가하였다.


실행 상태(SERVICE_RUNNING)인 드라이버를 언로드하기 위해서는 반드시

QueryServiceStatusEx를 호출하여 서비스 실행 상태를 얻고

실행 중이면 ControlService를 이용해 중지 명령을 내려야 한다.

(일부 드라이버는 delete pending에 들어가 재부팅 후에만 제대로 언로드가 될 수 있다.)


참고

IOCTL 예제 코드(https://code.msdn.microsoft.com/IOCTL-a583bbeb?SRC=VSIDE)

* VS2013에서는 New Project 다이얼로그의 Online - Samples에서 바로 컴파일 가능한 형태로 다운받을 수 있다.


6. 디바이스 핸들 얻기

CreateFile을 이용하여 디바이스 핸들을 얻기 위해서 드라이버에 반드시 추가해야할 코드가 있다.

첫번째는 IoCreateDevice, IoCreateSymbolicLink, IoDeleteSymbolicLink, IoDeleteDevice 함수 셋이다.

이 함수들이 뭐냐하면 디바이스를 생성하고 생성한 디바이스에 대해 유저 영역(Win32)에서 디바이스로 접근할 수 있는 이름을 생성하는 것이다.

IoCreateDevice에서 인자로 넣어주는 이름은 디바이스 이름이고, IoCreateSymbolicLink에서 넣어주는 이름은 유저 핸들 이름(?)이라 할 수 있겠다.

꼭 이렇게 해주고 드라이버 언로드 루틴에서 디바이스와 심볼릭 링크를 삭제해야 다음 로드시 드라이버 로드가 된다.

두번째는 IPR_MJ_CREATE와 IRP_MJ_CLOSE이다. 이 함수가 드라이버에 등록되지 않으면 CreateFile로 핸들 생성 자체가 안된다.

예전에 디폴트 커널 코드가 있다고 알고 있었는데 없어졌나 싶다.

(IRP_MJ_CLOSE는 아닐 수도 있다... 테스트할 시간이 없다.)


0. 드라이버 개발에 좋은 도구들

devicetree : 디바이스가 제대로 등록되어 있는지 확인할 수 있다.

osrloader : 등록한 드라이버가 서비스에 등록되어 있는지 확인할 수 있다.

winobj : 디바이스와 디바이스의 심볼릭 링크가 있는 전역이름공간(\\??\, 즉 \\.\)을 확인할 수 있다.


계속 추가 예정이다.

'프로그래밍' 카테고리의 다른 글

PsSetCreateProcessNotifyRoutineEx 접근 권한 문제  (1) 2016.05.10
Rstudio 3.3.0 스케일링 문제  (0) 2016.05.06
ofstream 한글 출력 문제  (0) 2014.10.22
ifstream 64  (0) 2014.09.25
CPP 벡터 반복문 중 원소 지우기  (0) 2014.09.22

들어가며

그냥 MS 심볼 정보를 얻어야 될 일이 있어서 여차저차 알아보다 보니까 그 동안 모르고 넘겼던 MS 심볼 디렉터리에 생기는 폴더 이름들에 대해 알게되었다. 알고보니까 직접 배포할 때도 이런 형식을 맞춰야 하는거 같다.

   

MS 심볼 폴더 구성

MS 심볼 폴더 구성은 크게 PE 파일에 대한 폴더pdb 파일에 대한 폴더 두 가지로 나뉜다. 우선 PE 파일 폴더 구성은 아래와 같다.

   

"%s\%s\%s%s\%s" % (serverName, peName, timeStamp, imageSize, peName)

   

딱 보면 이게 무슨 말인지 아시는 분들도 있고 모르시는 분들도 있겠다. 일단 아래의 사례를 통해 이해해보도록 하겠다.

   

   

위 심볼 정보는 MS 심볼 패키지 모음에서 다운받은 Windows 8.1 심볼 패키지 중 하나이다. ntoskrnl.exe는 심볼 서버의 저장된 PE 파일이다. 경로를 그려보면

"~\WebSymbols\ntoskrnl.exe\52341CF4781000\ntoskrnl.exe" 라 할 수 있다.

여기서 serverName은 WebSymbols로 심볼 정보를 설치한 폴더 이름이고, peName은 그대로 ntoskrnl.exe이다. 그다음 timeStamp + imageSize가 섞인 것을 볼 수 있는데 이는 해당 헥스값을 문자열로 표현한 것이다. timeStamp + imageSize 폴더 하위에는 다시 peName으로 PE 파일이 있다. 이 timeStamp와 imageSize 값은 dumpbin같은 PE 도구를 확인하여 확인할 수 있다.

   

   

자동화를 한다면 하드 코딩하거나 아래 정도로 사용하면 될 거 같다.

   

   

(텍스트)

~\WebSymbols\ntoskrnl.exe\52341CF4781000>dumpbin.exe ntoskrnl.exe /headers | grep "date stamp\|size of image"

52341CF4 time date stamp Sat Sep 14 17:23:16 2013

781000 size of image

   

   

확인하면 폴더명이 [52341CF4 + 781000] 인 것을 확인할 수 있다.

   

다음으로 pdb 파일에 대한 폴더인데 이 pdb 파일은 PE 파일에 대한 디버깅 정보를 포함하는 파일이다. pdb 파일은 아래와 같은 구성을 따른다.

   

"%s\%s\%s%s\%s" % (serverPath, pdbName, guid, age, pdbName)

   

여기서 guid는 PE 파일의 Directory 중 Debug Directory에서 찾아볼 수 있으나 왠만한 PE 도구에서는 GUID까지 보여주지 않는다. VC에서 포한하는 도구인 dumpbin을 이용하여 찾아볼 수 있다.

   

   

(텍스트)

~\WebSymbols\ntoskrnl.exe\52341CF4781000>dumpbin.exe ntoskrnl.exe /headers | grep "Format:"

52341CF4 cv 25 0001AFF0 1A5F0 Format: RSDS, {FD3D00D2-8EDC-4527-BB92-2BCC0509D285}, 1, ntkrnlmp.pdb

   

RSDS 다음에 나오는 헥스 문자열과 그 뒤에 오는 숫자(여기선 1)이 바로 GUID와 age이다. 또한 PDB 파일의 이름이 ntkrnlmp.pdb라고 친절하게 나와있다. 위의 폴더 구성을 통해 파일의 위치를 찾아보면 아래와 같은 폴더를 찾을 수 있다. 여기서 age란 incremental build를 사용하여 컴파일하면 초기값 1부터 시작하여 증가한다고 한다.

   

~\WebSymbols\ntkrnlmp.pdb\FD3D00D28EDC4527BB922BCC0509D2851\ntkrnlmp.pdb

   

   

근데 왜 PE 파일과 pdb 파일명이 서로 다를까? 생각해봤지만. 음… 뭐 MS의 마음이니까 라고 결론을 내렸다. 뭐 위와 같은 심볼 폴더 구성을 알면 뭐가 좋냐 하면 PE 파일명과 PDB 파일명이 달라 디버깅하지 못하는 이런 사태를 피할 수 있다.

   

마치며

내가 하고 싶은건 모든 ntoskrnl.exe의 모든 버전에 대한 심볼 정보를 얻어오는 것인데.. :(

뭐 이런 것도 정리해 놓으면 도움이 되겠지 생각한다.

참고

<Symbols the Microsoft Way, https://randomascii.wordpress.com/2013/03/09/symbols-the-microsoft-way/>

   

2015.03.13 추가.

ntoskrnl.exe는 윈도우 업데이트 폴더(ex. WinSxS)에서 구할 수 있다. 이 폴더는 그 동안 업데이트된 파일들을 저장한다.

그러나 모든 버전의 ntoskrl.exe는 구할 수 없다. 아마도 언어마다 업데이트가 다른 것도 있어서? 인거 같다. GRR 도구 참고.

'배려'의 명언

생활2014. 11. 24. 21:12

자네는 스스로에게 솔직한 적 있었는가?

지금의 자신을 인정하지 않다 보니 자꾸 허상만을 좇게 되는 거야.

그래서 박탈감을 느끼고 남의 탓만 하는 거지.

지금 처한 현실이 어렵다면, 대가를 치르고 있다고 생각하게.

내가 선택하지 않은 인생은 없지.

모든 것은 스스로 선택한 데 따른 결과물이야.

과거의 잘못된 선택에 대한 대가를 치르는 것이지.

그걸 솔직하게 인정해야 하네.

그게 행복의 첫 번째 조건이야.

자신에게 솔직해져야 마음이 편안해지고 행복을 받아들일 준비가 되는 거야.

행복은 추구해야 할 목표가 아니야 행복은 삶의 과정에서 언제든 찾아낼 수 있는 것이지.”

 

내가 주도해서 했건 남이 주도하는 걸 따랐건 결국 내가 선택한거다. 이건 나의 책임이다. 인정하자.