Microsoft MVP성태의 닷넷 이야기
디버깅 기술: 131. windbg/Visual Studio - HeapFree x86의 동작 분석 [링크 복사], [링크+제목 복사]
조회: 775
글쓴 사람
홈페이지
첨부 파일
 

windbg/Visual Studio - HeapFree x86의 동작 분석

들어가기에 앞서 우선 (개인적으로 ^^;) 헷갈리는 JUMP 기계어 코드를 정리합니다.

http://faydoc.tripod.com/cpu/jge.htm

JNE == Jump short if not equal (ZF = 0), Visual Studio의 경우 ZR = 0
JGE == Jump short if greater or equal (SF = OF), Visual Studio의 경우 PL = OV
JAE == Jump short if above or equal (CF = 0), Visual Studio의 경우 CY = 0

JL == Jump short if less (SF <> OF), Visual Studio의 경우 PL != OV

또한 Visual Studio의 경우 Flags 레지스터의 값을 디버깅 중에 확인하려면 "Debug" / "Windows" / "Registers(Ctrl + Alt + G)"를 선택해 "EFL" 값을 봐도 되지만, 기왕이면 각각의 플래그 값의 확인을 더욱 용이하게 할 수 있도록 다음과 같이 마우스 우 클릭해 나오는 메뉴에서 "Flags" 값을 check하면,

vs_heap_free_1.png

개별 필드 값을 아래의 단축 용어로 나눠서 확인할 수 있습니다.

OV (overflow)
UP (Direction)
EI (Enable Interrupt)
PL (Positive)
ZR (Zero)
AC (Auxilary Carry)
PE (Parity Even)
CY (Carry)

그 외에 레지스터 명칭 중 낯선 것 2개 소개합니다. ^^

SIL == ESI 레지스터의 하위 8비트
DIL == EDI 레지스터의 하위 8비트




아래는 이번 글의 실습 코드입니다.

// Windows 10 1909 - Visual C++ x86

#include <iostream>
#include <windows.h>

int main()
{
    int size = 20;

    HANDLE hHandle = HeapCreate(0, 0, 8192);
    printf("hHandle == 0x%x\n", hHandle);

    LPVOID pVoid1 = HeapAlloc(hHandle, 0, size);
    printf("pVoid1 == 0x%x\n", pVoid1);
    memset(pVoid1, 0xff, size);

    LPVOID pVoid2 = HeapAlloc(hHandle, 0, size + 1);
    printf("pVoid2 == 0x%x\n", pVoid2);
    memset(pVoid2, 0xee, size + 1);

    LPVOID pVoid3 = HeapAlloc(hHandle, 0, size + 2);
    printf("pVoid3 == 0x%x\n", pVoid3);
    memset(pVoid3, 0xcc, size + 2);

    LPVOID pVoid4 = HeapAlloc(hHandle, 0, 1);
    printf("pVoid4 == 0x%x\n", pVoid4);
    memset(pVoid4, 0xaa, 1);

    HeapFree(hHandle, 0, pVoid1);
    HeapFree(hHandle, 0, pVoid2);
    HeapFree(hHandle, 0, pVoid3);
    HeapFree(hHandle, 0, pVoid4);

    HeapDestroy(hHandle);

    printf("Exited!");

    return 0;
}

첫 번째 HeapFree(hHandle, 0, pVoid1)에서 BP를 잡고 실행했을 때 (제 경우) 각각의 포인터 값이 다음과 같이 나왔습니다.

hHandle == 0x19a0000
pVoid1 == 0x19a04b0
pVoid2 == 0x19a04d0
pVoid3 == 0x19a04f0
pVoid4 == 0x19a0510

여기서부터 Disassembly(Alt + G) 창을 띄워 아래의 "call esi" 명령까지 F11 키를 눌러 이동합니다.

    65:     HeapFree(hHandle, 0, pVoid1);
00E3110D 8B 35 04 20 E3 00    mov         esi,dword ptr [__imp__HeapFree@12 (0E32004h)]  
00E31113 83 C4 08             add         esp,8  
00E31116 C6 07 AA             mov         byte ptr [edi],0AAh  
00E31119 FF 75 F8             push        dword ptr [pVoid1]    // 세 번째 인자
00E3111C 6A 00                push        0                     // 두 번째 인자: dwFlags == 0
00E3111E FF 75 FC             push        dword ptr [hHandle]   // 첫 번째 인자: hHandle
00E31121 FF D6                call        esi  

