想写这个程序主要是因为看了KSSD的一篇帖子,http://bbs.pediy.com/showthread.php?t=108378

讲 的是360保险箱保护游戏账号的原理,实际上就是对各种请求的拦截。这个帖子是大约6年前的了,我简单的看了一下现在的360保险箱应该不再采用这种方法了。

这里主要的思路就是HOOK住系统服务的分发,这已经不是什么新鲜的手法了。比方说,很多外挂作者都使用了内核重载来突破游戏保护的重重HOOK,内核重载也是劫持KiFastCallEntry来实现劫持服务分发的。这篇文章只是写来做一个练习。

基本流程是

1.应用层:

负责安装驱动模块并与驱动通信,由用户选择是否要放行指定操作

2.内核层:

(1)设置SSDT HOOK并调用HOOK 函数,进行栈回溯获取KiFastCallEntry()基址
(2)利用KiFastCallEntry()基址暴力搜索找到HOOK点位置并设置Inline Hook
(3)判断服务请求是否合法,合法则放行,不合法则传递消息给用户层,由用户决定是否放行

其实以上三步就是360保险箱的做法,程序里的有些内容因为不知道该怎么写,所以直接由那篇帖子的汇编分析逆写出来了。

其实网上有很多HOOK KiFastCallEntry的代码,但是我没有找到有劫持ebx来劫持服务分发的例子,所以我写的就是

sub esp, ecx

shr ecx, 2

mov ebx,FuncAddress

结果一直蓝屏,调了整整两天也没找到哪里的问题

后来在群里问到要把顺序改成这样

mov ebx,FuncAddress

sub esp, ecx

shr ecx, 2

结果真的不会触发BSOD了,不知道原理是什么,因为我觉得两种应该没有本质的区别(无论是寄存器还是堆栈我都没有改掉),可是第一种就是不行。

本来应该生成一个设备对象与应用层通信的,结果被蓝屏弄的实在搞不下去,就以后再说吧,核心的程序就是这些了。

想法就是根据SSDT索引得知是什么函数,然后再用在内核栈中索引出SSDT函数的参数(因为在call ebx时参数肯定已经入栈了),最后根据情况用IRP与用户层通信询问是否放行。

 #include "ntddk.h"   //环境:WDK 7.1 WIN XP SP3 测试通过
