이번 덤프의 BugCheck는 0x50이다. 0x50은 대부분 다른 모듈이 메모리를 손상시켰거나 정말 유효하지 않은 메모리나 해제된 메모리를 접근할 때 주로 발생한다. 원인에 따라 분석이 불가능한 경우도 많다.
다행히 이번 덤프는 어렵지 않으면서 재미도 있으니 가벼운 마음으로 시작해보자.
kd> !analyze -v
*******************************************************************************
* *
* Bugcheck Analysis *
* *
*******************************************************************************
PAGE_FAULT_IN_NONPAGED_AREA (50)
Invalid system memory was referenced. This cannot be protected by try-except.
Typically the address is just plain bad or it is pointing at freed memory.
Arguments:
Arg1: ffff0000, memory referenced.
Arg2: 00000000, value 0 = read operation, 1 = write operation.
Arg3: 82ad19fe, If non-zero, the instruction address which referenced the bad memory
address.
Arg4: 00000000, (reserved)
Debugging Details:
------------------
DUMP_CLASS: 1
DUMP_QUALIFIER: 401
BUILD_VERSION_STRING: 7601.17514.x86fre.win7sp1_rtm.101119-1850
SYSTEM_MANUFACTURER: VMware, Inc.
VIRTUAL_MACHINE: VMware
SYSTEM_PRODUCT_NAME: VMware Virtual Platform
SYSTEM_VERSION: None
BIOS_VENDOR: Phoenix Technologies LTD
BIOS_VERSION: 6.00
BIOS_DATE: 07/31/2013
BASEBOARD_MANUFACTURER: Intel Corporation
BASEBOARD_PRODUCT: 440BX Desktop Reference Platform
BASEBOARD_VERSION: None
DUMP_TYPE: 1
BUGCHECK_P1: ffffffffffff0000
BUGCHECK_P2: 0
BUGCHECK_P3: ffffffff82ad19fe
BUGCHECK_P4: 0
READ_ADDRESS: ffff0000
FAULTING_IP:
nt!strstr+1e
82ad19fe 8a07 mov al,byte ptr [edi]
MM_INTERNAL_CODE: 0
CPU_COUNT: 1
CPU_MHZ: e07
CPU_VENDOR: GenuineIntel
CPU_FAMILY: 6
CPU_MODEL: 3c
CPU_STEPPING: 3
CPU_MICROCODE: 6,3c,3,0 (F,M,S,R) SIG: 19'00000000 (cache) 19'00000000 (init)
DEFAULT_BUCKET_ID: WIN7_DRIVER_FAULT
BUGCHECK_STR: 0x50
PROCESS_NAME: MyApp.exe
CURRENT_IRQL: 2
ANALYSIS_SESSION_HOST: PAUL-PC
ANALYSIS_SESSION_TIME: 11-29-2017 10:35:11.0546
ANALYSIS_VERSION: 10.0.10575.567 amd64fre
TRAP_FRAME: 89812c30 -- (.trap 0xffffffff89812c30)
ErrCode = 00000000
eax=ffff0000 ebx=00000000 ecx=9213a600 edx=ffff4d5c esi=ffff0000 edi=ffff0000
eip=82ad19fe esp=89812ca4 ebp=89813bfc iopl=0 nv up ei pl nz na pe nc
cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00010206
nt!strstr+0x1e:
82ad19fe 8a07 mov al,byte ptr [edi] ds:0023:ffff0000=??
Resetting default scope
LAST_CONTROL_TRANSFER: from 82a933d8 to 82ae041b
STACK_TEXT:
89812c18 82a933d8 00000000 ffff0000 00000000 nt!MmAccessFault+0x106
89812c18 82ad19fe 00000000 ffff0000 00000000 nt!KiTrap0E+0xdc
89813bfc 82a89593 84525860 843f0858 843f0858 nt!strstr+0x1e
89813c14 82c7d99f 84489e18 843f0858 843f08c8 nt!IofCallDriver+0x63
89813c34 82c80b71 84525860 84489e18 00000000 nt!IopSynchronousServiceTail+0x1f8
89813cd0 82cc73f4 84525860 843f0858 00000000 nt!IopXxxControlFile+0x6aa
89813d04 82a901ea 0000015c 00000000 00000000 nt!NtDeviceIoControlFile+0x2a
89813d04 76fd70b4 0000015c 00000000 00000000 nt!KiFastCallEntry+0x12a
0012f7f0 00000000 00000000 00000000 00000000 0x76fd70b4
STACK_COMMAND: kb
THREAD_SHA1_HASH_MOD_FUNC: 1d162d18111a222172b462becb3845e53e690213
THREAD_SHA1_HASH_MOD_FUNC_OFFSET: d3c548c893cd75b9806e6f8940169c9ae8e41dba
THREAD_SHA1_HASH_MOD: cb5f414824c2521bcc505eaa03e92fa10922dad8
FOLLOWUP_IP:
nt!strstr+1e
82ad19fe 8a07 mov al,byte ptr [edi]
FAULT_INSTR_CODE: c683078a
SYMBOL_STACK_INDEX: 2
SYMBOL_NAME: nt!strstr+1e
FOLLOWUP_NAME: MachineOwner
MODULE_NAME: nt
IMAGE_NAME: ntkrpamp.exe
DEBUG_FLR_IMAGE_TIMESTAMP: 4ce78a09
IMAGE_VERSION: 6.1.7601.17514
FAILURE_BUCKET_ID: 0x50_nt!strstr+1e
BUCKET_ID: 0x50_nt!strstr+1e
PRIMARY_PROBLEM_CLASS: 0x50_nt!strstr+1e
TARGET_TIME: 2017-11-28T10:00:12.000Z
OSBUILD: 7601
OSSERVICEPACK: 1000
SERVICEPACK_NUMBER: 0
OS_REVISION: 0
SUITE_MASK: 272
PRODUCT_TYPE: 1
OSPLATFORM_TYPE: x86
OSNAME: Windows 7
OSEDITION: Windows 7 WinNt (Service Pack 1) TerminalServer SingleUserTS
OS_LOCALE:
USER_LCID: 0
OSBUILD_TIMESTAMP: 2010-11-20 17:42:49
BUILDDATESTAMP_STR: 101119-1850
BUILDLAB_STR: win7sp1_rtm
BUILDOSVER_STR: 6.1.7601.17514.x86fre.win7sp1_rtm.101119-1850
ANALYSIS_SESSION_ELAPSED_TIME: 83a
ANALYSIS_SOURCE: KM
FAILURE_ID_HASH_STRING: km:0x50_nt!strstr+1e
FAILURE_ID_HASH: {955d5f89-fa0e-8221-ae1a-1f21f03e2986}
Followup: MachineOwner
---------
가장 먼저 .trap 명령을 사용해서 문제가 발생한 부분으로 컨텍스트를 맞춰야한다.
kd> .trap 0xffffffff89812c30
ErrCode = 00000000
eax=ffff0000 ebx=00000000 ecx=9213a600 edx=ffff4d5c esi=ffff0000 edi=ffff0000
eip=82ad19fe esp=89812ca4 ebp=89813bfc iopl=0 nv up ei pl nz na pe nc
cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00010206
nt!strstr+0x1e:
82ad19fe 8a07 mov al,byte ptr [edi] ds:0023:ffff0000=??
nt!strstr+0x1e 명령을 수행하다 ffff0000 주소가 유효하지 않아 문제가 발생했다.
kv 명령으로 파라미터를 포함한 콜 스택을 확인해보자.
kd> kv
*** Stack trace for last set context - .thread/.cxr resets it
# ChildEBP RetAddr Args to Child
00 89813bfc 82a89593 84525860 843f0858 843f0858 nt!strstr+0x1e
01 89813c14 82c7d99f 84489e18 843f0858 843f08c8 nt!IofCallDriver+0x63
02 89813c34 82c80b71 84525860 84489e18 00000000 nt!IopSynchronousServiceTail+0x1f8
03 89813cd0 82cc73f4 84525860 843f0858 00000000 nt!IopXxxControlFile+0x6aa
04 89813d04 82a901ea 0000015c 00000000 00000000 nt!NtDeviceIoControlFile+0x2a
05 89813d04 76fd70b4 0000015c 00000000 00000000 nt!KiFastCallEntry+0x12a (FPO: [0,3] TrapFrame @ 89813d34)
06 0012f7f0 00000000 00000000 00000000 00000000
0x76fd70b4
콜 스택을 보면 IofCallDriver 함수 내부에서 호출된 strstr 함수를 수행하다 문제가 발생한 것으로 보인다.
얼핏 봐서는 이상한 부분이 전혀 없지만 실은 굉장히 이상한 상황이다. IofCallDriver 함수 내부에는 strstr 함수를 부르는 곳이 없기 때문이다.
이게 도대체 무슨 소리인가? 부르지도 않은 함수가 콜 스택에 표시된다니 정말 말도 안 되는 상황이다. 사실 여부를 확인하기 위해 IofCallDriver 함수의 디스어셈블리 코드를 살펴 보자.
kd> u nt!IofCallDriver L30
nt!IofCallDriver:
82a8952f 8bff mov edi,edi
82a89531 55 push ebp
82a89532 8bec mov ebp,esp
82a89534 51 push ecx
82a89535 a15ccabb82 mov eax,dword ptr [nt!pIofCallDriver (82bbca5c)]
82a8953a 56 push esi
82a8953b 8bf1 mov esi,ecx
82a8953d 33c9 xor ecx,ecx
82a8953f 3bc1 cmp eax,ecx
82a89541 7409 je nt!IofCallDriver+0x1d (82a8954c)
82a89543 ff7504 push dword ptr [ebp+4]
82a89546 8bce mov ecx,esi
82a89548 ffd0 call eax
82a8954a eb47 jmp nt!IofCallDriver+0x63 (82a89593)
82a8954c fe4a23 dec byte ptr [edx+23h]
82a8954f 384a23 cmp byte ptr [edx+23h],cl
82a89552 7f0c jg nt!IofCallDriver+0x30 (82a89560)
82a89554 51 push ecx
82a89555 51 push ecx
82a89556 51 push ecx
82a89557 52 push edx
82a89558 6a35 push 35h
82a8955a e8a3790a00 call nt!KeBugCheckEx (82b30f02)
82a8955f cc int 3
82a89560 8b4260 mov eax,dword ptr [edx+60h]
82a89563 83e824 sub eax,24h
82a89566 894260 mov dword ptr [edx+60h],eax
82a89569 8a08 mov cl,byte ptr [eax]
82a8956b 897014 mov dword ptr [eax+14h],esi
82a8956e 80f916 cmp cl,16h
82a89571 7514 jne nt!IofCallDriver+0x57 (82a89587)
82a89573 8a4001 mov al,byte ptr [eax+1]
82a89576 3c02 cmp al,2
82a89578 7404 je nt!IofCallDriver+0x4e (82a8957e)
82a8957a 3c03 cmp al,3
82a8957c 7509 jne nt!IofCallDriver+0x57 (82a89587)
82a8957e 8bf2 mov esi,edx
82a89580 e8b6f2fdff call nt!IopPoHandleIrp (82a6883b)
82a89585 eb0c jmp nt!IofCallDriver+0x63 (82a89593)
82a89587 8b4608 mov eax,dword ptr [esi+8]
82a8958a 52 push edx
82a8958b 0fb6c9 movzx ecx,cl
82a8958e 56 push esi
82a8958f ff548838 call dword ptr [eax+ecx*4+38h]
82a89593 5e pop esi
82a89594 59 pop ecx
82a89595 5d pop ebp
82a89596
c3 ret
내 눈에는 strstr 함수를 호출하는 부분이 보이지 않는다. call dword ptr [eax+ecx*4+38h] 부분이 조금 의심스럽긴하다. 디스어셈블리 코드가 어려우니 간단한 의사 코드(Pseudo code)로 바꾼 코드를 보자.
NTSTATUS
IofCallDriver(
IN PDEVICE_OBJECT DeviceObject,
IN OUT PIRP Irp
)
{
PIO_STACK_LOCATION pIoStackLocation;
PDRIVER_OBJECT pDriverObject;
NTSTATUS ntStatus;
/* 조건에 따른 pIofCalldriver 함수 호출 */
Irp->CurrentLocation--;
// NO_MORE_IRP_STACK_LOCATIONS(0x35) 에러 처리
if (Irp->CurrentLocation <= 0)
{
KiBugCheckEx(NO_MORE_IRP_STACK_LOCATIONS, Irp, 0, 0, 0);
}
pIoStackLocation = IoGetNextIrpStackLocation( Irp );
Irp->Tail.Overlay.CurrentStackLocation = pIoStackLocation;
pIoStackLocation->DeviceObject = DeviceObject;
pDriverObject = DeviceObject->DriverObject;
// IRP 요청에 따른 드라이버의 디스패치 루틴 함수 호출
ntStatus = pDriverObject->MajorFunction[pIoStackLocation->MajorFunction](DeviceObject, Irp);
/* 조건에 따른 IopPoHandleIrp 함수 호출 */
return ntStatus;
}
어떤가? 어디에도 strstr 함수는 보이지 않는다. 나도 처음에는 굉장히 당황스럽고 혼란스러웠다.
다행히 예전에 IofCallDriver 함수를 분석해 본 경험이 있어 이상하다고 생각할 수 있었다.
이런 상황이라면 스택 정보에 문제가 있어 WinDbg가 정상적인 콜 스택을 보여주지 못하는 것은 아닌지 의심해볼 필요가 있다.
스택 정보를 담고 있는 곳은 esp(64비트는 rsp)다. dps esp 명령을 사용하면 콜 스택을 보는 k 명령으로 보여주지 않는 원본 스택 내용을 출력할 수 있다.
이 방법을 통해 스택에서 진짜 함수 호출의 흔적을 찾을 수 있다.
kd> dps esp
89812ca4 84525860
89812ca8 00000000
89812cac 84489e18
89812cb0 9213a4d1 MyDrv+0x44d1 // 2) 의심 부분
89812cb4 ffff0000
89812cb8 9213a600 MyDrv+0x4600 // 1) 의심 부분
89812cbc 00000060
89812cc0 ffff0000
89812cc4 00000000
89812cc8 00000000
89812ccc 0000000a
89812cd0 00000000
89812cd4 88173470
89812cd8 00000000
89812cdc 00000000
89812ce0 89812ca0
89812ce4 8454ba60
89812ce8 8d7e19ea
89812cec 9e50224a
89812cf0 88e1bb88
89812cf4 00000006
89812cf8 87148cde Ntfs!NtfsReadMftRecord+0x236
89812cfc 88e1ba98
89812d00 92d7c6a0
89812d04 8d7e1800
89812d08 00080008
89812d0c 89812d3c
89812d10 87163f6d Ntfs!NtfsFileIsEqual+0x56
89812d14 89812d2c
89812d18 89812d34
89812d1c 00000001
89812d20
896d4000
놀랍게도 콜 스택에 보이지 않던 MyDrv모듈의 함수 호출 흔적이 확인된다.
함수가 호출되면 esp에 함수 수행 후 복귀할 리턴 주소인 함수 호출 명령 다음 위치가 저장된다는 사실을 떠올려보자.
esp에 MyDrv 관련된 주소 두 곳이 보이는데, ub 명령으로 역 디스어셈블링했을 때 strstr 함수를 호출하는 부분이 바로 리턴 주소다.
1)번 위치인 MyDrv+4600 먼저 확인해보자.
kd> ub MyDrv+0x4600
MyDrv+0x45f8:
9213a5f8 cc int 3
9213a5f9 cc int 3
9213a5fa cc int 3
9213a5fb cc int 3
9213a5fc cc int 3
9213a5fd cc int 3
9213a5fe cc int 3
9213a5ff
cc int 3
strstr 함수 호출 부분이 확인되지 않으니 찾는 부분이 아니다.
다음 2)번 위치인 MyDrv+44d1을 확인해보자.
kd> ub MyDrv+44d1
MyDrv+0x44ab:
9213a4ab c7411c00000000 mov dword ptr [ecx+1Ch],0
9213a4b2 eb57 jmp MyDrv+0x450b (9213a50b)
9213a4b4 e857cbffff call MyDrv+0x1010 (92137010)
9213a4b9 8985c4f0ffff mov dword ptr [ebp-0F3Ch],eax
9213a4bf 6800a61392 push offset MyDrv+0x4600 (9213a600)
9213a4c4 8b95c4f0ffff mov edx,dword ptr [ebp-0F3Ch]
9213a4ca 52 push edx
9213a4cb ff1558801392 call
dword ptr [MyDrv+0x2058 (92138058)]
의미있는 정보가 나온다. 마지막 시점에 MyDrv+0x2058(92138058)가 가리키는 주소로 함수를 호출한다.
dword ptr 명령으로 92138058 주소를 참조하고 있으니 poi 명령으로 함수 호출한 부분을 확인해보자.
kd> u poi(92138058)
nt!strstr:
82ad19e0 8b4c2408 mov ecx,dword ptr [esp+8]
82ad19e4 57 push edi
82ad19e5 53 push ebx
82ad19e6 56 push esi
82ad19e7 8a11 mov dl,byte ptr [ecx]
82ad19e9 8b7c2410 mov edi,dword ptr [esp+10h]
82ad19ed 84d2 test dl,dl
82ad19ef
746f je
nt!strstr+0x80 (82ad1a60)
빙고! strstr 함수가 나온다. 스택의 2)번 위치인 MyDrv+0x44d1에서 strstr 함수를 호출했음이 밝혀졌다.
이제 문제 발생 원인에 초점을 맞춰보자. MyDrv 모듈에서 strstr 함수 호출시 전달한 파라미터에 문제가 있었을 가능성이 높다.
strstr 함수는 원본 문자열에 검색 문자열이 있을 경우 일치하는 원본 문자열의 첫 번째 위치를 리턴해주는데 함수 원형은 다음과 같다.
PTSTR StrStr(
_In_ PTSTR pszFirst,
_In_ PCTSTR pszSrch
함수 원형은 확인했으니 다시 dps esp 명령으로 스택 정보를 확인해보자.
kd> dps esp L10
89812ca4 84525860
89812ca8 00000000
89812cac 84489e18
89812cb0 9213a4d1 MyDrv+0x44d1 // esp+c : 리턴 어드레스
89812cb4 ffff0000 // esp+10 : 첫 번째 파라미터
89812cb8 9213a600 MyDrv+0x4600 // esp+14 : 두 번째 파라미터
89812cbc 00000060
89812cc0 ffff0000
89812cc4 00000000
89812cc8 00000000
89812ccc 0000000a
89812cd0 00000000
89812cd4 88173470
89812cd8 00000000
89812cdc 00000000
89812ce0
89812ca0
원본 문자열인 pszFirst 는 ffff0000이고, 검색할 문자열인 pszSrch는 9213a600이다.
문제가 되는 함수가 문자열 함수여서 da 명령으로 파라미터 문자열을 출력해 보았다.
kd> da ffff0000
ffff0000 "????????????????????????????????"
ffff0020 "????????????????????????????????"
ffff0040 "????????????????????????????????"
ffff0060 "????????????????????????????????"
ffff0080 "????????????????????????????????"
ffff00a0 "????????????????????????????????"
ffff00c0 "????????????????????????????????"
ffff00e0 "????????????????????????????????"
ffff0100 "????????????????????????????????"
ffff0120 "????????????????????????????????"
ffff0140 "????????????????????????????????"
ffff0160 "????????????????????????????????"
kd> da 9213a600
9213a600 "\Microsoft\Windows\Burn\"
원본 문자열인 첫 번재 파라미터의 주소는 페이지 아웃되어 ??로 표시된다. 접근할 수 없는 영역이라는 의미다. 검색 문자열인 두 번째 파라미터에는 정상적인 경로 문자열이 확인된다.
잘못된 주소인 ffff0000에서 "\Microsoft\Windows\Burn\" 문자열이 있는지 찾으려고 시도하다 문제가 발생한 것이 원인이다.
그렇다면, 원본 문자열 주소인 ffff0000는 어디서 온 것일까? ffff0000은 strstr 함수에 넘긴 첫 번째 파라미터니 strstr 함수를 호출한 MyDrv+44d1 부분을 다시 살펴보자.
kd> ub MyDrv+44d1
MyDrv+0x44ab:
9213a4ab c7411c00000000 mov dword ptr [ecx+1Ch],0
9213a4b2 eb57 jmp MyDrv+0x450b (9213a50b)
9213a4b4 e857cbffff call MyDrv+0x1010 (92137010) // 1) 내부 함수 호출
9213a4b9 8985c4f0ffff mov dword ptr [ebp-0F3Ch],eax // 2) eax를 ebp-f3c에 저장
9213a4bf 6800a61392 push offset MyDrv+0x4600 (9213a600) // 3) MyDrv+0x4600을 두 번째 파라미터로 push
9213a4c4 8b95c4f0ffff mov edx,dword ptr [ebp-0F3Ch] // 4) ebp-f3c을 edx에 저장
9213a4ca 52 push edx // 5) edx를 첫 번째 파라미터로 push
9213a4cb ff1558801392 call
dword ptr [MyDrv+0x2058 (92138058)] //
6) strstr 함수 호출
2)번을 보면 eax 값이 ebp-f3c에 저장되고, 4)번에서 다시 edx로 옮겨진다. 그리고 5)번을 보면 edx가 첫 번째 파라미터로 넘겨졌음을 알 수 있다.
즉 eax 가 첫 번째 파라미터이므로 2)번 앞 쪽에서 eax를 설정한 곳을 찾아봐야 한다.
1)번에 함수가 하나 호출되는데 그 안에서 eax가 설정되었을 가능성이 높다. 보통 eax는 함수 호출 완료 후 리턴 값을 저장하는 용도로 사용되기 때문이다.
1)번에서 호출된 함수 주소인 92137010을 살펴보자.
kd> u 92137010 L6
MyDrv+0x1010:
92137010 8bff mov edi,edi
92137012 55 push ebp
92137013 8bec mov ebp,esp
92137015 b80000ffff mov eax,0FFFF0000h // ffff0000을 eax에 저장
9213701a 5d pop ebp
9213701b c3 ret
이런! 이 함수에서 ffff0000 값을 리턴하고 있다. 이 값이 결국 strstr 함수의 첫 번째 파라미터로 전달되어 문제가 발생한 것이다.
이제 ffff0000을 리턴한 문제의 함수를 확인해서 정상적인 값을 리턴하도록 변경하면 문제가 해결될 것이다.
나는 앞서 원인 분석에 집중하기 위해 의도적으로 숨겨진 콜 스택이 발생한 이유에 대해서는 언급하지 않았다. 이제 문제 발생 원인에 대한 분석이 끝났으니 그 얘기를 마저 해보겠다.
콜 스택을 확인하는 k 명령으로 MyDrv의 콜 스택이 제대로 확인되지 않았던 이유는 strstr 함수가 컴파일된 방식에 원인이 있다.
다음은 strstr 함수와 memcpy 함수의 앞 부분을 비교한 내용이다.
<nt!strstr 함수 프롤로그>
kd> u nt!strstr
nt!strstr:
82ac59e0 8b4c2408 mov ecx,dword ptr [esp+8]
82ac59e4 57 push edi
82ac59e5 53 push ebx
82ac59e6 56 push esi
82ac59e7 8a11 mov dl,byte ptr [ecx]
82ac59e9 8b7c2410 mov edi,dword ptr [esp+10h]
82ac59ed 84d2 test dl,dl
82ac59ef 746f je nt!strstr+0x80 (82ac5a60)
<nt!memcpy 함수 프롤로그>
kd> u nt!memcpy
nt!memcpy:
82a7f7c0 55 push ebp
82a7f7c1 8bec mov ebp,esp
82a7f7c3 57 push edi
82a7f7c4 56 push esi
82a7f7c5 8b750c mov esi,dword ptr [ebp+0Ch]
82a7f7c8 8b4d10 mov ecx,dword ptr [ebp+10h]
82a7f7cb 8b7d08 mov edi,dword ptr [ebp+8]
82a7f7ce 8bc1 mov eax,ecx
어떤 차이가 보이는가? 32비트 환경에서 함수 호출을 하게 되면 기본적으로 스택의 베이스 포인터인 ebp를 기준으로 스택을 구성하게 된다.
memcpy 함수처럼 "push ebp, mov ebp, esp" 로 원본 ebp를 스택에 저장하고 현재 esp를 기준으로 ebp를 재설정하는 패턴이 함수 시작시 수행된다.
k 명령도 이 ebp 를 기준으로 콜 스택을 보여준다. 하지만 strstr 함수의 경우 재미있게도 ebp를 사용하지 않고 64비트 환경처럼 esp 를 기준으로 함수가 동작하게 컴파일되어 있다.
다음은 CompareString 함수 안에서 strstr 함수를 호출하는 테스트 코드를 만들어 콜 스택을 확인한 결과다.
1. CompareString 함수에서 strstr 함수 호출 전 콜 스택
kd> kv
# ChildEBP RetAddr Args to Child
00 92237bc8 913da27b 00000388 00000388 82b7d944 MyDrv!CompareString+0x37 (FPO: [Non-Fpo]) (CONV: stdcall)
01 92237d28 82a841ea 00000388 01f4f900 771670b4 MyDrv!TestMain+0x4b (FPO: [Non-Fpo]) (CONV: stdcall)
02 92237d28 771670b4 00000388 01f4f900 771670b4 nt!KiFastCallEntry+0x12a (FPO: [0,3] TrapFrame @ 92237d34)
kd> ub 913d9d3e
MyDrv!CompareString+0x26
913d9d27 7507 jne MyDrv!CompareString+0x2f (913d9d30)
913d9d29 32c0 xor al,al
913d9d2b e9b3000000 jmp MyDrv!CompareString+0xe2 (913d9de3)
913d9d30 8b55d0 mov edx,dword ptr [ebp-30h]
913d9d33 52 push edx
913d9d34 8b45dc mov eax,dword ptr [ebp-24h]
913d9d37 50 push eax
913d9d38 ff15f4103e91 call
dword ptr [MyDrv!_imp__strstr (913e10f4)] // 현재 strstr 함수를
호출하기 직전 상태
2. CompareString 함수에서 strstr 함수 호출 직후 콜 스택
kd> kv
# ChildEBP RetAddr Args to Child
00 92237bc8 913da27b 00000388 00000388 82b7d944 nt!strstr
01 92237d28 82a841ea 00000388 01f4f900 771670b4 MyDrv!TestMain+0x4b (FPO: [Non-Fpo]) (CONV: stdcall)
02 92237d28 771670b4 00000388 01f4f900 771670b4
nt!KiFastCallEntry+0x12a (FPO: [0,3] TrapFrame @ 92237d34)
예상대로 strstr 함수 내부에서 ebp를 설정하는 부분이 없으므로 CompareString 함수에 대한 콜 스택이 표시되지 않고 사라졌다.
이처럼 함수에 따라 예상과는 다른 코드 패턴으로 컴파일될 수 있다는 사실을 기억하자.
이 외에도 스택 오버플로우나 jmp를 이용한 코드 후킹 기법 등에 의해 스택이나 함수 프롤로그가 망가지면 ebp 기준으로 해석하는 k 명령은 콜 스택을 제대로 표시하지 못할 수 있다.
뭔가 콜 스택이 이상하다고 느껴지면 주저없이 dps esp(64비트는 rsp) 명령으로 스택을 확인하거나 k=address 명령으로 콜 스택을 재구성해보자. 의외의 단서를 얻을 수 있을 것이다.
'Dump Analysis' 카테고리의 다른 글
[0xC5] 풀 헤더 손상 (0) | 2018.07.16 |
---|---|
[0x1A] 페이지 손상 (0) | 2018.07.12 |
[0x50] 해제된 핸들 (0) | 2018.07.09 |
[0x50] UNICODE_STRING (0) | 2018.07.05 |
필터매니저(fltmgr.sys) 버그? DRAINING ZOMBIED 와 DOE_UNLOAD_PENDING (0) | 2015.01.22 |