Microsoft MVP성태의 닷넷 이야기
디버깅 기술: 198. Windbg - 스레드의 Win32 Message Queue 정보 조회 [링크 복사], [링크+제목 복사],
조회: 7356
글쓴 사람
정성태 (seongtaejeong at gmail.com)
홈페이지
첨부 파일
 
(연관된 글이 1개 있습니다.)
(시리즈 글이 4개 있습니다.)
디버깅 기술: 152. User 권한(Ring 3)의 프로그램에서 _ETHREAD 주소(및 커널 메모리를 읽을 수 있다면 _EPROCESS 주소) 구하는 방법
; https://www.sysnet.pe.kr/2/0/12102

디버깅 기술: 155. C# - KernelMemoryIO 드라이버를 이용해 실행 프로그램을 숨기는 방법(DKOM: Direct Kernel Object Modification)
; https://www.sysnet.pe.kr/2/0/12111

디버깅 기술: 159. C# - 디버깅 중인 프로세스를 강제로 다른 디버거에서 연결하는 방법
; https://www.sysnet.pe.kr/2/0/12117

디버깅 기술: 198. Windbg - 스레드의 Win32 Message Queue 정보 조회
; https://www.sysnet.pe.kr/2/0/13691




Windbg - 스레드의 Win32 Message Queue 정보 조회

이번 글을 실습하기 위해서는 커널 디버그 모드로 windbg를 사용해야 합니다. 따라서 (간단한) 테스트를 위해 Hyper-V를 이용해 VM을 구성하고, 원격 디버깅으로 연결하는 작업이 필요합니다.

Windbg - Hyper-V VM으로 이더넷 원격 디버깅 연결하는 방법
; https://www.sysnet.pe.kr/2/0/13343

그리고, 미리 말씀드리자면!!! 이번 글은 Message Queue 조회에 실패한 내용을 담고 있습니다. 단지, windbg 실습 차원에서 읽어주시면 됩니다. ^^




예전에, WPF의 Dispatcher Queue를 직접 다룬 적이 있었는데요,

C# - WPF의 Dispatcher Queue 동작 확인
; https://www.sysnet.pe.kr/2/0/13570

오늘은 문득, 그럼 Win32 Message Queue도 조회하는 것이 가능하지 않을까...라는 생각이 들었습니다. 이를 위해 우선 예제가 필요한데요, 간단하게 C# Windows Forms 애플리케이션을 다음과 같이 제작하고,

using System.Runtime.InteropServices;

namespace WinFormsApp1;

public partial class Form1 : Form
{
    [DllImport("kernel32.dll")]
    public static extern uint GetCurrentThreadId();

    public Form1()
    {
        InitializeComponent();
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        string text = $"PID: {Environment.ProcessId}(0x{Environment.ProcessId:x}), Main: {GetCurrentThreadId()}(0x{GetCurrentThreadId():x})";
        new Thread(() =>
        {
            text += $", Thread: {GetCurrentThreadId()}(0x{GetCurrentThreadId():x})";
            while (true)
            {
                Thread.Sleep(-1);
            }
        })
        { IsBackground = true }.Start();

        Thread.Sleep(1000);

        this.Text = text;
    }
}

실행 후, (원격 디버깅으로 접속한) WinDbg에서 WinFormsApp1.exe의 정보를 이렇게 구할 수 있습니다.

1: kd> !process 0 0 WinFormsApp1.exe
PROCESS ffffe60446b72140
    SessionId: 2  Cid: 2aa0    Peb: 9ecb8a3000  ParentCid: 1b8c
    DirBase: 1643d4000  ObjectTable: ffffae81ebec5d80  HandleCount: 305.
    Image: WinFormsApp1.exe

ffffe60446b72140 값이 바로 "EPROCESS"인데요, 이것을 이용해 해당 프로세스에 속한 스레드 목록 및 개별 스레드의 ETHREAD 값도 구할 수 있습니다.