#include <ntdef.h>  //注意我分发函数中是故意留空白的,不要直接拿来编译 #define NtSetEventID 219 typedef struct ServiceDescriptorEntry {
unsigned int *ServiceTableBase;
unsigned int *ServiceCounterTableBase;
unsigned int NumberOfServices;
unsigned char *ParamTableBase;
} ServiceDescriptorTableEntry_t, *PServiceDescriptorTableEntry_t; __declspec(dllimport) ServiceDescriptorTableEntry_t KeServiceDescriptorTable; NTSTATUS ZwSetEvent(__in HANDLE EventHandle,__out_opt PLONG PreviousState); PVOID AddressOfFuncAddress;
HANDLE HandleTemp = (HANDLE)0x288C58F1;
ULONG NtSetEventAddress, TheHookAddress,KiFastCallEntryAddress;
ULONG YesOrNo=;
ULONG AddressOffset = ;
ULONG TempDword,Test;
ULONG ProcessPID = ;
ULONG pid, DispatchAddress, TempBufferCopy;
PULONG DwordAddress = ;
INT8 i;
INT8 *PbyteAddress;
KSPIN_LOCK MySpinLock1;
KSPIN_LOCK MySpinLock2;
KSPIN_LOCK MySpinLock3;
KIRQL TempKirql1;
KIRQL TempKirql2;
ULONG DebugAddress = ,FuncAddress;
//设置SSDT HOOK 用来栈回溯得到KiFastCallEntry地址
Check()
NTSTATUS HookSSDT(PVOID FuncAdress)
{
ULONG OutTemp = ;
NtSetEventAddress = (ULONG)KeServiceDescriptorTable.ServiceTableBase[NtSetEventID];
DebugAddress=(ULONG)&KeServiceDescriptorTable.ServiceTableBase[NtSetEventID];
KeInitializeSpinLock(&MySpinLock1);
KeAcquireSpinLock(&MySpinLock1,&TempKirql1);
_asm {
cli
push eax
mov eax, cr0
and eax, not 10000h
mov cr0, eax
pop eax
}
KeServiceDescriptorTable.ServiceTableBase[NtSetEventID] = (ULONG)FuncAdress;
__asm {
push eax
mov eax, cr0
or eax, 10000h
mov cr0, eax
pop eax
sti
}
KeReleaseSpinLock(&MySpinLock1,&TempKirql1);
ZwSetEvent(HandleTemp,
&OutTemp);
return STATUS_SUCCESS;
}
//解除SSDT HOOK
void UnhookSSDTHook()
{
KeInitializeSpinLock(&MySpinLock2);
KeAcquireSpinLock(&MySpinLock2,&TempKirql1);
_asm {
cli
push eax
mov eax, cr0
and eax, not 10000h
mov cr0, eax
pop eax
};
KeServiceDescriptorTable.ServiceTableBase[NtSetEventID] = NtSetEventAddress; _asm {
push eax
mov eax, cr0
or eax, 10000h
mov cr0, eax
pop eax
sti
};
KeReleaseSpinLock(&MySpinLock2,&TempKirql1);
return;
}
ULONG TheDispatchFunc(ULONG arg1, ULONG arg2, ULONG arg3)
{
if (arg3== (ULONG)KeServiceDescriptorTable.ServiceTableBase)
{
//这里可以根据栈中参数进行做判断
}
return arg2; }
//被挂载在KiFastCallEntry中(作为一个中转函数)
__declspec(naked) void InlineFunc()
{ _asm {
pushad
pushfd push edi//服务表基址
push ebx//服务地址
push eax//服务序号
call TheDispatchFunc
mov FuncAddress,eax popfd
popad
//补全被覆盖的函数
mov ebx, FuncAddress
sub esp, ecx
shr ecx, jmp TempBufferCopy }; }
//被挂载在SSDT的函数,需判断伪句柄
//并且要进行Inline HOOK
__declspec(naked) void SSDTFunc()
{
_asm {
push eax
mov eax, [esp + ]
mov TempDword, eax
pop eax
} if (TempDword == HandleTemp)
{
_asm {
push eax
mov eax, [esp + ]
mov KiFastCallEntryAddress, eax
pop eax
};
UnhookSSDTHook();
}
else
{
//_asm {int 3};
_asm {
jmp NtSetEventAddress
};
}
for (i = ; i < ; i++)
{ if (*((PULONG)KiFastCallEntryAddress)==0xe9c1e12b)
{
TheHookAddress = KiFastCallEntryAddress;
YesOrNo = ;
break;
}
KiFastCallEntryAddress--;
}
if (YesOrNo)
{
AddressOffset = (ULONG)InlineFunc - - (ULONG)TheHookAddress;
PbyteAddress = (INT8 *)TheHookAddress;
*PbyteAddress = 0xe9;
DwordAddress = (PULONG)((ULONG)TheHookAddress + );
*DwordAddress = AddressOffset;
TempBufferCopy = (ULONG)PbyteAddress + ;
}
//_asm {int 3};
_asm{retn 0x8 }
}
NTSTATUS UnloadFunc(PDRIVER_OBJECT MyDriver, PUNICODE_STRING RegPath)
{
//清理必要资源
return STATUS_SUCCESS;
}
NTSTATUS DriverEntry(PDRIVER_OBJECT MyDriver, PUNICODE_STRING RegPath)
{
NTSTATUS Status = ;
AddressOfFuncAddress=ExAllocatePool(NonPagedPool, );
MyDriver->DriverUnload = UnloadFunc;
Status = HookSSDT((PVOID)SSDTFunc);
if (!NT_SUCCESS(Status))
{
return ;
}
return STATUS_SUCCESS;
}

