SYSENTER 는 level 0 의 시스템 프로시져를 호출하기 위한 명령어입니다.
쉽게 얘기한다면, 어플리케이션 레벨에서 커널 레벨로 진입하기 위한 명령이며
Windows XP 를 기준으로 했을 때, API 의 호출은 다음의 예와 같습니다.
예-1) OpenProcess 의 System Service 호출
↓
ntdll!ZwOpenProcess
↓
ntdll!KiFastSystemCall
↓
↓
nt!NtOpenProcess
예-2) SendMessage 의 System Service 호출
↓
USER32!SendMessageWorker
↓
USER32!NtUserMessageCall
↓
ntdll!KiFastSystemCall
↓
↓
win32k!NtUserMessageCall
두 가지 예를 보면, 어플리케이션 레벨에서 마지막으로 불리는 함수는 ntdll!KiFastSystemCall 이고, 커널 레벨에서 처음 불리는 함수는 nt!KiFastCallEntry 로 동일한 것을 볼 수 있습니다. 이 때, (XP 일 때) ntdll!KiFastSystemCall 에서 사용되는 명령이 바로 sysenter 입니다.
nt!KiFastCallEntry 에서, 어플리케이션이 원하는 시스템 서비스를 호출하는 과정은 다음과 같이 확인할 수 있습니다.
분석하고자 하는 API가 어떤 함수들을 호출하고 있는지 확인합니다.
OpenProcess 를 확인해보겠습니다.
kernel32!OpenProcess (7c81e079)
kernel32!OpenProcess+0x43 (7c81e0bc):
call to ntdll!ZwOpenProcess (7c90dd7b)
kernel32!OpenProcess+0x54 (7c838bc7):
call to kernel32!BaseSetLastNTError (7c80937b)
windbg 의 명령어를 사용하여 OpenProcess 는, ntdll 의 ZwOpenProcess 를 호출하는 것을 알 수 있습니다.
(굳이 확인할 필요는 없지만) 이것을 실제 코드에서 확인해 보면,
kernel32!OpenProcess:
7c81e079 8bff mov edi,edi
7c81e07b 55 push ebp
7c81e07c 8bec mov ebp,esp
7c81e07e 83ec20 sub esp,20h
7c81e081 8b4510 mov eax,dword ptr [ebp+10h]
7c81e084 8945f8 mov dword ptr [ebp-8],eax
7c81e087 8b450c mov eax,dword ptr [ebp+0Ch]
7c81e08a 56 push esi
7c81e08b 33f6 xor esi,esi
7c81e08d f7d8 neg eax
7c81e08f 1bc0 sbb eax,eax
7c81e091 83e002 and eax,2
7c81e094 8945ec mov dword ptr [ebp-14h],eax
7c81e097 8d45f8 lea eax,[ebp-8]
7c81e09a 50 push eax
7c81e09b 8d45e0 lea eax,[ebp-20h]
7c81e09e 50 push eax
7c81e09f ff7508 push dword ptr [ebp+8]
7c81e0a2 8d4510 lea eax,[ebp+10h]
7c81e0a5 50 push eax
7c81e0a6 8975fc mov dword ptr [ebp-4],esi
7c81e0a9 c745e018000000 mov dword ptr [ebp-20h],18h
7c81e0b0 8975e4 mov dword ptr [ebp-1Ch],esi
7c81e0b3 8975e8 mov dword ptr [ebp-18h],esi
7c81e0b6 8975f0 mov dword ptr [ebp-10h],esi
7c81e0b9 8975f4 mov dword ptr [ebp-0Ch],esi
7c81e0bc ff150c11807c call dword ptr [kernel32!_imp__NtOpenProcess (7c80110c)]
7c81e0c2 3bc6 cmp eax,esi
7c81e0c4 5e pop esi
7c81e0c5 0f8cfbaa0100 jl kernel32!OpenProcess+0x53 (7c838bc6)
...
위와 같이 kernel32!_imp__NtOpenProcess 가 호출되는 것을 볼 수 있는데요,
해당 포인터의 값을 확인해보면
7c80110c 7c90dd7b 7c9505c7 7c95081a 7c950689
7c80111c 7c9507d9 7c90e5c4 7c9506de 7c90e030
7c80112c 7c95085c 7c95070d 7c950734 7c950759
7c80113c 7c9140fd 7c9135c0 7c92bff2 7c90d421
7c80114c 7c92be02 7c90d9b5 7c928436 7c90d865
7c80115c 7c92b4dd 7c90dfc7 7c92c095 7c926459
7c80116c 7c90f1cb 7c912f9b 7c929794 7c914210
7c80117c 7c9010ed 7c901005 7c90d976 7c929464
다음과 같이 ntdll!ZwOpenProcess 인 것을 알 수 있습니다.
ntdll!ZwOpenProcess:
7c90dd7b b87a000000 mov eax,7Ah
7c90dd80 ba0003fe7f mov edx,offset SharedUserData!SystemCallStub (7ffe0300)
7c90dd85 ff12 call dword ptr [edx]
7c90dd87 c21000 ret 10h
ZwOpenProcess 는 다시 7ffe0300를 호출합니다.
7ffe0300 7c90eb8b 7c90eb94 00000000 00000000
7ffe0310 00000000 00000000 00000000 00000000
7ffe0320 00000000 00000000 00000000 00000000
7ffe0330 ac7348b3 00000000 00000000 00000000
7ffe0340 00000000 00000000 00000000 00000000
7ffe0350 00000000 00000000 00000000 00000000
7ffe0360 00000000 00000000 00000000 00000000
7ffe0370 00000000 00000000 00000000 00000000
이 위치를 확인해보면 KiFastSystemCall 인 것을 알 수 있습니다.
ntdll!KiFastSystemCall:
7c90eb8b 8bd4 mov edx,esp
7c90eb8d 0f34 sysenter
7c90eb8f 90 nop
7c90eb90 90 nop
7c90eb91 90 nop
7c90eb92 90 nop
7c90eb93 90 nop
7c90eb94 c3 ret
그리고, KiFastSystemCall 에서 드디어, sysenter 명령이 등장합니다.
Intel 에서 제공하는 INSTRUCTION SET REFERENCE 를 보면,
sysenter 에 대하여 다음과 같은 내용을 확인할 수 있습니다.
MSRs Used By the SYSENTER and SYSEXIT Instructions
IA32_SYSENTER_CS 0x174 code segment selector
IA32_SYSENTER_ESP 0x175 stack
IA32_SYSENTER_EIP 0x176 code segment to the first instruction of the selected oparating procedure or routine.
대충 보면, IA32_SYSENTER_EIP 에, 수행할 프로시져의 첫 주소가 있다는 얘기 같습니다.
IA32_SYSENTER_EIP는 0x176의 Address 를 갖고 있으므로 다음과 같이 확인합니다.
msr[176] = 00000000`8053c710
해당 주소가 가리키는 함수가 무엇인지 확인해보면,
(8053c710) nt!KiFastCallEntry | (8053c819) nt!KiServiceExit
Exact matches:
nt!KiFastCallEntry = <no type information>
위와 같이 nt!KiFastCallEntry 임을 알 수 있습니다.
정리하면, sysenter 에 의해서 MSR 0x176 에 등록된 함수가 실행되고, 이 함수가 KiFastCall Entry 인것 같습니다.
MSR 0x176 에 등록된 주소가 커널 주소이기 때문에 이 부분에서 특권 전환이 나타날 것 같습니다.
실제 OpenProcess의 호출을 따라가기 위해 ZwOpenProcess 에 브레이크 포인트를 걸고
(주. 실제로 커널에서 호출을 따라갈 때에는 특정 프로세스를 타겟으로 하는 것이 좋을 것 같습니다.)
sysenter 호출 직전의 레지스터를 확인합니다.
eax=0000007a ebx=00b10388 ecx=00357290 edx=00abfc10 esi=00000000 edi=00b109e8
eip=7c90eb8d esp=00abfc10 ebp=00abfc4c iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
ntdll!KiFastSystemCall+0x2:
001b:7c90eb8d 0f34 sysenter
이제 특권 전환이 일어나고,
KiFastCallEntry 가 수행됩니다.
KiFastCallEntry 가 어떻게 동작되는지를 확인해보면,
8053c710 b923000000 mov ecx,23h
8053c715 6a30 push 30h
8053c717 0fa1 pop fs
8053c719 8ed9 mov ds,cx
8053c71b 8ec1 mov es,cx
8053c71d 8b0d40f0dfff mov ecx,dword ptr ds:[0FFDFF040h]
8053c723 8b6104 mov esp,dword ptr [ecx+4]
8053c726 6a23 push 23h
8053c728 52 push edx
8053c729 9c pushfd
8053c72a 6a02 push 2
8053c72c 83c208 add edx,8
...
8053c79d 8bf8 mov edi,eax
8053c79f c1ef08 shr edi,8
8053c7a2 83e730 and edi,30h
8053c7a5 8bcf mov ecx,edi
8053c7a7 03bee0000000 add edi,dword ptr [esi+0E0h] ds:0023:820dfc10={nt!KeServiceDescriptorTableShadow (80552140)}
8053c7ad 8bd8 mov ebx,eax
8053c7af 25ff0f0000 and eax,0FFFh
8053c7b4 3b4708 cmp eax,dword ptr [edi+8]
8053c7b7 0f8345fdffff jae nt!KiBBTUnexpectedRange (8053c502)
8053c7bd 83f910 cmp ecx,10h
8053c7c0 751a jne nt!KiFastCallEntry+0xcc (8053c7dc)
8053c7c2 8b0d18f0dfff mov ecx,dword ptr ds:[0FFDFF018h]
8053c7c8 33db xor ebx,ebx
8053c7ca 0b99700f0000 or ebx,dword ptr [ecx+0F70h]
8053c7d0 740a je nt!KiFastCallEntry+0xcc (8053c7dc)
8053c7d2 52 push edx
8053c7d3 50 push eax
8053c7d4 ff15c4215580 call dword ptr [nt!KeGdiFlushUserBatch (805521c4)]
8053c7da 58 pop eax
8053c7db 5a pop edx
8053c7dc ff0538f6dfff inc dword ptr ds:[0FFDFF638h]
8053c7e2 8bf2 mov esi,edx
8053c7e4 8b5f0c mov ebx,dword ptr [edi+0Ch]
8053c7e7 33c9 xor ecx,ecx
8053c7e9 8a0c18 mov cl,byte ptr [eax+ebx]
8053c7ec 8b3f mov edi,dword ptr [edi]
8053c7ee 8b1c87 mov ebx,dword ptr [edi+eax*4] ds:0023:80501218={nt!NtOpenProcess (805bfb78)}
8053c7f1 2be1 sub esp,ecx
8053c7f3 c1e902 shr ecx,2
8053c7f6 8bfc mov edi,esp
8053c7f8 3b35b47b5580 cmp esi,dword ptr [nt!MmUserProbeAddress (80557bb4)]
8053c7fe 0f83a8010000 jae nt!KiSystemCallExit2+0x9f (8053c9ac)
8053c804 f3a5 rep movs dword ptr es:[edi],dword ptr [esi]
8053c806 ffd3 call ebx {nt!NtOpenProcess (805bfb78)}
8053c808 8be5 mov esp,ebp
...
KeServiceDescriptorTableShadow 를 베이스 주소로 하여, eax*4만큼 떨어져있는 포인터의 함수를 호출하는것을 확인할 수 있습니다.
이 과정을 연산으로 확인해본다면,
80552140 80501030 00000000 0000011c 805014a4
80552150 bf997600 00000000 0000029b bf998310
80552160 00000000 00000000 00000000 00000000
80552170 00000000 00000000 00000000 00000000
80552180 80501030 00000000 0000011c 805014a4
80552190 00000000 00000000 00000000 00000000
805521a0 00000000 00000000 00000000 00000000
805521b0 00000000 00000000 00000000 00000000
80501030 8059849a nt!NtAcceptConnectPort
80501034 805e5666 nt!NtAccessCheck
80501038 805e8ec4 nt!NtAccessCheckAndAuditAlarm
8050103c 805e5698 nt!NtAccessCheckByType
80501040 805e8efe nt!NtAccessCheckByTypeAndAuditAlarm
80501044 805e56ce nt!NtAccessCheckByTypeResultList
80501048 805e8f42 nt!NtAccessCheckByTypeResultListAndAuditAlarm
8050104c 805e8f86 nt!NtAccessCheckByTypeResultListAndAuditAlarmByHandle
KeServiceDescriptorTableShadow 의 주소가 80501030 이고,
앞서 sysenter 호출 직전에 확인했던 레지스터에서 eax가 0x7a 이므로,
다음과 같이 나타낼 수 있을겁니다.
80501218 805bfb78 nt!NtOpenProcess
확인해 보면, 해당 주소는 nt!NtOpenProcess 의 함수 포인터인것을 알 수 있습니다.
정리하면,
sysenter 직전의 eax 값을 확인하여 해당 API 가 호출하는 System Service 를 확인 할 수 있고,
이로서 eax 의 값이 System Service 의 Index 라는 것을 알 수 있습니다.
단, 이 내용은 모든 API 에 해당하는 것은 아니며,
우선, ntoskrnl 에 연결되는 시스템 서비스일 경우에 해당하는 것 같습니다.
win32k 에 연결되는 API 의 경우, eax 값의 설정이 약간 다른 모양을 볼 수 있습니다.
to be continued...
예외를 무작정 따라가보자.
Access Violation 을 일으키는 간단한 어플리케이션을 만들었습니다.
다음은 에러가 발생한 Process 의 정보입니다.
PROCESS 81d2b9e0 SessionId: 0 Cid: 06d8 Peb: 7ffdf000 ParentCid: 05a4
DirBase: 065402c0 ObjectTable: e1d46190 HandleCount: 43.
Image: accessviolation.exe
VadRoot 81d2d9a0 Vads 45 Clone 0 Private 91. Modified 9. Locked 0.
DeviceMap e188e0b0
Token e10927d0
ElapsedTime 00:00:21.625
UserTime 00:00:00.015
KernelTime 00:00:00.031
QuotaPoolUsage[PagedPool] 33308
QuotaPoolUsage[NonPagedPool] 1800
Working Set Sizes (now,min,max) (540, 50, 345) (2160KB, 200KB, 1380KB)
PeakWorkingSetSize 540
VirtualSize 16 Mb
PeakVirtualSize 20 Mb
PageFaultCount 592
MemoryPriority BACKGROUND
BasePriority 8
CommitCharge 111
82034198 SynchronizationEvent
8207f768 ProcessObject
81d34b38 NotificationTimer
Not impersonating
DeviceMap e188e0b0
Owning Process 81d2b9e0 Image: accessviolation.exe
Attached Process N/A Image: N/A
Wait Start TickCount 9254 Ticks: 1 (0:00:00:00.015)
Context Switch Count 104 LargeStack
UserTime 00:00:00.000
KernelTime 00:00:00.031
Win32 Start Address accessviolation (0x004013e2)
Start Address kernel32!BaseProcessStartThunk (0x7c810867)
Stack Init b26f6000 Current b26f595c Base b26f6000 Limit b26f1000 Call 0
Priority 9 BasePriority 8 PriorityDecrement 0 DecrementCount 16
MS Windows 는 예외나 인터럽트가 발생할 경우 Trap Frame을 생성하여 이를 관리합니다.
이 Trap Frame 은 KTHREAD 에서 확인할 수 있고, 해당 쓰레드의 Thread Context 정보를 확인할 수 있습니다.
+0x000 Header : _DISPATCHER_HEADER
...
+0x128 Preempted : 0 ''
+0x129 ProcessReadyQueue : 0 ''
+0x12a KernelStackResident : 0x1 ''
+0x12b NextProcessor : 0 ''
+0x12c CallbackStack : (null)
+0x130 Win32Thread : 0xe1092ac0
+0x134 TrapFrame : 0xb26f5d64 _KTRAP_FRAME
+0x138 ApcStatePointer : [2] 0x81d34a7c _KAPC_STATE
+0x140 PreviousMode : 1 ''
+0x141 EnableStackSwap : 0x1 ''
+0x142 LargeStack : 0x1 ''
+0x143 ResourceIndex : 0 ''
+0x144 KernelTime : 2
+0x148 UserTime : 0
+0x14c SavedApcState : _KAPC_STATE
+0x164 Alertable : 0 ''
+0x165 ApcStateIndex : 0 ''
+0x166 ApcQueueable : 0x1 ''
+0x167 AutoAlignment : 0 ''
+0x168 StackBase : 0xb26f6000
+0x16c SuspendApc : _KAPC
+0x19c SuspendSemaphore : _KSEMAPHORE
+0x1b0 ThreadListEntry : _LIST_ENTRY [ 0x81d2ba30 - 0x81d2ba30 ]
+0x1b8 FreezeCount : 0 ''
+0x1b9 SuspendCount : 0 ''
+0x1ba IdealProcessor : 0 ''
+0x1bb DisableBoost : 0 ''
+0x000 DbgEbp : 0x12dbb0
+0x004 DbgEip : 0x7c90eb94
+0x008 DbgArgMark : 0xbadb0d00
+0x00c DbgArgPointer : 0x12db1c
+0x010 TempSegCs : 0
+0x014 TempEsp : 0
+0x018 Dr0 : 0
+0x01c Dr1 : 0
+0x020 Dr2 : 0
+0x024 Dr3 : 0
+0x028 Dr6 : 0
+0x02c Dr7 : 0
+0x030 SegGs : 0
+0x034 SegEs : 0x23
+0x038 SegDs : 0x23
+0x03c Edx : 0x7c90eb94
+0x040 Ecx : 0x1000
+0x044 Eax : 0x8e0000
+0x048 PreviousPreviousMode : 1
+0x04c ExceptionList : 0xffffffff _EXCEPTION_REGISTRATION_RECORD
+0x050 SegFs : 0x3b
+0x054 Edi : 0x7ffdf000
+0x058 Esi : 0
+0x05c Ebx : 0x12db3c
+0x060 Ebp : 0x12dbb0
+0x064 ErrCode : 0
+0x068 Eip : 0x7c90eb94
+0x06c SegCs : 0x1b
+0x070 EFlags : 0x246
+0x074 HardwareEsp : 0x12db14
+0x078 HardwareSegSs : 0x23
+0x07c V86Es : 0
+0x080 V86Ds : 0
+0x084 V86Fs : 0
+0x088 V86Gs : 0
예외(에러)가 발생한 경우, 프로세스는 예외 핸들러를 호출하게 되고,
예외 핸들러가 등록되지 않은 경우 시스템의 기본 예외 핸들러를 호출합니다.
그리고, 예외 핸들러가 호출 될때에는 _EXCEPTION_RECORD 구조체를 넘겨주게 됩니다.
따라서, 예외가 발생한 쓰레드의 Call Stack 을 이용하여, _EXCEPTION_RECORD 를 확인할 수 있습니다.
위의 _KTHREAD 구조체에서, 현재 Stack 의 Base Pointer 는 0x12dbb0 입니다.
0012dbb0 0012dbcc ; 이전의 스택프레임
0012dbb4 7c809c86 kernel32!WaitForMultipleObjects+0x18 ; 복귀주소
0012dbb8 00000002
0012dbbc 0012dce0
0012dbc0 00000000
Stack Frame 의 구조에 따라, 복귀 주소가 0x0012dbcc 이므로,
호출 관계를 따라갈 수 있습니다.
0012dbcc 0012e560
0012dbd0 6945763c faultrep!StartDWException+0x5df
0012dbd4 00000002
0012dbd8 0012dce0
0012dbdc 00000000
kd> dds 0012e560
0012e560 0012f5d4
0012e564 694582b1 faultrep!ReportFault+0x533
0012e568 0012f884
0012e56c ffffffff
0012e570 00198310
호출 관계를 따라가면서, 함수의 호출 위치를 확인합니다.
아래는 faultrep!ReportFault+0x533 의 복귀주소를 갖고 호출된 함수의 호출부입니다.
6945828f b8a4184569 mov eax,offset faultrep!`string'+0x3c8 (694518a4)
69458294 8985fcefffff mov dword ptr [ebp-1004h],eax
6945829a 6aff push 0FFFFFFFFh
6945829c 50 push eax
6945829d ffb520f0ffff push dword ptr [ebp-0FE0h]
694582a3 ff750c push dword ptr [ebp+0Ch]
694582a6 ffb510f0ffff push dword ptr [ebp-0FF0h]
694582ac e8acedffff call faultrep!StartDWException (6945705d)
694582b1 eb3e jmp faultrep!ReportFault+0x573 (694582f1)
694582b3 399d24f0ffff cmp dword ptr [ebp-0FDCh],ebx
694582b9 741f je faultrep!ReportFault+0x55c (694582da)
StartDWException 함수는 DrWatson 의 예외처리 프로세스를 시작하는 함수로 추측되며,
다섯개의 인자를 받고 있습니다.
DrWatson 에서 해당 프로세스의 에러 정보를 처리하므로,
저 다섯가지의 인자에서 _EXCEPTION_RECORD 를 확인할 수 있다는 것을 유추할 수 있습니다.
해당 인자들의 위치를, 호출 스택의 구조에 따라 확인하면 다음과 같습니다.
0012e560 0012f5d4
0012e564 694582b1 faultrep!ReportFault+0x533
0012e568 0012f884 ; 첫번째 인자
0012e56c ffffffff ; 두번째 인자
0012e570 00198310 ; 세번째 인자
0012e574 0012f2ac ; 네번째 인자
0012e578 ffffffff ; 다섯번째 인자
0012e57c 00000000
첫번째 인자를 확인하면 다음과 같습니다.
0012f884 0012f978 0012f994 0012f8b0 7c9037bf
해당 인자가 스택을 가리키고 있으므로, 포인터로 볼 수 있습니다.
따라서, 다시 내용을 확인하면,
0012f978 c0000005 00000000 00000000 00401de4
0012f988 00000002 00000001 00401000 0001003f
kd> dt nt!_EXCEPTION_RECORD 0012f978
+0x000 ExceptionCode : c0000005 ; Access Violation
+0x004 ExceptionFlags : 0
+0x008 ExceptionRecord : (null)
+0x00c ExceptionAddress : 0x00401de4
+0x010 NumberParameters : 2
+0x014 ExceptionInformation : [15] 1
위와 같이 _EXCEPTION_RECORD 인 것을 확인할 수 있고,
예외가 발생한 주소와, 예외 코드를 알 수 있습니다.
Deki Host 를 Service 로 등록하기
Site settings could not be loaded
We were unable to locate the API to request site settings. Please see below for debugging information.
HTTP Response Status Code: 0
Trying API autodiscovery:
The API is currently located at http://localhost:8081/deki.
Trying http://192.168.10.102:10080/@api/deki ... failed (HTTP Status: 503)
Deki 를 사용하다가 위와 같은 에러가 발생하면, Deki Host 가 정상 작동하지 않는 경우입니다.
이 때는,
%dekiwiki%\config\ 폴더에 있는
mindtouch.host.bat 파일을 실행하여, Deki Host 를 실행하여야 하는데,
콘솔에서 동작하는 프로그램이기 때문에, 컴퓨터를 재부팅하고 로그인하기 전에는 동작하지 않습니다.
아파치 서버처럼 서비스로 등록하는 방법은 다음과 같습니다.
1. 여기를 클릭하여 파일을 다운받은 후 임의의 디렉토리에 압축을 풀어줍니다
2. cmd.exe 창을 띄워 압축을 푼 디렉토리에서 다음과 같이 실행합니다.
예 ) c:\reskit>instsrv dekihost c:\reskit\srvany.exe
3. Regedit.exe 를 실행하여 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\dekihost 으로 이동합니다.
4. dekihost 에 Parameters라는 키를 만들고 다음과 같은 문자열 키를 생성합니다.
Application // dekiwiki\bin 폴더의 mindtouch.host.exe 를 설정
AppParameters // mindtoych.host.bat 파일을 메모장으로 열어 실행 아규먼트 값을 설정
예 )
5. services.msc 를 실행하여 dekihost 서비스를 시작시킵니다
끝.
원문 : http://wiki.developer.mindtouch.com/MindTouch_Deki/Installation_and_Upgrade/1.8_Hayes_Official_Install_and_Upgrade_Guide/Windows/Dekihost_Windows_Service
User32 의 UnicodeString MultibyteString 간 변환 API
USER32!WCSToMBEx:
77d0d446 8bff mov edi,edi
77d0d448 55 push ebp
77d0d449 8bec mov ebp,esp
77d0d44b 53 push ebx
77d0d44c 8b5d18 mov ebx,dword ptr [ebp+18h]
77d0d44f 85db test ebx,ebx
77d0d451 56 push esi
77d0d452 57 push edi
0: kd> u USER32!MBToWCSEx
USER32!MBToWCSEx:
77cfadad 8bff mov edi,edi
77cfadaf 55 push ebp
77cfadb0 8bec mov ebp,esp
77cfadb2 53 push ebx
77cfadb3 56 push esi
77cfadb4 57 push edi
77cfadb5 8b7d10 mov edi,dword ptr [ebp+10h]
77cfadb8 85ff test edi,edi
에서 확인
Proto Type :
WORD CodePage,
LPWSTR UnicodeString,
DWORD UnicodeSize,
LPSTR *MBString,
DWORD MBSize,
BOOL Allocate);
WORD CodePage,
LPSTR MBString,
DWORD MBSize,
LPWSTR UnicodeString,
DWORD UnicodeSize,
BOOL Allocate);
주목할 Parameters
Size : -1 일 경우 사이즈 자동 체크.
Allocate : TRUE 일 경우, 받는 버퍼의 메모리를 할당. ( MultiByteToWideChar 계열 함수와 차이 )