그럼 IAT 테이블로 진입하게 되고,

_HeapFreeStub@12:
76BB1A70 8B FF                mov         edi,edi  
76BB1A72 55                   push        ebp  
76BB1A73 8B EC                mov         ebp,esp  
76BB1A75 5D                   pop         ebp  
76BB1A76 FF 25 E0 10 C2 76    jmp         dword ptr [__imp__HeapFree@12 (76C210E0h)] 

이제부터 본격적인 HeapFree 코드로 넘어갑니다.

771DDBD0 8B FF                mov         edi,edi  
771DDBD2 55                   push        ebp  
771DDBD3 8B EC                mov         ebp,esp  
771DDBD5 83 E4 F8             and         esp,0FFFFFFF8h  
771DDBD8 56                   push        esi  
771DDBD9 57                   push        edi  
771DDBDA 8B 7D 10             mov         edi,dword ptr [ebp+10h]  // edi == ebp + 10h == 세 번째 인자 pVoid1 
771DDBDD 85 FF                test        edi,edi  
771DDBDF 74 3D                je          RtlFreeHeap+4Eh (771DDC1Eh)  
771DDBE1 8B 75 08             mov         esi,dword ptr [ebp+8]  // esi == ebp + 8h == 첫 번째 인자 hHandle
771DDBE4 85 F6                test        esi,esi  
771DDBE6 0F 84 26 34 05 00    je          _RtlCaptureStackContext@12+7EF2h (77231012h)  
771DDBEC 81 7E 08 EE DD EE DD cmp         dword ptr [esi+8],0DDEEDDEEh  
771DDBF3 8B D7                mov         edx,edi  // _RtlpFreeHeapInternal로 첫 번째 인자 전달 (pVoid1)
771DDBF5 8B CE                mov         ecx,esi  // _RtlpFreeHeapInternal로 두 번째 인자 전달 (hHandle)
771DDBF7 0F 84 2B 34 05 00    je          _RtlCaptureStackContext@12+7F08h (77231028h)  
771DDBFD F6 05 EC E8 2B 77 02 test        byte ptr [_RtlpHpHeapFeatures (772BE8ECh)],2  
771DDC04 0F 85 2B 34 05 00    jne         _RtlCaptureStackContext@12+7F15h (77231035h)  
771DDC0A 6A 00                push        0  // _RtlpFreeHeapInternal로 세 번째 인자 전달
771DDC0C 6A 00                push        0  // _RtlpFreeHeapInternal로 네 번째 인자 전달
771DDC0E FF 75 0C             push        dword ptr [ebp+0Ch]  // _RtlpFreeHeapInternal로 다섯 번째를 HeapFree의 두 번째 인자로 전달
771DDC11 E8 42 89 04 00       call        _RtlpFreeHeapInternal@20 (77226558h) // ==> call
771DDC16 5F                   pop         edi  
771DDC17 5E                   pop         esi  
771DDC18 8B E5                mov         esp,ebp  
771DDC1A 5D                   pop         ebp  
771DDC1B C2 0C 00             ret         0Ch  
771DDC1E 5F                   pop         edi  
771DDC1F B8 01 00 00 00       mov         eax,1  
771DDC24 5E                   pop         esi  
771DDC25 8B E5                mov         esp,ebp  
771DDC27 5D                   pop         ebp  
771DDC28 C2 0C 00             ret         0Ch 

위의 코드는 별로 중요한 것이 없고 그냥 _RtlpFreeHeapInternal를 아래와 같은 식으로 호출하는 역할만 한다고 봐도 무방합니다.

_RtlpFreeHeapInternal(hHandle, pVoid1, 0, 0, 0);

이후 _RtlpFreeHeapInternal 코드로 넘어가서,

