专栏名称: 看雪学苑
致力于移动与安全研究的开发者社区,看雪学院(kanxue.com)官方微信公众帐号。
目录
相关文章推荐
嘶吼专业版  ·  开源DeepSOC,开放DeepSec,为网 ... ·  昨天  
财经三分钟  ·  冲上热搜,韵达出大事了! ·  2 天前  
网信内蒙古  ·  击碎谣言迷雾,共筑网络晴空 ·  2 天前  
网信内蒙古  ·  击碎谣言迷雾,共筑网络晴空 ·  2 天前  
政法频道  ·  涉嫌性骚扰!北京环球影城回应! ·  2 天前  
政法频道  ·  涉嫌性骚扰!北京环球影城回应! ·  2 天前  
中国标准化研究院  ·  ISO IEC ITU联合发布2月工作项目清单 ·  2 天前  
中国标准化研究院  ·  ISO IEC ITU联合发布2月工作项目清单 ·  2 天前  
51好读  ›  专栏  ›  看雪学苑

Hips篇高操之正确的全局Patch/拦截模块姿势

看雪学苑  · 公众号  · 互联网安全  · 2017-05-27 18:00

正文

潜水了两个月,由于工作的关系没有什么多余的时间发新帖了,由于临近端午准备休息一下, 于是乎决定在周末搞点事情, 恰逢北京今日又下起雨来,在这朦朦胧胧的雨天里给大家呈上一份 Hips 的高端操作,让大家燃一下。


这也是初入安全时我一直想实现的一个东西,但是由于当时技术局限,很菜,其实今天来看只是当时没有找到好的学习方法,没有办法实现很是遗憾。然而今日在团队的带领下,我改进了自己的学习方法,学会了如何有效看待问题分析问题以及解决问题。在此感谢我的导师以及 leader。


这个一直想实现的东西就是用驱动拦截模块,看似很简单的一个问题但是实际上要操作起来并非易事,要看得懂代码,得先理解了这张图:


可以看到,调用API加载模块的时候最后都逃不过ntdll!ZwMapViewOfSection,最后进入系统调用然后触发模块回调,我们唯一能做的就是在模块回调里干一些猥琐的事情。直接Patch?那是不可能的,因为模块回调有限制,这时候有EProcess.AddressCreationLock的限制不说,模块还未能初始化完成,直接去搞肯定是不正确的做法。那么可以想到的是用Apc延迟去Patch模块,因为在ZwMapViewOfSection在内核中最后会返回至Ring3,在返回的过程中调用Apc去Patch这样就完美了。


话又说回来,模块回调中为每一个模块都插一个Apc? 这显然也不现实,因此这种方法最好是有一个Ring3层进程来 制定策略 指定对哪一个进程加载哪一个模块时执行哪种Patch操作 那么这就涉及到Ring0与Ring3的通信问题。说到这里就有三种方法可供选择,一种是LPC(ZwConnetPort...),一种是内核可等待对象,还有一种就是Minifilter的双向通信机制。


当然,我选择的是最后一种,现在貌似运用这种方法做通信的不多,我也没怎么接触过,一切都是从0开始,那就试试吧...

首先由Ring3进程指定策略,这里拿金山的两个模块开刀:

注册这个通信是奠定与Ring3进程通信的基础,应用层进程可以通过连接之后发送策略(即要对哪个进程的哪个模块进行监控),然后由模块回调在匹配策略之后对应用程序进行通知

这里一定要注意,FltSendMessage这个函数msdn上说的很清楚,如果RelpyData为NULL, 只要是Ring3进程调用了FilterGetMessage取得了数据,那么这个函数不会再等待。而我们需要做的是在GetMessage之后发消息给驱动,让它为LoadImage这个当前线程插入Apc,那么在模块回调中必须卡死直到应用进程调用FilterRelpyMessage回应消息,否则这一次系统调用就返回了。

Ring3 进程拿到模块监控数据之后决定对该模块采取什么样的 Patch 措施,然后将决定结果送达至 Ring0,这里我就以 Patch 基地址即 DosHeader.e_magic 为例了。

DWORD WINAPI FilterMessageProc(PVOID lpParam)

