Microsoft MVP성태의 닷넷 이야기
글쓴 사람
정성태 (seongtaejeong at gmail.com)
홈페이지
첨부 파일
 

(시리즈 글이 2개 있습니다.)
.NET Framework: 786. ASP.NET - HttpCookieCollection을 다중 스레드에서 사용할 경우 무한 루프 현상
; https://www.sysnet.pe.kr/2/0/11587

디버깅 기술: 221. WinDbg 분석 사례 - ASP.NET HttpCookieCollection을 다중 스레드에서 사용할 경우 무한 루프 현상 - 두 번째 이야기
; https://www.sysnet.pe.kr/2/0/13916




WinDbg 분석 사례 - ASP.NET HttpCookieCollection을 다중 스레드에서 사용할 경우 무한 루프 현상 - 두 번째 이야기

아래와 같이 덤프 파일을 분석해,

windbg 분석 사례 - x86 ASP.NET 웹 응용 프로그램의 CPU 100% 현상 (4)
; https://www.sysnet.pe.kr/2/0/13914

requestValidationMode 값을 4.0으로 설정하면 문제가 발생하지 않을 거라고 했는데, 그래도 여전히 해당 현상이 재현된다는 소식과 함께 다시 덤프 파일을 받았습니다.

이럴 땐 자연스럽게, ^^; 제 눈으로 본 것이 아니기 때문에 정말 4.0으로 설정했는지 확인해야 합니다. 어떻게 할 수 있을까요? ^^

우선 HttpRuntimeSection.RequestValidationMode 속성의 역어셈블 코드를 보면,

[ConfigurationProperty("requestValidationMode", DefaultValue = "4.0")]
[TypeConverter(typeof(VersionConverter))]
public Version RequestValidationMode
{
    get
    {
        if (this._requestValidationMode == null)
        {
            this._requestValidationMode = (Version)base[HttpRuntimeSection._propRequestValidationMode];
        }
        return this._requestValidationMode;
    }
    set
    {
        this._requestValidationMode = value;
        base[HttpRuntimeSection._propRequestValidationMode] = value;
    }
}

보는 바와 같이 _requestValidationMode 필드에 값이 보관됩니다. 다행히 HttpRuntimeSection은 Web Application에 1개의 인스턴스, 또는 다른 이유로 인해 1~2개 정도 더 생성될 것이라고 짐작할 수 있으므로 GC Heap에 존재할 그 인스턴스를 검색해 보면 됩니다.

// 우선 해당 타입의 MethodTable을 알아내고,
0:000> !name2ee System.Web.dll!System.Web.Configuration.HttpRuntimeSection
Module:      19c1a4c4
Assembly:    System.Web.dll
Token:       020006fe
MethodTable: 1a7c4248
EEClass:     1b5966e0
Name:        System.Web.Configuration.HttpRuntimeSection

// GC Heap에서 HttpRuntimeSection 인스턴스를 검색
0:000> !dumpheap -mt 1a7c4248
 Address       MT     Size
0b6522c8 1a7c4248      112     
0b652438 1a7c4248      112     

Statistics:
      MT    Count    TotalSize Class Name
1a7c4248        2          224 System.Web.Configuration.HttpRuntimeSection
Total 2 objects
Fragmented blocks larger than 0.5 MB:
    Addr     Size      Followed by
0a862394    0.6MB         0a8f6234 System.Byte[]

보는 바와 같이 2개의 인스턴스가 있는데요, 각각을 덤프해 보면,

// 인스턴스 1개는 _requestValidationMode 필드가 비어 있고,

0:000> !do 0b6522c8
Name:        System.Web.Configuration.HttpRuntimeSection
MethodTable: 1a7c4248
EEClass:     1b5966e0
Size:        112(0x70) bytes
File:        C:\Windows\Microsoft.Net\assembly\GAC_32\System.Web\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Web.dll
Fields:
      MT    Field   Offset                 Type VT     Attr    Value Name
