성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] Working with Rust Libraries from C#...
[정성태] Detecting blocking calls using asyn...
[정성태] 아쉽게도, 커뮤니티는 아니고 개인 블로그입니다. ^^
[정성태] 질문이 잘 이해가 안 됩니다. 우선, 해당 소스코드에서 ILis...
[양승조
] var대신 dinamic으로 선언해서 해결은 했습니다. 맞는 해...
[양승조
] 또 막혔습니다. ㅠㅠ var list = props[i].Ge...
[양승조
] 아. 감사합니다. 어제는 안됐던것 같은데....정신을 차려야겠네...
[정성태] "props[i].GetValue(props[i])" 코드에서 ...
[정성태] 저렇게 조각 코드 말고, 실제로 재현이 되는 예제 프로젝트를 압...
[정성태] Modules 창(Ctrl+Shift+U)을 띄워서, 해당 Op...
글쓰기
제목
이름
암호
전자우편
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'>Trampoline을 이용한 후킹의 한계</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;' > C# - Win32 API를 Trampoline 기법을 이용해 C# 메서드로 가로채는 방법 ; <a target='tab' href='https://www.sysnet.pe.kr/2/0/12150'>https://www.sysnet.pe.kr/2/0/12150</a> </pre> <br /> 코드를 구현하면서 Sleep이 아닌, SleepEx API를 예로 들었습니다. 왜냐하면, (x64 환경에서) Sleep의 경우는 함수의 Body 구현이 다음과 같이 SleepEx로의 실행만 변경하는 JMP 문으로 이뤄졌기 때문입니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > KERNELBASE!Sleep: 00007ffc`f22e6880 33d2 xor edx,edx // 기본적으로 bAlertable 인자를 false로 설정해, SleepEx를 호출 00007ffc`f22e6882 <span style='color: blue; font-weight: bold'>e909000000 jmp KERNELBASE!SleepEx (00007ffc`f22e6890)</span> 00007ffc`f22e6887 cc int 3 ...[16바이트 정렬까지 cc 반복]... </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;' > C# - Win32 API를 Trampoline 기법을 이용해 C# 메서드로 가로채는 방법 - 두 번째 이야기 (원본 함수 호출) ; <a target='tab' href='https://www.sysnet.pe.kr/2/0/12151'>https://www.sysnet.pe.kr/2/0/12151</a> </pre> <br /> 이미 설명했지만, 원본 메서드는 우회를 위한 메서드로 JMP 패치될 것이고,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > KERNELBASE!Sleep: 00007ffc`f22e6880 e90b17c98a jmp 00007ffc`7cf77f90 00007ffc`f22e6885 0000 add byte ptr [rax],al 00007ffc`f22e6887 cc int 3 00007ffc`f22e6888 cc int 3 </pre> <br /> 이로 인해 영향받는 원본 함수의 진입 코드를 나중에 호출하기 위해 (또한 이후의 원본 코드로 JMP할 코드와 함께) 별도의 메모리에 다음과 같은 식으로 적재해 둘 것입니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 00000000`006b0000 <span style='color: blue; font-weight: bold'>33d2 xor edx,edx</span> 00000000`006b0002 <span style='color: blue; font-weight: bold'>e909000000</span> <span style='color: blue; font-weight: bold'>jmp 00000000`006b0010</span> 00000000`006b0007 48b887682ef2fc7f0000 mov rax,offset KERNELBASE!Sleep+0x7 (00007ffc`f22e6887) 00000000`006b0011 ffe0 jmp rax 00000000`006b0013 0000 add byte ptr [rax],al 00000000`006b0015 0000 add byte ptr [rax],al 00000000`006b0017 0000 add byte ptr [rax],al </pre> <br /> 그런데, JMP (0xe9) 코드는 현재의 RIP 주소를 기준으로 점프할 변위를 4바이트로 가지고 있으므로, 이것이 "KERNELBASE!Sleep" 기준으로는 정확히 SleepEx의 위치를 가리키는 반면,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > KERNELBASE!Sleep: 00007ffc`f22e6880 33d2 xor edx,edx 00007ffc`f22e6882 <span style='color: blue; font-weight: bold'>e909000000 jmp KERNELBASE!SleepEx (00007ffc`f22e6890)</span> // ...[생략]... </pre> <br /> 새롭게 백업이 된 "00000000`006b0000" 주소를 기준으로는 "00000000`006b0010" 위치로 점프하기 때문에 대부분의 경우 AccessViolationException 예외가 떨어지게 됩니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Unhandled Exception: System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt. at ConsoleApp1.Program.Replaced_TestMethod(Int32 milliseconds) at ConsoleApp1.Program.Sleep(Int32 milliseconds) at ConsoleApp1.Program.Main(String[] _) </pre> <br /> <hr style='width: 50%' /><br /> <br /> 이 문제를 해결하려면, 당연히 백업이 될 원본 코드에 대해 변위값을 갖는 명령어가 있는 경우 그 값을 보정해야만 합니다. 예를 들어, Sleep의 경우에는,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 00000000`006b0000 33d2 xor edx,edx 00000000`006b0002 e9<span style='color: blue; font-weight: bold'>09000000</span> jmp 00000000`006b0010 00000000`006b0007 48b887682ef2fc7f0000 mov rax,offset KERNELBASE!Sleep+0x7 (00007ffc`f22e6887) 00000000`006b0011 ffe0 jmp rax </pre> <br /> 0xe9 다음의 4바이트 "rel32" 값을 현재 00000000`006b0007 주소를 기준으로 원래 호출하려고 했던 KERNELBASE!SleepEx의 주소인 00007ffc`f22e6890까지의 변위로 맞춰야 합니다. 그런데 여기서도 문제가 있습니다. 기존 함수에서는 "JMP rel32"로 처리할 수 있었지만 새롭게 할당받은 함수의 백업 주소에서는 "00007ffc`f22e6890" 주소까지 +/- 2GB의 한계를 넘기 때문에 "MOV/JMP" 코드로 변경해 줘야 합니다.<br /> <br /> Sleep의 경우 위와 같은 처리만 해주면 정상 동작시킬 수 있습니다. 하지만, 여전히 100% 동작시킬 수 있다고는 장담할 수 없습니다. 왜냐하면 JMP 구문은 이외에도 JZ, JNZ,... 등으로 다양한 코드가 있기 때문에 그것들도 모두 처리해야 합니다. 그래도 끝이 아닙니다. 가령 원본 함수에서 백업된 코드 영역으로, 즉 마이너스 변위를 갖는 JMP 코드가 있다면 그것 또한 정상적인 동작을 하지 않게 됩니다. 결론적으로 봤을 때 Trampoline 패치는 100% 안전을 보증할 수는 없는 것입니다. (그래도 많은 경우, "원본 함수"를 호출할 필요 없이 "가로채기"만 필요하다면 제약이 그나마 덜합니다.)<br /> <br /> 그런저런 이유로 인해, 가능하다면 trampoline보다는 더 안전한 Export/Import Address 테이블에 대한 패치라던지, IL 메서드의 경우 "<a target='tab' href='https://www.sysnet.pe.kr/2/0/12144'>실행 시에 메서드 가로채기 - CLR Injection: Runtime Method Replacer 개선 - 두 번째 이야기</a>" 글에서 다룬 NetMethodReplacer.ReplaceMethod 정도의 기능으로 해결하는 것이 권장할 수 있는 방법입니다.<br /> <br /> 결국 "<a target='tab' href='https://www.sysnet.pe.kr/2/0/12148'>x64 환경에서 구현하는 다양한 Trampoline 기법</a>" 글의 가장 마지막에 소개했던 덧글 내용으로 이야기가 돌아갑니다.<br /> <br /> <div style='BACKGROUND-COLOR: #ccffcc; padding: 10px 10px 5px 10px; MARGIN: 0px 10px 10px 10px; FONT-FAMILY: Malgun Gothic, Consolas, Verdana; COLOR: #005555'> <a target='tab' href='https://niemand.com.ar/2019/01/01/how-to-hook-directx-11-imgui/'>How to Hook DirectX 11 + ImGui (Vermintide 2) - Niemand - Cyber Security</a> says:<br /> January 5, 2019 at 12:03 pm<br /> <br /> […] <span style='color: blue; font-weight: bold'>you are not aware of what trampoline are</span>, I really recommend you to read this post. For the sake of simplicity, we are going to be using Detours to inject a jmp to our method […] </div><br /> </p><br /> <br /><hr /><span style='color: Maroon'>[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
1070
(왼쪽의 숫자를 입력해야 합니다.)