{

FyLoadImageRecvDat Msg = {0};

FyReplyData ReplyMsg = {0};

while (TRUE)

{

DWORD bytesReturned = 0;

DWORD hResult;

TCHAR buf[260] = {0};

hResult = FilterGetMessage(

g_hPort,

(PFILTER_MESSAGE_HEADER)&Msg,

sizeof(Msg),

NULL);

if (hResult == S_OK)

{

// 拿到当前正在映射的模块信

// Now can Send Patch Info

FySendPatchInfoDat HipsData = {0};

HipsData.MessageType = Lowlayer_Msg_BlockImage;

HipsData.Signature = FY_FSFILTER_SIGNATURE;

HipsData.DataLength = sizeof(FyPatchInfo);

HipsData.Data.PatchType = 1;

HipsData.Data.ProcessId = Msg.Data.ProcessId;

HipsData.Data.ThreadId = Msg.Data.ThreadId;

HipsData.Data.PatchAddress = (ULONG64)Msg.Data.ImageBase;

*(DWORD*)HipsData.Data.lpPatchContent = 0x00905a4b;

HipsData.Data.PatchSize = 4;

// don't wait

FilterSendMessage(g_hPort,

&HipsData,

sizeof(FySendPatchInfoDat),

NULL,

NULL,

&bytesReturned);

// Reply load image message

ReplyMsg.ReplyHeader.MessageId = Msg.MsgHeader.MessageId;

ReplyMsg.ReplyHeader.Status = 0;

ReplyMsg.Signature = FY_FSFILTER_SIGNATURE;

hResult = FilterReplyMessage(

g_hPort,

(PFILTER_REPLY_HEADER)&ReplyMsg,

sizeof(ReplyMsg));

}

}

return 0;

}

这里要提一点的是,32位进程与64位驱动通信的时候一定要注意结构体的对齐粒度,不然会吃大亏的...

NTSTATUS FyFsFilterMessage (

__in PVOID ConnectionCookie,

__in_bcount_opt(InputBufferSize) PVOID InputBuffer,

__in ULONG InputBufferSize,

__out_bcount_part_opt(OutputBufferSize,*ReturnOutputBufferLength) PVOID OutputBuffer,

__in ULONG OutputBufferSize,

__out PULONG ReturnOutputBufferLength

)

{

NTSTATUS Status = STATUS_SUCCESS;

ULONG Command;

PVOID pContent = NULL;

ULONG ContentLength = 0;

UINT32 Signature;

UNREFERENCED_PARAMETER(ConnectionCookie);

PAGED_CODE();

#if defined(_WIN64)

if (IoIs32bitProcess( NULL )) {

if (!IS_ALIGNED(OutputBuffer,sizeof(ULONG))) {

Status = STATUS_DATATYPE_MISALIGNMENT;

return Status;

}

} else {

#endif

if (!IS_ALIGNED(OutputBuffer,sizeof(PVOID))) {

Status = STATUS_DATATYPE_MISALIGNMENT;

return Status;

}

#if defined(_WIN64)

}

#endif

if ((InputBuffer != NULL) &&

(InputBufferSize >= sizeof(FYFSFLT_SEND_DATA))) {

__try {

Command = ((PFYFSFLT_SEND_DATA) InputBuffer)->MessageType;

Signature = ((PFYFSFLT_SEND_DATA) InputBuffer)->Signature;

if (Signature != FY_FSFILTER_SIGNATURE)

return Status;

pContent = &((PFYFSFLT_SEND_DATA) InputBuffer)->Data;

ContentLength = ((PFYFSFLT_SEND_DATA) InputBuffer)->DataLength;

} __except( EXCEPTION_EXECUTE_HANDLER ) {

return GetExceptionCode();

}

DbgPrint("[%s]Command:%x\n", __FUNCTION__, Command);

switch (Command)

{

case Lowlayer_Msg_SetImagePolicy:

DbgPrint("[%s] Lowlayer_Msg_SetImagePolicy\n", __FUNCTION__);

SetProcessImagePolicy((PPOLICY_DATA)pContent, ContentLength);

break;

case Lowlayer_Msg_BlockImage:

DbgPrint("[%s] Lowlayer_Msg_BlockImage\n", __FUNCTION__);

ExecuteKernelPatchProcedure((PFyPatchInfo)pContent, ContentLength);







请到「今天看啥」查看全文