_RtlpFreeHeapInternal@20:
77226558 8B FF                mov         edi,edi  
7722655A 55                   push        ebp  
7722655B 8B EC                mov         ebp,esp  
7722655D 83 EC 40             sub         esp,40h  
77226560 53                   push        ebx  
77226561 56                   push        esi   
77226562 8B F1                mov         esi,ecx  // esi == hHandle
77226564 33 DB                xor         ebx,ebx  // ebx = 0
77226566 8B C2                mov         eax,edx  // eax == pVoid1
77226568 89 75 F8             mov         dword ptr [ebp-8],esi  // local_var1 == esi == hHandle
7722656B 57                   push        edi  
7722656C 89 45 F0             mov         dword ptr [ebp-10h],eax  // local_var2 == pVoid1
7722656F 8B FB                mov         edi,ebx  // edi == 0
77226571 81 7E 08 EE DD EE DD cmp         dword ptr [esi+8],0DDEEDDEEh  // cmp [hHandle + offset 8], 0DDEEDDEE 
                                                                        // cmp [0x019A0008] == 0xffeeffee
                                                                        // ZR = 0
77226578 0F 85 89 00 00 00    jne         _RtlpFreeHeapInternal@20+0AFh (77226607h) // ==> jump
...[생략]...
772265E1 5F                   pop         edi  
772265E2 5E                   pop         esi  
772265E3 5B                   pop         ebx  
772265E4 C9                   leave  
772265E5 C2 0C 00             ret         0Ch 

기본적인 변수 설정만 한 후 "jne _RtlpFreeHeapInternal@20+0AFh" 코드로 jump합니다. 이제부터 의미 있는 코드들이 나오는데,

77226607 F7 46 44 00 00 00 01 test        dword ptr [esi+44h],1000000h  // [hHandle + offset 44h] == 00000000
                                                                // 0x0 and 1000000h, ZR = 1
7722660E 8B 4D 08             mov         ecx,dword ptr [ebp+8]  // ecx = _RtlpFreeHeapInternal의 세 번째 인자 == 0
77226611 0F 85 B6 06 00 00    jne         _RtlpFreeHeapInternal@20+775h (77226CCDh)  
77226617 F6 46 48 01          test        byte ptr [esi+48h],1   // [hHandle + offset 48h] == 00000000
                                                        // 0x0 and 1 (ZR = 1)
7722661B 74 0B                je          _RtlpFreeHeapInternal@20+0D0h (77226628h) // ==> jump to 77226628
...[생략]...
...[생략]...
...[생략]...
77226628 A8 07                test        al,7  // eax == pVoid1(0x19a04b0), al == 0xb0
                                                // 0xb0 and 0x07 == 0x0 (ZR = 1)
7722662A 75 2A                jne         _RtlpFreeHeapInternal@20+0FEh (77226656h)  
7722662C 8D 78 F8             lea         edi,[eax-8]  // pVoid - 8 == 0x019A04A8
                                    0x019A04A8  2cdebacd // pVoid - 8 위치
                                    0x019A04AC  0c00bbf9 // pVoid - 4 위치
                                    0x019A04B0  ffffffff // pVoid 포인터가 가리키는 위치 - 데이터 구분을 위해 일부러 '0xff'로 채움
                                    0x019A04B4  ffffffff
                                    0x019A04B8  ffffffff
7722662F 80 7F 07 05          cmp         byte ptr [edi+7],5  // [edi + 7] == 0x0c
                                                              // cmp 0c, 5 == (ZF = 0)
77226633 75 09                jne         _RtlpFreeHeapInternal@20+0E6h (7722663Eh) // ==> jump to 7722663E
...[생략]...
...[생략]...
...[생략]...
7722663E F6 47 07 3F          test        byte ptr [edi+7],3Fh  // 0xc and 0x3f (ZR = 0)
77226642 75 20                jne         _RtlpFreeHeapInternal@20+10Ch (77226664h) // ==> jump to 77226664
...[생략]...
...[생략]...
...[생략]...
77226664 85 FF                test        edi,edi   // edi == 0x019A04A8 (pVoid - 8) (ZR = 0)
77226666 75 28                jne         _RtlpFreeHeapInternal@20+138h (77226690h) // ==> jump to 77226690
...[생략]...
...[생략]...
...[생략]...
77226690 8B 45 F0             mov         eax,dword ptr [ebp-10h]  // eax == [ebp - 10h] == local_var2 == pVoid1
77226693 80 78 FF 05          cmp         byte ptr [eax-1],5  // eax == 019a04b0, (byte)[eax - 1] == 0x0c
                                                              // cmp == 0x0c - 0x05 == 0x7 == (ZR = 0)
