关于几种dll注入方式的学习

本文详细介绍了Windows系统中四种DLL注入技术:全局钩子注入、远程线程注入、突破session 0的远程线程注入和APC注入。每种注入方式的核心函数、实现原理和过程都进行了详细阐述,包括如何利用SetWindowsHookEx、CreateRemoteThread、ZwCreateThreadEx和QueueUserAPC等API实现DLL注入,并涉及到进程间通信、权限提升和会话隔离等概念。
摘要由CSDN通过智能技术生成

何为dll注入

DLL注入技术,一般来讲是向一个正在运行的进程插入/注入代码的过程。我们注入的代码以动态链接库(DLL)的形式存在。DLL文件在运行时将按需加载(类似于UNIX系统中的共享库(share object,扩展名为.so))。然而实际上,我们可以以其他的多种形式注入代码(正如恶意软件中所常见的,任意PE文件,shellcode代码/程序集等)。

全局钩子注入

在Windows大部分应用都是基于消息机制,他们都拥有一个消息过程函数,根据不同消息完成不同功能,windows通过钩子机制来截获和监视系统中的这些消息。一般钩子分局部钩子与全局钩子,局部钩子一般用于某个线程,而全局钩子一般通过dll文件实现相应的钩子函数。

核心函数

SetWindowsHookEx

HHOOK WINAPI SetWindowsHookEx (
__in int idHook ,  \钩子类型
__in HOOKPROC lpfn ,  \回调函数地址
__in HINSTANCE hMod ,  \实例句柄
__in DWORD dwThreadId );  \线程ID 

通过设定钩子类型与回调函数的地址,将定义的钩子函数安装到挂钩链中。如果函数成功返回钩子的句柄,如果函数失败,则返回NULL

实现原理

由上述介绍可以知道如果创建的是全局钩子,那么钩子函数必须在一个DLL中。这是因为进程的地址空间是独立的,发生对应事件的进程不能调用其他进程地址空间的钩子函数。如果钩子函数的实现代码在DLL中,则在对应事件发生时,系统会把这个DLL加较到发生事体的进程地址空间中,使它能够调用钩子函数进行处理。

在操作系统中安装全局钩子后,只要进程接收到可以发出钩子的消息,全局钩子的DLL文件就会由操作系统自动或强行地加载到该进程中。因此,设置全局钩子可以达到DLL注入的目的。创建一个全局钩子后,在对应事件发生的时候,系统就会把 DLL加载到发生事件的进程中,这样,便实现了DLL注入。

为了能够让DLL注入到所有的进程中,程序设置WH_GETMESSAGE消息的全局钩子。因为WH_GETMESSAGE类型的钩子会监视消息队列,并且 Windows系统是基于消息驱动的,所以所有进程都会有自己的一个消息队列,都会加载 WH_GETMESSAGE类型的全局钩子DLL。

那么设置WH_GETMESSAGE就可以通过以下代码实现,记得加上判断是否设置成功

 // 设置全局钩子

BOOL SetHook ()
{
    g_Hook = :: SetWindowsHookEx ( WH_GETMESSAGE , ( HOOKPROC ) GetMsgProc , g_hDllMoudle , 0 );

    if ( g_Hook == NULL )
    {
        return FALSE ;
    }

    return TRUE ;
} 

这里第二个参数是回调函数,那么我们还需要写一个回调函数的实现,这里就需要用到CallNextHookEx这个api,主要是第一个参数,这里传入钩子的句柄的话,就会把当前钩子传递给下一个钩子,若参数传入0则对钩子进行拦截

 // 钩子回调函数
LRESULT GetMsgProc ( int code ,  WPARAM wParam ,  LPARAM lParam ) {
    return :: CallNextHookEx ( g_Hook , code , wParam , lParam );
} 

既然我们写入了钩子,如果不使用的情况下就需要将钩子卸载掉,那么这里使用到UnhookWindowsHookEx这个api来卸载钩子

 // 卸载钩子
BOOL UnsetHook ()
{
    if ( g_Hook )
    {
        :: UnhookWindowsHookEx ( g_Hook );
    }
} 

既然我们使用到了SetWindowsHookEx这个api,就需要进行进程间的通信,进程通信的方法有很多,比如自定义消息、管道、dll共享节、共享内存等等,这里就用共享内存来实现进程通信

 // 共享内存
