首页
社区
课程
招聘
[分享]基于ndis 的驱动后门分析
发表于: 2023-6-19 16:25 8609

[分享]基于ndis 的驱动后门分析

2023-6-19 16:25
8609

前言
十年前的老样本总算梳理清楚了关键流程,趁有时间记录,分享一下。该样本是一个后门程序,通过劫持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))
                {

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

上传的附件:
收藏
免费 2
支持
分享
最新回复 (1)
雪    币: 1556
活跃值: (2297)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2

编辑掉

最后于 2023-6-28 15:53 被killleer编辑 ,原因:
2023-6-25 19:13
0
游客
登录 | 注册 方可回帖
返回
//