77226697 0F 85 45 01 00 00    jne         _RtlpFreeHeapInternal@20+28Ah (772267E2h) // ==> jump to 772267E2
...[생략]...
...[생략]...
...[생략]...
772267E2 38 5F 07             cmp         byte ptr [edi+7],bl   // [edi + 7] == 0x0c, BL == 0
                                                                // cmp == (ZR = 0, OV = 0, PL = 0)
772267E5 0F 8D DF 04 00 00    jge         _RtlpFreeHeapInternal@20+772h (77226CCAh) // ==> jump to 77226CCA
...[생략]...
...[생략]...
...[생략]...
77226CCA 8B 4D 08             mov         ecx,dword ptr [ebp+8]    // ecx = _RtlpFreeHeapInternal의 세 번째 인자 == 0
77226CCD 8B D1                mov         edx,ecx  // edx = 0
77226CCF 8B CE                mov         ecx,esi  // ecx = hHandle
77226CD1 50                   push        eax  
77226CD2 57                   push        edi  
77226CD3 83 CA 02             or          edx,2  
77226CD6 E8 95 6F FB FF       call        @RtlpFreeHeap@16 (771DDC70h)  
...[생략]...

보는 바와 같이 "pVoid"가 가리키고 있는 포인터보다 8바이트 앞선 위치를 edi 레지스터에 저장 후, 실질적으로는 dword('pVoid - 4') 위치의 상위 첫 바이트를 대상으로 다양한 체크를 하고 있습니다. 별다른 이상이 없다면 RtlpFreeHeap 함수를 다음과 같은 형식으로 호출하게 됩니다.

RtlpFreeHeap(hHandle, 0, pVoid, pVoid - 8, 0 | 2);

나중에 잠깐 다루겠지만, dword('pVoid - 4') 위치의 상위 첫 바이트가 이상이 없다고 해도 RtlpFreeHeap 내부에서 한 번 더 dword(pVoid - 8), dword(pVoid - 4) 위치의 값을 테스트하게 되고 그 과정에서 변조가 판단되면 비정상 종료가 발생하게 됩니다.




일부러 비정상 종료를 한번 유도해 볼까요? ^^ HeapFree를 하기 전 다음과 같은 코드를 넣어두고,

*(((BYTE*)pVoid1) - 4) = 0x01;

실행하면, dword(pVoid - 4)의 최하위 바이트가 바뀌게 됩니다.

0x00E004A8  05010004 
0x00E004AC  0c000101 
0x00E004B0  ffffffff 
0x00E004B4  ffffffff 

ASLR이나, Heap의 다양한 내부 상태 값으로 인해 저 하나의 값이 어떻게 영향을 미칠지는 알 수 없습니다. 우선, 이런 식의 변조를 했을 때 RtlReportFatalFailure로 끝나는 사례를 먼저 살펴보겠습니다. (참고로, 운에 따라 비정상 종료하지 않는 경우도 있습니다.)

    ntdll.dll!_RtlReportFatalFailure@4()    Unknown
    ntdll.dll!_RtlReportCriticalFailure@12()    Unknown
    ntdll.dll!_RtlpReportHeapFailure@4()    Unknown
    ntdll.dll!_RtlpHpHeapHandleError@12()   Unknown
    ntdll.dll!_RtlpLogHeapFailure@24()  Unknown
    ntdll.dll!_RtlpAnalyzeHeapFailure@12()  Unknown
    ntdll.dll!@RtlpFreeHeap@16()    Unknown
    ntdll.dll!_RtlpFreeHeapInternal@20()    Unknown
    ntdll.dll!RtlFreeHeap() Unknown
>    ConsoleApplication1.exe!main() Line 60  C++

이렇게 되면 Visual Studio 디버깅 중에는 다음과 같은 식의 예외 메시지 창이 출력됩니다.

Unhandled exception at 0x7727F94D (ntdll.dll) in ConsoleApplication1.exe: 0xC0000374: A heap has been corrupted (parameters: 0x772BB960). occurred


정확히 "heap" 영역이 "corrupted"되었다고 알려주고 있으며 이 상황을 유발한 몇몇 문맥 정보를 ("parameters: 0x......")로 알려주고 있습니다. 실제로 이 주소의 메모리 값을 확인해 보면,

0x772BB960  00000002
0x772BB964  000003d0
0x772BB968  00000004
0x772BB96C  00e00000 // hHandle
0x772BB970  00e001e8
0x772BB974  00000000
0x772BB978  00000000
0x772BB97C  00000000
0x772BB980  00e00000 // hHandle
0x772BB984  00e004a8 // (pVoid - 8) 주소
0x772BB988  00000000
0x772BB98C  00000000

