33

如果我有一个foo()windows在kernel32.dll中实现的函数并且它总是返回true,我可以让我的程序:“bar.exe”挂钩/绕行那个windows函数并让它为所有进程返回false吗?

因此,例如,如果我的 svchost 调用foo(),它将返回 false 而不是 true。当前运行的所有其他进程都应该执行相同的操作。

如果是这样,怎么做?我想我正在寻找一个系统范围的钩子或其他东西。

4

5 回答 5

39

看看Detours,它非常适合这类东西。


对于系统范围的挂钩,请阅读MSDN 中的这篇文章


首先,创建一个处理挂钩函数的 DLL。下面的这个例子挂钩了套接字发送和接收函数。

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

#pragma comment( lib, "Ws2_32.lib" )
#pragma comment( lib, "detours.lib" )
#pragma comment( lib, "detoured.lib" )

int ( WINAPI *Real_Send )( SOCKET s, const char *buf, int len, int flags ) = send;
int ( WINAPI *Real_Recv )( SOCKET s, char *buf, int len, int flags ) = recv;  
int WINAPI Mine_Send( SOCKET s, const char* buf, int len, int flags );
int WINAPI Mine_Recv( SOCKET s, char *buf, int len, int flags );

int WINAPI Mine_Send( SOCKET s, const char *buf, int len, int flags ) {
    // .. do stuff ..

    return Real_Send( s, buf, len, flags );
}

int WINAPI Mine_Recv( SOCKET s, char *buf, int len, int flags ) {
    // .. do stuff ..

    return Real_Recv( s, buf, len, flags );
}

BOOL WINAPI DllMain( HINSTANCE, DWORD dwReason, LPVOID ) {
    switch ( dwReason ) {
        case DLL_PROCESS_ATTACH:       
            DetourTransactionBegin();
            DetourUpdateThread( GetCurrentThread() );
            DetourAttach( &(PVOID &)Real_Send, Mine_Send );
            DetourAttach( &(PVOID &)Real_Recv, Mine_Recv );
            DetourTransactionCommit();
            break;

        case DLL_PROCESS_DETACH:
            DetourTransactionBegin();
            DetourUpdateThread( GetCurrentThread() );
            DetourDetach( &(PVOID &)Real_Send, Mine_Send );
            DetourDetach( &(PVOID &)Real_Recv, Mine_Recv );
            DetourTransactionCommit(); 
        break;
    }

    return TRUE;
}

然后,创建一个程序以将 DLL 注入目标应用程序。

#include <cstdio>
#include <windows.h>
#include <tlhelp32.h>

void EnableDebugPriv() {
    HANDLE hToken;
    LUID luid;
    TOKEN_PRIVILEGES tkp;

    OpenProcessToken( GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken );

    LookupPrivilegeValue( NULL, SE_DEBUG_NAME, &luid );

    tkp.PrivilegeCount = 1;
    tkp.Privileges[0].Luid = luid;
    tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

    AdjustTokenPrivileges( hToken, false, &tkp, sizeof( tkp ), NULL, NULL );

    CloseHandle( hToken ); 
}

int main( int, char *[] ) {
    PROCESSENTRY32 entry;
    entry.dwSize = sizeof( PROCESSENTRY32 );

    HANDLE snapshot = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, NULL );

    if ( Process32First( snapshot, &entry ) == TRUE ) {
        while ( Process32Next( snapshot, &entry ) == TRUE ) {
            if ( stricmp( entry.szExeFile, "target.exe" ) == 0 ) {
                EnableDebugPriv();

                char dirPath[MAX_PATH];
                char fullPath[MAX_PATH];

                GetCurrentDirectory( MAX_PATH, dirPath );

                sprintf_s( fullPath, MAX_PATH, "%s\\DllToInject.dll", dirPath );

                HANDLE hProcess = OpenProcess( PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_WRITE, FALSE, entry.th32ProcessID );
                LPVOID libAddr = (LPVOID)GetProcAddress( GetModuleHandle( "kernel32.dll" ), "LoadLibraryA" );
                LPVOID llParam = (LPVOID)VirtualAllocEx( hProcess, NULL, strlen( fullPath ), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE );

                WriteProcessMemory( hProcess, llParam, fullPath, strlen( fullPath ), NULL );
                CreateRemoteThread( hProcess, NULL, NULL, (LPTHREAD_START_ROUTINE)libAddr, llParam, NULL, NULL );
                CloseHandle( hProcess );
            }
        }
    }

    CloseHandle( snapshot );

    return 0;
}

