Microsoft MVP성태의 닷넷 이야기
VC++: 36. Detours 라이브러리를 이용한 Win32 API - Sleep 호출 가로채기 [링크 복사], [링크+제목 복사],
조회: 42111
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일
 

(시리즈 글이 17개 있습니다.)
VC++: 36. Detours 라이브러리를 이용한 Win32 API - Sleep 호출 가로채기
; https://www.sysnet.pe.kr/2/0/631

.NET Framework: 187. 실행 시에 메서드 가로채기 - CLR Injection: Runtime Method Replacer 개선
; https://www.sysnet.pe.kr/2/0/942

디버깅 기술: 40. 상황별 GetFunctionPointer 반환값 정리 - x86
; https://www.sysnet.pe.kr/2/0/1027

VC++: 56. Win32 API 후킹 - Trampoline API Hooking
; https://www.sysnet.pe.kr/2/0/1231

VC++: 57. 웹 브라우저에서 Flash만 빼고 다른 ActiveX를 차단할 수 있을까?
; https://www.sysnet.pe.kr/2/0/1232

VC++: 58. API Hooking - 64비트를 고려해야 한다면? EasyHook!
; https://www.sysnet.pe.kr/2/0/1242

개발 환경 구성: 419. MIT 라이선스로 무료 공개된 Detours API 후킹 라이브러리
; https://www.sysnet.pe.kr/2/0/11764

.NET Framework: 883. C#으로 구현하는 Win32 API 후킹(예: Sleep 호출 가로채기)
; https://www.sysnet.pe.kr/2/0/12132

.NET Framework: 890. 상황별 GetFunctionPointer 반환값 정리 - x64
; https://www.sysnet.pe.kr/2/0/12143

.NET Framework: 891. 실행 시에 메서드 가로채기 - CLR Injection: Runtime Method Replacer 개선 - 두 번째 이야기
; https://www.sysnet.pe.kr/2/0/12144

디버깅 기술: 163. x64 환경에서 구현하는 다양한 Trampoline 기법
; https://www.sysnet.pe.kr/2/0/12148

.NET Framework: 895. C# - Win32 API를 Trampoline 기법을 이용해 C# 메서드로 가로채는 방법
; https://www.sysnet.pe.kr/2/0/12150

.NET Framework: 896. C# - Win32 API를 Trampoline 기법을 이용해 C# 메서드로 가로채는 방법 - 두 번째 이야기 (원본 함수 호출)
; https://www.sysnet.pe.kr/2/0/12151

.NET Framework: 897. 실행 시에 메서드 가로채기 - CLR Injection: Runtime Method Replacer 개선 - 세 번째 이야기(Trampoline 후킹)
; https://www.sysnet.pe.kr/2/0/12152

.NET Framework: 898. Trampoline을 이용한 후킹의 한계
; https://www.sysnet.pe.kr/2/0/12153

.NET Framework: 900. 실행 시에 메서드 가로채기 - CLR Injection: Runtime Method Replacer 개선 - 네 번째 이야기(Monitor.Enter 후킹)
; https://www.sysnet.pe.kr/2/0/12165

.NET Framework: 968. C# 9.0의 Function pointer를 이용한 함수 주소 구하는 방법
; https://www.sysnet.pe.kr/2/0/12409





Detours 라이브러리를 이용한 Win32 API - Sleep 호출 가로채기


엄밀히, 가로채기 자체는 이미 Detours 라이브러리에서 모두 해주기 때문에 이 글의 제목은 오히려 "Detours 소개"라고 하는 것이 더 낫겠습니다. 그럼, 한 단계씩 살펴볼까요? ^^

우선, 다운로드를 받으셔야 합니다. ^^ 다음의 경로에서.

Microsoft Research Detours Package - DetoursExpress.msi (ver 2.1)
; http://research.microsoft.com/research/downloads/Details/d36340fb-4d3c-4ddd-bf5b-1db25d03713d/Details.aspx
; https://github.com/microsoft/detours

보시는 것처럼, "Microsoft Research"의 어느 팀에서 만든 것으로 보입니다. 오호... 누구보다도 마이크로소프트가 만들었기에 더욱 그 안정성을 믿을 수 있을 것 같습니다.

아쉬운 점이라면, "Express" 버전은 현실적으로 테스트 목적으로만 사용할 수 있을 뿐 상업용으로 사용할 수 있는 라이선스가 아닙니다. 즉, 만약 이를 바탕으로 제품을 개발했다면 "Professional" 버전을 구매하셔야 합니다. (자세한 사항은 "Detours"에 방문하셔서 "Licensing" 탭에서 조회할 수 있습니다. 미리 말씀드리면... 개인이 구매하기에는 마이 비쌉니다. ^^;)

