얼마전에 한 독자로부터 메일을 받았다. “실전 윈도우 디바이스 드라이버”책의 7장에서 다루는 예재를 동작시켜야 하는데 잘 동작하지 않는다는 내용의 메일이었다.

 

7장에서 소개하는 예재는, 윈도우 탐색기에서 프로그램을 실행할 때, 해당하는 프로그램이 실행되지 않도록 강제로 방어하는 방법을 소개하는 예재가 포함되어 있다.

본 책에 513 페이지, “후킹할 오프셋을 구하자”에서 NtCreateUserProcess 커널함수의 시작부분을 가로채는 내용을 소개하고 있다. 해당하는 함수는 Export 함수가 아니라, 커널내부에서 전역으로 사용되는 전역함수이기 때문에 외부에서 이 함수의 주소를 직접 알기는 어렵다.

또한, 해당하는 커널함수의 주소를 알았다고 하더라도, 커널의 버전이 바뀌면 이 또한 무용지물이 될 수밖에 없다.

이번에 독자가 메일을 보낸 내용을 확인하고, 실제로 예재를 동작시켜보았더니 정말로 드라이버서비스가 정상동작을 하지 않는 것을 알 수 있었다.

MAIN.C 소스코드의 1848 라인에 코드에서 문제가 발생했다.

bSuccess = internal_Check_processCreateProcessHook();

// CreateUserProcess코드를후킹할수있는지를확인한다

if (bSuccess == FALSE)

{

return STATUS_UNSUCCESSFUL;

}

이 곳에서는 현재 커널코드내에 NtCreateUserProcess 함수의 주소를 찾아서 후킹할 수 있는 상황인지를 확인하는 작업이 들어가 있다. 필자가 이 글을 쓸 때 당시의 Windows 7 커널(32비트)에서는 문제가 없던 상황이어지만, 최근에 패치된 Windows 7 커널에서는 이 함수가 에러를 리턴한다.

이유는 NtCreateUserProcess 커널함수의 시작위치가 달라졌기 때문이다.

 

MAIN.C 소스코드의 1797 라인에 코드를 다음과 같이 수정해야 한다.

#define WIN7_32_CREATEUSERPROCESSOFFSET

((ULONG_PTR)0x00000000002733D6)

// Kernel Version 7601.19018.x86fre.win7sp1_gdr.150928-1507

//((ULONG_PTR)0x000000000026F3CD)

원래 이 상수값은 0x26F3CD 값을 가져야 했다. 하지만, 최근 패치된 커널에서는 위와 같이 0x2733D6 값으로 수정되어야 한다. 커널버젼이 바뀌면서 동시에 해당하는 NtCreateUserProcess 함수의 시작위치가 수정되었기 때문이다.

 

이와 같은 문제는 피할 수 없는 문제이다. 특히 Export 되는 함수가 아닌 전역함수의 경우, 해당하는 함수의 주소를 얻기란 여전히 힘들다.

따라서, 필자의 경우처럼 후킹을 시도하기 전에 반드시 후킹이 가능한지를 확인하는 것이 필요하다.

 

개인적인 생각으로, 윈도우 커널 디버거 WinDBG 프로그램은 인터넷으로부터 커널심볼을 가져와서 이를 토대로 커널 디버깅을 시도한다.

그렇다면, 커널심볼내부에는 당연히 전역함수에 대한 주소정보가 포함되어 있을것으로 추정될 수 있기 때문에, 할 수있다면, 커널심볼정보를 인터넷을 통해서 가져와서 이를 분석해서 사용하는것사 좋을 것 같다.

여러 가지 아이디어는 있을 수 있지만, 어떤 방법을 사용하더라도 커널 후킹코드를 안정적으로 오랫동안 유지하기는 곤란하다. 창과 방패가 있기 때문이다.

 

결론을 맺는다. 필자가 제공하는 예재는 커널코드가 어떤 식으로 후킹될 수 있는지를 보여주는 예재로 활용해주기만을 바란다. 이것을 상용버젼의 코드로 바로 사용하는 것은 문제가 있으며, 꼭 그래야하는 상황이라면, 반드시 커널버젼에 따라서 안정적으로 커널코드를 후킹할 수 있도록 수정한뒤에 배포하기를 바란다.