#pragma data_seg("mydata")
    HHOOK g_hHook = NULL ;
#pragma data_seg()
#pragma comment(linker, "/SECTION:mydata,RWS" 

实现过程

首先新建一个dll

pch.h头文件里面声明这几个我们定义的函数都是裸函数,由我们自己平衡堆栈

extern "C" _declspec ( dllexport ) int SetHook ();
extern "C" _declspec ( dllexport ) LRESULT GetMsgProc ( int code ,  WPARAM wParam ,  LPARAM lParam );
extern "C" _declspec ( dllexport ) BOOL UnsetHook (); 

然后在pch.cpp里面写入三个函数并创建共享内存

 // pch.cpp: 与预编译标头对应的源文件

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

extern HMODULE g_hDllModule ;

// 共享内存
#pragma data_seg("mydata")
HHOOK g_hHook = NULL ;
#pragma data_seg()
#pragma comment(linker, "/SECTION:mydata,RWS")

//钩子回调函数
LRESULT GetMsgProc ( int code ,  WPARAM wParam ,  LPARAM lParam )   {
    return :: CallNextHookEx ( g_hHook , code , wParam , lParam );
}

// 设置钩子
BOOL SetHook ()   {
    g_hHook = SetWindowsHookEx ( WH_GETMESSAGE , ( HOOKPROC ) GetMsgProc , g_hDllModule , 0 );
    if ( NULL == g_hHook ) {
        return FALSE ;
    }
    return TRUE ;
}

// 卸载钩子
BOOL UnsetHook ()   {
    if ( g_hHook ) {
        UnhookWindowsHookEx ( g_hHook );
    }
    return TRUE ;
} 

然后再在dllmain.cpp设置DLL_PROCESS_ATTACH,然后编译生成Golbal.dll

 // dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "pch.h"
HMODULE g_hDllModule = NULL ;

BOOL APIENTRY DllMain ( HMODULE hModule ,
                       DWORD  ul_reason_for_call ,
                       LPVOID lpReserved
                     )
{
    switch ( ul_reason_for_call )
    {
    case DLL_PROCESS_ATTACH : 
    {
        g_hDllModule = hModule ;
        break ;
    }
    case DLL_THREAD_ATTACH :
    case DLL_THREAD_DETACH :
    case DLL_PROCESS_DETACH :
        break ;
    }
    return TRUE ;
} 

再创建一个控制台项目

使用LoadLibrabryW加载dll,生成GolbalInjectDll.cpp文件

 // GolbalInjectDll.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include <Windows.h>

int main () 
 {
    typedef BOOL ( * typedef_SetGlobalHook )();
    typedef BOOL ( * typedef_UnsetGlobalHook )();
    HMODULE hDll = NULL ;
    typedef_SetGlobalHook SetGlobalHook = NULL ;
    typedef_UnsetGlobalHook UnsetGlobalHook = NULL ;
    BOOL bRet = FALSE ;

    do
    {
        hDll = :: LoadLibraryW ( TEXT ( "F:\C++\GolbalDll\Debug\GolbalDll.dll" ));
        if ( NULL == hDll )
        {
            printf ( "LoadLibrary Error[%d]\n" , :: GetLastError ());
            break ;
        }

        SetGlobalHook = ( typedef_SetGlobalHook ) :: GetProcAddress ( hDll , "SetHook" );
        if ( NULL == SetGlobalHook )
        {
            printf ( "GetProcAddress Error[%d]\n" , :: GetLastError ());
            break ;
        }

        bRet = SetGlobalHook ();
        if ( bRet )
        {
            printf ( "SetGlobalHook OK.\n" );
        }
        else
        {
            printf ( "SetGlobalHook ERROR.\n" );
        }

        system ( "pause" );

        UnsetGlobalHook = ( typedef_UnsetGlobalHook ) :: GetProcAddress ( hDll , "UnsetHook" );
        if ( NULL == UnsetGlobalHook )
        {
            printf ( "GetProcAddress Error[%d]\n" , :: GetLastError ());
            break ;
        }
        UnsetGlobalHook ();
        printf ( "UnsetGlobalHook OK.\n" );

    } while ( FALSE );

    system ( "pause" );
    return 0 ;
} 

执行即可注入GolbalDll.dll

远程线程注入

远程线程函数顾名思义,指一个进程在另一个进程中创建线程。

核心函数

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值