다운로드 받았으면 설치를 하는데, 저 같은 경우에는 다음의 경로에 설치했습니다. (앞으로의 진행은 기본적으로 다음의 경로를 포함합니다.)

C:\Research\Detours Express 2.1

그리고, 위의 폴더에는 다음과 같은 항목들을 포함합니다.

[그림 1: Detours 내용]
how_to_use_detours_express_library_1.PNG

자! 보이시죠? Makefile!
고맙게도, Detours 소스 및 전체 samples를 한꺼번에 빌드할 수 있는 Makefile을 제공해 주고 있습니다. 빌드를 위해 도스 명령창을 띄우고 다음과 같이 입력하시면 자동으로 Makefile이 빌드됩니다.

C:\Research\Detours Express 2.1>nmake

그럼, 폴더가 다음과 같이 생성됩니다.

[그림 2: Makefile 빌드 후]
how_to_use_detours_express_library_2.PNG

\bin\
    detoured.dll
    detoured.pdb
    ...[Samples 빌드 파일]...
    
\include\
    detours.h
    
\lib\
    detoured.exp
    detoured.lib
    detours.lib




끝났습니다. ^^ 이제 간단한 샘플을 하나 골라서 제대로 되는 지 확인을 해볼까요? "간단한" 걸로다가 "/samples/simple"을 예로 들어보겠습니다. 폴더에는 다음과 같은 파일들이 있습니다.

\samples\simple\
    Makefile
    simple.cpp
    sleep5.cpp

특이하게도, simple.cpp 하나가 곧 Win32 DLL로 빌드되는 파일이고, sleep5.cpp는 "Simple.dll"을 사용(!)하는 Console 응용 프로그램입니다.

소스를 잠깐 살펴볼까요?

simple.cpp는 다음과 같이 간단하고,

#include <stdio.h>
#include <windows.h>
#include "detours.h"

static LONG dwSlept = 0;
static VOID (WINAPI * TrueSleep)(DWORD dwMilliseconds) = Sleep;

VOID WINAPI TimedSleep(DWORD dwMilliseconds)
{
    DWORD dwBeg = GetTickCount();
    TrueSleep(dwMilliseconds);
    DWORD dwEnd = GetTickCount();

    InterlockedExchangeAdd(&dwSlept, dwEnd - dwBeg);
}

BOOL WINAPI DllMain(HINSTANCE hinst, DWORD dwReason, LPVOID reserved)
{
    LONG error;
    (void)hinst;
    (void)reserved;

    if (dwReason == DLL_PROCESS_ATTACH) 
    {
    ...[중간 생략]...
        if (error == NO_ERROR) {
            printf("simple.dll: Detoured Sleep().\n");
        }
        else {
            printf("simple.dll: Error detouring Sleep(): %d\n", error);
        }    
    }
    else if (dwReason == DLL_PROCESS_DETACH) 
    {
    ...[중간 생략]...
        printf("simple.dll: Removed Sleep() (result=%d), slept %d ticks.\n",
               error, dwSlept);
        fflush(stdout);
    }
    return TRUE;
}

sleep5.cpp는 소스를 굳이 생략하지 않아도 될 만큼 다음과 같이 매우 간단합니다.

#include <windows.h>
#include <stdio.h>

int __cdecl main(int argc, char ** argv)
{
    if (argc == 2) {
        Sleep(atoi(argv[1]) * 1000);
    }
    else {
        printf("sleep5.exe: Starting.\n");

        Sleep(5000);

        printf("sleep5.exe: Done sleeping.\n");
    }
    return 0;
}

물론, 빌드된 결과물은 좀전에 했던 "nmake"로 인해 "bin" 폴더에 있기 때문에 실행을 해보면 다음과 같이 나옵니다.

D:\workshop\XPaperBin\Research\Detours Express 2.1\bin>sleep5.exe
sleep5.exe: Starting.
sleep5.exe: Done sleeping.

잉! 바뀐 것이 없넹. ^^; detour가 제대로 동작하지 않았습니다. 여기서, detour의 단점(?)이 하나 발견됩니다. 즉, detour는 실행시간에 IAT(Import Address Table)을 바꾸는 기능은 포함하지 않습니다. 그보다, 미리 바꿔놓아야 하는 쪽을 선택했습니다. 그래서, 역시 samples 폴더 중에 하나로 포함되어 있는 setdll 예제를 빌드하면 생성되는 "setdll.exe"를 이용해서 대상 EXE 파일의 IAT 및 그 EXE가 참조하고 있는 DLL들의 IAT 내용을 미리 바꿔 놓아야 합니다. 다음은 그러한 과정을 포함한 sleep5.exe 실행 화면입니다.

