May 6, 2023

MINIFILTER

MINIFILTER

하드웨어 개발센터
https://developer.microsoft.com/ko-kr/windows/hardware

http://vaultmicro.blogspot.com/search/label/WHQL

MICROSOFT GITHUB

공개 릴리스 용 커널 드라이버에 서명하는 증명

Minifilter 드라이버에 대한 주문 그룹 및 고도로드

파일 시스템 필터 드라이버에 대한로드 순서 그룹

드라이버로드시 결정되는 사항

드라이버 패키지를 테스트하는 방법

Allocated Altitudes

Windows HLK 필수 구성 요소

공개 릴리스 드라이버 서명

mini filter driver 스터디 - 미니 필터 드라이버 생성 및 기본 개념

Windows Hardware Lab Kit

Windows 하드웨어 인증 요구 사항 다운로드 링크

Windows 하드웨어 인증 요구 사항 - 필터 드라이버

windows7, 8.1 > HCK

windows10 > HLK


Windows 드라이버 서명 자습서

코드 서명 모범 사례

드라이버 서명 설치 문제 해결

Windows Hardware Dev Center dashboard

Windows HCK Getting Started

Practical Windows Code and Driver Signing

안전모드에서 디바이스 드라이버를 사용하기 위해서는 드라이버를 정적 로딩을 해야 한다.
정적 로딩을 하기 위해서는 CreateService() 호출시 SERVICE_BOOT_START 로
등록후 리부팅을 해야 한다.

SERVICE_BOOT_START 로 등록하기 위해서는 .sys 파일이 c:\windows\system32\drivers 에 있어야 한다.

정적 등록된 드라이버를 안전모드에서 사용하기 위해서는

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SafeBoot\Minimal
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SafeBoot\Network

에 드라이버 이름으로 키를 만드고 (확장자 불필요), 기본값에 REG_SZ 로 "Driver" 라고 적어주면 된다.

드라이버에서 현재 안전모드인지 확인하기

Windows 운영 체제 커널 InitSafeBootMode라는 ULONG 변수에 포인터를 내보냅니다. 이 변수는 안전 모드 설정이 포함 되어 있습니다.

다음 표에서 다른 값에 대 한 모드입니다.

값 모드
1 SAFEBOOT_MINIMAL
2 SAFEBOOT_NETWORK
3 * SAFEBOOT_DSREPAIR

  • 참고값 3 Windows 도메인 컨트롤러에만 적용 됩니다.

extern PULONG InitSafeBootMode;

시스템 안전 모드에서 실행 중인지 여부를 확인 하려면 InitSafeBootMode 값을 확인 해야 합니다.

if (*InitSafeBootMode > 0){

     // The system is in Safe Mode.
     // Take appropriate action.
     //
}

출처: Hacker N0te

Windbg에서 디버깅을 하기위해선 심볼을 설정해주어야한다.

File -> Symbol Search Path 에 다음과 같이 입력해주면 된다.

SRVc:\symbolshttp://msdl.microsoft.com/download/symbols

커널디버깅 중 심볼을 로드하는경우

kd> .reload 명령어를 통하여 심볼을 재등록하도록 한다.

출처: Hacker N0te

Windbg 명령어 모음

eb
eb 주소값 00 00 00 00 00 : 주소값부터 시작해서 5바이트를 00으로 채운다.

  • 심볼이 맞는지 확인하는 명령
    0:000> !chksym ntdll

  • ntdll의 Export 함수 변경여부 확인하는 명령
    0:000> !chkimg ntdll -d

  • notepad.exe의 _EPROCESS 주소 찾기
    kd> !process 0 0 notepad.exe

  • notepad.exe의 스레드 주소 찾기(full detail 얻기)