5: kd> !process ffffe60446b72140 4
PROCESS ffffe60446b72140
    SessionId: 2  Cid: 2aa0    Peb: 9ecb8a3000  ParentCid: 1b8c
    DirBase: 1643d4000  ObjectTable: ffffae81ebec5d80  HandleCount: 338.
    Image: WinFormsApp1.exe

        THREAD ffffe6044b9b8080  Cid 2aa0.196c  Teb: 0000009ecb8a4000 Win32Thread: ffffe6044cf90eb0 WAIT
        THREAD ffffe6044c998080  Cid 2aa0.1e0c  Teb: 0000009ecb8ac000 Win32Thread: 0000000000000000 WAIT
        THREAD ffffe604466aa080  Cid 2aa0.0a38  Teb: 0000009ecb8ae000 Win32Thread: 0000000000000000 WAIT
        THREAD ffffe6044bdc7080  Cid 2aa0.18bc  Teb: 0000009ecb8b0000 Win32Thread: 0000000000000000 WAIT
        THREAD ffffe6044b207080  Cid 2aa0.2aa8  Teb: 0000009ecb8b6000 Win32Thread: ffffe6044cf9d8d0 WAIT
        THREAD ffffe6044b075080  Cid 2aa0.0864  Teb: 0000009ecb8b8000 Win32Thread: ffffe6044cf9e7b0 WAIT
        THREAD ffffe6044602a080  Cid 2aa0.2648  Teb: 0000009ecb8ba000 Win32Thread: 0000000000000000 WAIT
        THREAD ffffe6044961a080  Cid 2aa0.2abc  Teb: 0000009ecb8be000 Win32Thread: 0000000000000000 WAIT
        THREAD ffffe60446a80080  Cid 2aa0.2ab8  Teb: 0000009ecb8c0000 Win32Thread: 0000000000000000 WAIT
        THREAD ffffe60449c98080  Cid 2aa0.2060  Teb: 0000009ecb8c4000 Win32Thread: 0000000000000000 WAIT

또한 해당 프로세스로 문맥 전환을 하는 것도 가능합니다.

// 문맥 전환의 대상이 되는 프로세스의 EPROCESS 값을 설정만 한 후,
1: kd> .process /i ffffe60446b72140
You need to continue execution (press 'g' <enter>) for the context
to be switched. When the debugger breaks in again, you will be in
the new process context.

// (운영체제의) 실행을 계속해 EPROCESS 문맥 전환이 되는 순간, 곧바로 BP가 걸리는 것처럼 디버거로 제어가 넘어옵니다.
1: kd> g
Break instruction exception - code 80000003 (first chance)
nt!DbgBreakPointWithStatus:
fffff807`76624620 cc              int     3

대충 여기까지 실습을 했으면 Message Queue 탐색으로 넘어갈 준비가 끝났군요. ^^




자, 이제 Message Queue에 관련된 글을 찾아볼까요?

THREADINFO
; https://www.geoffchappell.com/studies/windows/km/win32k/structs/threadinfo/index.htm

The THREADINFO (formally tagTHREADINFO) is the most of what WIN32K.SYS keeps about a thread. A portion at its start is reproduced as a W32THREAD (formally _W32THREAD), apparently as an unnamed member. It is not clear what governs the separation.
...
Most direct and obvious is that in each TEB for a GUI thread, the Win32ThreadInfo member, reliably at offset 0x40 since version 3.51, is formally a pointer to void but what it actually holds is the kernel-mode address of the THREADINFO.


TEB 구조체에 Win32ThreadInfo 필드로 THREADINFO에 대한 포인터가 들어 있다고 하는군요, 따라서 TEB를 검사해야 하는데요, 우리가 작성한 예제의 Title에 출력한 정보에 따라,

PID: 10912 (0x2aa0), Main: 6508(0x196c), Thread: 10936(0x2ab8)

메시지 루프를 가지는 UI 스레드인 "Main: 6508(0x196c)"에 해당하는 스레드를 "!process ffffe60446b72140 4" 명령어의 출력에서 찾을 수 있습니다.

5: kd> !process ffffe60446b72140 4
        ...[생략]...
        THREAD ffffe6044b9b8080  Cid 2aa0.196c  Teb: 0000009ecb8a4000 Win32Thread: ffffe6044cf90eb0 WAIT
        ...[생략]...

ETHREAD == ffffe6044b9b8080 값을 가지고 있는데요, 이를 통해 TEB 구조체를 다음과 같이 조회할 수 있고,

5: kd> dt -v ffffe6044b9b8080 _ETHREAD Tcb.Teb
nt!_ETHREAD
struct _ETHREAD, 131 elements, 0x910 bytes
   +0x000 Tcb     : struct _KTHREAD, 226 elements, 0x480 bytes
      +0x0f0 Teb     : 0x0000009e`cb8a4000 Void

