1: kd> kvL 
 # ChildEBP RetAddr  Args to Child               
00 de94f82c 81534f6b 00000050 915c7488 00000011 nt!KeBugCheckEx 
01 de94f8d0 814e2912 915c7488 de94f9a0 00237d80 nt!MiSystemFault+0x83b (FPO: [Non-Fpo]) 
02 de94f988 815e4941 00000011 915c7488 00000000 nt!MmAccessFault+0x162 (FPO: [Non-Fpo]) 
03 de94f988 915c7488 00000011 915c7488 00000000 nt!KiTrap0E+0x2c9 (FPO: [0,0] TrapFrame @ de94fa28) 
WARNING: Frame IP not in any known module. Following frames may be wrong. 
04 de94fbb8 8157c748 8aea3f10 93763078 93763008 0x915c7488 
05 de94fbd4 817ffad9 0c002a26 00000208 0014ee94 nt!IofCallDriver+0x48 (FPO: [Non-Fpo]) 
06 de94fcb8 817ff52a 00000000 00000000 0014eea4 nt!IopXxxControlFile+0x5a9 (FPO: [Non-Fpo]) 
07 de94fce4 815de4ef 00000208 00000000 00000000 nt!NtDeviceIoControlFile+0x2a (FPO: [Non-Fpo]) 
08 de94fce4 770b07a0 00000208 00000000 00000000 nt!KiSystemServicePostCall (FPO: [0,3] TrapFrame @ de94fd14) 
09 0014eec4 00000000 00000000 00000000 00000000 0x770b07a0 

 

크래쉬 시점에 콜 스택을 오면 5번. nt!iofCallDriver  후 Trap 이 걸린걸 확인 할 수 있다. 

 

 

03 de94f988 915c7488 00000011 915c7488 00000000 nt!KiTrap0E+0x2c9 (FPO: [0,0] TrapFrame @ de94fa28) 

1: kd> .trap de94fa28 
ErrCode = 00000011 
eax=ffffffff ebx=93763008 ecx=87b92875 edx=00010004 esi=ffffffff edi=00000004 
eip=915c7488 esp=de94fa9c ebp=de94fbb8 iopl=0         nv up ei ng nz na pe nc 
cs=0008  ss=0010  ds=0023  es=0023  fs=0030  gs=0000             efl=00010286 
915c7488 0500800010      add     eax,10008000h 
1: kd> kvL 
  *** Stack trace for last set context - .thread/.cxr resets it 
 # ChildEBP RetAddr  Args to Child               
WARNING: Frame IP not in any known module. Following frames may be wrong. 
00 de94fbb8 8157c748 8aea3f10 93763078 93763008 0x915c7488 
01 de94fbd4 817ffad9 0c002a26 00000208 0014ee94 nt!IofCallDriver+0x48 (FPO: [Non-Fpo]) 
02 de94fcb8 817ff52a 00000000 00000000 0014eea4 nt!IopXxxControlFile+0x5a9 (FPO: [Non-Fpo]) 
03 de94fce4 815de4ef 00000208 00000000 00000000 nt!NtDeviceIoControlFile+0x2a (FPO: [Non-Fpo]) 
04 de94fce4 770b07a0 00000208 00000000 00000000 nt!KiSystemServicePostCall (FPO: [0,3] TrapFrame @ de94fd14) 
05 0014eec4 00000000 00000000 00000000 00000000 0x770b07a0 

 

.trap 명령으로 트랙이 걸린 시점에 context들을 확인 할 수 있다. 

 

nt!IofCallDriver: 
8157c700 8bff            mov     edi,edi 
8157c702 55              push    ebp 
8157c703 8bec            mov     ebp,esp 
8157c705 83e4f8          and     esp,0FFFFFFF8h 
8157c708 a1b0307281      mov     eax,dword ptr [nt!IopDispatchCallDriver (817230b0)] 
8157c70d 53              push    ebx 
8157c70e 56              push    esi 
8157c70f 8bf1            mov     esi,ecx 
8157c711 85c0            test    eax,eax 
8157c713 0f85f57b0a00    jne     nt!IofCallDriver+0xa7c0e (8162430e)  Branch 

