两种方法获取shadow ssdt

ULONG 
GetShadowSsdtCurrentAddresses(
    PSSDT_ADDRESS   AddressInfo, 
    PULONG          Length
    )
{
    PSYSTEM_SERVICE_TABLE KeServiceDescriptorTableShadow = NULL;
    ULONG NumberOfService = 0;
    ULONG ServiceId = 0;
    PKAPC_STATE ApcState;
    ULONG i;
    
    if (AddressInfo == NULL || Length == NULL)
    {
        KdPrint(("[GetShadowSsdtCurrentAddresses] 输入参数无效"));
        return 0;
    }

    //KdPrint(("pid = %d", PsGetCurrentProcessId()));
    ServiceId = (ULONG)PsGetCurrentProcessId();

    if (!g_CsrssProcess) {
        PsLookupProcessByProcessId((PVOID)ScPsGetCsrssProcessId(), &g_CsrssProcess);
    }

    KeServiceDescriptorTableShadow = GetKeServiceDescriptorTableShadow();

    if (KeServiceDescriptorTableShadow == NULL)  
    {
        KdPrint(("[GetShadowSsdtCurrentAddresses] GetKeServiceDescriptorTableShadow failed"));
        return 0;
    }

    NumberOfService = KeServiceDescriptorTableShadow->NumberOfService;
    if (Length[0] < NumberOfService * sizeof(SSDT_ADDRESS))
    {
        Length[0] = NumberOfService * sizeof(SSDT_ADDRESS);
        return 0;
    }

    ApcState = ExAllocatePoolWithTag(NonPagedPool, sizeof(KAPC_STATE), MEM_TAG);
    KeStackAttachProcess((PRKPROCESS)g_CsrssProcess, ApcState);

    for (ServiceId = 0; ServiceId < NumberOfService; ServiceId ++)
    {
        AddressInfo[ServiceId].FunAddress = (ULONG)
            KeServiceDescriptorTableShadow->ServiceTableBase[ServiceId];
        AddressInfo[ServiceId].nIndex = ServiceId;
    }

    KeUnstackDetachProcess(ApcState);
    ExFreePool(ApcState);

    Length[0] = NumberOfService * sizeof(SSDT_ADDRESS);
    return NumberOfService;
}

///////////////////////////////////////////////////////////////////////////////////
//
//    功能实现:枚举当前Shadow SSDT 表函数地址
//    输入参数:void
//    输出参数:返回Shadow ssdt table
//
///////////////////////////////////////////////////////////////////////////////////
PSYSTEM_SERVICE_TABLE 
GetKeServiceDescriptorTableShadow(VOID)
{
    PSYSTEM_SERVICE_TABLE ShadowTable = NULL;
    ULONG   ServiceTableAddress = 0;
    PUCHAR  cPtr = NULL; 

    for (cPtr = (PUCHAR)KeAddSystemServiceTable;
         cPtr < (PUCHAR)KeAddSystemServiceTable + PAGE_SIZE;
         cPtr += 1 )
    {
        if (!MmIsAddressValid(cPtr))  continue;

        ServiceTableAddress = *(PULONG)cPtr;
        if (!MmIsAddressValid((PVOID)ServiceTableAddress)) continue;

        if (memcmp((PVOID)ServiceTableAddress, &KeServiceDescriptorTable, 16) == 0)
        {
            if ((PVOID)ServiceTableAddress == &KeServiceDescriptorTable) continue;
            ShadowTable = (PSYSTEM_SERVICE_TABLE)ServiceTableAddress;
            ShadowTable ++;
            return ShadowTable;
        }
    }
    return NULL;
}
//
// 方法2,通过硬编码实现,不通用
// 
PSYSTEM_SERVICE_TABLE 
GetKeServiceDescriptorTableShadow_2(VOID)
/*++
    805ba5a3 8d8840a65580    lea    ecx,nt!KeServiceDescriptorTableShadow (8055a640)[eax]
    805ba5a9 833900          cmp    dword ptr [ecx],0
--*/
{
    PSYSTEM_SERVICE_TABLE ShadowTable;
    ULONG   ServiceTableAddress;
    PUCHAR  cPtr, pOpcode;
    ULONG   Length = 0;

    for (cPtr = (PUCHAR)KeAddSystemServiceTable;
         cPtr < (PUCHAR)KeAddSystemServiceTable + PAGE_SIZE;
         cPtr += Length )
    {
        if (!MmIsAddressValid(cPtr))  return NULL;

        Length = SizeOfCode(cPtr, &pOpcode);

        if (!Length || (Length == 1 && *pOpcode == 0xC3)) return NULL;

        if (*(PUSHORT)pOpcode == 0x888D)
        {
            ServiceTableAddress = *(PULONG)(pOpcode + 2);
            ShadowTable = (PSYSTEM_SERVICE_TABLE)ServiceTableAddress;
            ShadowTable ++;
            return ShadowTable;
        }
    }
    return NULL;
}

 

转载于:https://www.cnblogs.com/kedebug/archive/2010/12/22/2791751.html

本实例由VS2008开发,在提供了一套驱动开发框架的同时,又演示了如何获取Shadow SSDT表函数原始地址的办法。 主要函数:ULONG GetShadowSSDT_Function_OriAddr(ULONG index); 原理说明: 根据特征码搜索导出函数KeAddSystemServiceTable来获取Shadow SSDT基址,以及通过ZwQuerySystemInformation()函数获取win32k.sys基址,然后解析PE定位到Shadow SSDT在win32k.sys的偏移地址,并通过进一步计算来得到Shadow SSDT表函数的原始地址。 这里只测试了三个函数:(460)NtUserMessageCall、(475)NtUserPostMessage和(502)NtUserSendInput,具体使用时可以举一反三,网上完整的源代码实例并不太多,希望可以帮到真正有需要的朋友。 系统环境: 在WinXP SP3系统 + 瑞星杀毒软件 打印输出: [ LemonInfo : Loading Shadow SSDT Original Address Driver... ] [ LemonInfo : 创建“设备”值为:0 ] [ LemonInfo : 创建“设备”成功... ] [ LemonInfo : 创建“符号链接”状态值为:0 ] [ LemonInfo : 创建“符号链接”成功... ] [ LemonInfo : 驱动加载成功... ] [ LemonInfo : 派遣函数(DispatchRoutine) IRP 开始... ] [ LemonInfo : 派遣函数(DispatchRoutine) IRP Enter IRP_MJ_DEVICE_CONTROL... ] [ LemonInfo : 获取ShadowSSDT表 (460)NtUserMessageCall 函数的“当前地址”为:0xB83ECFC4,“起源地址”为:0xBF80EE6B ] [ LemonInfo : 获取ShadowSSDT表 (475)NtUserPostMessage 函数的“当前地址”为:0xB83ECFA3,“起源地址”为:0xBF8089B4 ] [ LemonInfo : 获取ShadowSSDT表 (502)NtUserSendInput 函数的“当前地址”为:0xBF8C31E7,“起源地址”为:0xBF8C31E7 ] [ LemonInfo : 派遣函数(DispatchRoutine) IRP_MJ_DEVICE_CONTROL 成功执行... ] [ LemonInfo : 派遣函数(DispatchRoutine) IRP 结束... ] [ LemonInfo : UnLoading Shadow SSDT Original Address Driver... ] [ LemonInfo : 删除“符号链接”成功... ] [ LemonInfo : 删除“设备”成功... ] [ LemonInfo : 驱动卸载成功... ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值