저렇게 Heap handle 값과 Free를 시도하려고 했던 주소의 (헤더 위치로 보정된) pVoid 주솟값을 알 수 있습니다. 따라서, 원래 HeapFree로 전달한 값이 00e004a8 + 0x8 == e004b0 임을 알 수 있습니다.




그런데, 또 다른 식으로 비정상 종료하는 케이스가 있습니다.

0x013B04A8  05010004 
0x013B04AC  0c001401 
0x013B04B0  ffffffff 
0x013B04B4  ffffffff 

역시 마찬가지로 하위 1바이트만 0x01 값으로 채운 경우인데 다음과 같이 오류 메시지 및 callstack이 다릅니다.

Unhandled exception at 771DE00D (ntdll.dll) in ConsoleApplication1.exe: 0xC0000005: Access violation reading location 0x00C9FDF2.


    ntdll.dll!@RtlpFreeHeap@16()    Unknown
    ntdll.dll!_RtlpFreeHeapInternal@20()    Unknown
    ntdll.dll!RtlFreeHeap() Unknown
>    ConsoleApplication1.exe!main() Line 60  C++

실제로 0x773CE00D 위치의 코드를 보면,

771DE002 8B 4F 4C             mov         ecx,dword ptr [edi+4Ch]  
771DE005 8B C1                mov         eax,ecx  
771DE007 C1 E8 14             shr         eax,14h  
771DE00A 22 47 52             and         al,byte ptr [edi+52h] // edi ==  0x013b0000
771DE00D 32 43 02             xor         al,byte ptr [ebx+2] // ebx == 0x00C9FDF0 == (invalid memory pointer)

xor의 두 번째 오퍼랜드의 주소가 (디버거에서 알려준) 0x00C9FDF2이고 이 주솟값의 영역은 한 번도 할당한 적이 없으므로 Access Violation 예외가 발생한 것입니다. 이전에 살펴 본 _RtlReportFatalFailure의 경우 문맥 정보를 통해 해제하려는 주솟값을 알아낼 수 있었지만, AV 예외가 발생한 이번에는 그 주소를 알기 쉽지 않습니다. 우선, 대충 각 callstack의 frame 별로 레지스터를 조사해 보면 다음과 같이 주솟값이 (운이 좋게) 나오는 것을 볼 수 있습니다. (또는, 각각의 함수 내부 코드를 통해 stack에 보관된 값을 찾아내는 식으로 조사할 수 있습니다.)

[ntdll.dll!@RtlpFreeHeap@16()]
esi == 013B04A8 == pVoid - 8

[ntdll.dll!_RtlpFreeHeapInternal@20()]
edi == 013B04A8 == pVoid - 8

[ntdll.dll!RtlFreeHeap()]
edi == 013B04B0 == pVoid

물론, 위의 상황은 운영체제의 버전/패치에 따라 달라질 수 있으므로 적당하게 취할 수 있는 센스를 발휘해야 합니다. ^^




이 정도면, Heap corruption 관련 예외가 발생했을 때 어떤 메모리를 해제하려고 했는지는 쉽게(?) 찾을 수 있을 것입니다. 다음번 글에서는 이번에 다뤘던 정보를 바탕으로 지난 글의 덤프 분석 사례를,

windbg - CoTaskMemFree/FreeCoTaskMem에서 발생한 덤프 분석 사례
; https://www.sysnet.pe.kr/2/0/12058

좀 더 깊이 있게 들어가 보겠습니다. ^^




마지막으로, pVoid + 8, pVoid + 4 위치의 값을 체크하는 코드를 아래에 (필요한 정도로만) 정리합니다.

772267E2 38 5F 07             cmp         byte ptr [edi+7],bl  // from 77226697
                                                            // [edi + 7] == 8c, BL == 0
                                                            // cmp == (ZF = 0, OV = 0, PL = 1)
772267E5 0F 8D DF 04 00 00    jge         _RtlpFreeHeapInternal@20+772h (77226CCAh)                  
772267EB 8B CF                mov         ecx,edi   // ecx == 0x01433A70
772267ED C1 E9 03             shr         ecx,3     // ecx == 0x0028674E
772267F0 33 0F                xor         ecx,dword ptr [edi]  
                                                    // ecx == 0x0028674E xor 0x2e3b9086 == 0x2e13f7c8