0663aa48  4000198       30       System.Boolean  1 instance        0 _bDataToWrite
...[생략]...
0663c9b0  4002e15       50         System.Int32  1 instance       -1 _RequestLengthDiskThresholdBytes
1a62e23c  4002e17       3c       System.Version  0 instance 00000000 _requestValidationMode
0663c9b0  4002e18       54         System.Int32  1 instance        0 _MaxUrlLength
...[생략]...

// 다른 인스턴스에는 4.0.-1.-1 값이 설정됨

0:000> !do 0b652438
Name:        System.Web.Configuration.HttpRuntimeSection
MethodTable: 1a7c4248
EEClass:     1b5966e0
Size:        112(0x70) bytes
File:        C:\Windows\Microsoft.Net\assembly\GAC_32\System.Web\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Web.dll
Fields:
      MT    Field   Offset                 Type VT     Attr    Value Name
0663aa48  4000198       30       System.Boolean  1 instance        0 _bDataToWrite
...[생략]...
0663c9b0  4002e15       50         System.Int32  1 instance    81920 _RequestLengthDiskThresholdBytes
1a62e23c  4002e17       3c       System.Version  0 instance 0b652664 _requestValidationMode
0663c9b0  4002e18       54         System.Int32  1 instance      260 _MaxUrlLength
...[생략]...

0:000> !do 0b652664
Name:        System.Version
MethodTable: 1a62e23c
EEClass:     1a63b0c4
Size:        24(0x18) bytes
File:        C:\Windows\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
Fields:
      MT    Field   Offset                 Type VT     Attr    Value Name
0663c9b0  400073a        4         System.Int32  1 instance        4 _Major
0663c9b0  400073b        8         System.Int32  1 instance        0 _Minor
0663c9b0  400073c        c         System.Int32  1 instance       -1 _Build
0663c9b0  400073d       10         System.Int32  1 instance       -1 _Revision
19c14e2c  400073e      1d0        System.Char[]  0   shared   static SeparatorsArray

그러니까, requestValidationMode 값을 4.0으로 설정한 것이 맞고, 그럼에도 불구하고 문제가 발생하고 있는 것입니다.




그렇다면, 분명히 어떤 식으로든 EnableGranularValidation 코드가 수행되고 있다는 건데요, 이건 어떻게 확인할 수 있을까요? ^^

이를 위해 WinDbg를 동원할 필요는 없고, 위의 분석 대상이었던 응용 프로그램의 유형이 ASP.NET MVC 프로젝트였으므로 이에 대한 간단한 예제 프로젝트를 Visual Studio에서 생성한 후 쿠키를 사용하는 코드를 넣어,

public class HomeController : Controller
{
    public ActionResult Index()
    {
        var oldCookie = this.Request.Cookies["test"];
        this.Response.Cookies.Add(new HttpCookie("test", "testValue") { Expires = DateTime.Now.AddDays(1) });

        return View();
    }

    // ...[생략]...
}

디버깅을 시작해 솔루션 탐색기의 "External Sources"로부터 HttpCookieCollection 소스 코드를 열어 BP를 걸어보면 됩니다.

cookie_validation_on_mvc_1.png

실제로, web.config의 requestValidationMode를 4.0으로 설정해도,

<httpRuntime targetFramework="4.8" requestValidationMode="4.0" />

동일하게 BP가 걸리는데요, 이때의 callstack을 따라가 보면,

