Programming/Kernel / Driver2008. 12. 3. 10:53

후킹은 프로그램 기술중에서 가장 멋진기술입니다.

하지만 일반적인 후킹(SetWindowsHookEx)은 윈도우가 제공하는 범위내에서 가능한것들이고 때때로 그것보다
아래 단계에서 후킹을 하고싶을때가 있는데 특히 Filemon이나 Packet sniffer 같은 멋진 프로그램들은
SetWindowsHookEx 가지고는 구현 불가능합니다. 여러분이 후킹에 목말라 있다면

좀 더 이 글을 읽어서 자신이 원하는 해답을 얻기를 바랍니다.


필요한 것


Visual Studio
Driver Development Kit


디바이스장치에 접근하는 방법은 몇가지가 있습니다. 필터 드라이버를 작성하는것과 드라이버를 후킹하는것인데
여기에서는 필터드라이버에 관한 내용은 다루지 않습니다. 필터드라이버는 현재 WDM책마다 최소한 한번 이상은
다루기 때문에 필터드라이버를 작성하시려면 책을 추천해 드립니다.

저는 윈도우 API중에서 SCM(Service control manager)을 이용해서 드라이버를 후킹하고 지우는 방법을 골랐는데
이유는 간단합니다. 재부팅이 무척 싫고 작업시간도 배로 늘어나기 때문에, 필터드라이버는 설치하면 재부팅을 해야합니다.


아래는 SCM을 이용해 드라이버를 등록하고 제거 하는방법이다.

BOOL CDeviceControlDlg::CreatDevice(char* sc_name, char* sc_path)
{
        SC_HANDLE hSCMan = NULL;
        SC_HANDLE hService = NULL;

        if((hSCMan = OpenSCManager(0, 0, SC_MANAGER_ALL_ACCESS)) == 0)
        {
                TRACE("서비스를 열수 없습니다.");
                return FALSE;
        }

        if((hService = CreateServiceA(hSCMan, sc_name, sc_name, SC_MANAGER_ALL_ACCESS, SERVICE_KERNEL_DRIVER,
                SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, sc_path, 0, 0, 0, 0, 0)) == 0)
        {
                if(GetLastError() == ERROR_SERVICE_EXISTS)
                        TRACE("이미 설치되어있습니다.\n");
                else if(GetLastError() == ERROR_SERVICE_MARKED_FOR_DELETE)
                        TRACE("서비스가 제거되도록 설정되어 있어 생성불가.\n");

                CloseServiceHandle(hSCMan);
                return FALSE;
        }

        StartService(hService, 0, 0);
        TRACE("설치완료\n");
        CloseServiceHandle(hService);
        CloseServiceHandle(hSCMan);
        return TRUE;
}

BOOL CDeviceControlDlg::UnloadDevice(char* sc_name)
{
        DWORD dwError = ERROR_SUCCESS;
        SC_HANDLE hSCMan = NULL;
        SC_HANDLE hService = NULL;
        SERVICE_STATUS serviceStatus;

        if((hSCMan = OpenSCManager(0, 0, SC_MANAGER_ALL_ACCESS)) == 0)
        {
                TRACE("서비스를 열수 없습니다.");
                return FALSE;
        }

        if((hService = OpenServiceA(hSCMan, sc_name, SERVICE_ALL_ACCESS)) == 0)
        {
                TRACE("서비스가 설치되지 않았습니다.\n");
                CloseServiceHandle(hSCMan);
                return FALSE;
        }

        ControlService(hService,SERVICE_CONTROL_STOP,&serviceStatus);

        if(DeleteService(hService) == 0)
        {
                if(GetLastError() == ERROR_SERVICE_MARKED_FOR_DELETE)
                        TRACE("서비스가 이미 제거 설정되었습니다.\n");
        }
        else
            TRACE("서비스가 제거되었습니다. 프로그램을 종료해야합니다.\n");

        CloseServiceHandle(hSCMan);
        return TRUE;
}


SCM을 이용해서 디바이스를 등록하는 과정은 약간의 제약이 있는데 한개의 프로세스 스레드에서
서비스를 제거시 바로 제거되는것이 아니라 서비스 제거 마킹만 할뿐 실질적으로 프로세스를 종료해야
서비스가 제대로 제거됩니다. 제거 마킹상태에서는 다시 서비스가 생성되지 않습니다.

또 주목해야할 부분은

CreateServiceA(hSCMan, sc_name, sc_name, SC_MANAGER_ALL_ACCESS, SERVICE_KERNEL_DRIVER,
                SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, sc_path, 0, 0, 0, 0, 0))

이 부분에서 5 번째와 6번째 파라메터 부분

5번째는 커널드라이버이기 때문에 당연히 SERVICE_KERNEL_DRIVER
라고 넣었겠지만 6번째는 어째서 SERVICE_AUTO_START를 사용하지 않고

SERVICE_DEMAND_START 넣은후에 StartService(hService, 0, 0); 서비스 시작을 해야만 하였는가...

그 부분에 대해서는 아직 내공이 부족해서 답을 얻지 못했는데
다만 SERVICE_AUTO_START 를 했을경우 드라이버 엔트리포인트에 진입하지 못한다는것을 확인 했기 때문에
이 글을 읽는 분들이라면 이 같은 실수는 하지 않길 바랍니다.


사용자 삽입 이미지


이제 윈도우 DDK에서 제공되는 Device Tree라는 툴로 후킹 드라이버가 성공적으로 올라간것을 확인할수 있습니다.

출처 : 데브피아

Posted by skensita