kd> !process _EPROCESS 7
PROCESS 8a3ceda0  SessionId: 0  Cid: 00f0    Peb: 7ffd7000  ParentCid: 0748
DirBase: 53ca5000  ObjectTable: e180c200  HandleCount: 411.
Image: xxx.exe
VadRoot 8a27db68 Vads 103 Clone 0 Private 591. Modified 2014. Locked 0.
DeviceMap e1862530
Token                             e5750d48
ElapsedTime                       00:04:22.375
UserTime                          00:00:00.187
KernelTime                        00:00:00.734
QuotaPoolUsage[PagedPool]         43944
QuotaPoolUsage[NonPagedPool]      4600
Working Set Sizes (now,min,max)  (1748, 50, 345) (6992KB, 200KB, 1380KB)
PeakWorkingSetSize                1748
VirtualSize                       46 Mb
PeakVirtualSize                   48 Mb
PageFaultCount                    4595
MemoryPriority                    BACKGROUND
BasePriority                      8
CommitCharge                      945

UserTime, KernelTime : 유난히 이 값이 높다면, 시스템 리소스를 대폭 감소시키는 프로세스라고 생각할 수 있다.
Working Set Sizes : 페이지 단위. 유난히 값이 높다면, 메모리 누수가 있거나 시스템 리소스를 대폭 감소시키는 프로세스의 표시로 볼 수 있다.
QuotaPoolUsageentries : 프로세스에서 사용되는 paged, nonpaged pool를 열거. 메모리 릭 시스템에서 모든 프로세스에서 과도한 nonpaged pool usage를 찾으면 프로세스가 메모리 릭을 갖고있다고 말할 수 있다.

  • notepad.exe의 주스레드를 이용 Context Swiching
    kd> .thread /p /r 주스레드

  • notepad.exe의 프로세스를 이용 Context Switching
    kd> !process /i XXXXXXXX

  • 모든 활성화된 프로세스의 정보를 보여줘라
    kd> !process 0
    PROCESS 897a9da0  SessionId: 0  Cid: 0914    Peb: 7ffdb000  ParentCid: 03dc
    DirBase: 6c325000  ObjectTable: e569ccd0  HandleCount: 103.
    Image: alg.exe

897a9da0 : EPROCESS 주소
Cid : 프로세스 아이디
e569ccd0 : Process Object Address(이건 뭥미? !handle로 호출을 해보면 정보를 더 얻어올수 있다)

현재디버깅중인 프로세스 보여줘라
kd> !process
해당 프로세스정보를 보여줘라
kd> !process 0 0 explorer.exe
유저심볼을 로드하라
.reload /user
강제로딩
.reload /i

유저모들에서 kd로 전환
.breakin

전체시스템메모리 보기 
kd>!vm

0:000> !handle (핸들 인덱스 생략이기 때문에 현재 프로세스 핸들 모두를 display)
0:000> !handle 8 f (핸들 인덱스 8에 대해서 모든 정보 display)
kd> !handle 0 4 (핸들 인덱스로 0이 입력되었기 때문에 모든 핸들 display, UMFlags값으로 4번이므로 "핸들이름"만 포함)
kd> !handle 14 13 (핸들 인덱스 14번에 대해서 "커널핸들테이블"로부터 정보 display)

bp 1002d7be "dps poi(pThunkData) L1;gc"
bp 명령어로 1002d7be 지점에 브레이크 포인트를 걸고, 이 브레이크 포인트가 Hit 되었을 때
이후에 나오는 "" 내부의 명령어를 실행하라는 의미이다.
dps 명령은 해당 메모리의 내용을 심벌로 보여주는 명령이다.
poi 는 포인터 참조 명령어로 C 언어의 * 와 같은 효과이다.
bp WS2_32!send "db poi(ebp+0x08);gc"
WS2_32!send가 Hit할때 그때의 ebp+0x08이 가리키고 있는 값을 바이트로 표시해주고 계속 실행하라는 명령
bu kernel32!CreateProcessW "db poi(esp+8)" 
CreateProcessW에서 Hit할때 2번째 매개변수로 입력된 값을 보고자 할때
bu 주소값 "j eax=9 'r eax';'gc'"
bu 주소값 ".if (eax=9) {r eax} .else {gc}"
위의 구문은 strlen()명령 다음에 멈출려고 했던 명령인데, 길이가 9인 경우는 eax값을 출력하고 멈추는 것이고, 9가 아닌 다른 값이면 계속 실행하라는 의미이다. 그 아래에 있는 명령은 .if를 사용한 완전히 똑같은 명령이다. 취향에 따라서 골라서 써라.

