겸손한 개발을 위한 자양분

SYSENTER

MYDN2009. 5. 12. 18:09

SYSENTER 는 level 0 의 시스템 프로시져를 호출하기 위한 명령어입니다.

쉽게 얘기한다면, 어플리케이션 레벨에서 커널 레벨로 진입하기 위한 명령이며
Windows XP 를 기준으로 했을 때, API 의 호출은 다음의 예와 같습니다.


예-1) OpenProcess 의 System Service 호출

Application Level

kernel32!OpenProcess

ntdll!ZwOpenProcess

ntdll!KiFastSystemCall
nt!KiFastCallEntry

nt!NtOpenProcess

Kernel Level


예-2) SendMessage 의 System Service 호출

Application Level

USER32!SendMessageA

USER32!SendMessageWorker

USER32!NtUserMessageCall

ntdll!KiFastSystemCall
nt!KiFastCallEntry

win32k!NtUserMessageCall

Kernel Level


두 가지 예를 보면, 어플리케이션 레벨에서 마지막으로 불리는 함수는 ntdll!KiFastSystemCall 이고, 커널 레벨에서 처음 불리는 함수는 nt!KiFastCallEntry 로 동일한 것을 볼 수 있습니다. 이 때, (XP 일 때) ntdll!KiFastSystemCall 에서 사용되는 명령이 바로 sysenter 입니다.


nt!KiFastCallEntry 에서, 어플리케이션이 원하는 시스템 서비스를 호출하는 과정은 다음과 같이 확인할 수 있습니다.


분석하고자 하는 API가 어떤 함수들을 호출하고 있는지 확인합니다.
OpenProcess 를 확인해보겠습니다.

kd> uf /c kernel32!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 를 호출하는 것을 알 수 있습니다.
(굳이 확인할 필요는 없지만) 이것을 실제 코드에서 확인해 보면,

kd> uf kernel32!OpenProcess
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 가 호출되는 것을 볼 수 있는데요,
해당 포인터의 값을 확인해보면

kd> dd 7c80110c
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 인 것을 알 수 있습니다.

kd> uf 7c90dd7b
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를 호출합니다.

kd> dd 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 인 것을 알 수 있습니다.

kd> uf 7c90eb8b
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 에 대하여 다음과 같은 내용을 확인할 수 있습니다.

SYSENTER - Fast System Call

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 를 갖고 있으므로 다음과 같이 확인합니다.

kd> rdmsr 0x176
msr[176] = 00000000`8053c710

해당 주소가 가리키는 함수가 무엇인지 확인해보면,

kd> ln 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 에 브레이크 포인트를 걸고
(주. 실제로 커널에서 호출을 따라갈 때에는 특정 프로세스를 타겟으로 하는 것이 좋을 것 같습니다.)

kd> bp ntdll!ZwOpenProcess

sysenter 호출 직전의 레지스터를 확인합니다.

kd> r
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 가 어떻게 동작되는지를 확인해보면,

nt!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만큼 떨어져있는 포인터의 함수를 호출하는것을 확인할 수 있습니다.

이 과정을 연산으로 확인해본다면,

kd> dd nt!KeServiceDescriptorTableShadow
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
kd> dds 80501030
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 이므로,

다음과 같이 나타낼 수 있을겁니다.

kd> dds 80501030 + (0x7a * 0x4)
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 의 정보입니다.

kd> !process 81d2b9e0 
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
        THREAD 81d34a48  Cid 06d8.06d4  Teb: 7ffde000 Win32Thread: e1092ac0 WAIT: (UserRequest) UserMode Non-Alertable
            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 정보를 확인할 수 있습니다.

kd> dt nt!_KTHREAD 81d34a48 
   +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 ''


kd> dt nt!_KTRAP_FRAME 0xb26f5d64
   +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 입니다.

kd> dds 0x12dbb0
0012dbb0  0012dbcc ; 이전의 스택프레임
0012dbb4  7c809c86 kernel32!WaitForMultipleObjects+0x18 ; 복귀주소
0012dbb8  00000002
0012dbbc  0012dce0
0012dbc0  00000000

Stack Frame 의 구조에 따라, 복귀 주소가 0x0012dbcc 이므로,
호출 관계를 따라갈 수 있습니다.

kd> dds 0012dbcc 
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 의 복귀주소를 갖고 호출된 함수의 호출부입니다. 

6945828d 7405            je      faultrep!ReportFault+0x516 (69458294)
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 를 확인할 수 있다는 것을 유추할 수 있습니다.
해당 인자들의 위치를, 호출 스택의 구조에 따라 확인하면 다음과 같습니다.

kd> dds 0012e560
0012e560  0012f5d4
0012e564  694582b1 faultrep!ReportFault+0x533
0012e568  0012f884 ; 첫번째 인자
0012e56c  ffffffff ; 두번째 인자
0012e570  00198310 ; 세번째 인자
0012e574  0012f2ac ; 네번째 인자
0012e578  ffffffff ; 다섯번째 인자

0012e57c  00000000

첫번째 인자를 확인하면 다음과 같습니다.
kd> dd 0012f884
0012f884  0012f978 0012f994 0012f8b0 7c9037bf

해당 인자가 스택을 가리키고 있으므로, 포인터로 볼 수 있습니다.
따라서, 다시 내용을 확인하면,

kd> dd 0012f978
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 인 것을 확인할 수 있고,
예외가 발생한 주소와, 예외 코드를 알 수 있습니다.

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 창을 띄워 압축을 푼 디렉토리에서 다음과 같이 실행합니다.

instsrv dekihost %절대경로%\srvany.exe

예 ) c:\reskit>instsrv dekihost c:\reskit\srvany.exe


3. Regedit.exe 를 실행하여 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\dekihost 으로 이동합니다.

4. dekihost 에 Parameters라는 키를 만들고 다음과 같은 문자열 키를 생성합니다.

AppDirectory      // dekiwiki\bin 패스 설정
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 Dll 에서 제공하는 변환 API

0: kd> u USER32!WCSToMBEx
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 :
DWORD STDCALL WCSToMBEx(
                                 WORD CodePage,
                                 LPWSTR UnicodeString,
                                 DWORD UnicodeSize,
                                 LPSTR *MBString,
                                 DWORD MBSize,
                                 BOOL Allocate);


DWORD STDCALL MBToWCSEx(
                                 WORD CodePage,
                                 LPSTR MBString,
                                 DWORD MBSize,
                                 LPWSTR UnicodeString,
                                 DWORD UnicodeSize,
                                 BOOL Allocate);


주목할 Parameters

Size : -1 일 경우 사이즈 자동 체크.
Allocate : TRUE 일 경우, 받는 버퍼의 메모리를 할당. ( MultiByteToWideChar 계열 함수와 차이 )