772267F2 33 0D 14 E9 2B 77    xor         ecx,dword ptr [_RtlpLFHKey (772BE914h)]  // [772BE914h] == 2f1df7c8
                                                    // 0x2e13f7c8 xor 2f1df7c8 == 10E0000
772267F8 33 CE                xor         ecx,esi   // 10E0000 xor g_hHeap == 01420000 == 4C0000
772267FA 66 85 C9             test        cx,cx     // cx == 0000 (ZR == 1)
772267FD 0F 85 B4 04 00 00    jne         _RtlpFreeHeapInternal@20+75Fh (77226CB7h)   // 하위 4바이트가 0이 아니라면 _RtlpLogHeapFailure
77226803 C1 E9 0D             shr         ecx,0Dh   // ecx == 0x260
77226806 8B C7                mov         eax,edi   // 0x01433A70 (pVoid - 8)
77226808 2B C1                sub         eax,ecx   // 0x01433A70 - 0x260 = 0x1433810
7722680A 8B 08                mov         ecx,dword ptr [eax]  // ecx == [0x1433810] 위치의 값
7722680C 89 4D F4             mov         dword ptr [ebp-0Ch],ecx  // [ebp - 0Ch] == ecx == [0x1433810] 위치의 값
7722680F 85 C9                test        ecx,ecx  // cx == 00fbcbc8 (ZR == 0)
77226811 0F 84 A0 04 00 00    je          _RtlpFreeHeapInternal@20+75Fh (77226CB7h)  // ecx == 0이면 _RtlpLogHeapFailure
                                                                 // 두 번째 쿠키 값 검증
77226817 8B 47 04             mov         eax,dword ptr [edi+4]  // eax == 8c001265
7722681A 8B 71 04             mov         esi,dword ptr [ecx+4]  // esi == [[0x1433810] 위치의 값 + offset 4]
7722681D C1 E8 08             shr         eax,8  
77226820 0F B7 D0             movzx       edx,ax  
77226823 8B 01                mov         eax,dword ptr [ecx]  
77226825 89 75 EC             mov         dword ptr [ebp-14h],esi  
77226828 89 5D E4             mov         dword ptr [ebp-1Ch],ebx  
7722682B 89 55 E0             mov         dword ptr [ebp-20h],edx  
7722682E 8B 00                mov         eax,dword ptr [eax]  
77226830 8B 48 0C             mov         ecx,dword ptr [eax+0Ch]  
77226833 8B 46 10             mov         eax,dword ptr [esi+10h]  
77226836 33 C1                xor         eax,ecx  
77226838 89 4D D8             mov         dword ptr [ebp-28h],ecx  
7722683B 33 C6                xor         eax,esi  
7722683D 33 05 14 E9 2B 77    xor         eax,dword ptr [_RtlpLFHKey (772BE914h)]  
77226843 8B F0                mov         esi,eax  
77226845 0F B7 C0             movzx       eax,ax  
77226848 C1 EE 10             shr         esi,10h  
7722684B 0F AF F2             imul        esi,edx  
7722684E 03 75 EC             add         esi,dword ptr [ebp-14h]  
77226851 03 C6                add         eax,esi  
77226853 3B C7                cmp         eax,edi  
77226855 74 1A                je          _RtlpFreeHeapInternal@20+319h (77226871h) 
77226857 8B 51 0C             mov         edx,dword ptr [ecx+0Ch]  
7722685A 53                   push        ebx  
7722685B 53                   push        ebx  
7722685C 53                   push        ebx  
7722685D 57                   push        edi  
7722685E 6A 03                push        3  
77226860 59                   pop         ecx  
77226861 E8 A9 A4 06 00       call        _RtlpLogHeapFailure@24 (77290D0Fh) // ==> failure




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]

[연관 글]





[최초 등록일: ]
[최종 수정일: 11/20/2019 ]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer@outlook.com

비밀번호

댓글 쓴 사람
 




