메신저가 message hook을 하는 이유
요즘 메신저 안 쓰시는 분들은 거의 없을겁니다.
그와 관련하여 자주 듣는 질문 중 하나가, 왜 메신저들이 남의 프로세스에 DLL을
집어넣느냐는 것입니다.
실제로 네이트온 같은 경우도 NateOnHook40u.dll이란 넘을 모든 프로세스에 집어넣죠.
예전에 신영진님과 이거에 대해 간단한 토론?을 한 적이 있는데요,
뭐 일단 그때 영진씨한테 들은 내용을 바탕으로 결론부터 말씀드리면 메신저가 이같이
dll을 넣는 이유는 "자리비움"기능을 구현하기 위해서라고 합니다.
그때 추가로 이루어졌던 토론이 꼭 메시지훅을 해서 자리비움을 구현할수밖에 없느냐...란 얘긴데
그건 결론이 나오진 않았었구요 :p
어쨌든 그렇게 얘기하고 머 멀 넣든 말든 별 문제는 없으니까 이후로도 걍 신경을 껏지만
얼마전에 저희 팀 메일로 메신저 부류가 왜 dll을 넣는지 궁금하다는 문의가 있어서
간만에 옛기억을 떠올려보며 한번 뜯어봤습니다.
간단한 화면캡쳐를 통해 그 원리를 말씀 드려 보겠습니다.
메신저 dll을 IDA로 간단히 본 화면입니다.
2008년도부터 리버스 엔지니어링에 대한 법적인 조항이 생긴다는 얘기가 있어서
무슨 프로그램인지에 대한 언급은 생략하겠습니다 :p
일단 아래 화면은 dll을 넣기 위해 message hook을 하는 코드입니다.
Hook id는 2번과 7번이 들어가는데 이는 각각 키보드 훅, 마우스 훅 입니다.
키보드 입력과 마우스 움직임을 감지하기 위한 것입니다.
#define WH_KEYBOARD 2
#define WH_MOUSE 7
후킹 프로시져인 fn과 sub_10001110은 동일한 기능을 하고 있으므로 하나만 보겠습니다.
마우스 훅에 대한 프로시져인 sub_10001110를 볼까요,
보시면 머 잡다한 짓을 하다가 sub_1000830E 를 부르는데요 쟤가 바로 시간을 계산하는
부분입니다. 안으로 들어가보면 GetLocalTime과 GetSystemTime등으로 난리부르스를 떨고
적절한 상수를 eax에 뱉어내줍니다. 그 값이 time_t 타입의 현재 시간을 나타내는 값입니다.
어쨌든 머 현재 시간을 계산하는 부분이라고 생각하시면 되겠네요
아 참고로 쓸데없는 부연지식을 첨가해보자면, 정확히는 저 부분은 개발자가 구현한 시간 루틴이 아니고
우리가 많이 쓰는 time()함수입니다. 즉, time_t time( time_t *timer ); 이거 입니다.
실제로 time()함수는 리버싱을 해보신분은 아시겠지만 저 함수가 실제로 있는것이 아니고
컴파일러가 GetLocalTime과 GetSystemTime 등을 조합해서 만들어주는 함수입니다.
따라서 빌드 후에 확인해보면 dll로 점프하지 않고 exe내부의 call문으로 생성되죠.
궁금하신 분들은 MSDN의 time() 예제코드를 빌드해보시고 직접 리버싱 해보세요 :p
참고로 IDA는 똘똘이스머프이기 때문에 그 call문을 time()이라고 완벽히 해석해주지만
OllyDBG는 바보이기 때문에 걍 흔해빠진 call문중의 하나로 보여줍니다 ㅋ
어쨌든 훅을 걸고 시간을 계산했습니다. 그리고 time_t 형태의 리턴값을 받았구요
위 이미지를 보시면 걔를 전역변수 어딘가에 넣어줍니다. 이곳은 어디일까요
네~ 정답은 쉐어드 섹션이 되겠습니다. 다른 프로세스에서(정확히는 메신저의 exe인
메인 모듈에서) 타 영역의 프로세스에도 접근하기 위하여 이같은 섹션을 만들어 두고
거기에 현재 시간 값을 가져와 비교하는 것으로 확인됩니다.
그럼 정리해 보겠습니다.
1) 메시지 훅을 걸어 모든 프로세스에 DLL 주입
2) 사용자가 마우스를 움직여서 훅이 걸리면 현재의 시간 shared section에 기록.
3) exe에서 shared section을 읽어와서 사용자가 마지막으로 마우스를 움직였을때의 시간과
현재 시간을 비교
4) 그 시간이 3분 등 자리비움 설정 시간을 넘어서면 현재 상태를 "자리 비움"으로 변경
5) 다른 어떤 프로세스가 포그라운드로 오게 되어도 DLL이 들어가 있으므로 역시
마우스 움직임 캐취 가능
자 대충 이정도 알고리즘이 되겠네요 :p
여기서 수정 또는 덧붙힐 내용이 있습니다.
먼저 exe에서는 키보드 훅과 마우스 훅 외에 WH_CBT 훅까지 걸고 있습니다.
WH_CBT 훅은 윈도우가 생성/소멸/활성화 될때의 훅 체인을 걸 수 있습니다.
따라서 새 프로그램이 실행되어도 dll 을 주입할 수 있는 이유는 이 훅 때문이겠죠.
하지만 이로써 알 수 있는 부분은, 초반에 "모든 프로세스에 DLL을 주입.."이라고 했는데
CBT Hook에 의한 것이므로 정확히는 "윈도우를 가진 모든 프로세스"가 되겠죠 :)
따라서 윈도우가 없는 프로세스는 dll이 들어가지 않을거구요 :p
대충 이정도로 정리를 해보았습니다.
그런데 지금 글을 쓰면서 확인해보니 MSN 8.1은 더이상 남의 프로세스에 dll을 집어넣지 않네요?
예전에는 분명히 넣었던 것을 확인했는데 현재 dll 리스트를 보니 확실히 아무것도 없습니다.
MSN 8.1은 영진씨와 고민했던 "메시지훅을 하지 않고 자리비움 기능을 구현" 과제를 해결했나 보네요 :p
나중에 시간이 날 때 msn도 한번 살펴보도록 하겠습니다(혹시 이미 알고계신 분 있으시면 알려주세요)
2007년 12월.