성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
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'>WinDbg로 EXE의 EntryPoint에서 BP 거는 방법</h1> <p> 지난 글에서,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > EXE를 LoadLibrary로 로딩해 PE 헤더에 있는 EntryPoint를 직접 호출하는 방법 ; <a target='tab' href='http://www.sysnet.pe.kr/2/0/11858'>http://www.sysnet.pe.kr/2/0/11858</a> </pre> <br /> 2가지 유형의 EntryPoint를 갖는 EXE를 만들었습니다.<br /> <br /> <ol> <li>콘솔 프로그램: 사용자 main 함수</li> <li>콘솔 프로그램: mainCRTStartup 또는 wmainCRTStartup</li> </ol> <br /> 우선, windbg로 첫 번째 유형의 EXE 프로그램을 "Open Executable (Ctrl + E)" 메뉴로 로드해 보면 다음과 같이 나옵니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Microsoft (R) Windows Debugger Version 10.0.17763.132 X86 Copyright (c) Microsoft Corporation. All rights reserved. CommandLine: c:\temp\ConsoleApplication1\Debug\exe_entry.exe ************* Path validation summary ************** Response Time (ms) Location Deferred SRV*e:\Symbols*http://msdl.microsoft.com/download/symbols Symbol search path is: SRV*e:\Symbols*http://msdl.microsoft.com/download/symbols Executable search path is: ModLoad: 00840000 00859000 exe_entry.exe ModLoad: 77560000 776fc000 ntdll.dll ModLoad: 74c50000 74d30000 C:\WINDOWS\SysWOW64\KERNEL32.DLL ModLoad: 759b0000 75baa000 C:\WINDOWS\SysWOW64\KERNELBASE.dll (4f5c.730): Break instruction exception - code 80000003 (first chance) eax=00000000 ebx=002ef000 ecx=cf060000 edx=00000000 esi=00432ea0 edi=775737ec eip=7760f126 esp=001df5b8 ebp=001df5e4 iopl=0 nv up ei pl zr na pe nc cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246 ntdll!LdrpDoDebuggerBreak+0x2b: 7760f126 cc int 3 </pre> <br /> 그러니까, 운영체제의 ntdll Loader 단계부터 디버깅이 시작되는데 EntryPoint는 이후 한참(?) 후에 나오게 됩니다. 그 시점까지 진행하는 방법은 AddressOfEntryPoint를 이용해 BP를 걸면 됩니다.<br /> <br /> 이를 위해 PE 헤더를 분석해주는 도구로 AddressOfEntryPoint의 값을 구하고, 현재 EXE 모듈이 로드된 주소를 찾아서 더하면 됩니다. 모듈의 로딩 주소는 windbg의 lm 명령어로 구할 수 있으므로,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 0:000> <span style='color: blue; font-weight: bold'>lm</span> start end module name <span style='color: blue; font-weight: bold'>00840000</span> 00859000 <span style='color: blue; font-weight: bold'>exe_entry</span> (deferred) 74c50000 74d30000 KERNEL32 (deferred) 759b0000 75baa000 KERNELBASE (deferred) 77560000 776fc000 ntdll (pdb symbols) e:\symbols\wntdll.pdb\06265607D3AAB293F80811D978F5F5B31\wntdll.pdb </pre> <br /> AddressOfEntryPoint의 값이 110f라고 구해졌다면 다음과 같이 EntryPoint 주소를 구할 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 0:000> <span style='color: blue; font-weight: bold'>? 00840000 + 1100f</span> Evaluate expression: 8720399 = <span style='color: blue; font-weight: bold'>0085100f</span> </pre> <br /> 따라서 이 주소에 BP를 걸고,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 0:000> <span style='color: blue; font-weight: bold'>bp 0085100f</span> *** WARNING: Unable to verify checksum for exe_entry.exe 0:000> <span style='color: blue; font-weight: bold'>bl</span> 0 e Disable Clear 0085100f 0001 (0001) 0:**** exe_entry!ILT+10(_main) </pre> <br /> g 키를 눌러 실행을 계속하면 우리가 원하던 EntryPoint에서 실행이 멈추는 것을 확인할 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 0:000> <span style='color: blue; font-weight: bold'>g</span> Breakpoint 0 hit eax=001dfb60 ebx=002ef000 ecx=0085100f edx=0085100f esi=0085100f edi=0085100f eip=0085100f esp=001dfb08 ebp=001dfb14 iopl=0 nv up ei pl zr na pe nc cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246 exe_entry!ILT+10(_main): <span style='color: blue; font-weight: bold'>0085100f e93c000000 jmp exe_entry!main (00851050)</span> </pre> <br /> (Windows 10의 경우) 이 시점에서 콜 스택은 다음과 같습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > exe_entry!ILT+10(_main) ntdll!__RtlUserThreadStart+0x2f ntdll!_RtlUserThreadStart+0x1b </pre> <br /> 결국 EntryPoint의 호출은 ntdll!__RtlUserThreadStart에서,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > ntdll!__RtlUserThreadStart: 775c65fe 6a30 push 30h 775c6600 6840926677 push offset ntdll!QueryRegistryValue+0x10da (77669240) 775c6605 e84add0100 call ntdll!_SEH_prolog4 (775e4354) 775c660a 8bf9 mov edi,ecx 775c660c 8365fc00 and dword ptr [ebp-4],0 775c6610 8b351c096877 mov esi,dword ptr [ntdll!Kernel32ThreadInitThunkFunction (7768091c)] 775c6616 52 push edx 775c6617 85f6 test esi,esi 775c6619 0f844ac90300 je ntdll!__RtlUserThreadStart+0x3c96b (77602f69) 775c661f 8bce mov ecx,esi 775c6621 ff15e0416877 call dword ptr [ntdll!__guard_check_icall_fptr (776841e0)] 775c6627 8bd7 mov edx,edi 775c6629 33c9 xor ecx,ecx <span style='color: blue; font-weight: bold'>775c662b ffd6 call esi</span> </pre> <br /> 위의 call esi로 인해 발생하며 이때의 esi 값이 바로 0085100f입니다.<br /> <br /> <hr style='width: 50%' /><br /> <br /> 위의 경우에는 사용자가 작성한 main 함수를 EntryPoint로 지정한 EXE였기 때문에 마지막 call stack에 exe_entry!main이 나왔습니다. CRT가 연결된 EXE라면 EntryPoint의 주소는 mainCRTStartup 또는 wmainCRTStartup이 됩니다.<br /> <br /> 확인 방법 역시 위에서 설명한 것과 동일하지만 이번에는 다른 방법으로 접근해 보겠습니다. ^^<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > How to get to entry point with windbg ; <a target='tab' href='https://stackoverflow.com/questions/13387691/how-to-get-to-entry-point-with-windbg'>https://stackoverflow.com/questions/13387691/how-to-get-to-entry-point-with-windbg</a> </pre> <br /> 그렇습니다. windbg가 제공하는 가상 레지스터인 $exentry 값을 사용하면 되는 것입니다. 따라서 lm 명령이나 AddressOfEntryPoint 값을 알아낼 필요도 없이 곧바로 BP를 걸 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 0:000> <span style='color: blue; font-weight: bold'>bp $exentry</span> *** WARNING: Unable to verify checksum for exe_dll_entry.exe 0:000> <span style='color: blue; font-weight: bold'>bl</span> 0 e Disable Clear 002313c0 0001 (0001) 0:**** exe_dll_entry!ILT+955(_mainCRTStartup) 0:000> <span style='color: blue; font-weight: bold'>g</span> Breakpoint 0 hit eax=006ffa8c ebx=00434000 ecx=002313c0 edx=002313c0 esi=002313c0 edi=002313c0 eip=002313c0 esp=006ffa34 ebp=006ffa40 iopl=0 nv up ei pl zr na pe nc cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246 exe_dll_entry!ILT+955(_mainCRTStartup): <span style='color: blue; font-weight: bold'>002313c0 e92b1b0000 jmp exe_dll_entry!mainCRTStartup (00232ef0)</span> </pre> <br /> 보는 바와 같이 진입 지점의 함수가 "exe_dll_entry!mainCRTStartup"라고 나옵니다.<br /> <br /> <hr style='width: 50%' /><br /> <br /> 지난 글에서, EXE 모듈을 윈도우 운영체제로 하여금 DLL로써 다루도록 Characteristics에 IMAGE_FILE_DLL 속성을 부여할 수 있다고 했는데요. 재미있게도, windbg의 경우 IMAGE_FILE_DLL 속성이 부여된 EXE를 로드하는 경우 다음과 같은 오류를 발생시키며 디버깅 진입에 실패합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Could not create process 'c:\temp\ConsoleApplication1\Debug\exe_dll_entry.exe', Win32 error 0n193 %1 is not a valid Win32 application. </pre> <br /> 따라서 windbg로 로드하려면 다시 IMAGE_FILE_DLL을 제거해야만 합니다.<br /> </p><br /> <br /><hr /><span style='color: Maroon'>[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
3402
(왼쪽의 숫자를 입력해야 합니다.)