这应该足以让你开始!

于 2009-05-17T00:59:24.113 回答
13

EASYHOOK http://www.codeplex.com/easyhook

Dominate 在简单性、灵活性和功能性方面的所有上述技术。

之前也没有讨论过Hook 进程。我已经阅读了该线程的所有内容,并且绝对确定,EASYHOOK非常优越。无论您使用的是 C、C++、CLR 等。

我将从 codeplex 主页粘贴一些内容,以确保支付足够的费用。

以下是不完整的功能列表:

  1. 一个所谓的“线程死锁屏障”将在 hook 未知 API 时摆脱许多核心问题;该技术是 EasyHook 独有的
  2. 您可以为非托管 API 编写托管钩子处理程序
  3. 您可以使用所有便利的托管代码,例如 NET Remoting、WPF 和 WCF
  4. 一个文档化的、纯非托管的挂钩 API
  5. 支持 32 位和 64 位内核模式挂钩(还可以查看我的 PatchGuard 3 旁路驱动程序,它可以在发布列表中找到)
  6. 目标中没有资源或内存泄漏
  7. 不会引起任何当前 AV 软件关注的实验性隐形注入机制
  8. EasyHook32.dll 和 EasyHook64.dll 是纯非托管模块,无需安装任何 NET 框架即可使用!
  9. 所有挂钩均以稳定的方式安装和自动移除
  10. 通过利用完全未记录的 API 支持 Windows Vista SP1 x64 和 Windows Server 2008 SP1 x64,仍然允许连接到任何终端会话。
  11. 挂钩处理程序内的托管/非托管模块堆栈跟踪
  12. 在钩子处理程序中调用托管/非托管模块
  13. 在钩子处理程序中创建自定义堆栈跟踪
  14. 您将能够编写为 AnyCPU 编译的注入库和宿主进程,这将允许您在所有情况下都使用相同的程序集将代码从 64 位和 32 位进程注入到 32 位和 64 位进程中。
  15. EasyHook 支持 64 位目标的 RIP 相对寻址重定位。
  16. 无需拆包/安装。
  17. 不需要 Visual Studio Redistributable。

我很高兴我的妓女仍然知道一些让我保留他们的技巧。但可以肯定的是,当您需要一个 HOOK 时,100 次的 99 次,EASYHOOK'r 会让您更快地到达那里。它得到了非常积极的维护。

于 2009-05-17T01:21:15.810 回答
8

请详细说明您要挂钩的功能!在这种情况下,有几种方法可以调用您自己的代码,例如:

  • 您可以构建一个与包含要挂钩的函数的 DLL 同名的假 DLL(并将其复制到 的文件夹中foo.exe)。该库将公开与原始 DLL 完全相同的功能。每个公开的函数只是绕过对原始 DLL 的调用,但要挂钩的函数除外。

  • 您可以在运行时更改函数指针表,例如使用“厨房”提到的(商业)Detour 包。但是,您可以自己轻松完成此类挂钩,请参阅本文了解如何操作。

  • 您可以找出调用特定函数的位置foo.exe,只需将调用该函数的汇编代码替换为“返回true”的代码即可。基本上,您正在修补“ foo.exe”..

  • 对于特定功能,Windows 提供自动挂钩,例如键和鼠标事件。为此检查函数SetWindowsHook

于 2009-05-17T01:08:40.580 回答
3

这在一定程度上取决于您要定位的 Windows 版本。尽管如此,如果您在 Pre-Vista 上玩,您可以简单地使用 SetWindowsHookEx 将您的 DLL 注入到每个正在运行的进程中。然后,您的 DLL 将需要使用 Detours 或类似方法来挂钩相应的函数。

于 2009-07-16T13:05:47.253 回答
-2

如果您在汇编中编写钩子而不使用 Detours(无论出于何种原因),那么您需要一些有关返回 FALSE 的关键信息:

  • Win32,将 EAX 设置为 0
  • Win64,将 RAX 设置为 0

您需要将 EAX 或 RAX(取决于平台)设置为零,作为您要挂钩的功能的最后一件事。这将导致调用代码接收 0 作为返回值(假设它们返回一个 int 或指针类型值)。

于 2010-04-07T09:26:08.833 回答