조건 브레이크는 특정조건일때에만 멈추게 할 수 있으므로 잘 아는것이 중요하다.
위의 명령에다가 메시지를 뿌려주고자 할때에는 다음과 같이 할 수가 있다.
bu 주소값 "j eax=9 '.echo eax9' ; 'gc'"
bu 주소값 ".if (eax=9) {.echo eax
9} .else {.echo eax!=9; gc}"
두개 이상의 명령을 사용하려면 ;으로 명령어를 구분한다.
gc커맨드를 쓰는 이유는 g커맨드는 F5결과이고 gc커맨드는 F10결과이다

핸들값이 0인 경우에는 메시지만 뿌려주고 계속 진행하고, 0이 아닌 경우는 멈춰라
bp nt!NtTerminateProcess ".if( poi(esp+4)=0 ) {.echo esp+4==0; gc} .else { }"

address에 1바이트 쓰기가 될때 멈춰라
ba w1 address

패턴모두에 대해서 멈춰라
bm notepad!Win*

bd 0-3
0번부터 3번까지를 Disable해주겠다.

0:000> dt pThunkData -r1
Local var @ 0x7f5c8 Type _IMAGE_THUNK_DATA32*
0x01001104
+0x000 u1 : _IMAGE_THUNK_DATA32::
+0x000 ForwarderString : 0x7c8107f0
+0x000 Function : 0x7c8107f0
+0x000 Ordinal : 0x7c8107f0
+0x000 AddressOfData : 0x7c8107f0
dt 명령어는 structure 를 표시해주는 명령어이고, 옵션인 –r1 은 내부에 또 다른 structure 가 있을 때 1 단계까지 펼쳐서 보여준다는 의미이다.

.reload
.reload /u kernel32.dll (디버깅 심볼 언로딩)
.reload /i kernel32.dll(강제 로딩)
.reload /f kernel32.dll(즉시 로딩)
ld
ld kernel32(deferred loading된 디버깅 심볼 로딩. 주의 확장자 없음)
lm
lmv : 상세정보볼때
lml : 디버깅 심볼이 로딩된 모듈만 보여줘라.
~
~# : 예외를 일으킨 쓰레드를 볼때 사용
k
kf : 로컬스택의 크기를 보고자 할때 사용
kn : 스택프레임 번호를 함께 본다.
.frame 1 : 해당 프레임 설정
kp : 함수정보출력
kb : 인자표시
kv : FPO 정보표시
g
gu : 현재 함수 종료까지 실행하겠다.
lmi
!lmi user32.dll (모듈상세정보표시)
x
x /v user32!BitBlt 심볼타입표시
x /v user32!BitBlt 데이터타입표시
x /n user32!Text* 이름순정렬
r
r $proc 현재 프로세스의 PEB주소, 현재 프로세스의 EPROCESS주소
r $thread 현재 스레드의 TEB주소, 현재 스레드의 ETHREAD주소
r $tpid 현재 프로세스 PID
r $tid 현재 스레드 ID
dv
dv /i (변수 심볼유형, 인자유형 표시)
dv /v (변수저장위치표시)
dt
dt _EPROCESS 주소 : 주소를 _EPROCESS형으로 변환해서 표시
dt _PEB @$peb : 현재 프로세스 PEB정보를 보여줘라
dpu 
dpu 주소 l4 (UNICODE 스트링 배열을 덤프해라)
s
s -d 00100000 0010F000 C0000005 (00100000 ~ 0010F000사이에서 C00000005의 값을 찾아라)
다른 스레드는 Freeze 시키고 현재 스레드에서 한 문장 실행
~.t
스레드 0을 제외한 모든 스레드 Freeze 시키고 현재 함수 복귀할때까지 실행
~0 gu