nt!IofCallDriver+0x19: 
8157c719 fe4a23          dec     byte ptr [edx+23h] 
8157c71c 8a4223          mov     al,byte ptr [edx+23h] 
8157c71f 84c0            test    al,al 
8157c721 0f8ed97b0a00    jle     nt!IofCallDriver+0xa7c00 (81624300)  Branch 

nt!IofCallDriver+0x27: 
8157c727 8b4260          mov     eax,dword ptr [edx+60h] 
8157c72a 83e824          sub     eax,24h 
8157c72d 894260          mov     dword ptr [edx+60h],eax 
8157c730 8a18            mov     bl,byte ptr [eax] 
8157c732 897014          mov     dword ptr [eax+14h],esi 
8157c735 80fb16          cmp     bl,16h 
8157c738 7414            je      nt!IofCallDriver+0x4e (8157c74e)  Branch 

nt!IofCallDriver+0x3a: 
8157c73a 8b4e08          mov     ecx,dword ptr [esi+8] 
8157c73d 0fb6c3          movzx   eax,bl 
8157c740 52              push    edx 
8157c741 56              push    esi 
8157c742 8b448138        mov     eax,dword ptr [ecx+eax*4+38h] 
8157c746 ffd0            call    eax 

nt!IofCallDriver+0x48: 
8157c748 5e              pop     esi

 

01 de94fbd4 817ffad9 0c002a26 00000208 0014ee94 nt!IofCallDriver+0x48 (FPO: [Non-Fpo]) 

 

콜스택 상 nt!IofCallDriver+0x48 부분에서 크래쉬가 발생하였지만 크래시 발생 시점의 다음 명령주소를 가르킨다. 

그래서 실제 크래시 위치는 8157c746  이 된다. 

일단 eax를 역분석을 통해 구해 본다. 

 

8157c742 8b448138        mov     eax,dword ptr [ecx+eax*4+38h] 

 

eax는 [ecx+eax*4+38h]값의 데이터 이다. 

ecx 는  8157c73a 8b4e08          mov     ecx,dword ptr [esi+8]에서 구해 오고 있다. 

esi는 함수의 시작 위치부분까지 찾아봤을때,  8157c70f 8bf1            mov     esi,ecx 이 위치에서 ecx 값으로 대체 된것을 볼수 있다. 

 

해당 함수는 fastcall 방식으로 1번째 인자는 ecx, 2번째 인자는 edx 그리고 나머지를 스택에 저장 한다. 

여기서 fastcall 이라고 알 수 있는 이유는 해당 함수를 호출한곳에서 인자를 어떻게 전달하는지 보면 알 수 있다. 

 

817ffac9 0f852d020000    jne     nt!IopXxxControlFile+0x7cc (817ffcfc) 
817ffacf 8bd6            mov     edx,esi 
817ffad1 8b4d94          mov     ecx,dword ptr [ebp-6Ch] 
817ffad4 e827ccd7ff      call    nt!IofCallDriver (8157c700)

 

  nt!IopXxxControlFile 함수에서 nt!IofCallDriver 함수를 호출하기전에 ecx 와 edx 에 데이터를 넣고 있는것 볼 수 있다. 있는 fastcall 방식임을 암시 한다. 

 

nt!IopXxxControlFile 함수 위 부분을 보면 아래와 같은 코드를 볼수있다. 

 

817ff80c e87fcbd7ff      call    nt!IopAllocateIrpExReturn (8157c390) 
817ff811 8bf0            mov     esi,eax 
817ff813 8975a4          mov     dword ptr [ebp-5Ch],esi

 

irp 를 생성하고 그 생성된 값을 esi 에 저장 한다음 해당 함수의 BasePointer(Ebp) 에서 -5C 부분에 저장 하고 있다. 

결국 esi 값은 irp 임을 알수 있고 해당 데이터는 해당 함수의 BasePointer -5c 부분을 가져 오면된다. 

 

 

     Ebp         Ret       Arg1