通过构造系统服务分发实现拦截&过滤 (仿360游戏保险箱)的更多相关文章

  1. 如何构造一个简单的USB过滤驱动程序

    本文分三部分来介绍如何构造一个简单的USB过滤驱动程序,包括"基本原理"."程序的实现"."使用INF安装".此文的目的在于希望读者了解基本 ...

  2. 一文读懂 Android TouchEvent 事件分发、拦截、处理过程

    什么是事件?事件是用户触摸手机屏幕,引起的一系列TouchEvent,包括ACTION_DOWN.ACTION_MOVE.ACTION_UP.ACTION_CANCEL等,这些action组合后变成点 ...

  3. MVC的Filters(拦截过滤)的Error页面,支持Ajax报错

    报错拦截过滤到error页面 [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true, A ...

  4. 拦截过滤防御XSS攻击 -- Struts2.3 以及 2.5 的解决方式

    使用Struts2框架开发的后台在防御XSS攻击的时候很多方式都不能用,因为Struts2对请求进行的二次封装有区别.以下针对Struts2的XSS攻击进行拦截过滤防御解决: Struts2.3 本方 ...

  5. C#制作高仿360安全卫士窗体(三)

    距上篇C#制作高仿360安全卫士窗体(二)也将近一个多月了,这个月事情还是像往常一样的多.不多我也乐在其中,毕竟我做的是我喜欢做的东西.今天特地抽空把怎么制作文本框写一下.同时也希望有爱好这些玩意的同 ...

  6. C#制作高仿360安全卫士窗体3

    C#制作高仿360安全卫士窗体(三)   距上篇C#制作高仿360安全卫士窗体(二)也将近一个多月了,这个月事情还是像往常一样的多.不多我也乐在其中,毕竟我做的是我喜欢做的东西.今天特地抽空把怎么制作 ...

  7. Web编程基础--HTML、CSS、JavaScript 学习之课程作业“仿360极速浏览器新标签页”

    Web编程基础--HTML.CSS.JavaScript 学习之课程作业"仿360极速浏览器新标签页" 背景: 作为一个中专网站建设出身,之前总是做静态的HTML+CSS+DIV没 ...

  8. C#制作高仿360安全卫士窗体<二>

    继上次C#制作高仿360安全卫士窗体<一>发布之后响应还不错,我的博客放肆雷特也来了不少的新朋友,在这里先谢谢大家的支持!我自己也反复看了一下觉得对不起大家,写的非常乱而且很少文字介绍.在 ...

  9. C#制作高仿360安全卫士窗体<一>

    开始写这一系列博客之前先要向大家说声抱歉,放肆雷特建立很久却很少有更新.当然博客人气也不旺,大部分都是看的人多评论收藏的人少.一直想要改变这种状态,正好赶上了最近工作上做了一个高仿360安全卫士窗体. ...

随机推荐

  1. Python之paramiko模块和SQL连接API

    堡垒机前戏 开发堡垒机之前,先来学习Python的paramiko模块,该模块机遇SSH用于连接远程服务器并执行相关操作 SSHClient 用于连接远程服务器并执行基本命令 基于用户名密码连接: i ...

  2. 怎样彻底卸载(删除)SQL server2000

    如何完全卸载SQL server 2000 一.卸载安装程序:找到电脑右下角的Windows开始按钮,找到控制面板——卸载程序. 找到server 2000的安装程序,并点击后面的卸载按钮.  是,确 ...

  3. 什么是ground truth(GT)

    转自ground truth的含义 ground truth在不同的地方有不同的含义,下面是参考维基百科的解释,ground truth in wikipedia. 1.在统计学和机器学习中 在机器学 ...

  4. 根据Bool值挑选数组中元素

    根据Bool值挑选数组中元素 觉得有用的话,欢迎一起讨论相互学习~Follow Me 使用Boolean类型的数组挑选一维数组中的值 使用一维Boolean数组选取数组中的特定元素,对应位置为True ...

  5. Java并发编程原理与实战三十八:多线程调度器(ScheduledThreadPoolExecutor)

    在前面介绍了java的多线程的基本原理信息:线程池的原理与使用 本文对这个java本身的线程池的调度器做一个简单扩展,如果还没读过上一篇文章,建议读一下,因为这是调度器的核心组件部分. 我们如果要用j ...

  6. HttpContext.Current為空匯總

    1. async異步模式下為空 解决办法: <httpRuntime targetFramework="4.5" /> 或者: In your appSettings, ...

  7. 20155303 2016-2017-2 《Java程序设计》第七周学习总结

    20155303 2016-2017-2 <Java程序设计>第七周学习总结 教材学习中的问题和解决过程 『问题一』:SimpleDateFormat中每个字符的含义都是什么? 『问题一解 ...

  8. js之事件冒泡和事件捕获及其阻止详细介绍

    虽然精通jquery,但对它的原型javascript却不是很了解,最近在学习javascript中遇到了一些困难,比如冒泡和捕获,很多次被提到,但又不知究竟应用在何处.找到了一些好文章解惑,在这里分 ...

  9. Ajax异步请求struts的JSON机制(省市区三级联动)

    1.struts.xml <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts P ...

  10. SDL封装的系统操作(转载)

    Andrew Haung bluedrum@163.com SDL封装很多操作系统的功能,为了保证SDL程序可移植性,最好尽量用这一些封装函数,哪果没有的话,才使用各种操作本地函数.  对于如何封各个 ...