성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] VT sequences to "CONOUT$" vs. STD_O...
[정성태] NetCoreDbg is a managed code debugg...
[정성태] Evaluating tail call elimination in...
[정성태] What’s new in System.Text.Json in ....
[정성태] What's new in .NET 9: Cryptography ...
[정성태] 아... 제시해 주신 "https://akrzemi1.wordp...
[정성태] 다시 질문을 정리할 필요가 있을 것 같습니다. 제가 본문에...
[이승준] 완전히 잘못 짚었습니다. 댓글 지우고 싶네요. 검색을 해보...
[정성태] 우선 답글 감사합니다. ^^ 그런데, 사실 저 예제는 (g...
[이승준] 수정이 안되어서... byteArray는 BYTE* 타입입니다...
글쓰기
제목
이름
암호
전자우편
HTML
홈페이지
유형
제니퍼 .NET
닷넷
COM 개체 관련
스크립트
VC++
VS.NET IDE
Windows
Team Foundation Server
디버깅 기술
오류 유형
개발 환경 구성
웹
기타
Linux
Java
DDK
Math
Phone
Graphics
사물인터넷
부모글 보이기/감추기
내용
<div style='display: inline'> <h1 style='font-family: Malgun Gothic, Consolas; font-size: 20pt; color: #006699; text-align: center; font-weight: bold'>AcLayers의 API 후킹과 FaultTolerantHeap</h1> <p> FaultTolerantHeap을 살펴보기 위해 일부러 CRT로부터 할당받은 메모리의 헤더를 망가뜨리는 코드를,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Need Sample code for heap corruption in C++ ; <a target='tab' href='https://stackoverflow.com/questions/35123189/need-sample-code-for-heap-corruption-in-c'>https://stackoverflow.com/questions/35123189/need-sample-code-for-heap-corruption-in-c</a> </pre> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > // Visual C++ // ...[생략]... void ReleaseBuf(char* pBuffer) { delete[] pBuffer; } char* AllocBuf() { char* cp = new char[10]; <span style='color: blue; font-weight: bold'>(*(cp - 5))++;</span> return cp; } char* _p; __declspec(dllexport) int __fastcall UseCRTHeap(int value) { if (value == 0) { _p = AllocBuf(); } else if (value == 1) { ReleaseBuf(_p); } return 0; } </pre> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > // C# class Program { [DllImport("Win32Project1.dll")] internal static extern int UseCRTHeap(int value); static unsafe void Main(string[] args) { Console.WriteLine("Allocating..."); UseCRTHeap(0); Console.WriteLine("Allocated"); Console.WriteLine("Releasing..."); UseCRTHeap(1); Console.WriteLine("Released..."); } } </pre> <br /> 사용한 프로그램을 실행하면 최초에는 다음과 같이 3개의 이벤트 로그가 생성됩니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Log Name: Application Source: Application Error Date: 2019-11-14 오전 10:21:10 Event ID: 1000 Task Category: (100) Level: Error Keywords: Classic User: N/A Computer: TESTPC Description: Faulting application name: ConsoleApplication1.exe, version: 1.0.0.0, time stamp: 0x5dcca494 Faulting module name: ntdll.dll, version: 10.0.18362.418, time stamp: 0x99ca0526 Exception code: 0xc0000374 Fault offset: 0x00000000000f9269 Faulting process id: 0x7200 Faulting application start time: 0x01d59a89cc5d5fd2 Faulting application path: c:\temp\ConsoleApplication1.exe Faulting module path: C:\WINDOWS\SYSTEM32\ntdll.dll Report Id: 50e4663e-286d-48dc-aba8-696a11188ac6 Faulting package full name: Faulting package-relative application ID: </pre> <br /> <pre style='height: 400px; margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Log Name: Application Source: Windows Error Reporting Date: 2019-11-14 오전 10:21:12 Event ID: 1001 Task Category: None Level: Information Keywords: Classic User: N/A Computer: TESTPC Description: Fault bucket 2118073145157684012, type 4 Event Name: APPCRASH Response: Not available Cab Id: 0 Problem signature: P1: ConsoleApplication1.exe P2: 1.0.0.0 P3: 5dcca494 P4: StackHash_b2bc P5: 10.0.18362.418 P6: 99ca0526 P7: c0000374 P8: PCH_03_FROM_ntdll+0x000000000009CC14 P9: P10: Attached files: \\?\C:\ProgramData\Microsoft\Windows\WER\Temp\WER84F4.tmp.mdmp \\?\C:\ProgramData\Microsoft\Windows\WER\Temp\WER8582.tmp.WERInternalMetadata.xml \\?\C:\ProgramData\Microsoft\Windows\WER\Temp\WER85A2.tmp.xml \\?\C:\ProgramData\Microsoft\Windows\WER\Temp\WER85A6.tmp.csv \\?\C:\ProgramData\Microsoft\Windows\WER\Temp\WER85D6.tmp.txt These files may be available here: \\?\C:\ProgramData\Microsoft\Windows\WER\ReportArchive\AppCrash_ConsoleApplicati_75e6a768f43e63769fa883e35983a378d047bd80_6103db0b_e38e88b9-59cf-414d-aaa9-282f7a013f53 Analysis symbol: Rechecking for solution: 0 Report Id: 50e4663e-286d-48dc-aba8-696a11188ac6 Report Status: 268435456 Hashed bucket: c8396419a04467d1ed64e84db16b0b2c Cab Guid: 0 </pre> <br /> <pre style='height: 400px; margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Log Name: Application Source: Windows Error Reporting Date: 2019-11-14 오전 10:21:14 Event ID: 1001 Task Category: None Level: Information Keywords: Classic User: N/A Computer: TESTPC Description: Fault bucket 1186916719236790934, type 5 <span style='color: blue; font-weight: bold'>Event Name: FaultTolerantHeap</span> Response: Not available Cab Id: 1329775288456208175 Problem signature: P1: ConsoleApplication1.exe P2: 1.0.0.0 P3: 5DCCA494 P4: ffffbaad P5: P6: P7: P8: P9: P10: Attached files: \\?\C:\WINDOWS\SERVIC~1\LOCALS~1\AppData\Local\Temp\FTH84D5.tmp\fthempty.txt \\?\C:\ProgramData\Microsoft\Windows\WER\Temp\WER84D6.tmp.WERInternalMetadata.xml \\?\C:\ProgramData\Microsoft\Windows\WER\Temp\WER84D7.tmp.xml \\?\C:\ProgramData\Microsoft\Windows\WER\Temp\WER84D9.tmp.csv \\?\C:\ProgramData\Microsoft\Windows\WER\Temp\WER84F9.tmp.txt \\?\C:\Windows\ServiceProfiles\LocalService\AppData\Local\Temp\WER88CF.tmp.WERDataCollectionStatus.txt These files may be available here: Analysis symbol: Rechecking for solution: 0 Report Id: e1740ff6-55b8-4d78-80c0-b80185bc9d28 Report Status: 268435464 Hashed bucket: 4c18d2a648f924301078c677b414ba96 Cab Guid: 94e535c5-8c62-4522-9274-4f9453865f2f </pre> <br /> 주의 깊게 보면, 3번째 로그의 "Event Name"이 "FaultTolerantHeap"인 것을 알 수 있습니다. 그런데, 이후 실행하게 되면 FaultTolerantHeap에 대한 이벤트 로그가 더 이상 생성이 안 됩니다. 재미있는 것은, 이렇게 몇 번 "FaultTolerantHeap"에 해당하는 비정상 종료 프로그램을 실행하다 보면 윈도우는 해당 프로그램을 다음의 레지스트리 경로에 등록하게 됩니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers Value name: c:\temp\ConsoleApplication1.exe Value type: REG_SZ Value data: FaultTolerantHeap (또는, HKCU\Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers) </pre> <br /> 만약, 운(?)이 따른다면 이후에는 비정상 종료를 하지 않을 가능성도 있습니다. 왜냐하면, 윈도우는 이런 유의 비정상 종료를 완화하기 위해 후킹을 제공하기 때문입니다. 실제로, AppCompatFlags에 등록되기 전에는 비정상 종료 시 메모리 덤프를 뜨게 되면 다음과 같은 식의 call stack을 보여줍니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > ntdll!NtWaitForMultipleObjects+14 KERNELBASE!WaitForMultipleObjectsEx+107 KERNELBASE!WaitForMultipleObjects+e kernel32!WerpReportFaultInternal+51b kernel32!WerpReportFault+ac KERNELBASE!UnhandledExceptionFilter+3b8 ntdll!RtlUserThreadStart$filt$0+a2 ntdll!_C_specific_handler+96 ntdll!RtlpExecuteHandlerForException+f ntdll!RtlDispatchException+219 ntdll!KiUserExceptionDispatch+2e ntdll!RtlpFreeHeapInternal+65ed4 ntdll!RtlFreeHeap+51 ucrtbase!_free_base+1b Win32Project1!ExternC_FAST_Func_By_DEF+34 DomainBoundILStubClass.IL_STUB_PInvoke(Int32)+76 Program.Main(System.String[])+8b clr!CallDescrWorkerInternal+83 clr!CallDescrWorkerWithHandler+4e clr!MethodDescCallSite::CallTargetWorker+102 clr!RunMain+25f clr!Assembly::ExecuteMainMethod+b7 clr!SystemDomain::ExecuteMainMethod+643 clr!ExecuteEXE+3f clr!_CorExeMainInternal+b2 clr!CorExeMain+14 mscoreei!CorExeMain+112 mscoree!CorExeMain_Exported+6c kernel32!BaseThreadInitThunk+14 ntdll!RtlUserThreadStart+21 </pre> <br /> 반면, 일단 윈도우가 FaultTolerantHeap 유형임을 알고 개입하기 시작하면 다음과 같이 AcLayers.dll의 함수가 중간에 들어가는 것을 볼 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > ntdll!NtWaitForMultipleObjects+14 KERNELBASE!WaitForMultipleObjectsEx+107 KERNELBASE!WaitForMultipleObjects+e kernel32!WerpReportFaultInternal+51b kernel32!WerpReportFault+ac KERNELBASE!UnhandledExceptionFilter+3b8 ntdll!RtlUserThreadStart$filt$0+a2 ntdll!_C_specific_handler+96 ntdll!RtlpExecuteHandlerForException+f ntdll!RtlDispatchException+219 ntdll!KiUserExceptionDispatch+2e <span style='color: blue; font-weight: bold'>ntdll!RtlSizeHeap+1af </span> <span style='color: blue; font-weight: bold'>AcLayers!NS_FaultTolerantHeap::APIHook_RtlFreeHeap+146 </span> ucrtbase!_free_base+1b Win32Project1!ExternC_FAST_Func_By_DEF+34 DomainBoundILStubClass.IL_STUB_PInvoke(Int32)+76 Program.Main(System.String[])+8b clr!CallDescrWorkerInternal+83 clr!CallDescrWorkerWithHandler+4e clr!MethodDescCallSite::CallTargetWorker+102 clr!RunMain+25f clr!Assembly::ExecuteMainMethod+b7 clr!SystemDomain::ExecuteMainMethod+643 clr!ExecuteEXE+3f clr!_CorExeMainInternal+b2 clr!CorExeMain+14 mscoreei!CorExeMain+112 mscoree!CorExeMain_Exported+6c kernel32!BaseThreadInitThunk+14 ntdll!RtlUserThreadStart+21 </pre> <br /> APIHook_RtlFreeHeap에서 할당된 Heap 크기를 알기 위해 <a target='tab' href='https://source.winehq.org/WineAPI/RtlSizeHeap.html'>RtlSizeHeap</a>을 호출하는데, 아쉽게도 이번 오류는 Header 영역이 깨졌기 때문에 그런 시도조차 실패하게 된 것입니다.<br /> <br /> <hr style='width: 50%' /><br /> <br /> 그렇다면 다시 AcLayers의 개입을 없앨 수 있을까요? 제가 해본 바로는 "AppCompatFlags\Layers" 레지스트리에 등록된 것을 지운다고 해결되지는 않았습니다. 대신 해당 EXE를 다른 경로에 복사해 실행하면 다시 "FaultTolerantHeap" 이벤트 로그가 생성되었고 이후 마찬가지로 몇 번 실행하면 "AppCompatFlags\Layers" 레지스트리에 등록이 되었습니다. (물론, 다시 그 EXE의 실행에는 AcLayers가 개입합니다.)<br /> <br /> 검색해 보면, 아예 FTH 기능을 끄는 방법이 나옵니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Disabling a Shim ; <a target='tab' href='https://learn.microsoft.com/en-us/archive/blogs/maartenb/disabling-a-shim'>https://learn.microsoft.com/en-us/archive/blogs/maartenb/disabling-a-shim</a> </pre> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > You can disable the whole shim engine through this setting from GPEdit.msc: Administrative Templates \ Windows Components \ Application Compatibility \ Turn off Application Compatibility Engine Setting it to enabled means that the Shim engine is off. Reboot and there you have it. No output in DebugView. </pre> <br /> 또한 다음의 글을 보면,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Fault Tolerant Heap ; <a target='tab' href='https://learn.microsoft.com/en-us/windows/win32/win7appqual/fault-tolerant-heap'>https://learn.microsoft.com/en-us/windows/win32/win7appqual/fault-tolerant-heap</a> </pre> <br /> HKLM\Software\Microsoft\FTH 경로의 Enabled 값을 0으로 설정해도 FTH 기능을 시스템 전역적으로 끌 수 있다고 나옵니다.<br /> <br /> 참고로, 소개된 이벤트 로그 경로(Event Viewer > Applications and Services Logs > Microsoft > Windows > Fault-Tolerant-Heap)를 보면 FTH에 대해 "service started" / "service stopped" 이벤트들을 볼 수 있는데 NT Service처럼 내부적으로 다뤄지고 있는 듯한데 실제로 이를 제어할 수 있는 방법은 gpedit.msc와 레지스트리 설정 이외에는 없는 것 같습니다.<br /> <br /> 그리고 "Application Compatibility"에 등록된 항목들을 전부 초기화(reset) 할 수 있는 명령어를 소개하는데,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Rundll32.exe fthsvc.dll,FthSysprepSpecialize </pre> <br /> (권장하지는 않지만) 실제로 저 명령을 내리면 "AppCompatFlags\Layers" 레지스트리 설정까지 전부 초기화되는 것을 볼 수 있습니다. 따라서 call stack에 보이던 AcLayers의 개입도 없어집니다.<br /> <br /> 이번엔 여기까지만! ^^<br /> </p><br /> <br /><hr /><span style='color: Maroon'>[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
1913
(왼쪽의 숫자를 입력해야 합니다.)