1. Introduce
커널 인라인 후킹을 하기 위하여 WriteProtect( CR0 레지스터 내 WP)를 비활성화 하기 위해서 입니다.
2. Memory Descriptor List (MDL)
가상 메모리(Virtual Address)는 연속된 메모리 주소를 가지고 있으나. 물리 메모리(Physical Memory)의 경우 연속적이지 않을 수 있으며 OS는 MDL을 이용하여 가상 메모리(Virtual Memory)의 물리 메모리(Physical Memory) 페이지 레이아웃을 설명한다.
라고 MSDN에서 설명하며 또한 MDL은 반투명한(semi-opque) 구조체라 Next, MdlFlags를 제외한
다른 멤버에 대하여 직접 접근을 하지 말 것을 권고하며
접근을 할 경우에 특정 매크로를 사용하라고 설명하고 있습니다.
Mdl의 구조체와 해당 맴버의 정보를 얻는 매크로들을 주석으로 작성하였습니다.
0: kd> dt _MDL
nt!_MDL
+0x000 Next : Ptr64 _MDL // Direct Access
+0x008 Size : Int2B // MmGetMdlByteCount
+0x00a MdlFlags : Int2B // Direct Access
+0x00c AllocationProcessorNumber : Uint2B
+0x00e Reserved : Uint2B
+0x010 Process : Ptr64 _EPROCESS
+0x018 MappedSystemVa : Ptr64 Void // MmGetSystemAddressForMdlSafe
+0x020 StartVa : Ptr64 Void
+0x028 ByteCount : Uint4B // MmGetMdlByteCount
+0x02c ByteOffset : Uint4B // MmGetMdlByteOffset
// +0x30 physical address area // non offical
// #define MmGetMdlVirtualAddress(Mdl)
// (PVOID) ((PCHAR) ((Mdl)->StartVa) + (Mdl)->ByteOffset))
C
복사
3. PoC
PoC에 사용할 소스입니다.
/*
#Name : driver.c
#Desc : Driver Main
*/
#include "define.h"
NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriver, IN PUNICODE_STRING pRegPath)
{
UNREFERENCED_PARAMETER(pDriver);
UNREFERENCED_PARAMETER(pRegPath);
pDriver->DriverUnload = UnloadDriver;
DbgPrintEx(DPFLTR_ACPI_ID, 0, "[+] Load Driver\n");
PMDL pMDL = NULL;
pMDL = IoAllocateMdl(ExAllocatePoolWithTag, 0x10, FALSE, FALSE, NULL);
/*
PMDL IoAllocateMdl(
__drv_aliasesMem PVOID VirtualAddress, // [in, optional] MDL이 설명할 가상 주소 포인터
ULONG Length, // [in] MDL이 설명할 길이
BOOLEAN SecondaryBuffer, // [in] 버퍼가 기본버퍼인지 보조 버퍼인지 결정 여부를 나타내는 변수.
BOOLEAN ChargeQuota, // Reserved 변수. 무조건 FALSE
PIRP Irp // MDL과 연관 될 IRP에 대한 포인터.
);
*/
__try
{
MmProbeAndLockPages(pMDL, KernelMode, IoReadAccess);
/*
void MmProbeAndLockPages(
PMDL MemoryDescriptorList, // MDL 포인터
KPROCESSOR_MODE AccessMode, // AccessMode에 대한 값 "KernalMode" 또는 "UserMode" 중 선택
LOCK_OPERATION Operation //
);
*/
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
IoFreeMdl(pMDL);
DbgPrintEx(DPFLTR_ACPI_ID, 0, "[!] IoAllocateMdl Error\n");
return STATUS_FAILED_DRIVER_ENTRY;
}
PVOID MappingData = MmMapLockedPagesSpecifyCache(pMDL, KernelMode, MmNonCached, NULL, FALSE, NormalPagePriority);
if (MappingData)
{
MmUnmapLockedPages(MappingData, pMDL);
}
MmUnlockPages(pMDL);
IoFreeMdl(pMDL);
return STATUS_SUCCESS;
}
VOID UnloadDriver(IN PDRIVER_OBJECT pDriver)
{
UNREFERENCED_PARAMETER(pDriver);
DbgPrintEx(DPFLTR_ACPI_ID, 0, "[+] Unload Driver\n");
}
C
복사
/*
# Name : define.h
# Desc : 사용할 함수를 정의함
*/
#pragma once
#include <ntifs.h>
#pragma warning(disable: 4152) // nonstandar extension warning disable
// define DrvierEntry, Unload Driver
NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriver, IN PUNICODE_STRING pRegPath);
VOID UnloadDriver(IN PDRIVER_OBJECT pDriver);
C
복사
3.0 MdlFlags
wdm.h 에 정의되어 있는 MdlFlags입니다.
#define MDL_MAPPED_TO_SYSTEM_VA 0x0001
#define MDL_PAGES_LOCKED 0x0002
#define MDL_SOURCE_IS_NONPAGED_POOL 0x0004
#define MDL_ALLOCATED_FIXED_SIZE 0x0008
#define MDL_PARTIAL 0x0010
#define MDL_PARTIAL_HAS_BEEN_MAPPED 0x0020
#define MDL_IO_PAGE_READ 0x0040
#define MDL_WRITE_OPERATION 0x0080
#define MDL_LOCKED_PAGE_TABLES 0x0100
#define MDL_PARENT_MAPPED_SYSTEM_VA MDL_LOCKED_PAGE_TABLES
#define MDL_FREE_EXTRA_PTES 0x0200
#define MDL_DESCRIBES_AWE 0x0400
#define MDL_IO_SPACE 0x0800
#define MDL_NETWORK_HEADER 0x1000
#define MDL_MAPPING_CAN_FAIL 0x2000
#define MDL_PAGE_CONTENTS_INVARIANT 0x4000
#define MDL_ALLOCATED_MUST_SUCCEED MDL_PAGE_CONTENTS_INVARIANT
#define MDL_INTERNAL 0x8000
#define MDL_MAPPING_FLAGS (MDL_MAPPED_TO_SYSTEM_VA | \
MDL_PAGES_LOCKED | \
MDL_SOURCE_IS_NONPAGED_POOL | \
MDL_PARTIAL_HAS_BEEN_MAPPED | \
MDL_PARENT_MAPPED_SYSTEM_VA | \
MDL_SYSTEM_VA | \
MDL_IO_SPACE )
C
복사
3.1 IoAllocateMdl
IoAllocateMdl을 호출한 뒤 MDL입니다.
1: kd> dt _mdl ffffc60c83a9fc20
nt!_MDL
+0x000 Next : (null)
+0x008 Size : 0n56
+0x00a MdlFlags : 0n8 // MDL_ALLOCATED_FIXED_SIZE
+0x00c AllocationProcessorNumber : 1
+0x00e Reserved : 0xffff
+0x010 Process : 0xffffc60c`81bb9340 _EPROCESS
+0x018 MappedSystemVa : 0xffff8981`99ce5928 Void
+0x020 StartVa : 0xfffff807`46dc9000 Void
+0x028 ByteCount : 0x10
+0x02c ByteOffset : 0x160
//physical address area
1: kd> dp ffffc60c83a9fc20+0x30
ffffc60c`83a9fc50 00000000`00023c7e 00000000`0007d68f
ffffc60c`83a9fc60 00000000`00004e08 00000000`00005109
ffffc60c`83a9fc70 006d0061`0069006c 00700070`0041005c
ffffc60c`83a9fc80 00610074`00610044 0063006f`004c005c
ffffc60c`83a9fc90 004d005c`006c0061 006f0072`00630069
ffffc60c`83a9fca0 00740066`006f0073 0065006e`004f005c
ffffc60c`83a9fcb0 00760069`00720044 006e004f`005c0065
ffffc60c`83a9fcc0 00690072`00440065 0065002e`00650076
1: kd> !db 23c7e*1000+0x160 // (MDL+0x30)*1000 + ByteOffset
#23c7e160 5c 00 77 00 69 00 6e 00-65 00 76 00 74 00 5c 00 \.w.i.n.e.v.t.\.
#23c7e170 4c 00 6f 00 67 00 73 00-5c 00 53 00 79 00 73 00 L.o.g.s.\.S.y.s.
#23c7e180 74 00 65 00 6d 00 2e 00-65 00 76 00 74 00 78 00 t.e.m...e.v.t.x.
#23c7e190 00 00 78 00 00 00 38 00-45 00 34 00 45 00 37 00 ..x...8.E.4.E.7.
#23c7e1a0 43 00 2e 00 70 00 66 00-00 00 35 00 43 00 2d 00 C...p.f...5.C.-.
#23c7e1b0 41 00 42 00 35 00 45 00-2d 00 34 00 44 00 39 00 A.B.5.E.-.4.D.9.
#23c7e1c0 41 00 2d 00 42 00 42 00-41 00 31 00 2d 00 37 00 A.-.B.B.A.1.-.7.
#23c7e1d0 34 00 35 00 39 00 41 00-41 00 35 00 34 00 32 00 4.5.9.A.A.5.4.2.
C
복사
IoAllocateMdl 호출한 뒤 아직 Physical Address에는 ExAllocatePoolWithTag가 아직 할당되어 있지 않습니다.
3.2 MmProbeAndLockPages
MmProbeAndLockPages을 호출한 뒤 MDL입니다.
1: kd> dt _mdl ffffc60c83a9fc20
nt!_MDL
+0x000 Next : (null)
+0x008 Size : 0n56
+0x00a MdlFlags : 0n10 // MDL_ALLOCATED_FIXED_SIZE | MDL_PAGES_LOCKED
+0x00c AllocationProcessorNumber : 1
+0x00e Reserved : 0xffff
+0x010 Process : (null)
+0x018 MappedSystemVa : 0xffff8981`99ce5928 Void
+0x020 StartVa : 0xfffff807`46dc9000 Void
+0x028 ByteCount : 0x10
+0x02c ByteOffset : 0x160
1: kd> dp ffffc60c83a9fc20+0x30
ffffc60c`83a9fc50 00000000`00003db3 00000000`0007d68f
ffffc60c`83a9fc60 00000000`00004e08 00000000`00005109
ffffc60c`83a9fc70 006d0061`0069006c 00700070`0041005c
ffffc60c`83a9fc80 00610074`00610044 0063006f`004c005c
ffffc60c`83a9fc90 004d005c`006c0061 006f0072`00630069
ffffc60c`83a9fca0 00740066`006f0073 0065006e`004f005c
ffffc60c`83a9fcb0 00760069`00720044 006e004f`005c0065
ffffc60c`83a9fcc0 00690072`00440065 0065002e`00650076
1: kd> !db 3db3*1000 +0x160 //(MDL+0x30)*1000 + ByteOffset
# 3db3160 48 89 5c 24 08 48 89 6c-24 10 48 89 74 24 18 57 H.\$.H.l$.H.t$.W
# 3db3170 41 56 41 57 48 83 ec 30-65 48 8b 04 25 20 00 00 AVAWH..0eH..% ..
# 3db3180 00 45 8b f0 44 0f b7 3d-74 6e 34 00 48 8b ea 8b .E..D..=tn4.H...
# 3db3190 f1 4c 8b 88 c0 00 00 00-41 0f b7 b9 92 00 00 00 .L......A.......
# 3db31a0 0f ba ef 1f 0f ba f7 1f-33 db 8b c7 89 5c 24 68 ........3....\$h
# 3db31b0 44 8b c8 89 5c 24 20 45-8b c6 48 8b d5 8b ce e8 D...\$ E..H.....
# 3db31c0 cc 23 96 ff 48 85 c0 0f-84 2b 00 00 00 48 8b d8 .#..H....+...H..
# 3db31d0 48 8b 6c 24 58 48 8b c3-48 8b 5c 24 50 48 8b 74 H.l$XH..H.\$PH.t
1: kd> db ExAllocatePoolWithTag
fffff807`46dc9160 48 89 5c 24 08 48 89 6c-24 10 48 89 74 24 18 57 H.\$.H.l$.H.t$.W
fffff807`46dc9170 41 56 41 57 48 83 ec 30-65 48 8b 04 25 20 00 00 AVAWH..0eH..% ..
fffff807`46dc9180 00 45 8b f0 44 0f b7 3d-74 6e 34 00 48 8b ea 8b .E..D..=tn4.H...
fffff807`46dc9190 f1 4c 8b 88 c0 00 00 00-41 0f b7 b9 92 00 00 00 .L......A.......
fffff807`46dc91a0 0f ba ef 1f 0f ba f7 1f-33 db 8b c7 89 5c 24 68 ........3....\$h
fffff807`46dc91b0 44 8b c8 89 5c 24 20 45-8b c6 48 8b d5 8b ce e8 D...\$ E..H.....
fffff807`46dc91c0 cc 23 96 ff 48 85 c0 0f-84 2b 00 00 00 48 8b d8 .#..H....+...H..
fffff807`46dc91d0 48 8b 6c 24 58 48 8b c3-48 8b 5c 24 50 48 8b 74 H.l$XH..H.\$PH.t
C
복사
MdlFlags에 MDL_PAGES_LOCKED가 추가되었고 Physical Memory 주소값이 변경되었습니다.
또한 바뀐 Physical Address 주소에 ExAllocatePoolWithTag 함수가 매핑되었습니다.
3.3 MmMapLockedPagesSpecifyCache
MmMapLockedPagesSpecifyCache을 호출한 뒤 MDL입니다.
1: kd> dt _mdl ffffc60c83a9fc20
nt!_MDL
+0x000 Next : (null)
+0x008 Size : 0n56
+0x00a MdlFlags : 0n11 // MDL_ALLOCATED_FIXED_SIZE | MDL_PAGES_LOCKED | MDL_MAPPED_TO_SYSTEM_VA
+0x00c AllocationProcessorNumber : 1
+0x00e Reserved : 0xffff
+0x010 Process : (null)
+0x018 MappedSystemVa : 0xffff8981`99ce6160 Void // Mapped
+0x020 StartVa : 0xfffff807`46dc9000 Void
+0x028 ByteCount : 0x10
+0x02c ByteOffset : 0x160
1: kd> dp ffffc60c83a9fc20+0x30
ffffc60c`83a9fc50 00000000`00003db3 00000000`0007d68f
ffffc60c`83a9fc60 00000000`00004e08 00000000`00005109
ffffc60c`83a9fc70 006d0061`0069006c 00700070`0041005c
ffffc60c`83a9fc80 00610074`00610044 0063006f`004c005c
ffffc60c`83a9fc90 004d005c`006c0061 006f0072`00630069
ffffc60c`83a9fca0 00740066`006f0073 0065006e`004f005c
ffffc60c`83a9fcb0 00760069`00720044 006e004f`005c0065
ffffc60c`83a9fcc0 00690072`00440065 0065002e`00650076
1: kd> !db 3db3*1000 +0x160
# 3db3160 48 89 5c 24 08 48 89 6c-24 10 48 89 74 24 18 57 H.\$.H.l$.H.t$.W
# 3db3170 41 56 41 57 48 83 ec 30-65 48 8b 04 25 20 00 00 AVAWH..0eH..% ..
# 3db3180 00 45 8b f0 44 0f b7 3d-74 6e 34 00 48 8b ea 8b .E..D..=tn4.H...
# 3db3190 f1 4c 8b 88 c0 00 00 00-41 0f b7 b9 92 00 00 00 .L......A.......
# 3db31a0 0f ba ef 1f 0f ba f7 1f-33 db 8b c7 89 5c 24 68 ........3....\$h
# 3db31b0 44 8b c8 89 5c 24 20 45-8b c6 48 8b d5 8b ce e8 D...\$ E..H.....
# 3db31c0 cc 23 96 ff 48 85 c0 0f-84 2b 00 00 00 48 8b d8 .#..H....+...H..
# 3db31d0 48 8b 6c 24 58 48 8b c3-48 8b 5c 24 50 48 8b 74 H.l$XH..H.\$PH.t
1: kd> db 0xffff8981`99ce6160 // MappedSystemVa
ffff8981`99ce6160 48 89 5c 24 08 48 89 6c-24 10 48 89 74 24 18 57 H.\$.H.l$.H.t$.W
ffff8981`99ce6170 41 56 41 57 48 83 ec 30-65 48 8b 04 25 20 00 00 AVAWH..0eH..% ..
ffff8981`99ce6180 00 45 8b f0 44 0f b7 3d-74 6e 34 00 48 8b ea 8b .E..D..=tn4.H...
ffff8981`99ce6190 f1 4c 8b 88 c0 00 00 00-41 0f b7 b9 92 00 00 00 .L......A.......
ffff8981`99ce61a0 0f ba ef 1f 0f ba f7 1f-33 db 8b c7 89 5c 24 68 ........3....\$h
ffff8981`99ce61b0 44 8b c8 89 5c 24 20 45-8b c6 48 8b d5 8b ce e8 D...\$ E..H.....
ffff8981`99ce61c0 cc 23 96 ff 48 85 c0 0f-84 2b 00 00 00 48 8b d8 .#..H....+...H..
ffff8981`99ce61d0 48 8b 6c 24 58 48 8b c3-48 8b 5c 24 50 48 8b 74 H.l$XH..H.\$PH.t
C
복사
MappedSystemVa 주소값이 변경되었고 ExAllocatePoolWithTag가 Mapped 되었습니다.
해당 방법을 통하여 Kernel Inline 후킹이 가능합니다.
1.
후킹 할 함수를 MDL로 매핑 합니다.
2.
MmProtectMdlSystemAddress 함수를 이용하여 매핑 한 MDL의 Protect를 PAGE_READWRITE로 변경합니다.
3.
인라인 패치를 수행합니다.