>    System.Web.dll!System.Web.HttpCookieCollection.EnableGranularValidation(System.Web.ValidateStringCallback validationCallback = {Method = Inspecting the state of an object in the debuggee of type System.Delegate is not supported in this context.}) Line 127 C#  Symbols loaded.
    System.Web.dll!System.Web.HttpRequest.Cookies.get() Line 1225   C#  Symbols loaded.
    net48_mvc.dll!net48_mvc.Controllers.HomeController.Index() Line 14  C#  Symbols loaded.
    [Lightweight Function]      Annotated Frame
    System.Web.Mvc.dll!System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(System.Web.Mvc.ControllerContext controllerContext = {System.Web.Mvc.ControllerContext}, System.Web.Mvc.ActionDescriptor actionDescriptor = {System.Web.Mvc.ReflectedActionDescriptor}, System.Collections.Generic.IDictionary<string, object> parameters) Line 253  C#  Symbols loaded.
    System.Web.Mvc.dll!System.Web.Mvc.Async.AsyncControllerActionInvoker.BeginInvokeSynchronousActionMethod.AnonymousMethod__9_0(System.IAsyncResult asyncResult, System.Web.Mvc.Async.AsyncControllerActionInvoker.ActionInvocation innerInvokeState) Line 304 C#  Symbols loaded.
    System.Web.Mvc.dll!System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult<System.__Canon, System.Web.Mvc.Async.AsyncControllerActionInvoker.ActionInvocation>.CallEndDelegate(System.IAsyncResult asyncResult) Line 224   C#  Symbols loaded.
    // ...[생략]...
    System.Web.dll!System.Web.Hosting.PipelineRuntime.ProcessRequestNotification(System.IntPtr rootedObjectsPointer, System.IntPtr nativeRequestContext, System.IntPtr moduleData, int flags) Line 386  C#  Symbols loaded.
    [AppDomain Transition]      Annotated Frame

관련 코드의 역어셈블 결과에서,

// HttpRequest.cs

public HttpCookieCollection Cookies
{
    get
    {
        EnsureCookies();
        if (_flags[4])
        {
            _flags.Clear(4);
            ValidateCookieCollection(_cookies);
        }
        return _cookies;
    }
}

private void ValidateCookieCollection(HttpCookieCollection cc)
{
	if (GranularValidationEnabled)
	{
		cc.EnableGranularValidation(delegate(string key, string value)
        {
            ValidateString(value, key, RequestValidationSource.Cookies);
        });
		return;
	}
	int count = cc.Count;
	for (int i = 0; i < count; i++)
	{
		string key2 = cc.GetKey(i);
		string value2 = cc.Get(i).Value;
		if (!string.IsNullOrEmpty(value2))
		{
			ValidateString(value2, key2, RequestValidationSource.Cookies);
		}
	}
}

Cookies get 메서드로부터 결국 _flags[4] 값으로 인해 EnableGranularValidation이 호출되고 있음을 알 수 있습니다. 그리고 다시, 그것은 GranularValidationEnabled get 속성이 true를 반환하기 때문인데,

// HttpRequest.cs

private const int granularValidationEnabled = 1073741824; // 0x40000000

private bool GranularValidationEnabled => _flags[0x40000000]; // 0x40000000

internal void EnableGranularRequestValidation()
{
	_flags[0x40000000] = true;
}

따라서 EnableGranularRequestValidation 메서드가 호출된 적이 있다는 것이므로 이것도 BP를 걸어 확인하면, 호출 스택이 이렇게 나오고,

