首页 > 系统相关 >使用detours进行windows api hook

使用detours进行windows api hook

时间:2022-12-28 21:12:15浏览次数:41  
标签:return windows dll hook api detours FALSE NULL TRUE

例子在这里:https://github.com/mschadev/detours-example

 

detours-example

API hooking example project using Microsoft Detours

Install

  1. Run git bash
git clone https://github.com/zxc010613/detours-example.git
cd detours-example
git submodule init
git submodule update
  1. Run `Developer Command Prompt for VS 2019(or 2017)
cd Detours
nmake
cd ..
devenv detours-example.sln /build  "release|x86"

 

Usage

  1. Run detours-example.exe
  2. Run dll-injector.exe(Run as administrator)

 

我们就重点讲解下其原理:

运行效果截图:

首先,运行detours-example.exe

 

 点击回车后,弹出对话框:

 

 

然后,管理员下:运行,dll-injector.exe,注意将test-dll.dll放在同一个目录。

可以看到弹出的对话框已经修改了!使用的就是api hook方式操作的!

 

 最后退出以后,又恢复正常了:

 

 

好了,我们看下代码逻辑:

首先是要注入的程序,很简单就是一个无线循环弹窗的代码:

// detours-example.cpp : 이 파일에는 'main' 함수가 포함됩니다. 거기서 프로그램 실행이 시작되고 종료됩니다.
//

#include <iostream>
#include <Windows.h>
int main()
{
    while (true) {
        MessageBox(GetFocus(), L"Hello world!", L"detours-example", MB_OK);
        std::cout << "Enter to show messagebox:";
        std::cin.get();
        system("cls");
    }
}

 

然后是注入的代码:基本上也没有什么依赖,就是使用test-dll.dll文件作为dll注入,注意里面有提权啊。

// dll-injector.cpp : 이 파일에는 'main' 함수가 포함됩니다. 거기서 프로그램 실행이 시작되고 종료됩니다.
//

#include <iostream>
#include "windows.h"
#include <TlHelp32.h>
#include <tchar.h>
BOOL SetPrivilege(LPCTSTR lpszPrivilege, BOOL bEnablePrivilege)
{
    TOKEN_PRIVILEGES tp;
    HANDLE hToken;
    LUID luid;

    // 현재 프로세스의 핸들을 가져와 관련된 액세스토큰을 가져옴.
    if (!OpenProcessToken(GetCurrentProcess(),
        TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
        &hToken))
    {
        printf("OpenProcessToken error: %u\n", GetLastError());
        return FALSE;
    }

    // 로컬 시스템에 대한 LUID를 가져옴.
    if (!LookupPrivilegeValue(NULL,          // lookup privilege on local system
        lpszPrivilege,   // privilege to lookup
        &luid))         // receives LUID of privilege
    {
        printf("LookupPrivilegeValue error: %u\n", GetLastError());
        return FALSE;
    }

    tp.PrivilegeCount = 1;
    tp.Privileges[0].Luid = luid;

    if (bEnablePrivilege)
        tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
    else
        tp.Privileges[0].Attributes = 0;

    // Enable the privilege or disable all privileges.
    if (!AdjustTokenPrivileges(hToken,  // 액세스 토큰 핸들
        FALSE,  // TURE일 경우 모든 권한 비활성화
        &tp,        // TOKEN_PRIBILEGES 구조체 포인터
        sizeof(TOKEN_PRIVILEGES),   // 다음에 오는 버퍼의 사이즈
        (PTOKEN_PRIVILEGES)NULL,    // 이전 상태 없어도 됨
        (PDWORD)NULL))
    {
        printf("AdjustTokenPrivileges error: %u\n", GetLastError());
        return FALSE;
    }

    if (GetLastError() == ERROR_NOT_ALL_ASSIGNED)
    {
        printf("The token does not have the specified privilege. \n");
        return FALSE;
    }

    return TRUE;
}
BOOL InjectDll(DWORD dwPID, LPCTSTR szDllPath)
{
    HANDLE                  hProcess, hThread;
    LPVOID                  pRemoteBuf;
    DWORD                   dwBufSize = (DWORD)(_tcslen(szDllPath) + 1) * sizeof(TCHAR);
    LPTHREAD_START_ROUTINE  pThreadProc;

    // 파라미터로 받은 프로세스의 핸들을 받아옴.
    if (!(hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID)))
    {
        printf("OpenProcess(%d) failed!!!\n", dwPID);
        return FALSE;
    }

    // 해당 프로세스의 가상메모리 공간을 할당 받음.
    // 대상 핸들, 할당할 메모리 번지 지정(NULL이면 시스템이 자동 지정), 할당할 메모리 양,
    // 할당 방법 지정, 할당한 페이지의 액세스 타입 지정
    // 할당한 메모리 번지 반환 / NULL 반환
    pRemoteBuf = VirtualAllocEx(hProcess, NULL, dwBufSize,
        MEM_COMMIT, PAGE_READWRITE);

    // 해당 프로세스 메모리를 조작.
    // 조작할 대상 프로세스 핸들, 조작할 가상메모리 주소, 메모리에 적을 값(인젝션 시킬 DLL 경로),
    // 메모리에 쓸 크기, 특정 프로세스의 바뀔 바이트를 받는 변수(NULL 사용 안함)
    WriteProcessMemory(hProcess, pRemoteBuf,
        (LPVOID)szDllPath, dwBufSize, NULL);

    pThreadProc = (LPTHREAD_START_ROUTINE)
        GetProcAddress(GetModuleHandle(L"kernel32.dll"),
            "LoadLibraryW");

    hThread = CreateRemoteThread(hProcess, NULL, 0,
        pThreadProc, pRemoteBuf, 0, NULL);
    WaitForSingleObject(hThread, INFINITE);

    VirtualFreeEx(hProcess, pRemoteBuf, 0, MEM_RELEASE);

    CloseHandle(hThread);
    CloseHandle(hProcess);

    return TRUE;
}

// 삽입했던 Dll 제거
// 삽입과 역순
BOOL EjectDll(DWORD dwPID, LPCTSTR szDllPath)
{
    BOOL                    bMore = FALSE, bFound = FALSE;
    HANDLE                  hSnapshot, hProcess, hThread;
    MODULEENTRY32           me = { sizeof(me) };
    LPTHREAD_START_ROUTINE  pThreadProc;

    if (INVALID_HANDLE_VALUE ==
        (hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwPID)))
        return FALSE;

    bMore = Module32First(hSnapshot, &me);
    for (; bMore; bMore = Module32Next(hSnapshot, &me))
    {
        if (!_tcsicmp(me.szModule, szDllPath) ||
            !_tcsicmp(me.szExePath, szDllPath))
        {
            bFound = TRUE;
            break;
        }
    }

    if (!bFound)
    {
        CloseHandle(hSnapshot);
        return FALSE;
    }

    if (!(hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID)))
    {
        printf("OpenProcess(%d) failed!!!\n", dwPID);
        CloseHandle(hSnapshot);
        return FALSE;
    }

    pThreadProc = (LPTHREAD_START_ROUTINE)
        GetProcAddress(GetModuleHandle(L"kernel32.dll"),
            "FreeLibrary");
    hThread = CreateRemoteThread(hProcess, NULL, 0,
        pThreadProc, me.modBaseAddr, 0, NULL);
    WaitForSingleObject(hThread, INFINITE);

    CloseHandle(hThread);
    CloseHandle(hProcess);
    CloseHandle(hSnapshot);

    return TRUE;
}
int main()
{

    SetPrivilege(SE_DEBUG_NAME, TRUE);
    PROCESSENTRY32 entry;
    entry.dwSize = sizeof(PROCESSENTRY32);

    HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);

    if (Process32First(snapshot, &entry) == TRUE)
    {
        while (Process32Next(snapshot, &entry) == TRUE)
        {
            if (wcscmp(entry.szExeFile, L"detours-example.exe") == 0)
            {

                InjectDll(entry.th32ProcessID, L"test-dll.dll");
                std::cout << "Enter to exit";
                std::cin.get();
                EjectDll(entry.th32ProcessID, L"test-dll.dll");
                break;
            }
        }
    }

    CloseHandle(snapshot);

    return 0;
}

其中main函数就是查询进程,然后注入dll,用户手动输入后可以解除注入。

    SetPrivilege(SE_DEBUG_NAME, TRUE);
    PROCESSENTRY32 entry;
    entry.dwSize = sizeof(PROCESSENTRY32);

    HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);

    if (Process32First(snapshot, &entry) == TRUE)
    {
        while (Process32Next(snapshot, &entry) == TRUE)
        {
            if (wcscmp(entry.szExeFile, L"detours-example.exe") == 0)
            {

                InjectDll(entry.th32ProcessID, L"test-dll.dll");
                std::cout << "Enter to exit";
                std::cin.get();
                EjectDll(entry.th32ProcessID, L"test-dll.dll");
                break;
            }
        }
    }

 

我们看下detour注入的部分,也就是test-dll的代码:

// dllmain.cpp : DLL 애플리케이션의 진입점을 정의합니다.
// #include "detours.h"

#include "pch.h"
#include "../Detours/include/detours.h"


static int (WINAPI* NativeMessageBox)(
    HWND    hWnd,
    LPCTSTR lpText,
    LPCTSTR lpCaption,
    UINT    uType
) = MessageBox;
int WINAPI MyMessageBox(
	HWND    hWnd,
	LPCTSTR lpText,
	LPCTSTR lpCaption,
	UINT    uType) {
	
	return NativeMessageBox(hWnd, L"Detours Hooking!", lpCaption, uType);
}
BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{

	if (DetourIsHelperProcess()) {
		return TRUE;
	}
	switch (ul_reason_for_call)
	{
	case DLL_PROCESS_ATTACH:

		DetourRestoreAfterWith();
		DetourTransactionBegin();
		DetourUpdateThread(GetCurrentThread());
		DetourAttach(&(PVOID&)NativeMessageBox, MyMessageBox);
		DetourTransactionCommit();
		break;
	case DLL_THREAD_ATTACH:
		break;
	case DLL_THREAD_DETACH:
		break;
	case DLL_PROCESS_DETACH:
		
		DetourTransactionBegin();
		DetourUpdateThread(GetCurrentThread());
		DetourDetach(&(PVOID&)NativeMessageBox, MyMessageBox);
		DetourTransactionCommit();
		break;
	}
	return TRUE;
}

 其核心是将NativeMessageBox 修改为自己的标题,看起来也没啥复杂的!

从这个例子看,使用detour进行注入还是比较干净整洁的!

todo:我自己注入一个ssl socket的试试。

 

标签:return,windows,dll,hook,api,detours,FALSE,NULL,TRUE
From: https://www.cnblogs.com/bonelee/p/17011282.html

相关文章

  • API对象--Deployment(chrono《kubernetes入门实战课》笔记整理)
    【概念介绍】“Deployment”,顾名思义,它是专门用来部署应用程序的,能够让应用永不宕机,多用来发布无状态的应用,是Kubernetes里最常用也是最有用的一个对象。之前学习过的两......
  • windows 禁止ping 和 允许 ping
    以管理员身份启动cmd.exe:启用ping:netshadvfirewallfirewalladdrulename="ICMPAllowincomingV4echorequest"protocol=icmpv4:8,anydir=inaction=allow禁......
  • Windows批处理文件创建文本文档/doc文档
    桌面右键单击新建文本文档修改文件后缀名为.bat如下右键编辑输入如下内容@echoofffor/L%%xin(1,1,25)do@echo%%x>%%x.txtechooff:表示在批处理文件执行过程......
  • 使用DataSecurity Plus监控Windows文件完整性
    使用我们的文件完整性监控软件DataSecurityPlus,与精明的黑客,突发的恶意软件爆发以及挑战法规要求进行战斗。这种先进的工具还有助于生成可操作的报表,提供基于严重性的告警,......
  • windows上clion+minGW+cmake配置G-Nut/Anubis
    注:这里只讲Anubis的配置,windows上clion、minGW和cmake的安装请参考别的博客! 源码下载地址:https://gnutsoftware.com/software/anubis下滑鼠标,找到下载区,点击”Getfree......
  • windows PHPStudy Apach…
    在设置Apache+SSL之前,需要做:安装Apache,下载安装Apache时请下载带有ssl版本的Apache安装程序.并且ssl需要的文件在如下的位置: 创建SSL证书(注意,我下载的是PHP......
  • IsapiCache组件 - 自动为网站生成…
    sapiCache是一款自动为网站生成静态页面的IIS组件(ISAPI筛选器),静态页面可以有效的加快网站访问速度,大大减轻服务器负担。工作原理是组件把服务器返回给客户端的网页源码保存......
  • IntellIJ开发简单Minecraft插件(利用paper API)
    有的时候想实现服务器里的一些简单的功能,但是网上又找不到,这个时候可以尝试写一个出来。例如,在游戏里想要实现这样一个功能,玩家噶了之后在聊天栏处显示死亡坐标,这样可以方......
  • windows 怎么把软件添加到鼠标右键菜单中
    这里我以​​将SublimeText3软件添加到鼠标右键菜单​​为例1.进入到sublimetext3的安装目录下2.新建txt文件,将以下内容复制进去[Version]Signature="$WindowsNT$"[De......
  • 当云原生网关遇上图数据库,NebulaGraph 的 APISIX 最佳实践
    本文介绍了利用开源API网关APISIX加速NebulaGraph多个场景的落地最佳实践:负载均衡、暴露接口结构与TLSTermination。API网关介绍什么是API网关API网关是......