5: kd> dt 0000009ecb8a4000 _TEB Win32ThreadInfo
win32k!_TEB
   +0x078 Win32ThreadInfo : 0x00000000`0000196c Void

5: kd> dd 0x00000000`0000196c L4
00000000`0000196c  ???????? ???????? ???????? ????????

추적해 봤지만 저렇게 해당 주소는 할당이 안 된 영역입니다. 윈도우의 경우 0x00400000(4MB) 이하 영역은 사용하지 않으므로, 아마도 저 필드의 값은 포인터라기보다는 값 유형으로 보입니다.

그나마 소득이라면, 메시지 루프가 없는 스레드의 경우 Win32ThreadInfo는 비어 있는 것을 확인할 수 있습니다.

5: kd> dt -v ffffe60446a80080 _ETHREAD Tcb.Teb
nt!_ETHREAD
struct _ETHREAD, 131 elements, 0x910 bytes
   +0x000 Tcb     : struct _KTHREAD, 226 elements, 0x480 bytes
      +0x0f0 Teb     : 0x0000009e`cb8c0000 Void

5: kd> dt 0x0000009e`cb8c0000 _TEB Win32ThreadInfo
win32k!_TEB
   +0x078 Win32ThreadInfo : (null) 

UI 스레드인지, Worker 스레드인지 구분하는 방법으로 쓸만할지도 모르겠습니다. ^^




다른 글을 검색해 봤더니,

Window Messages as a Forensic Resource
; https://moyix.blogspot.com/2008/09/window-messages-as-forensic-resource.html

Each thread in Windows (represented by the _ETHREAD strucutre) has a field in its Thread Control Block (or Tcb, which is a _KTHREAD) called Win32Thread. This field points to a data structure, _W32THREAD, which is defined in the kernel-mode portion of the Windows graphical subsystem, win32k.sys


Tcb의 Win32Thread 필드에 대한 글이 나옵니다. 실제로 UI 스레드에 대해 이것을 확인해 보면,

5: kd> dt ffffe6044b9b8080 _ETHREAD Tcb.Win32Thread
nt!_ETHREAD
   +0x000 Tcb             : 
      +0x1c8 Win32Thread     : 0xffffe604`4cf90eb0 Void

정말 포인터인 듯한 값이 나왔는데요, 글쓴이에 의하면 이 필드가 가리키는 것은 _W32THREAD 구조체라고 합니다. Windows XP SP2 시절에 _W32THREAD 구조체의 0xd0 위치에 _MSG_QUEUE 형식의 구조체가 있었다고 하는데요,

typedef struct _MSG_QUEUE 
{
    PMSG_QUEUE_ENTRY Head;
    PMSG_QUEUE_ENTRY Tail;
    unsigned long NumberOfMessages;
} MSG_QUEUE;

Windows 11에서 저 값을 확인해 보면, 아쉽게도 Message Queue일 것으로 추정되는 데이터가 없습니다.