1  2  3  4  5  6  7  8  9  [10]  11  12  13  14  15  ...
NoWriterDateCnt.TitleFile(s)
12040정성태10/23/2019907오류 유형: 571. Unhandled Exception: System.Net.Mail.SmtpException: Transaction failed. The server response was: 5.2.0 STOREDRV.Submission.Exception:SendAsDeniedException.MapiExceptionSendAsDenied
12039정성태10/22/2019676스크립트: 16. cmd.exe의 for 문에서는 ERRORLEVEL이 설정되지 않는 문제
12038정성태10/17/2019544오류 유형: 570. SQL Server 2019 RC1 - SQL Client Connectivity SDK 설치 오류
12037정성태10/15/2019868.NET Framework: 867. C# - Encoding.Default 값을 바꿀 수 있을까요?파일 다운로드1
12036정성태10/21/20191531.NET Framework: 866. C# - 고성능이 필요한 환경에서 GC가 발생하지 않는 네이티브 힙 사용파일 다운로드1
12035정성태10/13/2019755개발 환경 구성: 461. C# 8.0의 #nulable 관련 특성을 .NET Framework 프로젝트에서 사용하는 방법파일 다운로드1
12034정성태1/31/20201022개발 환경 구성: 460. .NET Core 환경에서 (프로젝트가 아닌) C# 코드 파일을 입력으로 컴파일하는 방법 [1]
12033정성태10/11/20191484개발 환경 구성: 459. .NET Framework 프로젝트에서 C# 8.0 컴파일러를 사용하는 방법
12032정성태11/25/2019928.NET Framework: 865. .NET Core 2.2/3.0 웹 프로젝트를 IIS에서 호스팅(Inproc, out-of-proc)하는 방법 - AspNetCoreModuleV2 소개
12031정성태10/7/2019569오류 유형: 569. Azure Site Extension 업그레이드 시 "System.IO.IOException: There is not enough space on the disk" 예외 발생
12030정성태11/12/20192315.NET Framework: 864. .NET Conf 2019 Korea - "닷넷 17년의 변화 정리 및 닷넷 코어 3.0" 발표 자료 [1]파일 다운로드1
12029정성태9/27/2019684제니퍼 .NET: 29. Jennifersoft provides a trial promotion on its APM solution such as JENNIFER, PHP, and .NET in 2019 and shares the examples of their application.
12028정성태9/26/2019817.NET Framework: 863. C# - Thread.Suspend 호출 시 응용 프로그램 hang 현상을 해결하기 위한 시도파일 다운로드1
12027정성태9/26/2019510오류 유형: 568. Consider app.config remapping of assembly "..." from Version "..." [...] to Version "..." [...] to solve conflict and get rid of warning.
12026정성태9/26/2019707.NET Framework: 862. C# - Active Directory의 LDAP 경로 및 정보 조회
12025정성태9/25/2019810제니퍼 .NET: 28. APM 솔루션 제니퍼, PHP, .NET 무료 사용 프로모션 2019 및 적용 사례 (8)
12024정성태9/20/2019937.NET Framework: 861. HttpClient와 HttpClientHandler의 관계
12023정성태9/19/2019867.NET Framework: 860. ServicePointManager.DefaultConnectionLimit와 HttpClient의 관계파일 다운로드1
12022정성태9/12/20191884개발 환경 구성: 458. C# 8.0 (Preview) 신규 문법을 위한 개발 환경 구성 [3]
12021정성태7/1/20204684도서: 시작하세요! C# 8.0 프로그래밍 [3]
12020정성태9/11/2019913VC++: 134. SYSTEMTIME 값 기준으로 특정 시간이 지났는지를 판단하는 함수
12019정성태9/11/2019715Linux: 23. .NET Core + 리눅스 환경에서 Environment.CurrentDirectory 접근 시 주의 사항
12018정성태9/25/2019620오류 유형: 567. IIS - Unrecognized attribute 'targetFramework'. Note that attribute names are case-sensitive. (D:\lowSite4\web.config line 11)
12017정성태9/11/20191009오류 유형: 566. 비주얼 스튜디오 - Failed to register URL "http://localhost:6879/" for site "..." application "/". Error description: Access is denied. (0x80070005)
12016정성태9/5/20191600오류 유형: 565. git fetch - warning: 'C:\ProgramData/Git/config' has a dubious owner: '(unknown)'.
12015정성태9/3/20192393개발 환경 구성: 457. 윈도우 응용 프로그램의 Socket 연결 시 time-out 시간 제어
1  2  3  4  5  6  7  8  9  [10]  11  12  13  14  15  ...