C:\workshop\Research\Detours Express 2.1\bin>setdll
Usage:
    setdll [options] binary_files
Options:
    /d:file.dll  : Add file.dll binary files
    /r           : Remove extra DLLs from binary files
    /?           : This help screen.

C:\workshop\Research\Detours Express 2.1\bin>setdll /d:simple.dll sleep5.exe
Adding simple.dll to binary files.
  sleep5.exe:
    simple.dll
    KERNEL32.dll -> KERNEL32.dll

C:\workshop\Research\Detours Express 2.1\bin>sleep5.exe
simple.dll: Starting.
simple.dll: Detoured Sleep().
sleep5.exe: Starting.
sleep5.exe: Done sleeping.
simple.dll: Removed Sleep() (result=0), slept 5008 ticks.

C:\workshop\Research\Detours Express 2.1\bin>

이것으로 설명은 끝이군요. 정리해 보면, 여러분들이 Detours를 이용해 개발을 하기로 정했다면, API 가로채기를 정의할 DLL을 하나 만들고, 모든 제품 빌드 후에는 대상 EXE에 setdll.exe를 이용하여 IAT 변경을 해줘야 합니다.




마지막으로 Detours 라이브러리 관련해서 몇가지 특이사항들을 정리해 보았습니다.

- 대상 응용 프로그램이 "Windows File Protection"에 의해서 보호 받는 것이라면 IAT가 변경된 대상 모듈들은 운영체제에 의해서 다시 복원이 되어집니다. 즉, 일반적인 상황이라면 그런 모듈들에 대해서는 Detours는 무용지물입니다.

- IAT 변경으로 인해 해당 파일이 변경되기 때문에 "코드 인증"이 깨집니다. 이것 역시 어쩔 수 없는 문제입니다.

- detours 라이브러리 자체는 static library이지만, 하는 일 없이 marker 용도로 사용되는 detoured.dll이 요구됩니다. 이것을 지우는 방법은 소스 코드를 수정하면 되는 데 이에 대해서는 다음의 글을 참고하세요.

Detours에서 Detoured.dll 제거하기
; http://www.securityproof.net/zboard/bbs/view.php?id=rv&page=1&sn1=&divpage=1&sn=off&ss=on&sc=on&select_arrange=headnum&desc=asc&no=4

- 현재 (2008년 12월 10) 2.1 버전의 makefile은 VS.NET 2008과 함께 설치되는 VC++ 빌드에서는 다음과 같은 오류가 발생합니다.

       cl /nologo /Zi /MT /Gm- /W4 /WX /O1 "/I..\..\include" "/I..\include" /Gs
 /DDETOURS_X86=1 /D_X86_ /Fe..\..\bin\symtest.exe /Fd..\..\bin\symtest.pdb symte
st.cpp  /link /release /machine:x86 "..\lib\syelog.lib" "..\..\lib\detours.lib"
"..\..\lib\detoured.lib"  kernel32.lib gdi32.lib user32.lib shell32.lib  /subsys
tem:console /incremental:no /fixed:no ..\..\bin\target.lib
symtest.cpp
symtest.cpp(270) : error C2664: 'BOOL (HANDLE,PSYM_ENUMMODULES_CALLBACK64,PVOID)
' : cannot convert parameter 2 from 'overloaded-function' to 'PSYM_ENUMMODULES_CALLBACK64'
        None of the functions with this name in scope match the target type
NMAKE : fatal error U1077: '"C:\Program Files\Microsoft Visual Studio 9.0\VC\BIN\cl.EXE"' : return code '0x2'
Stop.
NMAKE : fatal error U1077: '"C:\Program Files\Microsoft Visual Studio 9.0\VC\BIN\nmake.exe"' : return code '0x2'
Stop.
NMAKE : fatal error U1077: '"C:\Program Files\Microsoft Visual Studio 9.0\VC\BIN\nmake.exe"' : return code '0x2'
Stop.

원인은 헤더 파일이 달라져서 그렇다고 합니다. 다음의 토픽에서 이를 위한 코드 수정 방법을 알려주고 있습니다. (저는 그냥 귀찮아서 ^^; Visual Studio 2005 명령어 창에서 빌드했습니다.)

Cannot make detours.lib....
; http://social.msdn.microsoft.com/Forums/en-US/vcgeneral/thread/fcb5a809-5404-481f-82c0-40ffa6f58c9b/




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







[최초 등록일: ]
[최종 수정일: 6/9/2021]

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

비밀번호

댓글 작성자
 