5: kd> dt 0xffffe604`4cf90eb0 _W32THREAD
win32k!_W32THREAD
   +0x000 pEThread         : 0xffffae81`eb711420 _ETHREAD
   +0x008 RefCount         : 0
   +0x010 ptlW32           : (null) 
   +0x018 pgdiDcattr       : (null) 
   +0x020 pgdiBrushAttr    : (null) 
   +0x028 UMPDOBJList      : _LIST_ENTRY [ 0x00000000`00000000 - 0x00000000`00000000 ]
   +0x038 pUMPDHeap        : (null) 
   +0x040 pProxyPort       : (null) 
   +0x048 pClientID        : 0xffffe604`4b9b8080 Void
   +0x050 DxThread         : (null) 
   +0x058 GdiTmpTgoList    : _LIST_ENTRY [ 0x00000000`00000000 - 0x00000000`00000000 ]
   +0x068 pRBRecursionCount : 0
   +0x06c pNonRBRecursionCount : 0
   +0x070 tlSpriteState    : _TLSPRITESTATE
   +0x118 pSpriteState     : (null) 
   +0x120 pDevHTInfo       : (null) 
   +0x128 ulDevHTInfoUniqueness : 0
   +0x130 pdcoAA           : (null) 
   +0x138 pdcoRender       : (null) 
   +0x140 pdcoSrc          : (null) 
   +0x148 bEnableEngUpdateDeviceSurface : 0y0
   +0x148 bIncludeSprites  : 0y0
   +0x148 bEnableAppContainerRendering : 0y0
   +0x148 bSnapWindowScreenAccess : 0y0
   +0x148 bGdiEngMode      : 0y0
   +0x14c ulWindowSystemRendering : 0
   +0x150 iVisRgnUniqueness : 0
   +0x154 dpiContext       : 0
   +0x158 dpiHostingBehavior : 0 ( DPI_HOSTING_BEHAVIOR_DEFAULT )
   +0x160 pUmfdTls         : (null) 
   +0x168 pdci             : (null) 
   +0x170 pdhbi            : (null) 
   +0x178 ulDCompQuotaGuardCount : 0
   +0x180 psoUMPDTmpSrc    : (null) 

5: kd> dt -r 0xffffe604`4cf90eb0+0x70 win32k!_TLSPRITESTATE 
   +0x000 bInsideDriverCall : 0 ''
   +0x004 flOriginalSurfFlags : 0
   +0x008 iOriginalType    : 0
   +0x00c flSpriteSurfFlags : 0
   +0x010 iSpriteType      : 0
   +0x014 flags            : 0
   +0x018 iType            : 0
   +0x020 pState           : 0xffffe604`4b9b8080 Void
   +0x028 pfnStrokeAndFillPath : (null) 
   +0x030 pfnStrokePath    : (null) 
   +0x038 pfnFillPath      : (null) 
   +0x040 pfnPaint         : (null) 
   +0x048 pfnBitBlt        : (null) 
   +0x050 pfnCopyBits      : (null) 
   +0x058 pfnStretchBlt    : (null) 
   +0x060 pfnTextOut       : (null) 
   +0x068 pfnLineTo        : (null) 
   +0x070 pfnTransparentBlt : (null) 
   +0x078 pfnAlphaBlend    : (null) 
   +0x080 pfnPlgBlt        : (null) 
   +0x088 pfnGradientFill  : (null) 
   +0x090 pfnSaveScreenBits : (null) 
   +0x098 pfnStretchBltROP : (null) 
   +0x0a0 pfnDrawStream    : (null) 

하지만, 무엇보다도 첫 번째 필드의 값이 올바르지 않습니다.

pEThread         : 0xffffae81`eb711420 != 0xffffe604`4cf90eb0

_W32THREAD와 관련된 ETHREAD에 대한 포인터 값이 나와야 하는데, 엉뚱한 값이 나온 것입니다. 따라서 어쩌면 저 구조체는 _W32THREAD가 아닌, 그와 관련된 선행 구조체일 수도 있습니다. 하지만, 제 실력으로는 더 추적이 안 됩니다. ^^

참고로, 아래의 글을 보면,

Jumping the Queues
; https://blog.airesoft.co.uk/2009/11/jumping-the-queues/

메시지 루프를 직접 역어셈블로 추적한 듯한 기록을 남기고 있습니다. 아마도 저런 식의 추적을 해야만 Message Queue를 확인할 수 있을 것 같은데... 음... 이번에는 그냥 여기까지만 하겠습니다. ^^

그나저나, 저 글에 첨부된 tagTHREADINFO 구조체가 재미있는데요,

// This tagTHREADINFO structure (the first part of which is also known as _W32THREAD), 

typedef struct tagTHREADINFO6
{
    // enabler for the template
    typedef MLIST<QMSG6> MListType;
    typedef QUEUE<QMSG6>* QPtr;

    // members
    PETHREAD pEThread; // 0x0
    DECLARE_GAP(0x28); // 0x4
    PVOID pProcessInfo; // 0x2c
    QPtr pq; // 0x30
    ULONG pNonRBRecursionCount; // 0x34
    PCLIENTTHREADINFO pClientThreadInfo; // 0x38
    PVOID pDesktop; // 0x3c
    PVOID pDeskInfo; // 0x40
    DECLARE_GAP(0x4); // 0x44
    PVOID pClientInfo; // 0x48
    ULONG TIF_Flags; // 0x4c
    DECLARE_GAP(0x4); // 0x50
    PSMSMSG psmsSent; // 0x54
    PSMSMSG psmsCurrent; // 0x58
    PSMSMSG psmsReceiveList; // 0x5c (sent messages)
    DECLARE_GAP(0x4); // 0x60
    ULONG idLast; // 0x64
    ULONG exitCode; // 0x68
    DECLARE_GAP(0x4); // 0x68
    ULONG cPaintsReady; // 0x70
    ULONG cTimersReady; // 0x74
    DECLARE_GAP(0x64); // 0x78
    MListType mlPost; // 0xdc (posted messages)
    ULONG fsChangeBitsRemoved;// 0xe8
    DECLARE_GAP(0x10); // 0xec
    ULONG cVisWindows; // 0xfc
} THREADINFO6, *PTHREADINFO6;

THREADINFO 구조체의 초기 영역은 _W32THREAD 구조체와 동일하다고 했던 말 그대로, 실제로 저 구조체와 Windbg에서 출력한 _W32THREAD 구조체가 유사합니다. 리버스 엔지니어링만으로 저 정도 수준의 구체적인 필드 용도까지 알아냈다는 것이 참 대단한 것 같습니다. ^^

그건 그렇고, 메시지 루프가 없는 스레드의 경우 저 필드도 역시 비어 있습니다.

5: kd> dt ffffe60446a80080 _ETHREAD Tcb.Win32Thread
nt!_ETHREAD
   +0x000 Tcb             : 
      +0x1c8 Win32Thread     : (null) 




아래의 글을 보면, ETHREAD, KTHREAD, TEB의 관계를 좀 더 명확하게 알 수 있습니다.

Processes, Threads, and Jobs in the Windows Operating System
; https://www.microsoftpressstore.com/articles/article.aspx?p=2233328&seqNum=4

teb_from_ethread_1.jpg

ETHREAD는 (커널의 ring0 권한으로만 접근할 수 있는) 시스템 공간의 메모리에 있는 구조체이고, TEB는 사용자 공간의 메모리에 있는 구조체입니다. 그러니까 windbg로도 커널 모드 디버깅이 아니면 그 영역을 헤쳐갈 수 없습니다. 일례로 단순히, Local Kernel Debug 모드에서 ETHREAD의 필드를 조사하려고 하면,

0:014> dx -r1 (*((ntdll!_KTHREAD *)0xffffc70458f65080))
(*((ntdll!_KTHREAD *)0xffffc70458f65080))                 [Type: _KTHREAD]
    [+0x000] Header           [Type: _DISPATCHER_HEADER]
    [+0x018] SListFaultAddress : Unable to read memory at Address 0xffffc70458f65098
    ...[생략]...
    [+0x1c8] Win32Thread      : Unable to read memory at Address 0xffffc70458f65248

대부분의 메모리가 "Unable to read memory"로 나옵니다. 이 외에도, !thread 명령같은 것들도 "Local Kernel Debug" 모드에선 값이 구해지지 않습니다.

||1:1:008> !thread
Could not get address of nt!KdVersionBlock.
Could not get address of nt!KdVersionBlock.
unable to get nt!MmUserProbeAddress
0000008ff2922000 is not a thread object, interpreting as stack value...
Unable to get address of PsActiveProcessHead
TYPE mismatch for thread object at 0000008ff2922000

아울러, 저처럼 찾아보실 분들이 계실 것 같아 미리 말씀드리면, 아쉽게도 위의 그림에서도 잘 나오듯이 TEB로부터 역으로 KTHREAD, ETHREAD를 구할 수는 없습니다. 만약 User Mode에서 구하고 싶다면 Process Explorer의 힘을 빌려 구하는 것이 차라리 빠를 것입니다.




마지막으로, Kernel Mode의 WinDbg에서 사용자 프로세스의 개별 스레드에 대한 콜스택을 얻는 방법은,

How to examine user thread call stack from windbg kernel debugger?
; https://stackoverflow.com/questions/38323635/how-to-examine-user-thread-call-stack-from-windbg-kernel-debugger

우선, 프로세스 문맥으로 진입한 다음,

.process /i ffffe60446b72140
g

이후 스레드 문맥을 선택하고 "k" 명령을 내리면 됩니다.

.thread ffffe6044b9b8080
k

이 방법을 통해 "!process ffffe60446b72140 4" 명령어로 열거된 스레드의 목록에 대해,

5: kd> !process ffffe60446b72140 4
...[생략]...

        THREAD ffffe6044b9b8080  Cid 2aa0.196c  Teb: 0000009ecb8a4000 Win32Thread: ffffe6044cf90eb0 WAIT
        THREAD ffffe6044c998080  Cid 2aa0.1e0c  Teb: 0000009ecb8ac000 Win32Thread: 0000000000000000 WAIT
        THREAD ffffe604466aa080  Cid 2aa0.0a38  Teb: 0000009ecb8ae000 Win32Thread: 0000000000000000 WAIT
        THREAD ffffe6044bdc7080  Cid 2aa0.18bc  Teb: 0000009ecb8b0000 Win32Thread: 0000000000000000 WAIT
        THREAD ffffe6044b207080  Cid 2aa0.2aa8  Teb: 0000009ecb8b6000 Win32Thread: ffffe6044cf9d8d0 WAIT
        THREAD ffffe6044b075080  Cid 2aa0.0864  Teb: 0000009ecb8b8000 Win32Thread: ffffe6044cf9e7b0 WAIT
        THREAD ffffe6044602a080  Cid 2aa0.2648  Teb: 0000009ecb8ba000 Win32Thread: 0000000000000000 WAIT
        THREAD ffffe6044961a080  Cid 2aa0.2abc  Teb: 0000009ecb8be000 Win32Thread: 0000000000000000 WAIT
        THREAD ffffe60446a80080  Cid 2aa0.2ab8  Teb: 0000009ecb8c0000 Win32Thread: 0000000000000000 WAIT
        THREAD ffffe60449c98080  Cid 2aa0.2060  Teb: 0000009ecb8c4000 Win32Thread: 0000000000000000 WAIT

Win32Thread 필드 값이 있는 스레드와 없는 스레드의 콜 스택을 확인하면 메시지 루프와 관련된 함수의 유무를 확인할 수 있습니다. 그러니까, 저 값이 아마도 메시지 루프로의 관문일 듯한데 win32k!_W32THREAD로 덤프가 잘 안되니 아쉬울 따름입니다. ^^

(혹시, 메시지 큐에 대한 접근에 성공하신 분은 관련 덧글 좀 부탁드립니다. ^^)




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

[연관 글]






[최초 등록일: ]
[최종 수정일: 7/23/2024]

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

비밀번호

댓글 작성자
 




[1]  2  3  4  5  6  7  8  9  10  11  12  13  14  15  ...
NoWriterDateCnt.TitleFile(s)
13917정성태4/30/202545VS.NET IDE: 199. Directory.Build.props에 정의한 속성에 대해 Condition 제약으로 값을 변경하는 방법
13916정성태4/23/2025446디버깅 기술: 221. WinDbg 분석 사례 - ASP.NET HttpCookieCollection을 다중 스레드에서 사용할 경우 무한 루프 현상 - 두 번째 이야기
13915정성태4/13/20251652닷넷: 2331. C# - 실행 시에 메서드 가로채기 (.NET 9)파일 다운로드1
13914정성태4/11/20251976디버깅 기술: 220. windbg 분석 사례 - x86 ASP.NET 웹 응용 프로그램의 CPU 100% 현상 (4)
13913정성태4/10/20251204오류 유형: 950. Process Explorer - 64비트 윈도우에서 32비트 프로세스의 덤프를 뜰 때 "Error writing dump file: Access is denied." 오류
13912정성태4/9/2025863닷넷: 2330. C# - 실행 시에 메서드 가로채기 (.NET 5 ~ .NET 8)파일 다운로드1
13911정성태4/8/20251091오류 유형: 949. WinDbg - .NET Core/5+ 응용 프로그램 디버깅 시 sos 확장을 자동으로 로드하지 못하는 문제
13910정성태4/8/20251257디버깅 기술: 219. WinDbg - 명령어 내에서 환경 변수 사용법
13909정성태4/7/20251725닷넷: 2329. C# - 실행 시에 메서드 가로채기 (.NET Framework 4.8)파일 다운로드1
13908정성태4/2/20252138닷넷: 2328. C# - MailKit: SMTP, POP3, IMAP 지원 라이브러리
13907정성태3/29/20251937VS.NET IDE: 198. (OneDrive, Dropbox 등의 공유 디렉터리에 있는) C# 프로젝트의 출력 경로 변경하기
13906정성태3/27/20252191닷넷: 2327. C# - 초기화되지 않은 메모리에 접근하는 버그?파일 다운로드1
13905정성태3/26/20252221Windows: 281. C++ - Windows / Critical Section의 안정화를 위해 도입된 "Keyed Event"파일 다운로드1
13904정성태3/25/20251902디버깅 기술: 218. Windbg로 살펴보는 Win32 Critical Section파일 다운로드1
13903정성태3/24/20251522VS.NET IDE: 197. (OneDrive, Dropbox 등의 공유 디렉터리에 있는) C++ 프로젝트의 출력 경로 변경하기
13902정성태3/24/20251737개발 환경 구성: 742. Oracle - 테스트용 hr 계정 및 데이터 생성파일 다운로드1
13901정성태3/9/20252112Windows: 280. Hyper-V의 3가지 Thread Scheduler (Classic, Core, Root)
13900정성태3/8/20252346스크립트: 72. 파이썬 - SQLAlchemy + oracledb 연동
13899정성태3/7/20251806스크립트: 71. 파이썬 - asyncio의 ContextVar 전달
13898정성태3/5/20252124오류 유형: 948. Visual Studio - Proxy Authentication Required: dotnetfeed.blob.core.windows.net
13897정성태3/5/20252367닷넷: 2326. C# - PowerShell과 연동하는 방법 (두 번째 이야기)파일 다운로드1
13896정성태3/5/20252178Windows: 279. Hyper-V Manager - VM 목록의 CPU Usage 항목이 항상 0%로 나오는 문제
13895정성태3/4/20252220Linux: 117. eBPF / bpf2go - Map에 추가된 요소의 개수를 확인하는 방법
13894정성태2/28/20252251Linux: 116. eBPF / bpf2go - BTF Style Maps 정의 구문과 데이터 정렬 문제
13893정성태2/27/20252197Linux: 115. eBPF (bpf2go) - ARRAY / HASH map 기본 사용법
[1]  2  3  4  5  6  7  8  9  10  11  12  13  14  15  ...