02 de94fcb8 817ff52a 00000000 00000000 0014eea4 nt!IopXxxControlFile+0x5a9 (FPO: [Non-Fpo]) 

Windbg 에서 kvL 명령으로 콜스택을 보면 2번재 부분이 해당 함수의 EBP 값을 가지고 있다. 

 

[de94fcb8 - 5c] 메모리 값은 

1: kd> dd de94fcb8 - 5c L1 
de94fc5c  93763008

93763008 이다. 

 

!irp 명령으로 irp 데이터인지 확인 

1: kd> !irp 93763008  
Irp is active with 1 stacks 1 is current (= 0x93763078) 
 No Mdl: System buffer=8b44ea80: Thread b2f22a80:  Irp stack trace.   
     cmd  flg cl Device   File     Completion-Context 
>[IRP_MJ_DEVICE_CONTROL(e), N/A(0)] 
            5  0 8aea3f10 915c7488 00000000-00000000     
       \Driver\JRSKD24 
Args: 00000004 0000028c 0x22e018 00000000 

 

IRP 데이터임이 확인 되었다. 

nt!IofCallDriver 함수를 호출 할때 esi 데이터가 irp 이므로 두번재 인자로 irp 데이터가 전달되었다. 

이제 ecx 값을 구하면 된다 .  nt!IofCallDriver 함수 원형을 찾아 보면 첫 번째 인자로 deviceObject 가 전달된다. 

 

817ffad1 8b4d94          mov     ecx,dword ptr [ebp-6Ch]
817ffad4 e827ccd7ff      call    nt!IofCallDriver (8157c700)

 

 nt!IofCallDriver  호출 하기전 바로 위 코드르를 보면 [ebp-6Ch]값을 ecx 로 전달 하고 있다. 예상컨데 해당 값은 deviceObject 가 확실 할 것이다. 

[de94fcb8 -0x6c] 데이터를 찾아가 보면 

 

1: kd> dd [de94fcb8 -0x6c]
de94fc4c  8aea3f10 00000001 0000028c 00000000
de94fc5c  93763008 00000000 01000000 00000004

 

 

1: kd> !devobj 8aea3f10 
Device object (8aea3f10) is for:
 JRSKD24 \Driver\JRSKD24 DriverObject c43eb4d0
Current Irp 00000000 RefCount 1 Type 00000022 Flags 00000044
SecurityDescriptor 866ef450 DevExt 00000000 DevObjExt 8aea3fc8 
ExtensionFlags (0x00000800)  DOE_DEFAULT_SD_PRESENT
Characteristics (0x00000100)  FILE_DEVICE_SECURE_OPEN
Device queue is not busy.

 

deviceObje 임을 확인 할 수 있다. 

 

다시 크래쉬가 발생 한 함수  nt!IofCallDriver  로 돌아가서 분석을 진행 한다. 

ecx = 8aea3f10    -> deviceObject

edx = 93763008  ->  Irp 

 

 

 

최종 ecx 는 구조체 deviceObject 에서 8바이트 떨어진 지점의 데이터 이다. 

 

1: kd> dt _Device_Object  8aea3f10  
nt!_DEVICE_OBJECT
   +0x000 Type             : 0n3
   +0x002 Size             : 0xb8
   +0x004 ReferenceCount   : 0n1
   +0x008 DriverObject     : 0xc43eb4d0 _DRIVER_OBJECT
   +0x00c NextDevice       : (null) 
   +0x010 AttachedDevice   : (null) 
   +0x014 CurrentIrp       : (null) 
   +0x018 Timer            : (null) 
   +0x01c Flags            : 0x44
   +0x020 Characteristics  : 0x100
   +0x024 Vpb              : (null) 
   +0x028 DeviceExtension  : (null) 
   +0x02c DeviceType       : 0x22
   +0x030 StackSize        : 1 ''
   +0x034 Queue            : <unnamed-tag>
   +0x05c AlignmentRequirement : 0
   +0x060 DeviceQueue      : _KDEVICE_QUEUE
   +0x074 Dpc              : _KDPC
   +0x094 ActiveThreadCount : 0
   +0x098 SecurityDescriptor : 0x866ef450 Void
   +0x09c DeviceLock       : _KEVENT
   +0x0ac SectorSize       : 0
   +0x0ae Spare1           : 0
   +0x0b0 DeviceObjectExtension : 0x8aea3fc8 _DEVOBJ_EXTENSION
   +0x0b4 Reserved         : (null) 

 

 

