Windbg가 무엇일까가 먼저 나와야 하는 질문인 거 같다.
Windbg는 윈도우의 내부를 분석하는데 가장 효율적인 도구 이고, 정식 명칭은 Windows Debugging Tool 이며, 도구의 실행 파일 이름이 windbg.exe 이다보니, Windbg로 불리다.
Windbg를 통해서 여러분들은 윈도우에서 실행중인 프로세스와 스레드의 상태 그리고 윈도우 내부에서 처리하는 개체들의 상태를 확인할 수 있고 수정도 가능한 일명 전지전능한 도구라 할 수 있다. 이처럼 윈도우 분석에 막강한 도구를 사용하기 위해서 우리가 가장 먼저 해야 할 일은 Windbg를 설치하는 것이다.
커널 디버깅이 리버싱에 필요한 이유를 간단히 애기하자면 자신의 프로그램에는 문제가 없는데 윈도우에서 버그가 있는것 같을 때 이를 확인하기 위한 수단이다.
그리고 윈도우를 실행하고 있다면 수많은 프로세스와 명령들이 내부에서 처리되어 우리가 보고 싶은 부분을 놓칠 수 있다. 이를 놓치지 않기 위해 윈도우를 일시중지해야 하는데 커널 디버깅을 통해 일시 중지와 같은 제어가 가능하다.
그럼 어떻게 운영중인 윈도우를 제어할까? 바로 이 부분을 Windbg를 통해 가능한 것이다.
Windbg는 마이크로소프트(Microsoft, 윈도우 개발사)에서 무료로 제공하는 강력한 커널 디버깅 도구이다. Windbg는 윈도우 커널 디버깅을 완벽하게 지원하며, 확장 플러그인 등 강력한 기능을 내장하고 있으나, 명령어를 직접 입력해야 하는 CLI(Command Line Interface, 명령어 입력 방식으로 도스 명령창등이 이에 포함된다) 방식이기 때문에 숙지해야 하는 명령어가 많아, 능숙하게 사용하는 데는 어느 정도 시간이 필요하다.
실습 준비
이제 윈도우 내부 구조 분석을 위해 Windbg를 이용한 커널 디버깅 환경을 구성해야 한다. 이를 위해 아래와 같은 프로그램들을 준비하도록 하자.
Windows 10/11
운영체제, 필자의 경우 Windows 11을 설치 하였다.
Windbg
http://msdn.microsoft.com/en-us/windows/hardware/gg463009
이번장을 통해 배울 도구로 강력한 커널 디버깅을 자랑한다(현재 Windbg는 WDK와 SDK로 통합되었다. Windbg 툴만 설치하고자 한다면, http://msdn.microsoft.com/en-US/windows/hardware/hh852363의 SDK를 이용하여 Debugging Tools for Windows를 선택하기 바란다).
Windbg는 가상 머신의 호스트 머신과 가상 머신에 각각 설치하자.
VMware Player
개인이 무료로 사용할 수 있는 가상 머신으로. 이 책에서 모든 실습은 VMware Player에 설치한 가상 머신인 윈도우 10안에서 진행할 예정이다.
VMware사의 무료 소프트웨어인 VMware Player는 가상으로 컴퓨터를 하나 더 생성할 수 있는 가상화 머신이다. 이러한 가상 환경 구성은 실제 분석가들도 많이 사용한다. 더욱이 최근에 급속히 발전한 가상화 기술은 이를 더욱 편리하게 하였는데, 여기서도 실시간 커널 디버깅 테스트를 위해 가상화로 만든 머신을 이용할 것이다. 커널 디버깅을 위해 물리적으로 컴퓨터를 하나 더 구성하는것도 좋지만, 테스트를 위한 환경에서는 설정과 관리가 쉽지 않아, 대체로 요즘 많이 사용되는 가상 머신을 이용하여 구성하는 경우가 많다. 그리고 가상 머신의 가장 큰 장점인, 분석을 진행하다가 운영체제가 망가지더라도, 가상 머신만 삭제하거나 스냅샷이라는 백업기술로 간단히 복구가 가능하여 빠른게 분석을 제개할 수 있다(Player 버전은 스냅샵 기능을 제공하지 않는다. 유료버전인 Workstation 버전부터 사용가능하다). 우리가 앞으로 진행할 분석 머신들도 대부분이 이처럼 가상 머신을 통해 진행할 예정이다.
가상화 서버 기술로는 VMware가 Hyper-V보다 많이 사용되고 있으며 회사에서 이용할 경우 유료이며 VMware Player의 경우 개인의 이용에 한하여 무료로 제공한다.
커널 디버깅
유저 모드에서는 커널 영역의 접근은 통제되기 때문에, 우리가 배우고자 하는 커널 영역을 확인할 수 없다. 그리고 이를 위해서는 먼저 운영체제를 커널 디버깅을 할 수 있도록 커널 디버깅 모드의 활성화를 진행하여야 커널 모드를 분석할 수 있다(임의의 분석 행위를 막는 안전장치라 할 수 있다).
Windbg에서 제공하는 기능중 현재 구동 중인 머신에서는 제한된 기능으로 커널 디버깅을 할 수 있는 로컬 커널 디버깅 모드가 존재하지만, 추적과 중지와 제어 기능을 다 사용할 수는 없으므로, 온전한 커널 디버깅을 진행하기 위해서는 별도의 머신을 통한 원격 커널 디버깅을 진행해야 한다.
그럼 먼저 용어에 대해 알아보자.
실시간 커널 디버깅은 운영체제에 문제가 발생하였을 때 문제가 되는 머신(Target)을 디버깅 모드로 설정한 후 COM 포트를 이용하여 호스트(Host)와 연결해 실시간으로 분석을 진행하는데, 디버깅을 할 때 대상에 대해 분석을 행하는 주체를 디버거(Debugger), 분석을 당하는 주체를 디버기(Debuggee)라는 용어로 구분해 사용된다.
여기서는 디버깅 당하는 가상머신이 디버기가 되며, 디버깅을 행하는 호스트 머신이 디버거라 할 수 있다.
그럼 앞서 준비한 VMware Player를 이용하여 가상 머신을 생성하고 해당 가상 머신에 윈도우 10/11를 설치하자.
가상 머신 만들기
그리고 커널 디버깅 연결을 위해 먼저 가상 머신에 Add 버튼을 통해 Serial Port를 추가한 후 직렬 포트 설정을 아래 그림과 같이 파이프 연결로 설정한 후, 가상 머신을 실행하자.
위와 같이 설정후 새로 만든 가상 머신에 윈도우 10/11를 설치하였다면, 이 운영체제는 앞서 말한 디버기로 사용할 준비가 거희 완료 되었다. 이제 커널 디버깅 모드를 진행하기 위해서 디버기를 부팅하여 Bcdedit.exe를 이용하여 디버깅 모드를 활성화를 진행하자.
Bcdedit.exe를 이용하여 앞서 VMware Player에서 추가한 Serial Port 2를 커널 디버깅 모드로 이용하기 위해서 다음과 같이 진행하여 부팅 메뉴를 추가하여야 한다(Bcdedit, Msconfig와 같이 시스템에 변경이 필요한 도구를 실행하기 위해서는 관리지 권한을 이용하여야 한다).
사용자 계정 컨트롤 비활성화
윈도우 비스타 이후부터 보안을 강화할 목적으로 사용자 계정 컨트롤(User Account Control, 이하 UAC)이라는 기능을 이용하여 관리자 권한이 필요한 경우 이를 사용자에게 확인하도록 하는 보안 기능을 추가하였다. 즉 관리자 권한 없는 상태에서는 함부로 시스템을 변경하거나 실행할 수 없도록 보안을 강화한 것인데 보안적으로는 더 없이 좋을 수 있으나, 책에서 진행하는 많은 실습에서 제한사항으로 다가온다.
따라서 원활한 실습 진행을 위해 UAC기능을 비활성화 할 필요가 있다.
먼저 시작 > 실행(Win(윈도우아이콘키) + R키) 을 누른후 Msconfig를 입력하여 시스템 구성을 실행하자.
명령프롬프트 창이 실행되면 아래와 같은 명령을 입력하자.
bcdedit /copy {current} /d "Windows 10 [Debug Mode]" |
그리고 작업표시줄에서 시작 à 실행을 누룬후 Msconfig 명령으로 시스템 구성을 실행한 후 부팅 탭에서 새로 추가한 Windows 7 [Debug Mode]의 고급 옵션을 통해 디버그 와 디버그 포트 및 전송 속도를 아래 그림과 같이 구성하도록 하자.
디버깅 모드를 체크하면, 기본적으로 연결 타입은 디버그 포트는 COM1:, 전송속도(Baudrate)는 115200이 된다. 우리는 현재 VMware Palyer에 Serial Port 2가 추가되었으므로 COM1:을 COM2:로 변경하여야 정상적으로 디버깅 모드가 연결된다.
커널 디버깅 연결
우선 가상 머신 실행 이후 디버거에 Windbg를 실행하고, File à Kernel Debug을 선택한 후 앞서 Boot.ini에 설정한 “/baudrate=115200”의 115200과 가상 머신에 설정한 파이프 값 \\.\pipe\com_1를 입력한 후 Pipe 선택상자를 체크하고 확인을 누르면, 디버기의 연결을 대기하게 된다.
이후 디버기에서 디버깅 모드로 부팅을 시작하면, 디버거에서 실행한 Windbg가 디버기와 연결이 진행되면서, 커널 디버깅 준비가 완료된다.
이렇게 커널 디버깅이 연결되고 나면, Windbg에서 Ctrl+Break(Pause) 키를 통해 언제든지 디버기의 운영체제를 일시 중지하고 분석을 진행할 수 있게 된다(다시 디버기를 실행하기 위해서는 g 명령을 입력하면 된다). 일시 중지를 하게 되면, 아래와 같은 메시지가 나오면서 일시 중지가 되었음을 디버거 분석자에게 알린다.
여기까지 잘 진행하였다면 커널 디버깅을 위한 준비 작업이 절반 이상 성공했다고 봐도 된다.
이제 커널 디버깅에서 중요한 부분인 심볼 설정하는 방법에 대해서 알아보자.
심볼 설정
Windbg를 이용하기 위해서 제일 먼저 해야 할 일은 심볼 설정이다.
심볼 파일이란 어셈블리 코드에서 소스코드의 위치, 함수 이름, 변수 이름과 같은 정보를 담고 있는 파일로써, 윈도우 2000 이후 .pdb, .dbg 확장자로 혼용하여 심볼 파일로 생성하였으나, 윈도우 XP와 .NET부터 .pdb 만을 심볼 파일 확장자로 사용하게 되었다. 심볼 파일은 아래와 같은 정보를 가지고 있다.
- 전역 변수의 이름과 주소
- 각 엔트리 포인트의 함수 이름과 주소
- FPO 데이터 (Frame Pointer Omission, 6장 덤프 분석에서 다룬다)
- 로컬 변수의 이름과 주소
- 소스 파일의 경로와 줄 번호
- 변수와 구조 등의 타입 정보
운영체제는 여러 개발자들이 함께 개발한 커다란 프로그램이라 할 수 있다. 따라서 개발 단계와 다르게 외부에 공개할 때 여러 부분에서 최적화를 진행하면서 개발단계의 불필요한 정보들을 삭제하게 된다. 즉 메모리에서 운영제체에 불필요한 정보들은 삭제하여 최적화하는 것이다. 이때 운영체제의 동작에는 이상이 없지만, 분석가들이 운영체제를 추가 개발 혹은 버그를 수정하기 위해 코드를 확인하는 작업은 어려워지게 된다. 이유는 불필요 하다고 판단되어 삭제된 정보들이 여기에 속하기 때문이다.
따라서 심볼 설정이 없는 상태에서는, 순수 기계어 상태로 확인하여야 하며, 이를 분석한다는 것은 지도 없이 좌표만 있는 상태와 같다고 할 수 있다. 따라서 해당 좌표가 어디를 가르키는지, 어느 지도에 맞춰진건지 모르기 때문에, 디버깅이나 패치는 거희 불가능하게 된다.
즉, 심볼은 지도와 같다. 지도와 같은 심볼을 설정하지 않으면, 메모리 자체, 즉 무의미한 0과 1을 단순히 눈으로 보는거라 할 수 있다.
이를 확인하기 위해 조금전 실행한 커널 디버깅 상태의 Windbg를 Ctrl+Break(Pause) 키를 눌려 가상 머신을 일시 정지한 후 프로세스를 확인해 보자.
// 심볼 미설정 상태에서는 아무런 정보도 얻을 수 없다. 1: kd> !process 0 0 NT symbols are incorrect, please fix symbols // 프로세스 구조체 정보 역시 표시하지 못한다. 1: kd> dt nt!_EPROCESS Symbol _EPROCESS not found. |
그럼 심볼은 어떻게 만들어질까? 일반적으로 심볼은 프로그램이나, 라이브러리, 드라이버 등의 컴파일 작업(개발한 프로그램 코드를 실행 파일로 변환하는 작업) 진행시 생성되며, 프로그램 디버깅에 필요한 정보들을 가지고 있다.
우리가 분석하는 커널 영역이나, 컴파일한 프로그램 파일은 실행에 최적화된 기계어 코드로, 개발코드가 제거된 순수 실행을 위한 기계어인 것이다. 이러한 기계어들의 각 코드의 정보를 담고 있는 심볼 파일의 경로를 지정하여, 디버깅할 때 각 코드의 의미를 알 수 있게 도와준다(이는 개별 응용프로그램 분석할 때도 사용된다).
심볼은 실행에는 필요없지만, 분석시 유용한 정보를 내장하고 있기 때문에 심볼 설정을 하지 않은 상태에서는 해당 값의 의미와 역할을 확인하는 작업이 매우 어렵게 된다. 이런 때를 모래밭에서 바늘찾기라 할 수 있겠다.
따라서 윈도우를 개발한 마이크로소프트는 외부에 심볼 서버를 공개해서, 윈도우 디버깅시 내부 정보를 확인할 수 있도록 하고 있다. 하지만 모든 정보를 공개한 것은 아니다. 마이크로소프트 내부에서 사용하는 비공개 심볼도 존재한다. 하지만 외부에 공개된 심볼 서버로도 윈도우 구조를 이해하는데 활용가치가 높으므로 적극적으로 이용하도록 하자.
그리고 외부와 네트워크 연결이 되지 않는 환경과 같은 특수 환경을 위해, 직접 심볼 서버를 구성하여 사용할 수 있는데, 여기서는 해당 부분에 대해서는 언급하지 않는다.
여기서는 마이크로소프트에서 제공하는 공개 심볼 서버를 설정할 것이다. 사설 심볼 서버 구성에 대한 정보는 다음 링크에서 확인하기 바란다.
Install WinDbg - Windows drivers | Microsoft Learn
Install WinDbg - Windows drivers
Start here for an overview on the Windows debugger and installing WinDbg.
learn.microsoft.com
심볼을 설정할 수 있는 방법으로는 사전에 윈도우 환경 변수로 설정해 사용할 수 있고, 그 외에도 Windbg 실행시 설정하거나 실행 이후에도 가능하다.
윈도우 환경 변수로 설정하는 방법은 Set 명령을 이용하는 방법으로, 명령 프롬프트 창(Cmd.exe)에서 Set _NT_SYMBOL_PATH 명령을 통해 사전에 정의한다. Windbg 실행시에는 –y 파라미터를 추가하여 설정할 수 있고, Windbg 실행 이후라면 Windbg 명령어 .sympath 혹은 GUI 메뉴인 Ctrl+S키를 눌려 심볼 서버를 설정할 수 있다.
이 3가지 경로를 이용하여 심볼을 설정이 가능하니, 아래와 같이 설정하기 바란다.
// 윈도우 환경 변수에 심볼 경로 등록, 심볼 경로를 사전에 등록하여, 운영체제 모든 환경에서 기본적으로 지정한 심볼 경로를 이용한다. 명령 프롬프트창에서 아래와 같이 입력할 수 있다.
set _NT_SYMBOL_PATH=srv*DownstreamStore*http://msdl.microsoft.com/download/symbols
// Windbg 실행 이후 메뉴를 통해 심볼 설정, 개별 분석 케이스 별로 필요한 심볼 지정시 유용하다.
SRV*C:\Symbols*http://msdl.microsoft.com/download/symbols
// Windbg의 명령창을 통해 실행, 분석 중 심볼을 추가하여야 하는 경우 이용된다.
.sympath srv*C:\Symbols*http://msdl.microsoft.com/download/symbols
주로 사용되는 방식으로는 Windbg 실행 이후 등록하는 방식으로, File à Symbol File Path를 이용하여 설정할 수 있다.
위 심볼 설정중 srv는 심볼을 저장할 위치로, 로컬에 저장할 디렉토리를 입력해 주면 된다. 커맨드 설정이 번거롭다면 Windbg의 File 메뉴를 이용하기 바란다.
확인하지 못했던 정보를 심볼을 설정한 이후에 다시 진행해 보자(커널 디버깅중이라면, 일시정지(Ctrl+Break(Pause)키)후 진행하여야 한다).
// Windbg에 심볼을 추가하기 위해 .sympath명령과 .reload 명령을 실행하자. 1: kd> .sympath srv*C:\Symbols*http://msdl.microsoft.com/download/symbols Symbol search path is: srv*C:\Symbols*http://msdl.microsoft.com/download/symbols Expanded Symbol search path is: srv*c:\symbols*http://msdl.microsoft.com/download/symbols 1: kd> .reload Connected to Windows 7 7601 x86 compatible target at (Mon Sep 9 16:22:50.655 2013 (UTC + 9:00)), ptr64 FALSE Loading Kernel Symbols ............................................................... ................................................................ ........................... Loading User Symbols Loading unloaded module list .... // 심볼 설정이 완료되었다면 프로세스 리스트와 프로세스 구조체 정보를 확인할 수 있다. 1: kd> !process 0 0 **** NT ACTIVE PROCESS DUMP **** PROCESS 847c49e8 SessionId: none Cid: 0004 Peb: 00000000 ParentCid: 0000 DirBase: 00185000 ObjectTable: 88201b80 HandleCount: 524. Image: System PROCESS 85b9ad40 SessionId: none Cid: 0114 Peb: 7ffdd000 ParentCid: 0004 DirBase: 3eba9020 ObjectTable: 8be5c0e8 HandleCount: 29. Image: smss.exe PROCESS 862c5260 SessionId: 0 Cid: 0170 Peb: 7ffda000 ParentCid: 0164 DirBase: 3eba9060 ObjectTable: 882bdfc0 HandleCount: 495. Image: csrss.exe PROCESS 862313a8 SessionId: 0 Cid: 0198 Peb: 7ffd9000 ParentCid: 0164 DirBase: 3eba90a0 ObjectTable: 9624cbe0 HandleCount: 78. Image: wininit.exe …중략 // 프로세스 구조체 정보도 조금전과 다르게 확인이 가능하다. 1: kd> dt nt!_EPROCESS nt!_EPROCESS +0x000 Pcb : _KPROCESS +0x098 ProcessLock : _EX_PUSH_LOCK +0x0a0 CreateTime : _LARGE_INTEGER +0x0a8 ExitTime : _LARGE_INTEGER +0x0b0 RundownProtect : _EX_RUNDOWN_REF +0x0b4 UniqueProcessId : Ptr32 Void +0x0b8 ActiveProcessLinks : _LIST_ENTRY +0x0c0 ProcessQuotaUsage : [2] Uint4B +0x0c8 ProcessQuotaPeak : [2] Uint4B +0x0d0 CommitCharge : Uint4B …중략 |
심볼 설정이 정상적으로 로드 되었다면, 기본적인 Windbg를 사용하기 위한 준비는 끝이 났다. 이렇게 커널 디버깅 연결하게 되면 Windbg를 이용하여 실시간 커널 디버깅을 진행할 준비가 완료된 것이다.
이렇게 Windbg를 이용할 준비를 마친 것 같다. 이 내용은 처음에는 조금 어려울 수 도 있겠다.
하지만 윈도우 커널 영역을 공부하는데 있는 Windbg는 필수이므로 이 내용은 차후 실무에서도 많은 도움이 될 것이다. 다음은 커널을 생성하는 Ntoskrnl.exe에 대해 해당 파일의 역할과 처리 방식에 대해 설명하고 Windbg를 이용해 확인해 보는 과정으로 진행하겠다.