Microsoft MVP성태의 닷넷 이야기
디버깅 기술: 198. Windbg - 스레드의 Win32 Message Queue 정보 조회 [링크 복사], [링크+제목 복사],
조회: 4065
글쓴 사람
정성태 (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)
13739정성태9/24/20242392닷넷: 2297. C# - ssh-keygen으로 생성한 Public Key 파일 해석과 fingerprint 값(md5, sha256) 생성 [1]파일 다운로드1
13738정성태9/22/20242157C/C++: 174. C/C++ - 윈도우 운영체제에서의 file descriptor, FILE*파일 다운로드1
13737정성태9/21/20242761개발 환경 구성: 727. Visual C++ - 리눅스 프로젝트를 위한 빌드 서버의 msbuild 구성
13736정성태9/20/20242390오류 유형: 923. Visual Studio Code - Could not establish connection to "...": Port forwarding is disabled.
13735정성태9/20/20242710개발 환경 구성: 726. ARM 플랫폼용 Visual C++ 리눅스 프로젝트 빌드
13734정성태9/19/20242628개발 환경 구성: 725. ssh를 이용한 원격 docker 서비스 사용
13733정성태9/19/20242510VS.NET IDE: 194. Visual Studio - Cross Platform / "Authentication Type: Private Key"로 접속하는 방법
13732정성태9/17/20242627개발 환경 구성: 724. ARM + docker 환경에서 .NET 8 설치
13731정성태9/15/20243200개발 환경 구성: 723. C# / Visual C++ - Control Flow Guard (CFG) 활성화 [1]파일 다운로드2
13730정성태9/10/20242573오류 유형: 922. docker - RULE_APPEND failed (No such file or directory): rule in chain DOCKER
13729정성태9/9/20243195C/C++: 173. Windows / C++ - AllocConsole로 할당한 콘솔과 CRT 함수 연동 [1]파일 다운로드1
13728정성태9/7/20243093C/C++: 172. Windows - C 런타임에서 STARTUPINFO의 cbReserved2, lpReserved2 멤버를 사용하는 이유파일 다운로드1
13727정성태9/6/20243578개발 환경 구성: 722. ARM 플랫폼 빌드를 위한 미니 PC(?) - Khadas VIM4 [1]
13726정성태9/5/20243989C/C++: 171. C/C++ - 윈도우 운영체제에서의 file descriptor와 HANDLE파일 다운로드1
13725정성태9/4/20242763디버깅 기술: 201. WinDbg - sos threads 명령어 실행 시 "Failed to request ThreadStore"
13724정성태9/3/20244208닷넷: 2296. Win32/C# - 자식 프로세스로 HANDLE 상속파일 다운로드1
13723정성태9/2/20245130C/C++: 170. Windows - STARTUPINFO의 cbReserved2, lpReserved2 멤버 사용자 정의파일 다운로드2
13722정성태9/2/20242891C/C++: 169. C/C++ - CRT(C Runtime) 함수에 의존성이 없는 프로젝트 생성
13721정성태8/30/20243009C/C++: 168. Visual C++ CRT(C Runtime DLL: msvcr...dll)에 대한 의존성 제거 - 두 번째 이야기
13720정성태8/29/20242779VS.NET IDE: 193. C# - Visual Studio의 자식 프로세스 디버깅
13719정성태8/28/20243163Linux: 79. C++ - pthread_mutexattr_destroy가 없다면 메모리 누수가 발생할까요?
13718정성태8/27/20243509오류 유형: 921. Visual C++ - error C1083: Cannot open include file: 'float.h': No such file or directory [2]
13717정성태8/26/20243247VS.NET IDE: 192. Visual Studio 2022 - Windows XP / 2003용 C/C++ 프로젝트 빌드
13716정성태8/21/20243100C/C++: 167. Visual C++ - 윈도우 환경에서 _execv 동작
13715정성태8/19/20243201Linux: 78. 리눅스 C/C++ - 특정 버전의 glibc 빌드 (docker-glibc-builder)
13714정성태8/19/20243440닷넷: 2295. C# 12 - 기본 생성자(Primary constructors) (책 오타 수정) [3]
1  2  3  4  [5]  6  7  8  9  10  11  12  13  14  15  ...