결국 ecx 는 0xc43eb4d0 _DRIVER_OBJECT 임을 알 수 있다. 

8157c742 8b448138        mov     eax,dword ptr [ecx+eax*4+38h]
8157c746 ffd0            call    eax

 

 

eax 는 bl 값을 가지고 있다. bl은 2바이트 크기를 가진다. 

edx + 60 은 irp +60의 값이다. 메모리 값을 직접 찾아보면 

 

1: kd> dd 93763008+ 0x60                                   mov     eax,dword ptr [edx+60h]
93763068  93763078 915c7488 00000000 00000000
93763078  0005000e 00000004 0000028c 0022e018

 

1: kd> dd 93763078                                            mov     bl,byte ptr [eax]
93763078  0005000e 00000004 0000028c 0022e018

byte 즉 1바이트많을 bl에 저장 하고 있으므로 bl의 값은 0xe 이다.

최종적으로 eax 값은 0xe를 가진다. 

 

ecx = 0xc43eb4d0 _DRIVER_OBJECT 

eax = 0xe

8157c742 8b448138        mov     eax,dword ptr [ecx+eax*4+38h] 
8157c746 ffd0            call    eax

 

이제 해당 값을 연산해 보면

[0xc43eb4d0 + 0e *4 + 0x38] = >c43eb540

 

1: kd> dd c43eb540
c43eb540  87b9bc76 87b9ba1e 87b9ba1e 87b9ba1e

 

1: kd> u 87b9bc76 

 

모 모듈의 함수 임을 알 수 있다.  결론적으로 해당 함수를 호출 하면서 크래쉬가 발생 했다. 

 

 

[0xc43eb4d0 + 0e *4 + 0x38] = >c43eb540

데이터를 좀더 분석 해 보면

0xc43eb4d0 즉 driveObject의 내부의 데이터이임을 알수 있으므로 driveObject 구조체 내용을 확인해 보면 다음과 같다 

 

 

1: kd> dt _DRIVER_OBJECT 0xc43eb4d0 
nt!_DRIVER_OBJECT
   +0x000 Type             : 0n4
   +0x002 Size             : 0n168
   +0x004 DeviceObject     : 0x8aea3f10 _DEVICE_OBJECT
   +0x008 Flags            : 0x12
   +0x00c DriverStart      : 0x87b80000 Void
   +0x010 DriverSize       : 0x2a800
   +0x014 DriverSection    : 0x93544008 Void
   +0x018 DriverExtension  : 0xc43eb578 _DRIVER_EXTENSION
   +0x01c DriverName       : _UNICODE_STRING "\Driver\JRSKD24"
   +0x024 HardwareDatabase : 0x81a78238 _UNICODE_STRING "\REGISTRY\MACHINE\HARDWARE\DESCRIPTION\SYSTEM"
   +0x028 FastIoDispatch   : (null) 
   +0x02c DriverInit       : 0x87b9cdae     long  +0
   +0x030 DriverStartIo    : (null) 
   +0x034 DriverUnload     : 0x87b9c23e     void  +0
   +0x038 MajorFunction    : [28] 0x87b9b9e2     long  +0
