본문 바로가기

High Level Technique/Reversing

Service Debugging

Service Debugging




Service Process 동작 원리


서비스 프로그램은 Service Control Manager(이하 SCM)에서 관리됩니다. 서비스 프로그램이 실행 되려면 Service Controller가 필요합니다.

Service Controller가 서비스 제어 요청을 하면 SCM이 서비스 프로그램에 제어 명령을 전달하고 리턴 값을 받습니다.












Service Controller


서비스 컨트롤러는 제어판 - 서비스를 실행하면 나타납니다. 또는 실행 - services.msc 를 실행해도 됩니다.



위 Service Controller에 들어가게 되면 시스템에 설치된 서비스 목록들이 나타나게 됩니다.











서비스 시작 과정





1. Service Controller에서 StartService()를 호출합니다. SCM은 해당 Service Process를 생성하고 Service Process의 EP Code가 실행됩니다.


2. Service Process 내의 StartServiceCtrlDispatcher()를 호출합니다. Service Process 내부에서 StartServiceCtrlDispatcher()를 호출하여 SvcMain() 주소를 등록해야 합니다.

StartServiceCtrlDispatcher()가 호출되면 Service Controller의 StartService() 함수가 리턴되고 SCM은 Service Process의 SvcMain을 호출합니다.


3. Service Process에서 SetService Status를 호출합니다. Service process가 생성되긴 했지만 아직 정식 서비스로 동작하는 것은 아니고 SERVICE_START_PENDING 상태인데 SvcMain에서 SetServiceStatus(SERVICE_RUNNING)을 호출해야 정상적인 Service Process로 동작할 수 있습니다.









서비스 설치


핵심원리의 DebugMe1.exe를 분석해 보도록 하겠습니다.


cmd를 이용하여 DebugMe1.exe install 을 입력해 줍니다.




Services.msc 를 실행시켜서 SvcTest 서비스가 정상적으로 설치가 되어있는지 확인합니다.






동작 - 속성에 들어갑니다.



위 화면에서 시작을 눌러줍니다.


Process Explorer를 이용해서 DebugMe1.exe가 실행되는지 확인해 봅니다.




DebugView 를 이용해서 문자열을 확인합니다.



혹시 문자가 뜨지 않는 경우 관리자 권한으로 실행하시고 Capture Global Win32를 체크해 주세요.














서비스 디버깅


서비스를 디버깅 할때 일반적인 프로그램의 디버깅 처럼 서비스 프로그램을 시작해서 디버깅 하면 안됩니다. SCM에 의해 실행되는 서비스 프로세스에 디버거를 붙여서 디버깅을 해야 합니다.


핵심

서비스 프로세스는 SCM에 의해서 실행된다.

서비스 핵심 코드는 SvcMain()에 존재한다.

SvcMain은 SCM에 의해서 호출된다.



디버거로 서비스 프로그램의 실행 파일을 열고 디버깅을 시작하면 서비스 메인함수가 실행되지 않아서 SCM을 통해서 정살 실행된 서비스 프로세스에 Attach해서 디버깅을 해야 합니다.



EIP 강제 세팅


디버거로 서비스 파일을 직접 열어서 디버깅하는 방법입니다. 앞서 말한것 처럼  SCM에서 실행되지 않고 디버거에 의해서 실행된 서비스 프로세스는 SvcMain과 SvcHandler가 호출되지 않습니다. 함수들의 주소를 알아내서 그곳으로 디버깅 위치를 옮겨야 합니다. 


DebugMe1.exe를 OllyDBG로 열어서 보면 아래와 같은 main함수가 나타납니다.



40106C 주소에서 StartServiceCtrlDispatcherW가 나타납니다. 이 API를 찾으면 SCM에게 서비스 메인 함수 SvcMain 주소를 넘겨줘야하기 때문에 StartServiceCtrlDispatcher API를 찾으면 SvcMain 주소를 알아낼 수 있습니다.


DLL 파일의 서비스 경우 기본적으로 ServiceMain을 Export하고 SCM Export 함수를 실행시켜 줍니다. 이러한 경우에는 StartServiceCtrlDispatcher를 따로 호출할 필요가 없습니다.