>    System.Web.dll!System.Web.HttpRequest.EnableGranularRequestValidation() Line 2672   C#  Symbols loaded.
    System.Web.Mvc.dll!System.Web.Mvc.MvcHandler.ProcessRequestInit(System.Web.HttpContextBase httpContext = {System.Web.HttpContextWrapper}, out System.Web.Mvc.IController controller = null, out System.Web.Mvc.IControllerFactory factory = null) Line 168  C#  Symbols loaded.
    System.Web.Mvc.dll!System.Web.Mvc.MvcHandler.BeginProcessRequest(System.Web.HttpContextBase httpContext, System.AsyncCallback callback = {Method = {System.Reflection.RuntimeMethodInfo}}, object state = null) Line 86 C#  Symbols loaded.
    System.Web.dll!System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() Line 648 C#  Symbols loaded.
    System.Web.dll!System.Web.HttpApplication.ExecuteStepImpl(System.Web.HttpApplication.IExecutionStep step) Line 3596 C#  Symbols loaded.
    System.Web.dll!System.Web.HttpApplication.ExecuteStep(System.Web.HttpApplication.IExecutionStep step = {System.Web.HttpApplication.CallHandlerExecutionStep}, ref bool completedSynchronously = false) Line 3622    C#  Symbols loaded.
    System.Web.dll!System.Web.HttpApplication.PipelineStepManager.ResumeSteps(System.Exception error) Line 1161 C#  Symbols loaded.
    System.Web.dll!System.Web.HttpApplication.BeginProcessRequestNotification(System.Web.HttpContext context, System.AsyncCallback cb) Line 4054    C#  Symbols loaded.
    System.Web.dll!System.Web.HttpRuntime.ProcessRequestNotificationPrivate(System.Web.Hosting.IIS7WorkerRequest wr = {System.Web.Hosting.IIS7WorkerRequest}, System.Web.HttpContext context = {System.Web.HttpContext}) Line 1407  C#  Symbols loaded.
    System.Web.dll!System.Web.Hosting.PipelineRuntime.ProcessRequestNotificationHelper(System.IntPtr rootedObjectsPointer, System.IntPtr nativeRequestContext = 0x0000026e78687998, System.IntPtr moduleData, int flags) Line 461   C#  Symbols loaded.
    System.Web.dll!System.Web.Hosting.PipelineRuntime.ProcessRequestNotification(System.IntPtr rootedObjectsPointer, System.IntPtr nativeRequestContext, System.IntPtr moduleData, int flags) Line 386  C#  Symbols loaded.
    [Native to Managed Transition]      Annotated Frame
    [Managed to Native Transition]      Annotated Frame
    System.Web.dll!System.Web.Hosting.PipelineRuntime.ProcessRequestNotificationHelper(System.IntPtr rootedObjectsPointer, System.IntPtr nativeRequestContext, System.IntPtr moduleData, int flags) Line 499    C#  Symbols loaded.
    System.Web.dll!System.Web.Hosting.PipelineRuntime.ProcessRequestNotification(System.IntPtr rootedObjectsPointer, System.IntPtr nativeRequestContext, System.IntPtr moduleData, int flags) Line 386  C#  Symbols loaded.
    [AppDomain Transition]      Annotated Frame

Mvc 프레임워크에 놓인 ProcessRequestInit 메서드에서 ValidationUtility.EnableDynamicValidation 메서드를 호출하며, 그 원인은 다시 ValidationUtility.IsValidationEnabled가 true를 반환하기 때문입니다.


// MvcHandler.cs (System.Web.Mvc.dll)
private void ProcessRequestInit(HttpContextBase httpContext, out IController controller, out IControllerFactory factory)
{
    HttpContext current = HttpContext.Current;
    if (current != null && ValidationUtility.IsValidationEnabled(current) == true)
    {
        ValidationUtility.EnableDynamicValidation(current);
    }
    AddVersionHeader(httpContext);
    RemoveOptionalRoutingParameters();
    string requiredString = RequestContext.RouteData.GetRequiredString("controller");
    factory = ControllerBuilder.GetControllerFactory();
    controller = factory.CreateController(RequestContext, requiredString);
    if (controller == null)
    {
        throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, MvcResources.ControllerBuilder_FactoryReturnedNull, new object[2]
        {
            factory.GetType(),
            requiredString
        }));
    }
}

// Microsoft.Web.Infrastructure.dll

[EditorBrowsable(EditorBrowsableState.Never)]
public static class ValidationUtility
{
    // ...[생략]...

    [SecuritySafeCritical]
    public static bool? IsValidationEnabled(HttpContext context)
    {
        if (DynamicValidationShimReflectionUtil.Instance != null)
        {
            return DynamicValidationShimReflectionUtil.Instance.IsValidationEnabled(context);
        }
        return CollectionReplacer.IsValidationEnabled(context);
    }
}

// System.Web.dll

internal static class DynamicValidationShim
{
    internal static bool IsValidationEnabled(HttpContext context)
    {
        return context.Request.ValidateInputWasCalled;
    }

    // ...[생략]...
}

// HttpRequest.cs (System.Web.dll)

internal bool ValidateInputWasCalled => _flags[32768]; // 0x8000