windbg 상태에서 regedit를 열어보지 않고 레지스트리값들을 확인해 볼 수 있다.
0:000> !dreg hklm\System\Select!*

Value: "Current" - REG_DWORD: 3 = 0x00000003

Value: "Default" - REG_DWORD: 3 = 0x00000003
Value: "Failed" - REG_DWORD: 2 = 0x00000002
Value: "LastKnownGood" - REG_DWORD: 4 = 0x00000004

0:000> !uniqstack -b
Processing 2 threads, please wait
.  0  Id: ab8.de8 Suspend: 1 Teb: 7ffdd000 Unfrozen
Start: WinDbgTest!mainCRTStartup (00401ad6)
Priority: 0  Priority class: 32  Affinity: 3
ChildEBP RetAddr  Args to Child
0013ff38 00401962 00252124 5c2e0280 7ffde000 WinDbgTest!OnBnClickedBtnCheckMem+0x29 [D:\Work_Test__WINDBG_\WinDbgTest\WinDbgTest.cpp @ 76]
0013ff4c 00401bb9 00000001 00032c38 00033288 WinDbgTest!main+0xc [D:\Work_Test__WINDBG_\WinDbgTest\WinDbgTest.cpp @ 138]
0013ffc0 7c816fe7 00252124 5c2e0280 7ffde000 WinDbgTest!mainCRTStartup+0xe3
0013fff0 00000000 00401ad6 00000000 78746341 kernel32!BaseProcessStart+0x23
.  1  Id: ab8.e6c Suspend: 1 Teb: 7ffdc000 Unfrozen
Priority: 0  Priority class: 32  Affinity: 3
ChildEBP RetAddr  Args to Child
003affc8 7c981e38 00000005 00000004 00000001 ntdll!DbgBreakPoint+0x1
003afff4 00000000 00000000 00000000 00000000 ntdll!DbgUiRemoteBreakin+0x2d
Total threads: 2

해당 메모리의 속성을 보여줘라
0:000> !vprot 0013ff34
BaseAddress:       0013f000
AllocationBase:    00040000
AllocationProtect: 00000004  PAGE_READWRITE
RegionSize:        00001000
State:             00001000  MEM_COMMIT
Protect:           00000004  PAGE_READWRITE
Type:              00020000  MEM_PRIVATE

할당된 가상메모리 덤프
!vadump -v

!list 명령

errlook 실행하지 말고 아래의 명령어로 해당 명령어 설명을 확인해라
!error 2

0:000> !imgreloc (로드된 모듈들의 재배치되기전의 주소 출력해라)
00400000 WinDbgTest - at preferred address
76d90000 Apphelp - at preferred address
77bc0000 MSVCRT - at preferred address
77d80000 RPCRT4 - at preferred address
77ef0000 Secur32 - at preferred address
77f50000 ADVAPI32 - at preferred address
7c800000 kernel32 - at preferred address
7c930000 ntdll - at preferred address

로드된 모듈들에 대한 커스터마이징 출력해라
!for_each_module ["명령어"]
예) !for_each_module .echo @#ModuleIndex : @#Base @#End @#ModuleName @#ImageName  @#LoadedImageName

가상메모리에서 MZ검색
.imgscan

디버그 레지스터 확인
0:000> rm 0x20;r
범용레지스터 확인
0:000> rm 0x01;r

r eip=7c800000
r eax = @ebx; 수도코드를 사용해서 바꿀수 있다는 부분에 주목
r zf=0; 플래그값도 바꿀수 있다는 부분에 주목

특정주소에 어셈블 코드 삽입
a eip
00000000 sub esp,10

진수변경
n 8(10, 16)

커널모드에서 함수 사용시간 측정 명령어
kernrate -z module -j module

특정 메시지만 필터링하기
.ofilter "test" : test가 들어가는 모든것을 보여줘
.ofilter "test" : test만 보여줘
.ofiter /i "test" : test만 제외하고 다 보여줘

