*yenas0님과 함께한 실습의 아카이빙입니다.
그냥 검색하면 마케팅에서 사용하는 서비스 프로세스만 나온다.
Windows에서 "서비스 프로그램" 은 일반 프로세스와 다른 특성을 가지는 특별한 백그라운드 프로세스 를 의미한다.
"서비스"라는 이름이 붙은 이유는, 단순한 사용자 애플리케이션과 달리 시스템이나 다른 프로그램에 필수적인 기능을 지속적으로 제공 하기 때문이다.
백그라운드에서 지속적으로 특정 기능을 제공 하기 때문
→ 예: Windows Defender 서비스가 백그라운드에서 악성코드를 감시
사용자가 직접 실행하지 않아도 운영체제가 필요할 때 관리 하기 때문
→ 예: 네트워크 연결 서비스는 Windows가 알아서 관리
여러 프로그램이 동시에 이용할 수 있는 기능을 제공 하기 때문
→ 예: 프린터 서비스(spoolsv.exe)는 모든 프로그램이 공유
쉽게 말해, 서비스 프로그램은 사용자가 요청하지 않아도 시스템이 알아서 운영하는 필수 기능을 제공하는 프로그램 이기 때문에 "서비스"라고 불리는 것이다.
이런 서비스들이 없으면 시스템이 제대로 동작하지 않거나, 사용자가 불편을 겪게 된다.
그래서 서비스 프로그램은 단순한 앱이 아니라, 운영체제와 긴밀하게 연결된 필수적인 기능을 담당하는 프로그램 으로 구별되는 거야.
| 구분 | 서비스 프로그램 | 일반 프로세스 |
|---|---|---|
| 실행방식 | 운영체제(SCM)에 의해 자동 실행 | 사용자가 직접 실행 |
| 관리 주체 | Service Control Manager (SCM) | 운영체제가 일반적으로 관리 |
| 실행 계정 | LocalSystem, LocalService, NetworkService 등 | 주로 사용자 계정 |
| 인터페이스 | GUI 없고 백그라운드에서 작동 | 윈도우 창 있는 GUI |
| 역할 | 시스템 기능 지원(네트워크, 보안, 업데이트 등) | 사용자의 목적이 담긴 응용프로그램 |
SCM이 서비스 프로그램의 호출과 운영을 관리한다.
서비스 제어기, Service Controller가 시작 명령을 내린다.
Controller가 SCM에게 제어 요청을 보낸다
제어명령 : Start / Stop / Pause / Restart
SCM이 제어명령을 서비스 프로그램에 전달한다.
서비스 프로그램이 리턴값을 되돌려준다.

윈도우 메뉴에서 서비스 제어기라고 검색하면 걍 나옴.
들어가면!

라고 나온다.
서비스 제어기 : StartService( ) 호출
호출하고 나면 SCM은 서비스 프로세스 생성 -> 서비스 프로세스의 EP코드 실행
서비스 프로세스 : StartServiceCtrlDispatcher( ) 호출
서비스 프로세스 내에서 반드시 반드시 StartServiceCtrlDispatcher( )를 호출해야 한다.
그래야 서비스 프로세스의 메인함수인 SvcMain( )의 주소가 등록된다.
-> StartServiceCtrlDispatcher( )의 리턴으로 StartService( )가 리턴된다.
엥 왜 이게 또 호출됨????
SCM은 서비스 프로세스 내의 SvcMain( )를 호출한다.
정식 서비스로 동작시키기
서비스를 실행상태로 돌려야 한다.
SERVICE_START_PENDING 상태이다 지금은. 메인함수에서 SetServiceStatus(SERVICE_RUNNING) API를 호출해야 한다.
관리자 모드로 DebugMe.exe를 실행한다.
그리고 나서 서비스 제어기를 보면 SvcTest가 보인다.

서비스를 실행시켜주자.
그러면 매시간마다 디버그 문자열을 출력한다. DebugView 같은 유틸리티로 확인해보며 알 수 있다.

소스코드는 예...심플하니 직접 보시면 됩니다.
서비스 프로그램은 일반 PE 파일 디버깅하듯이 디버거에 파일을 올려서 할 수가 없다.
서비스 프로그램을 디버깅하는 건 결국 메인을 보려는 것이다. 근데 이 메인함수는 SCM에 의해서 호출된다.
우리가 디버거로 서비스 프로그램을 실행시키면, 메인함수를 호출할 수가 없는 것이다.
그래서 디버거로 실행시키는 게 아니라, 실행된 서비스프로그램에 디버거를 Attach 해야 한다.
디버거로 실행하면 메인함수를 호출해주지 않는다고 해서 안되는 건 아니지. 그냥 디버깅 시작 위치를 메인함수 시작 주소로 강제로 옮기면 되지. 뭐...그냥 할 순 있다고.
디버거로 계속 실행해서 메인까지 진행을 하면 중요한 API를 찾을 수 있다. 메인함수의 주소를 등록하는 건 StartServiceCtrlDispatcher( )였다.
이 친구의 파라미터에는 메인함수의 주소가 들어가야 한다.
이 파라미터에는 pServiceTable이란게 있는데 이건 구조체 포인터다. 여기에 바로 메인함수 주소가 있다 이 말이야.
그럼 StartServiceCtrlDispatcher( ) 호출 명령까지 실행하고 나서 스택을 보면 파라미터가 쌓여있겠지. 거기에 메인함수가 주소가 있다.

요시!
메인함수 주소가 00401320이래.
여기로 eip 이동해서 가면 된다.

짠!
근데 실제 서비스 프로그램은 더 복잡할 수도 있고 뭐가 있을 수도 있으니까 정석대로 하자
이 방법의 핵심은 간단하다. EP에 무한루프를 걸어놓고, 그 동안에 디버거를 붙여놓은 뒤에, 무한루프를 풀어주고 실행하면 된다.

무한루프를 설치하고 디버거를 붙일 때 문제가 있다.
SCM은 서비스 프로그램을 실행하고 30초 안에 서비스 상태가 STATUS_RUNNING으로 바뀌지 않으면 에러로 간주하고 서비스를 종료한다.
그럼 우리는 30초 안에
1. 디버거 설치
2. 서비스 상태 running으로 변경 -> 메인함수에서 SetServiceStatus( ) 호출
이걸 30초 안에 하기가 진짜 개빡세다.
그래서 손을 빨리 할 바에, service start timeout을 크게 늘려주는게 낫다ㅣ
레지스트리 편집기를 열어야 한다. 그리고 새로운 DWORD을 생성해주고 대기 시간을 아주 넉넉하게 늘리면 좋다. 뭐 예를 들어 24시간
원본 EP의 파일 오프셋으로 간다.

엔트리 포인트의 오프셋 주소가 0C24다.
헥스 에디터로 보면 ep코드 주소의 값이 E8 C0이다.

무한루프를 설치하는 커맨드는 0xEB, 0xFE이다.
이게 뭐냐면, "자기 주소로 점프"다.
EB : 근거리 점프
FE : 얼마나 점프할거야? -> 다음 EIP에서 FE(-2)만큼
합치면?
자기 자신으로 점프해
제어기로 서비스 시작시켜라
디버거의 메뉴에서 Attach을 실행하면 DebugME.exe에 붙일 수 있다. 그러면 시스템 라이브러리 부분에서 멈춘다.
EP까지로 eip를 이동시킨 다음에 엔트리포인트에 BP걸어서 실행하면 여기서 제어가 멈추겠지. 무한루프 걸었던 거 다시 원복시킨 다음에 실행하면.