public void ValidateInput()
{
    if (!ValidateInputWasCalled && !RequestValidationSuppressed)
    {
        _flags.Set(32768);
        _flags.Set(1);
        _flags.Set(2);
        _flags.Set(4);
        _flags.Set(64);
        _flags.Set(128);
        _flags.Set(256);
        _flags.Set(512);
        _flags.Set(8);
    }
}

끝이 보이는군요. ^^ 이제 ValidateInput이 호출된 위치를 다시 BP를 걸어 확인해 보면,

internal void ValidateInputIfRequiredByConfig()
{
    RuntimeConfig config = RuntimeConfig.GetConfig(Context);
    HttpRuntimeSection httpRuntime = config.HttpRuntime;
    if (CanValidateRequest())
    {
        string path = Path;
        if (path.Length > httpRuntime.MaxUrlLength)
        {
            throw new HttpException(400, SR.GetString("Url_too_long"));
        }
        if (QueryStringText.Length > httpRuntime.MaxQueryStringLength)
        {
            throw new HttpException(400, SR.GetString("QueryString_too_long"));
        }
        char[] requestPathInvalidCharactersArray = httpRuntime.RequestPathInvalidCharactersArray;
        if (requestPathInvalidCharactersArray != null && requestPathInvalidCharactersArray.Length != 0)
        {
            int num = path.IndexOfAny(requestPathInvalidCharactersArray);
            if (num >= 0)
            {
                string text = new string(path[num], 1);
                throw new HttpException(400, SR.GetString("Dangerous_input_detected", "Request.Path", text));
            }
            _flags.Set(65536);
        }
    }
    Version requestValidationMode = httpRuntime.RequestValidationMode;
    if (requestValidationMode == VersionUtil.Framework00)
    {
        _flags[int.MinValue] = true;
    }
    else if (requestValidationMode >= VersionUtil.Framework40)
    {
        ValidateInput();
        if (requestValidationMode >= VersionUtil.Framework45)
        {
            EnableGranularRequestValidation();
        }
    }
}

이렇게 requestValidationMode >= VersionUtil.Framework40인 상황에서 호출된 것이 MVC Framework에서는 (마이크로소프트가 의도한 것인지, 논리적으로 버그인 것인지 알 수 없으나) 기본적으로 Cookie의 EnableGranularValidation 기능을 활성화시켜버리는 것입니다.

결국, MVC 프로젝트라면 web.config에 requestValidationMode 값을 오히려 4.0 미만으로 설정해야 하는데, 가능한 값이 정해져 있으므로 2.0 정도로 내려야 합니다.




부가적으로 하나 더 정리하자면, ValidationUtility의 경우 중간에 DynamicValidationShimReflectionUtil.Instance를 접근하는데,

// ValidationUtility.cs (Microsoft.Web.Infrastructure.dll)

[SecuritySafeCritical]
public static bool? IsValidationEnabled(HttpContext context)
{
    if (DynamicValidationShimReflectionUtil.Instance != null)
    {
        return DynamicValidationShimReflectionUtil.Instance.IsValidationEnabled(context);
    }
    return CollectionReplacer.IsValidationEnabled(context);
}

이것은 Reflection을 이용해 System.Web.dll에 있는 Microsoft.Web.Infrastructure.DynamicValidationHelper.DynamicValidationShim 타입 정보를 로드하는 역할을 합니다.

// DynamicValidationShimReflectionUtil.cs (Microsoft.Web.Infrastructure.dll)

namespace Microsoft.Web.Infrastructure.DynamicValidationHelper;

[SecurityCritical]
internal sealed class DynamicValidationShimReflectionUtil
{
    // ...[생략]...