실행시 옵션 -logo, -c
출력창에 뿌려지는 문자열을 아래 명시한 파일로 생성해줘라.
windbg -logo "console.log"

실행시의 동작을 -c를 이용해서 해주는 예제
windbg -logo "console.log" -c ".reload" -c "~*kb"

watch, local 변수창에 유니코드 표시
.enable_unicode 1

비스타이상에서 DbgPrint 출력을 해줘라
ed Kd_DEFAULT_MASK 8

출처: Hacker N0te

출처: Hacker N0te

[windows] 윈도우 64bit Driver 서명없이 로드하기

64bit windows driver sign

안타깝지만 64비트 윈도우의 경우 드라이버에 정식 서명이 되어있지 않으면 시스템에 Load할 수 없습니다.

MSDN에 보면 다음과 같이 나와있습니다.
서명된 장치 드라이버는 Windows의 주요 보안 기능입니다. x64 기반 컴퓨터에 설치된 드라이버에는 디지털 서명이 있어야 합니다. 디지털 서명이 필요하지 않더라도 x86 기반 컴퓨터에 드라이버를 설치하기 전에 드라이버가 서명되어 있는지 확인하는 것이 좋습니다.
부팅에 필요한 모든 드라이버에는 포함된 서명이 있어야 합니다. PnP(플러그 앤 플레이) 드라이버에는 디지털 서명이 필요하지 않습니다. 그러나 실행 중인 운영 체제에 서명되지 않은 PnP 드라이버가 설치되어 있을 경우에는 관리자 자격 증명이 필요하며 64비트 운영 체제에는 이러한 드라이버를 설치할 수 없습니다.

x86 기반에서는 상관이 없습니다!

다르게 말하면 x86에선 악성코드를 만들기도 더 쉽다는 얘기가 되고, 더욱 취약하다는 이야기가 됩니다.

x64에선 패치가드라는게 존재해서 Kernel에서 SSDT후킹등이 불가능하여 제약이 많습니다. 하지만 이 또한 x86에선 가능합니다.

본론으로 가서 저희는 정식 배포를 위해 x64 테스트가 필요하지만 아직 개발중이거나 공식 인증서가 없는곳도 있을겁니다.
그렇기에 MS에서 제공되는 인증서 없이 Driver Load 방법을 소개하겠습니다.

윈도우 8.1 기준 화면 이며, 윈도우 10의 설정은 시작->설정 에 있습니다.
시작 설정

부팅시 나오는 시작 설정 화면입니다.

윈도우 8.1부터는 F8을 눌러도 안전모드에 들어갈 수 없어졌기때문에 해당 방법으로 해야하는 불편함이 있습니다.

  1. 디버깅 사용

  2. 부팅 로깅 사용

  3. 저해상도 비디오 사용

  4. 안전모드 사용

  5. 안전모드 (네트워킹 사용) 사용

  6. 안전모드 (명령 프롬프트 사용) 사용

  7. 드라이버 서명 적용 사용 안 함

  8. 맬웨어 방지 보호 조기 실행 사용 안 함

  9. 오류 발생 후 자동 다시 시작 사용 안 함

이중 저희가 원하는 기능은 7번 입니다.

숫자 7 키를 누르시거나 F7 을 누르시면 해당 모드로 부팅되며,

해당 방법은 부팅시 매번 해주어야 합니다.

vmware등 테스트 PC의 경우엔 TEST MODE로 동작하는 방법이 별도로 존재하며,

로컬 PC의 경우엔 해당 방법으로 필요할때만 부팅하시는 방법을 권장해드리겠습니다.

매번 위의 방법으로 부팅해야 드라이버가 로드 되는 불편함이 있겠지만, TEST와 사용을 병행하는 PC의 경우엔 이 방법이 조금 더 안전하겠네요

출처: Hacker N0te

http://www.windbg.org/

http://kktechkaizen.blogspot.com/2011/06/windows-mini-filter-driver.html