摘除XP系统LoadImageNotifyRoutine回调例程

本文深入解析了XP系统中如何通过调用PsSetLoadImageNotifyRoutine注册LoadImage回调例程,实现对进程或DLL加载的监控与响应。通过分析汇编代码与C代码,详细介绍了回调注册过程及其实现细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在XP系统下调用PsSetLoadImageNotifyRoutine注册LoadImage回调例程,就能够在每个进程或者DLL加载的时候注册的例程得到回调。

看看PsSetLoadImageNotifyRoutine的代码

kd> u PsSetLoadImageNotifyRoutine L22

nt!PsSetLoadImageNotifyRoutine:

805c718c 8bff            mov     edi,edi

805c718e 55              push    ebp

805c718f 8bec            mov     ebp,esp

805c7191 53              push    ebx

805c7192 57              push    edi

805c7193 33ff            xor     edi,edi

805c7195 57              push    edi

805c7196 ff7508          push    dword ptr [ebp+8]

805c7199 e87cd10300      call    nt!ExAllocateCallBack (8060431a)

805c719e 8bd8            mov     ebx,eax

805c71a0 3bdf            cmp     ebx,edi

805c71a2 7507            jne     nt!PsSetLoadImageNotifyRoutine+0x1f (805c71ab)

805c71a4 b89a0000c0      mov     eax,0C000009Ah

805c71a9 eb2a            jmp     nt!PsSetLoadImageNotifyRoutine+0x49 (805c71d5)

805c71ab56             push    esi

805c71acbe80b25580      mov     esi,offset nt!PspLoadImageNotifyRoutine(8055b280)

805c71b1 6a00            push    0

805c71b3 53              push    ebx

805c71b4 56              push    esi

805c71b5 e890d10300      call    nt!ExCompareExchangeCallBack (8060434a)

805c71ba 84c0            test    al,al

805c71bc 751d            jne     nt!PsSetLoadImageNotifyRoutine+0x4f (805c71db)

805c71be 83c704          add     edi,4

805c71c1 83c604          add     esi,4

805c71c4 83ff20          cmp     edi,20h

805c71c7 72e8            jb      nt!PsSetLoadImageNotifyRoutine+0x25 (805c71b1)

805c71c9 53              push    ebx

805c71ca e819d00300      call    nt!RtlpFreeAtom (806041e8)

805c71cf b89a0000c0      mov     eax,0C000009Ah

805c71d4 5e              pop     esi

805c71d5 5f              pop     edi

805c71d6 5b              pop     ebx

805c71d7 5d              pop     ebp

805c71d8 c20400          ret     4

以上0x56和0xbe是特征码


对应的C代码(摘自WRK 1.2)

NTSTATUS

PsSetLoadImageNotifyRoutine(

    __in PLOAD_IMAGE_NOTIFY_ROUTINE NotifyRoutine

    )

{

    ULONG i;

    PEX_CALLBACK_ROUTINE_BLOCK CallBack;

 

    PAGED_CODE();

    //Allocate a new callback block.

    CallBack = ExAllocateCallBack ((PEX_CALLBACK_FUNCTION) NotifyRoutine, NULL);

    if (CallBack == NULL) {

        return STATUS_INSUFFICIENT_RESOURCES;

    }

 

    for (i = 0; i < PSP_MAX_LOAD_IMAGE_NOTIFY; i++) {

        // Try and swap a null entry for the new block.

        if (ExCompareExchangeCallBack (&PspLoadImageNotifyRoutine[i],

                                       CallBack,

                                       NULL)) {

            InterlockedIncrement ((PLONG) &PspLoadImageNotifyRoutineCount);

            PsImageNotifyEnabled = TRUE;

            return STATUS_SUCCESS;

        }

    }

    // No slots left. Free the block and return.

    ExFreeCallBack (CallBack);

    return STATUS_INSUFFICIENT_RESOURCES;

}


看到PspLoadImageNotifyRoutine是一个数组,定义如下:

EX_CALLBACK PspLoadImageNotifyRoutine[PSP_MAX_LOAD_IMAGE_NOTIFY];

要摘除回调例程就必须得到PspLoadImageNotifyRoutine变量的地址,这就使用了特征码搜索法来定位变量位置(相关文章可在看雪上面找到)

这里附上摘除回调函数的代码

 

// LoadImage回调结构体(摘自WRK)

#pragma pack(1)           

typedef struct _EX_FAST_REF

{

    union

    {

        PVOID Object;

        ULONG_PTR RefCnt:3;

        ULONG_PTR Value;

    };

} EX_FAST_REF, *PEX_FAST_REF;

 

typedef struct _EX_CALLBACK_ROUTINE_BLOCK

{

    EX_RUNDOWN_REF RundownProtect;

    PEX_CALLBACK_FUNCTION Function;

    PVOID Context;

} EX_CALLBACK_ROUTINE_BLOCK, *PEX_CALLBACK_ROUTINE_BLOCK;

#pragma pack()

 

// PspLoadImageNotifyRoutine数组大小

#define PSP_MAX_LOAD_IMAGE_NOTIFY           8

 

// 系统PspLoadImageNotifyRoutine变量位置

PULONG g_PspLoadImageNotifyRoutine = NULL;


// 根据特征码查找PspLoadImageNotifyRoutine变量的地址

PULONG FindPspLoadImageNotifyRoutine( PUCHAR FuncBase )

{

    ULONG nIndex;

    PULONG result = NULL;

 

    // 查找ing

    for ( nIndex = 0; nIndex < 512; ++nIndex )

    {

        // 比较头部(这里的0x56和0xbe是特征码)

        if ( (*(UCHAR*)FuncBase == 0x56) && (*(UCHAR*)(FuncBase + 1) == 0xbe) )

        {

            // 保存地址并返回

            result = *(PULONG)(FuncBase + 2);

            break;

        }

 

        // 继续遍历

        ++FuncBase;

    }

 

    return result;

}


// 检测并挂钩NP的回调函数

VOID RemoveLoadImageCallBack()

{

    PEX_FAST_REF ExRef;

    ULONG nIndex;

    NTSTATUS status;

 

    ExRef = (PEX_FAST_REF)(g_PspLoadImageNotifyRoutine);

    for ( nIndex = 0; nIndex < PSP_MAX_LOAD_IMAGE_NOTIFY; ++nIndex )

    {

        PEX_CALLBACK_ROUTINE_BLOCK Point;

        // 去掉末尾3位数

        Point = (PEX_CALLBACK_ROUTINE_BLOCK)(ExRef->Value & ~7);      // 详见WRK

        if ( MmIsAddressValid((PVOID)Point) )

        {

            // 移除注册的回调函数

            status = PsRemoveLoadImageNotifyRoutine( Point->Function );

            if ( NT_SUCCESS(status) )

            {

                KdPrint(("remove LoadImage notify success: %d.\n", nIndex));

            }

        }

        ++ExRef;

    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值