    [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "We catch and ignore all errors because we do not want to bring down the application.")]
    private static DynamicValidationShimReflectionUtil GetInstance()
    {
        try
        {
            DynamicValidationShimReflectionUtil dynamicValidationShimReflectionUtil = new DynamicValidationShimReflectionUtil();
            Type type = CommonAssemblies.SystemWeb.GetType("Microsoft.Web.Infrastructure.DynamicValidationHelper.DynamicValidationShim", throwOnError: false);
            if (type == null)
            {
                return null;
            }
            MethodInfo method = CommonReflectionUtil.FindMethod(type, "EnableDynamicValidation", isStatic: true, new Type[1] { typeof(HttpContext) }, typeof(void));
            dynamicValidationShimReflectionUtil.EnableDynamicValidation = CommonReflectionUtil.MakeDelegate<Action<HttpContext>>(method);
            CommonReflectionUtil.Assert(dynamicValidationShimReflectionUtil.EnableDynamicValidation != null);
            MethodInfo method2 = CommonReflectionUtil.FindMethod(type, "IsValidationEnabled", isStatic: true, new Type[1] { typeof(HttpContext) }, typeof(bool));
            dynamicValidationShimReflectionUtil.IsValidationEnabled = CommonReflectionUtil.MakeDelegate<Func<HttpContext, bool>>(method2);
            CommonReflectionUtil.Assert(dynamicValidationShimReflectionUtil.IsValidationEnabled != null);
            MethodInfo method3 = CommonReflectionUtil.FindMethod(type, "GetUnvalidatedCollections", isStatic: true, new Type[3]
            {
                typeof(HttpContext),
                typeof(Func<NameValueCollection>).MakeByRefType(),
                typeof(Func<NameValueCollection>).MakeByRefType()
            }, typeof(void));
            dynamicValidationShimReflectionUtil.GetUnvalidatedCollections = CommonReflectionUtil.MakeDelegate<GetUnvalidatedCollectionsCallback>(method3);
            CommonReflectionUtil.Assert(dynamicValidationShimReflectionUtil.GetUnvalidatedCollections != null);
            return dynamicValidationShimReflectionUtil;
        }
        catch
        {
            return null;
        }
    }
}

그리고 System.Web.dll에 있는 DynamicValidationShim은 마치 "Microsoft.Web.Infrastructure.dll"에서 접근할 수 있는 통로를 열어두는 것처럼 구현돼 있습니다.

// DynamicValidationShim.cs (System.Web.dll)
using System;
using System.Collections.Specialized;
using System.Web;

namespace Microsoft.Web.Infrastructure.DynamicValidationHelper;

internal static class DynamicValidationShim
{
    internal static void EnableDynamicValidation(HttpContext context)
    {
        context.Request.EnableGranularRequestValidation();
    }

    internal static bool IsValidationEnabled(HttpContext context)
    {
        return context.Request.ValidateInputWasCalled;
    }

    internal static void GetUnvalidatedCollections(HttpContext context, out Func<NameValueCollection> formGetter, out Func<NameValueCollection> queryStringGetter)
    {
        UnvalidatedRequestValues unvalidated = context.Request.Unvalidated;
        formGetter = () => unvalidated.Form;
        queryStringGetter = () => unvalidated.QueryString;
    }
}

사실 Microsoft.Web.Infrastructure.dll은 System.Web.dll을 직접 참조하고 있으므로 저런 식으로 접근할 필요가 없습니다. 그런데도, 이렇게 구현된 것은...? 아마도 닷넷 프레임워크의 BCL에 기본 포함된 System.Web.dll과는 달리 Microsoft.Web.Infrastructure.dll의 경우 .NET Framework 버전에 의존적이지 않게 만들 목적이었지 않았을까 싶습니다. 일례로, .NET 3.5 버전의 System.Web.dll에는 DynamicValidationShim 타입이 없다는 식의 고려를 한 것이 아닐까...라고 추측해 봅니다. ^^




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







[최초 등록일: ]
[최종 수정일: 4/23/2025]

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

비밀번호

댓글 작성자
 