ServiceMain이 아닌 다른 이름으로 지정하고 싶으면 관련 레지스트리에 등록하면 됩니다.




StartServiceCtrl Dispatcher의 파라미터 pserviceTable은 SERVICE_TABLE_ENTRY 구조체 포인터 입니다. 이 구조체를 따라가면 서비스의 이름과 SvcMain의 주소를 알 수 있습니다.



40106C 주소까지 디버깅을 한 후 스택을 보면 아래와 같습니다.




스택을 보면 pServiceTable값인 19FD1C의 첫 번째 멤버 40A9CC는 SvcHost 문자열이고 두 번째 멤버 401320이 바로 SvcMain 함수의 주소입니다.


이제 SvcMain의 주소가 401320 이라는 것을 알았기 때문에 해당 주소로 이동합니다.


이동 후 EIP를 바꿔줍니다.



이 부분부터 디버깅을 하면 됩니다.


이때 주의할 점은 SCM으로부터 정상적으로 실행된 서비스 프로세스가 아니기 대문에 일부 서비스 API를 호출할 때 EXCEPTION이 발생할 수 있습니다. 

EXCEPTION_ACCESS_VIOLATION 예외가 발생할 수 있는데 OllyDBG에서 Debugging Option 중 Memory access violation에 체크를 하고 진행하면 됩니다.









Attach 방식 - 정석


SCM을 통해서 정식으로 실행되는 서비스 프로세스를 Attach해서 디버깅 해야하는 경우가 있습니다. 


디버깅 흐름은 아래와 같습니다.


서비스 설치 - EP코드에 무한루프 설치 - 서비스 실행 - 무한루프에 걸림 - 디버거를 붙임 - EP코드 복구 - EP 코드부터 분석


디버거를 붙이기 전까지 서비스 프로세스의 중요 코드가 실행되지 못하도록 무한루프에 들어가도록 하는 것입니다. 여기서 중요한 것은 Service Start Timeout(기본 30초)이내에 완료해야 한다는 것입니다.


실상 분석을하는데 코드 패치를 하고 다시 복원하면서 분석하기에는 30초는 짧습니다. 그래서 이 시간을 늘려줘야 합니다.




해당 위치로 이동해서 ServicePipeTimeout 항목을 추가해 주어야 합니다. 이 값은 밀리세컨드로 입력해야하므로 86400000 (24시간)으로 설정해 주면 됩니다.




위와 같이 설정을 해준 후에 재부팅을 하면 적용이 됩니다.



이제 무한 루프를 설정해 주어야 합니다.


EP 주소에 무한루프를 덮어 줍니다. Exeinfo PE를 이용해서 EP 주소와 File Offset 주소를 알아냅니다.



EP 주소는 1824 File Offset은 C24라는 것을 알 수 있습니다.

이제 HxD를 이용해서 해당 값을 무한루프로 바꿔줍니다.



해당 위치의 값을 EB FE로 바꿉니다.




이제 SvcTest 서비스를 실행하고 다시 OllyDBG를 이용해서 DebugMe1.exe를 Attach 합니다.


서비스를 실행했더니 아래와 같은 메시지 박스가 나타납니다.




그러면 다시 서비스 시작을 눌은 상태에서 Attach를 합니다. 이때 DebugMe1.exe 항목이 나타나지 않는다면 OllyDBG를 관리자 권한으로 실행시키길 바랍니다.



Attach를 하면 위와 같은 주소에서 멈추게 됩니다.


여기서 아까 찾았던 EP주소 401824로 이동합니다.







해당 주소로 이동해서 BreakPoint를 걸어 해당 주소까지 실행시킨 후 원래의 값으로 변경시켜줍니다.


그리고 SetServiceStatus API를 호출해주고 나면 서비스는 정상적으로 시작됨으로 변경됩니다.




'High Level Technique > Reversing' 카테고리의 다른 글

PE Image Switching  (2) 2016.08.10
Self Creation Debugging  (0) 2016.08.09
Advanced Anti Debugging  (0) 2016.08.09
Anti Debugging - Dynamic  (1) 2016.08.08
Anti Debugging - Static  (0) 2016.08.07