1: kd> dx -id 0,0,998fa040 -r1 (*((ntkrpamp!long (*(*)[28])(_DEVICE_OBJECT *,_IRP *))0xc43eb508))
(*((ntkrpamp!long (*(*)[28])(_DEVICE_OBJECT *,_IRP *))0xc43eb508))                 [Type: long (* [28])(_DEVICE_OBJECT *,_IRP *)]
    [0]              : 0x87b9b9e2 [Type: long (*)(_DEVICE_OBJECT *,_IRP *)]
    [1]              : 0x87b9ba1e [Type: long (*)(_DEVICE_OBJECT *,_IRP *)]
    [2]              : 0x87b9bae2 [Type: long (*)(_DEVICE_OBJECT *,_IRP *)]
    [3]              : 0x87b9ba1e [Type: long (*)(_DEVICE_OBJECT *,_IRP *)]
    [4]              : 0x87b9ba1e [Type: long (*)(_DEVICE_OBJECT *,_IRP *)]
    [5]              : 0x87b9ba1e [Type: long (*)(_DEVICE_OBJECT *,_IRP *)]
    [6]              : 0x87b9ba1e [Type: long (*)(_DEVICE_OBJECT *,_IRP *)]
    [7]              : 0x87b9ba1e [Type: long (*)(_DEVICE_OBJECT *,_IRP *)]
    [8]              : 0x87b9ba1e [Type: long (*)(_DEVICE_OBJECT *,_IRP *)]
    [9]              : 0x87b9ba1e [Type: long (*)(_DEVICE_OBJECT *,_IRP *)]
    [10]             : 0x87b9ba1e [Type: long (*)(_DEVICE_OBJECT *,_IRP *)]
    [11]             : 0x87b9ba1e [Type: long (*)(_DEVICE_OBJECT *,_IRP *)]
    [12]             : 0x87b9ba1e [Type: long (*)(_DEVICE_OBJECT *,_IRP *)]
    [13]             : 0x87b9ba1e [Type: long (*)(_DEVICE_OBJECT *,_IRP *)]
   [14]             : 0x87b9bc76 [Type: long (*)(_DEVICE_OBJECT *,_IRP *)]
    [15]             : 0x87b9ba1e [Type: long (*)(_DEVICE_OBJECT *,_IRP *)]
    [16]             : 0x87b9ba1e [Type: long (*)(_DEVICE_OBJECT *,_IRP *)]
    [17]             : 0x87b9ba1e [Type: long (*)(_DEVICE_OBJECT *,_IRP *)]
    [18]             : 0x87b9ba1e [Type: long (*)(_DEVICE_OBJECT *,_IRP *)]
    [19]             : 0x87b9ba1e [Type: long (*)(_DEVICE_OBJECT *,_IRP *)]
    [20]             : 0x87b9ba1e [Type: long (*)(_DEVICE_OBJECT *,_IRP *)]
    [21]             : 0x87b9ba1e [Type: long (*)(_DEVICE_OBJECT *,_IRP *)]
    [22]             : 0x87b9ba1e [Type: long (*)(_DEVICE_OBJECT *,_IRP *)]
    [23]             : 0x87b9ba1e [Type: long (*)(_DEVICE_OBJECT *,_IRP *)]
    [24]             : 0x87b9ba1e [Type: long (*)(_DEVICE_OBJECT *,_IRP *)]
    [25]             : 0x87b9ba1e [Type: long (*)(_DEVICE_OBJECT *,_IRP *)]
    [26]             : 0x87b9ba1e [Type: long (*)(_DEVICE_OBJECT *,_IRP *)]
    [27]             : 0x8155dae0 [Type: long (*)(_DEVICE_OBJECT *,_IRP *)]

 

해당 드라이버의 14번 index 의 디스패치 루틴의 주소 값이다.

위 인덱스는 디바이스드라이버 개발 문서를 보면 확인 할 수 있다. 아래 URL 참조 docs.microsoft.com/en-us/windows-hardware/drivers/ifs/registering-irp-dispatch-routines

 

이상 덤프를 분석하여 문제가 되는 함수를 찾았다.

 

 

 

 

 

'개발 > Windows' 카테고리의 다른 글

[windbg] - 1  (0) 2021.05.26
[악성코드 분석]  (0) 2021.02.28
PE구조 (1)  (0) 2020.09.12

+ Recent posts