... 61  62  63  64  65  66  67  68  69  70  71  72  [73]  74  75  ...
NoWriterDateCnt.TitleFile(s)
12109정성태1/10/202016559오류 유형: 588. Driver 프로젝트 빌드 오류 - Inf2Cat error -2: "Inf2Cat, signability test failed."
12108정성태1/10/202017392오류 유형: 587. Kernel Driver 시작 시 127(The specified procedure could not be found.) 오류 메시지 발생
12107정성태1/10/202018528.NET Framework: 877. C# - 프로세스의 모든 핸들을 열람 - 두 번째 이야기
12106정성태1/8/202019613VC++: 136. C++ - OSR Driver Loader와 같은 Legacy 커널 드라이버 설치 프로그램 제작 [1]
12105정성태1/8/202018127디버깅 기술: 153. C# - PEB를 조작해 로드된 DLL을 숨기는 방법
12104정성태1/7/202019307DDK: 9. 커널 메모리를 읽고 쓰는 NT Legacy driver와 C# 클라이언트 프로그램 [4]
12103정성태1/7/202022400DDK: 8. Visual Studio 2019 + WDK Legacy Driver 제작- Hello World 예제 [1]파일 다운로드2
12102정성태1/6/202018775디버깅 기술: 152. User 권한(Ring 3)의 프로그램에서 _ETHREAD 주소(및 커널 메모리를 읽을 수 있다면 _EPROCESS 주소) 구하는 방법
12101정성태1/5/202018997.NET Framework: 876. C# - PEB(Process Environment Block)를 통해 로드된 모듈 목록 열람
12100정성태1/3/202016494.NET Framework: 875. .NET 3.5 이하에서 IntPtr.Add 사용
12099정성태1/3/202019301디버깅 기술: 151. Windows 10 - Process Explorer로 확인한 Handle 정보를 windbg에서 조회 [1]
12098정성태1/2/202019068.NET Framework: 874. C# - 커널 구조체의 Offset 값을 하드 코딩하지 않고 사용하는 방법 [3]
12097정성태1/2/202017130디버깅 기술: 150. windbg - Wow64, x86, x64에서의 커널 구조체(예: TEB) 구조체 확인
12096정성태12/30/201919850디버깅 기술: 149. C# - DbgEng.dll을 이용한 간단한 디버거 제작 [1]
12095정성태12/27/201921560VC++: 135. C++ - string_view의 동작 방식
12094정성태12/26/201919280.NET Framework: 873. C# - 코드를 통해 PDB 심벌 파일 다운로드 방법
12093정성태12/26/201918848.NET Framework: 872. C# - 로딩된 Native DLL의 export 함수 목록 출력파일 다운로드1
12092정성태12/25/201917659디버깅 기술: 148. cdb.exe를 이용해 (ntdll.dll 등에 정의된) 커널 구조체 출력하는 방법
12091정성태12/25/201919940디버깅 기술: 147. pdb 파일을 다운로드하기 위한 symchk.exe 실행에 필요한 최소 파일 [1]
12090정성태12/24/201920041.NET Framework: 871. .NET AnyCPU로 빌드된 PE 헤더의 로딩 전/후 차이점 [1]파일 다운로드1
12089정성태12/23/201918950디버깅 기술: 146. gflags와 _CrtIsMemoryBlock을 이용한 Heap 메모리 손상 여부 체크
12088정성태12/23/201917938Linux: 28. Linux - 윈도우의 "Run as different user" 기능을 shell에서 실행하는 방법
12087정성태12/21/201918384디버깅 기술: 145. windbg/sos - Dictionary의 entries 배열 내용을 모두 덤프하는 방법 (do_hashtable.py) [1]
12086정성태12/20/201920880디버깅 기술: 144. windbg - Marshal.FreeHGlobal에서 발생한 덤프 분석 사례
12085정성태12/20/201918836오류 유형: 586. iisreset - The data is invalid. (2147942413, 8007000d) 오류 발생 - 두 번째 이야기 [1]
12084정성태12/19/201919287디버깅 기술: 143. windbg/sos - Hashtable의 buckets 배열 내용을 모두 덤프하는 방법 (do_hashtable.py) [1]
... 61  62  63  64  65  66  67  68  69  70  71  72  [73]  74  75  ...