2008-12-15 11시04분
kevin25
2021-06-09 04시09분
정성태
2023-08-28 10시26분
Spartacus DLL Hijacking - Spartacus DLL Hijacking Discovery Tool
; https://github.com/Accenture/Spartacus
정성태

... 76  [77]  78  79  80  81  82  83  84  85  86  87  88  89  90  ...
NoWriterDateCnt.TitleFile(s)
12011정성태8/27/201926247사물인터넷: 57. C# - Rapsberry Pi Zero W와 PC 간 Bluetooth 통신 예제 코드파일 다운로드1
12010정성태8/27/201919191VS.NET IDE: 138. VSIX - DTE.ItemOperations.NewFile 메서드에서 템플릿 이름을 다국어로 설정하는 방법
12009정성태8/26/201920016.NET Framework: 858. C#/Windows - Clipboard(Ctrl+C, Ctrl+V)가 동작하지 않는다면?파일 다운로드1
12008정성태8/26/201919678.NET Framework: 857. UWP 앱에서 SQL Server 데이터베이스 연결 방법
12007정성태8/24/201918290.NET Framework: 856. .NET Framework 버전을 올렸을 때 오류가 발생할 수 있는 상황
12006정성태8/23/201921784디버깅 기술: 129. guidgen - Encountered an improper argument. 오류 해결 방법 (및 windbg 분석) [1]
12005정성태8/13/201919386.NET Framework: 855. 닷넷 (및 VM 계열 언어) 코드의 성능 측정 시 주의할 점 [2]파일 다운로드1
12004정성태8/12/201927640.NET Framework: 854. C# - 32feet.NET을 이용한 PC 간 Bluetooth 통신 예제 코드 [14]
12003정성태8/12/201919778오류 유형: 564. Visual C++ 컴파일 오류 - fatal error C1090: PDB API call failed, error code '3'
12002정성태8/12/201919140.NET Framework: 853. Excel Sheet를 WinForm에서 사용하는 방법 - 두 번째 이야기 [5]
12001정성태8/10/201924341.NET Framework: 852. WPF/WinForm에서 UWP의 기능을 이용해 Bluetooth 기기와 Pairing하는 방법 [1]
12000정성태8/9/201923748.NET Framework: 851. WinForm/WPF에서 Console 창을 띄워 출력하는 방법파일 다운로드1
11999정성태8/1/201918003오류 유형: 563. C# - .NET Core 2.0 이하의 Unix Domain Socket 사용 시 System.IndexOutOfRangeException 오류
11998정성태7/30/201920139오류 유형: 562. .NET Remoting에서 서비스 호출 시 SYN_SENT로 남는 현상파일 다운로드1
11997정성태7/30/201920411.NET Framework: 850. C# - Excel(을 비롯해 Office 제품군) COM 객체를 제어 후 Excel.exe 프로세스가 남아 있는 문제 [2]파일 다운로드1
11996정성태7/25/201923408.NET Framework: 849. C# - Socket의 TIME_WAIT 상태를 없애는 방법파일 다운로드1
11995정성태7/23/201927149.NET Framework: 848. C# - smtp.daum.net 서비스(Implicit SSL)를 이용해 메일 보내는 방법 [2]
11994정성태7/22/201921827개발 환경 구성: 454. Azure 가상 머신(VM)에서 SMTP 메일 전송하는 방법파일 다운로드1
11993정성태7/22/201916513오류 유형: 561. Dism.exe 수행 시 "Error: 2 - The system cannot find the file specified." 오류 발생
11992정성태7/22/201918627오류 유형: 560. 서비스 관리자 실행 시 "Windows was unable to open service control manager database on [...]. Error 5: Access is denied." 오류 발생
11991정성태7/18/201915683디버깅 기술: 128. windbg - x64 환경에서 닷넷 예외가 발생한 경우 인자를 확인할 수 없었던 사례
11990정성태7/18/201917935오류 유형: 559. Settings / Update & Security 화면 진입 시 프로그램 종료
11989정성태7/18/201916780Windows: 162. Windows Server 2019 빌드 17763부터 Alt + F4 입력시 곧바로 로그아웃하는 현상
11988정성태7/18/201919295개발 환경 구성: 453. 마이크로소프트가 지정한 모든 Root 인증서를 설치하는 방법
11987정성태7/17/201925218오류 유형: 558. 윈도우 - KMODE_EXCEPTION_NOT_HANDLED 블루스크린(BSOD) 문제 [1]
11986정성태7/17/201916959오류 유형: 557. 드라이브 문자를 할당하지 않은 파티션을 탐색기에서 드라이브 문자와 함께 보여주는 문제
... 76  [77]  78  79  80  81  82  83  84  85  86  87  88  89  90  ...