关于个人防火墙的真相

原文作者:MaD 
原文标题:The truth aboutpersonal firewalls
电子邮件:mad-factor@mail.ru
作者国籍:俄罗斯

声明:1、本人翻译水平有限,有不当之请大家理解。如部分看不懂可以和原文对照。
            2、欢迎转载,但请不要漏掉原文作者和翻译者的信息。
            3、欢迎大家指出我翻译中的错误,我好改正。

内容:

        有多种方式来保护你的计算机免受恶意软件的侵害,比如软件防火墙,病毒和Rootkit检 测软件等。所有这些防护软件都基于一些众所周知而几乎没有改进的技术,而且这些技术你也许已经知道,继承这些技术的安全产品也是不完善的。这样的后果通常 是可怕的。然而这些安全公司却天真的认为他们的产品是最先进的,包含了最新的特性,是用户必备的。但是只要你透过他们的华丽的外衣就会看到,他们的Bug和错误甚至比你在学校的设计还要多。虽说生产一款产品首要的是好而强有力的广告。但沉重的广告和糟糕的测试结合在一起能向用户展示一些产品所谓的强大吗,能使其产生一种强烈的购买欲望吗?当然不行。
        保护你的个人电脑免受外部的和内部的第三者的攻击是一个好主意。一些保护你的PC远离木马和间谍软件“启发式”的方法好像真在工作。如果他们工作的话,付30到50美元就能获得实时的保护和更新的确是个非常好的想法。可惜,他们不能。
        首先我想为我糟糕的英语道歉。我们的讨论将会涉及以下产品:
           ZoneAlarm Firewall 6.x
           Outpost Firewall 3.x and 4.x
           Look'n'Stop Firewall 2.0
           Kerio Firewall 4.3
           Sygate Firewall 5.6
           Jetico Firewall 1.0
           PortsLock Firewall 1.9
           Tiny Firewall 6.5
           Norton Internet Security 8.0
           Comodo Firewall 2.4
           OnlineArmor Firewall 2.1
        个人软件防火墙的保护有2种基本级别:NDIS(网络驱动接口规范)和TDI(传输数据接口)。NDIS级是建立在TCP/IP栈的基础上的,在这个级别上的保护能阻止基于TCP/IP栈BUG的攻击,甚至你不用更新你的栈;他也能防御许多电子欺骗,洪水攻击和分布式拒绝服务攻击。没有使用NDIS技术的防火墙自然变成了局外人。失败者有PortsLock防火墙, Norton Internet Security, Comodo防火墙 等。你真的愿意为PortsLock防火墙付35欧元吗,他甚至不能抵御低级别的TCP/IP攻击。或者为Comodo付79美元?为你的系统感到悲哀。真正的防火墙是基于NDIS级的。基于NDIS有两种不同的保护方法。第一种是NDIS-hooking保护。主要方法是HooksNdisRegisterProtocol()/NdisOpenAdapter()。当NDIS协议试图被注册时或是正要绑定某个适配器时,防火墙将接到通知。在防火墙正在HOOK NDIS_PROTOCOL_BLOCK andNDIS_OPEN_BLOCK的句柄的这个关键时刻,并且当系统想要发送或接收数据包时,防火墙将会被通知当这些发生的时候。防火墙正试图安装他们的钩子时是有趣的时候,几乎每个防火墙都是hook NDIS_PROTOCOL_BLOCK的句柄,但是Sygate, Kerio 和Jetico等除外,他们是HOOK NDIS_PROTOCOL_CHARACTERISTICS的句柄,而不是调用真正的NdisRegisterProtocol(),在那之后他们又移动到原来的句柄。更安全吗?对吗?正是,防火墙应该独立工作,与多少协议被注册和多少被绑定无关。是的,每个防火墙都支持这个。例如,当ZoneAlarm正在hook一个句柄时,他是分配一个无分页的内存并且放入以下几条指令。

pop        eax        ; 58
push        HookData    ; 68 XX XX XX XX
push        eax        ; 50
jmp        HookedHandler    ; E9 XX XX XX XX


        然后,他写一些重要的信息在其他内存片,调用HookData和所有在NDIS_PROTOCOL_BLOCK中被hook的句柄:
       

OpenAdapterCompleteHandler
CloseAdapterCompleteHandler
BindAdapterHandler
UnbindAdapterHandler


        在NDIS_OPEN_BLOCK中的:
       

    SendHandler
    ReceiveHandler
    ReceivePacketHandler
    SendPacketsHandler


        对NDIS_PROTOCOL_BLOCK象下面这样:
       

    VOID HookedOpenAdapterComplete(
       PVOID HookData,
        INNDIS_HANDLE  ProtocolBindingContext,
        INNDIS_STATUS  Status,
        INNDIS_STATUS  OpenErrorStatus
    );


       真正的OpenAdapterComplete() 句柄被放在这:[HookData + 0x770]
       

    VOID HookedCloseAdapterComplete(
       PVOID HookData,
        INNDIS_HANDLE  ProtocolBindingContext,
        INNDIS_STATUS  Status
    );


       真正的CloseAdapterComplete() 句柄被放在这:[HookData + 0x774]
       

    VOID HookedBindAdapter(
       PVOID HookData,
       OUT PNDIS_STATUS Status,
        INNDIS_HANDLE  BindContext,
        INPNDIS_STRING  DeviceName,
        INPVOID  SystemSpecific1,
        INPVOID  SystemSpecific2
    );


       真正的BindAdapter() 句柄被放在这:[HookData + 0x764]
     

   VOID HookedUnbindAdapter(
       PVOID HookData,
       OUT PNDIS_STATUS  Status,
        INNDIS_HANDLE  ProtocolBindingContext,
        INNDIS_HANDLE  UnbindContext
    );


        真正的UnbindAdapter()  句柄被放在这: [HookData + 0x768]
        For NDIS_OPEN_BLOCK:

   VOIDHookedSend(
       PVOID HookData,
        INNDIS_HANDLE  NdisBindingHandle,
       IN  PNDIS_PACKET  Packet
    );


       真正的Send()  句柄被放在这: [HookData + 0x1A4]
    

 VOID  HookedReceive(
       PVOID HookData,
       IN  NDIS_HANDLE            ProtocolBindingContext,
       IN NDIS_HANDLE            MacReceiveContext,
       IN PVOID                  HeaderBuffer,
       IN UINT                   HeaderBufferSize,
       IN PVOID                  LookAheadBuffer,
       IN UINT                   LookaheadBufferSize,
       IN UINT                   PacketSize
    );


       真正的Receive() 句柄被放在这: [HookData + 0x4D0]

 VOID HookedReceivePacket(
       PVOID HookData,
       IN NDIS_HANDLE            ProtocolBindingContext,
       IN PNDIS_PACKET           Packet
);


       真正的ReceivePacket() 句柄被放在这: [HookData + 0x570]

VOID HookedSendPackets(
       PVOID HookData,
        INNDIS_HANDLE             MiniportAdapterContext,
        INPPNDIS_PACKET           PacketArray,
        INUINT                    NumberOfPackets
);

       真正的SendPackets()  句柄被放在这:  [HookData+2E4h]

        可怜的ZoneAlarm,这是如此的简单对于获取真实的句柄并恢复他。
        我说过,每个防火墙都支持多数的注册协议。事实上,并不是每个。Sygate认为,保持关于协议和公开包的所有信息在他的.data段中已经足够了。不幸是个坏主意。他的句柄HOOK方式比ZoneAlarm简单,但是说明哪些内存将被分配的指令被 放在Sygate的驱动Teefer.sys中:

   pop       eax        ; 58
   push        HookData    ; 68XX XX XX XX
   push       eax        ; 50
   jmp        FakeHandler    ;E9 XX XX XX XX


        HookData也是放在.data中的。Sygate总共能HOOK576个句柄(包括协议和开放块句柄)。于是,大约有40-50个NDIS_PROTOCOL_BLOCK和NDIS_OPEN_BLOCK能被Hook(不要忘记几个开放块能被附加到一个协议块)。大概40-50块已经足够了,但那样的代码实在是个糟糕的设计,给缓冲区溢出打了个招呼。

        我有另外一个好例子,是关于关于多么有必要知道怎样Hook和hook多少。那些来自Kerio防火墙小组的家伙不知道这些。作为一个好的防火墙,设置HOOK在 NdisRegisterProtocol(), NdisDeregisterProtocol(), NdisOpenAdapter(),NdisCloseAdapter() 等函数并且HOOK句柄。就像我说的,Kerio只是hook NDIS_PROTOCOL_CHARACTERISTICS的句柄并且仅仅调用NdisRegisterProtocol()函数,但他不将句柄移回NDIS_PROTOCOL_CHARACTERISTICS。这会怎样?未公开的特性?我不这样认为,恰恰是粗心的编码和对内核标准和架构的误解。另一个好的例子是,Kerio团队不知道任何关于NDIS的开发,事实就是这样,他们甚至不知道怎样去HOOK。Kerio防火墙HOOK在NDIS_PROTOCOL_CHARACTERISTICS里:

    OpenAdapterCompleteHandler
   CloseAdapterCompleteHandler

    并这样hook NDIS_OPEN_BLOCK:
    SendHandler
    SendPacketsHandler


        不是太多?刚好。他能被用来绕过他的NDIS保护,并发送一个包给TCP/IP栈。你虽然已经按了“阻止所有”按钮,但仍然能在本地嗅探器下看到进来的数据包。我可不喜欢像Kerio防火墙假装的那样假装自己受保护的时候,再去嗅探器下看数据包。从另一个方面来说,Outpost防火墙,喜欢在NDIS_PROTOCOL_BLOCK中hook更多的句柄:

    OpenAdapterCompleteHandler
    SendCompleteHandler
   TransferDataCompleteHandler
    RequestCompleteHandler
    ReceiveHandler
    StatusHandler
    ReceivePacketHandler
    BindAdapterHandler
    UnbindAdapterHandler


        在 NDIS_OPEN_BLOCK中:
        Outpost4.0:

    SendCompleteHandler
   TransferDataCompleteHandler
    ReceiveHandler
    ReceivePacketHandler
    StatusHandler


       Outpost 3.x:

    SendHandler
    TransferDataHandler
    SendCompleteHandler
   TransferDataCompleteHandler
    ReceiveHandler
   RequestCompleteHandler
    ReceivePacketHandler
    SendPacketsHandler
    StatusHandler


       他的句柄调用和防火墙之间的代码是非常有趣的:

    call   ImCode        ; E8 XX XX XX XX
    

     For Outpost3.x:

   pop       eax        ; 58
   push       [eax]        ; FF30        Pushing the real handler
   pushad               ; 60
   push       [eax+4]        ; FF 70 04
   push        [esp+28h]    ; FF74 24 28    Pushing return address
   jmp       [eax+8]        ; FF 60 08

    For Outpost 4.0:

   pop       eax        ; 58
   add        eax,3        ; 83 C0 03   Missing three zero bytes after call
   push       [eax]        ; FF30        Pushing the real handler
   pushad               ; 60
   push       [eax+4]        ; FF 70 04
   push        [esp+28h]    ; FF74 24 28    Pushing return address
   jmp       [eax+8]        ; FF 60 08


       像我们看到的那样,那不是一个问题对于卸载所有的HOOK并立即获取系统控制权。如果你厌烦了这中间的汇编代码,他们通常是能够转换成普通C代码的,我能向你展示一些来自Tiny防火墙团队有趣的东西,他假装是真正的安全,并且向我们展示了很多的hook:

    NdisOpenAdapter
    NdisCloseAdapter
    NdisInitializeWrapper
    NdisTerminateWrapper
    NdisMRegisterMiniport
   NdisIMRegisterLayeredMiniport
    NdisRegisterProtocol
    NdisMSetAttributesEx
    NdisRegisterMac
   NdisIMAssociateMiniport
   NdisClOpenAddressFamily
   NdisCmRegisterAddressFamily
   NdisMCmRegisterAddressFamily
    NdisMCoSendComplete


       哦,看起来很优秀,也真是很优秀的样子,他们试图对这些函数做一个结合HOOK通过设置跳转到他们的句柄。我不喜欢“结合”,知道为什么吗?那不是因为他难以实现或是有些指令很难“结合”(理论上可行,实践上未必,我不认为在真正函数的开端那样做可行)。主要的原因是那样不安全。Rootkit开发者使用他是因为那是一种获取控制权的简单的方式,但不要试图把他用作安全软件中,就像用恐怖份子的方法对付恐怖分子一样。还有要说的是,我没有发现任何线程安全和多处理器安全的代码。再一次失败。当你在“结合”某些代码的时候,你需要确信没有一个线程、没有一个CPU在运行这些代码。
        Tiny防火墙为每个HOOK句柄申请内存,并拷贝这些C函数在开端和结尾:

   push       ebp                   ; 55
   mov        ebp,esp               ; 8B EC
   sub        esp,XXh               ; 83 EC XX
   mov        byte ptr [ebp-1],XXh            ; C6 45FF XX
   mov        dword ptr [ebp-8],HookedHandler    ; C7 45 F8 XX XX XX XX
    <...>
   push        RealHandler
   call        [ebp-8]
   mov        esp, ebp
   pop        ebp
   ret        XXh


       于是这就变的相当简单,对于从新句柄偏移0xD去获得真的句柄。对所有的句柄,Tiny都是拷贝上面的代码。

    hook在NDIS_PROTOCOL_BLOCK中:

    SendCompleteHandler
    StatusHandler

    Hooked 在 NDIS_OPEN_BLOCK中:

    TransferDataHandler
    SendCompleteHandler
   TransferDataCompleteHandler
    ReceiveHandler
    ReceivePacketHandler
    StatusHandler


       需要说的是,有些防火墙变聪明了,如果他们被别人hook的时候,他们会试图恢复他们的hook。例如,Outpost防火墙就检测这个并监视他们的hook,但仅仅像指针的安全那样。也许他们不认为会有剪接戏法?Outpost小组不知道,白帽子Sygate防火墙也能恢复他们的hook,但他恢复的仅仅是NDIS_OPEN_BLOCK.SendHandler和 NDIS_OPEN_BLOCK.SendPacketsHandler。那是奇怪的,因为因为他们hook了很多NDIS_PROTOCOL_BLOCK中的句柄:

    OpenAdapterCompleteHandler
   CloseAdapterCompleteHandler
   TransferDataCompleteHandler
    ReceiveHandler
    StatusHandler

    和 NDIS_OPEN_BLOCK 的hook:

    SendHandler
    TransferDataHandler
   TransferDataCompleteHandler
    ReceiveHandler
    ReceivePacketHandler
    SendPacketsHandler
    StatusHandler


       只有几种防火墙用中间层NDIS驱动来做NDIS级的保护。这是一个聪明的解决方案。例如,Look’n’Stop 和 Outpost 2008 防火墙用IM NDIS驱动。Outpost好的改进是在去年。但是现在绕过防火墙变的容易使因为没有HOOK,没有伎俩和没有任何未公布的特性被使用。现在你能粉碎所有的IM NDIS防火墙只是绕过他们。不需要扰乱防火墙接受和发送包的句柄,你也不用向他们发送包。总之,使用IM NDIS驱动是好的,众所周知的,已公布的,一个正确的保护系统不受外部攻击的方法。

        像你可能看到的那样,技术各个防火墙的技术是相似的,思路甚至能被盗用并且没有人会说你盗用了一个想法。好的方式是透过表面创新你的产品。不需去思考,不用产生想法,去反汇编、调试并且对它感兴趣。第二种主级别的防火墙基于TDI,传输数据接口能为内核传输协议栈提供更高级别的访问。Afd.sys,能解析winsock,经由tdi.sys(TDI层,上面层说过)与Windows TCP/IP栈(tcpip.sys)通信。于是,又几种方式和地方去安装hook并监视你的程序和网络通信。设置你的保护最好的地方正是在tcpip.sys设备,它能在协议栈的最上层解释执行:
        DeviceIp
        DeviceTcp
        DeviceUdp
       DeviceIPMULTICAST
       DeviceRawIp

        好的,你甚至能通过/Device/RawIp来戏弄一些人。对于阻止程序的一个访问网络的请求最好的方式(公开
的方式,也是重要的),是附加到这些设备上并监视他们。几乎所有的防火墙都这样做了,因为这是通知用户陌生程序要访问网络的好方法。例如,Look’n’Stop附加他的设备到tcpip.sys设备:
       DevicePcaTcpFilter -> DeviceTcp
       DevicePcaUdpFilter -> DeviceUdp
       DevicePcaRawIpFilter -> DeviceRawIp

        /Device/Ip在那里?不是足够的,我们需要确信,所有种类的连接需要被监视,或是他们恰恰通过了这个假冒的保护。
        你的看见这些设备在你的WinObj工具里:
       DeviceComodoRawIpFilter
       DeviceComodoUdpFilter
       DeviceComodoTcpFilter
       DeviceComodoIpFilter
        我希望你能猜到,Comodo防火墙是附加设备到相同名字的tcpip.sys设备。

        Outpost、Kerio、Jetico 防火墙, Norton InternetSecurity仅仅附加一个无名的设备到Tcp,Udp,Ip,RawIp,没有感兴趣的事。了解设备栈结构的人应该知道抛开这些附加设备使防火墙不再提示是相当容易的。你只需要找到tcpip.sys的DRIVER_OBJECT的指针,遍历DeviceObject列表,清空所有DEVICE_OBJECT的附加项。相当容易吧?但对对抗防火墙很有效,他们的防护程序就是在那附近。另一个脆弱防火墙的错误和夸大的广告。除了附加技术外,还有另一种有趣而复杂的的技术,但对恶意软件更有效,这就是MajorTable hook。大家都知道,当用户态程序想与驱动交互的时候,他通知要交互驱动的I/O管理器。I/O管理器产生一个IRP,并调用DRIVER_OBJECT.MajorTable[IRP_MJ_XXX]的句柄。就在tcpip.sys这,一些防火墙仅仅hook一个IRP_MJ_XXX句柄并监视所有调用,通过允许请求和拒绝禁止。找到一个真的句柄不是很容易,哈?几乎每个人都认为那不可能。寻找一些被hook的句柄的主要方法是,他必须被调用然后会被发现。通过hook Int 0x01,设置TF,防火墙句柄的所有调用,我们能发现一个防火墙要调用的真的句柄。简单,MajorTable-hooking技术被像ZoneAlarm这样的防火墙青睐,他是这样HOOK的:
    IRP_MJ_CREATE
    IRP_MJ_CLOSE
    IRP_MJ_DEVICE_CONTROL
   IRP_MJ_INTERNAL_DEVICE_CONTROL
    IRP_MJ_CLEANUP

        另一个局部hook的失败是,tcpip.sys仅有TCPDispatch() 和TCPDispatchInternalDeviceControl()2个IRP句柄,第一个被所有 MajorTable填充,把它从另一个句柄上移出时容易的。TCPDispatchInternalDeviceControl()你能通过使用另一个方法 (例如前面说的追踪方法和反汇编方法)来发现。Sygate防火墙喜欢HOOK这些句柄:
       IRP_MJ_CREATE
        IRP_MJ_CLOSE
       IRP_MJ_DEVICE_CONTROL
       IRP_MJ_INTERNAL_DEVICE_CONTROL

        PortsLock防火墙,hook所有MajorTable句柄。好主要,既不将TCPDispatch()也不将TCPDispatchInternalDeviceControl()给敌人。Tiny防火墙是hook下面的句柄。
       IRP_MJ_CREATE
       IRP_MJ_CLOSE
        IRP_MJ_DEVICE_CONTROL
       IRP_MJ_INTERNAL_DEVICE_CONTROL
       IRP_MJ_CLEANUP

        对于在一个防火墙中仅有这种类型的保护是不严重的,你不这样认为吗?我认为像PortsLock防火墙,Norton Internet Security,Comodo防火墙和其他有“防火墙”这个错误称号的,就像一些有着很漂亮界面的保护系统。恶意软件正在变的越来越猖獗,每天都有大量的ROOTKIT杯注册,更多老练的,先进的,比防火墙更底层的正在不断涌现。他们试图影响其他进程并隐匿其中。就像一个披着羊皮的狼。我谈到,injection, OpenProcess()/WriteProcessMemory()/CreateRemoteThread()和一个好的shellcode或一个self-mapped模块等都能透过防护与外部通信,而且工作的很好,也很容易编写,所有需要好的保护而不受其侵害。系统服务标提供内核函数的访问通道,他是通过调_KiSystemService,那是用用户模式和驱动来实现的。防火墙为了阻止这些动作使系统保持健壮,成功地hook了打开进程、写进程内存、创建远线程、进程、文件、文件编辑等函数。防火墙喜欢做这些,例如,ZoneAlarm防火墙hook以下系统服务:

     ZwConnectPort
    ZwCreateFile
    ZwCreateKey
    ZwCreatePort
    ZwCreateProcess
    ZwCreateProcessEx
    ZwCreateSection
    ZwCreateWaitablePort
    ZwDeleteFile
    ZwDeleteKey
    ZwDeleteValueKey
    ZwDuplicateObject
    ZwLoadKey
    ZwMapViewOfSection
    ZwOpenFile
    ZwOpenProcess
    ZwOpenThread
    ZwReplaceKey
   ZwRequestWaitReplyPort
    ZwRestoreKey
    ZwSecureConnectPort
    ZwSetInformationFile
    ZwSetSystemInformation
    ZwSetValueKey
    ZwTerminateProcess


       他监视对注册表,进程,驱动,文件的访问,并阻止自己被关闭。Outpost Firewall 4 hook更多的服务:

    ZwAssignProcessToJobObject
    ZwClose
    ZwCreateFile
    ZwCreateKey
    ZwCreateProcess
    ZwCreateProcessEx
    ZwCreateSymbolicLinkObject
    ZwCreateThread
    ZwDeleteFile
    ZwDeleteKey
    ZwDeleteValueKey
    ZwLoadDriver
    ZwMakeTemporaryObject
    ZwOpenFile
    ZwOpenKey
    ZwOpenProcess
   ZwProtectVirtualMemory
    ZwQueryDirectoryFile
    ZwQueryKey
    ZwQueryValueKey
    ZwReplaceKey
    ZwRestoreKey
    ZwSaveKey
    ZwSaveKeyEx
    ZwSetInformationFile
    ZwSetValueKey
    ZwTerminateProcess
    ZwTerminateThread
    ZwUnloadDriver
    ZwWriteVirtualMemory


       但事实上他仅用了他们的一半。他不关心驱动,你能加载任何你想要的,但他hook了ZwLoadDriver。更多的hook就更好吗?啊哈,对漏洞挖掘者来说更好。不是每个人都知道代码的质量怎样,它将要运行当我们调用ZwOpenKey时。我的系统将要蓝屏吗?另一个关于hook的例子是Kerio防火墙:

    ZwClose
    ZwCreateFile
    ZwCreateKey
    ZwCreateProcess
    ZwCreateProcessEx
    ZwCreateThread
    ZwDeleteFile
    ZwDeleteKey
    ZwDeleteValueKey
    ZwLoadDriver
    ZwMapViewOfSection
    ZwOpenFile
    ZwOpenKey
    ZwResumeThread
    ZwSetInformationFile
    ZwSetValueKey
    ZwTerminateProcess
    ZwWriteFile


       没看见ZwOpenProcess/ZwWriteVirtualMemory的hook。使用Kerio你能插入你想要的每个进程,包括允许的进程。Sygate所用的hook比其他的少:

    ZwTerminateProcess
    ZwMapViewOfSection
   ZwAllocateVirtualMemory
    ZwCreateThread
   ZwProtectVirtualMemory
    ZwWriteVirtualMemory


       他们认为能通过hookZwWriteVirtualMemory来保护系统。那是有BUG的:你能打开进程,并改变一些线程的context,几乎与 Jetico做的相同:

    ZwConnectPort
    ZwCreatePort
    ZwCreateThread
    ZwTerminateProcess
    ZwWriteVirtualMemory

       
        不是很有趣。Tiny防火墙做的最有趣:

    ZwCreateKey
    ZwCreateSection
    ZwOpenKey
    ZwSetInformationProcess
    ZwTerminateProcess


       你能这样说吗?:这是容易的对于通过ZwWriteVirtualMemory来插入一些东西。当然,但当此恶意行为发生时,用户将被通知。这是个愚蠢的小玩笑,对于在用户模式下来保护,Tiny防火墙载入他的UmxSbxExw.dll 到每个进程并hook许多进程通过安装每个函数开始的跳转:

kernel32.dll:
CreateProcessA
CreateProcessW
CreateRemoteThread
DebugActiveProcess
FreeLibrary
GetProcAddress
LoadLibraryExW
OpenThread
TerminateProcess
TerminateThread
WriteProcessMemory

user32.dll:
BroadcastSystemMessage
BroadcastSystemMessageA
BroadcastSystemMessageExA
BroadcastSystemMessageExW
BroadcastSystemMessageW
EndTask
ExitWindowsEx
OpenClipboard
PostMessageA
PostMessageW
PostThreadMessageA
PostThreadMessageW
SendDlgItemMessageA
SendDlgItemMessageW
SendMessageA
SendMessageCallbackA
SendMessageCallbackW
SendMessageTimeoutA
SendMessageTimeoutW
SendMessageW
SendNotifyMessageA
SendNotifyMessageW
SetUserObjectSecurity
SetWindowsHookA
SetWindowsHookExA
SetWindowsHookExW
SetWindowsHookW

advapi32.dll:
AbortSystemShutdownW
AdjustTokenPrivileges
ChangeServiceConfig2A
ChangeServiceConfig2W
ChangeServiceConfigA
ChangeServiceConfigW
ControlService
CreateProcessAsUserA
CreateProcessAsUserW
CreateProcessWithLogonW
CreateServiceA
CreateServiceW
DeleteService
EnumDependentServicesA
EnumDependentServicesW
EnumServicesStatusA
EnumServicesStatusExA
EnumServicesStatusExW
EnumServicesStatusW
InitiateSystemShutdownExW
InitiateSystemShutdownW
OpenSCManagerA
OpenSCManagerW
OpenServiceA
OpenServiceW
QueryServiceConfig2A
QueryServiceConfig2W
QueryServiceConfigA
QueryServiceConfigW
QueryServiceStatus
QueryServiceStatusEx
SetFileSecurityW
SetKernelObjectSecurity
SetNamedSecurityInfoW
SetSecurityInfo
SetServiceObjectSecurity
StartServiceA
StartServiceW


       哦,Tiny是个hook怪物。你能看见在kernel32.dll上的hook!WriteProcessMemory在他们的保护之下以防止被插入。Tiny防火墙团队认为那是一个很酷的保护方式,在一些不稳定的程序中他可能会挂掉。从那些进程中卸载掉他的Dll也不是件难事,恢复所有的函数入口就可以享受生活了。Outpost也喜欢这样做,他加载他的wl_hook.dll到应该被保护以防止恶意软件的每个进程。那是庞大的hook队列:

kernel32.dll:
CreateProcessA
CreateProcessW
CreateRemoteThread
DebugActiveProcess
WinExec

ntdll.dll:
LdrLoadDll
LdrUnloadDll
NtCreateThread
NtResumeProcess
NtResumeThread
NtSetContextThread
NtSetValueKey
NtSuspendProcess
NtSuspendThread
NtTerminateProcess
NtWriteVirtualMemory
ZwCreateThread
ZwResumeProcess
ZwResumeThread
ZwSetContextThread
ZwSetValueKey
ZwSuspendProcess
ZwSuspendThread
ZwTerminateProcess
ZwWriteVirtualMemory

user32.dll:
CallNextHookEx
ChangeDisplaySettingsExA
ChangeDisplaySettingsExW
DdeConnect
DdeConnectList
DdeInitializeA
DdeInitializeW
EndTask
ExitWindowsEx
FindWindowExA
FindWindowExW
PostMessageA
PostMessageW
SendInput
SendMessageA
SendMessageCallbackA
SendMessageCallbackW
SendMessageTimeoutA
SendMessageTimeoutW
SendMessageW
SendNotifyMessageA
SendNotifyMessageW
SetForegroundWindow
SetWindowPos
SetWindowsHookExA
SetWindowsHookExW


        那不是一个保护,是没有必要的代码。是的,他能抵制一些稀有恶意代码,但没有更多。一些防火墙不仅想被作为一个防火墙来使用,他们包含了一些有趣的特性像间谍软件或rootkit的检测程序。是的,他们工作了 ,这就产生了一个印象。在遇到调试之前的几分钟。一些防火墙试图监视模块的加载通过设置经由PsSetLoadImageNotiryRoutine()的例行检查。Jetico Firewall, Look’n’Stop Firewall, Tiny Firewall,ZoneAlarm Firewall, Outpost Firewall是这样做的。例如,当Outpost加载时,监视dnsapi.dll的加载,他通知用户一些程序试图使用DNS服务。这将会发生,当你将要调用gethostbyname()时,dnsapi.dll 会自动加载。不是很酷。重命名dnsapi.dll到xxx.dll,加载它,找到DnsQuery_A的指针,并使用它来解析,OutPost将会关闭。这是个糟糕的方式对于在这儿的保护。几乎在每个防火墙中,你都能发现很多无用的,无效的东西。有时,它帮助理解部分代码或给出一个例子函数命名,甚至你能发现一些调式信息。Look’n’Stop防火墙团队没有区分发布版和调试版,可能那就是他们为什么留下这些东西在这:

    push    offsetasc_187DC ; "f://dev//lns//2.05.cur//tdisys//w32api.c"
   push    offset aKegetcurren_23 ; "KeGetCurrentIrql() ==PASSIVE_LEVEL"
   call    ds:RtlAssert


        断言在调试构建时是有用的,但不是在发布版中。Tiny防火墙有很多奇怪的格式串日志:

 .text:00011608 aNbh0x08xMac0x0 db9,'nbh:0xX mac:0xX mah:0xX        pbc:0xX',0Dh,0Ah
.text:00011608 ; DATA XREF:HookedNdisOpenAdapter+273 o
.text:00011608 db9,'med:"%s"',0Dh,0Ah
.text:00011608 db9,'drv:"%s"',0Dh,0Ah
.text:00011608 db9,'dev:"%s"',0Dh,0Ah
.text:00011608 db9,'ada:"%s"',0
.text:00011661 align 4

我认为没人想因为这些奇怪的记录而看见蓝屏。ZoneAlarm也喜欢记录:
.text:0001A610 aUPacketSProtoS db '%uPacket %s: Proto: %s Flags: 0xlx Src: %2u.%2u.%2u.%2u '
.text:0001A610 ; DATA XREF:sub_1A693+119 o
.text:0001A610 db 'Dest: %2u.%2u.%2u.%2u',0

他尤其喜欢记录在发布版本中,当然。
.text:00025A84 aSFragTLxHLxPfl db '%sfrag: t=%lx h=%lx pflg=%lx subp=%lx sip=%d.%d.%d.%d dip=%'
.text:00025A84 ; DATA XREF:sub_25BAA+2D1 o
.text:00025A84 db 'd.%d.%d.%d id=%xf=%s%s%s off=%hu act=%lx',0Ah,0

我喜欢 ZoneAlarm,他给我一些函数的名字:
.text:00050250 aVsdatantVstdic db'VSDATANT:vsTdiClientRequestReceivePreProc(): FO=%p SE=%p RE#'
.text:00050250 ; DATA XREF: sub_502A6+D3o
.text:00050250 db '=%d IRP=%p :TIMEOUT(%u)',0Ah,0

Kerio防火墙团队不包含路径就不能生成他们的驱动:
.rdata:00433704aCProjectsNetsecuritytoolsFire db 'C:/Projects/netsecuritytools/FirewallSDK/Build.Release/4.3.'
.rdata:00433704 db'x/bin/Release/fwdrv.pdb',0

他们也这样记录:
.data:00434020 aFwdrvApicopyas db'FWDRV: ApiCopyAssociatedEndpoint: Local: %u.%u.%u.%u:%u Remo'
.data:00434020 ; DATA XREF:sub_401150+3B4 o
.data:00434020 db 'te:%u.%u.%u.%u:%u,SpeedIn: %u, SpeedOut: %u, PID: 0xX, A'
.data:00434020 db 'pp: [%s], Service:[%s]',0

并且真是有大量这样的记录:
.data:0043B1D4 aSPagedCodeCa_7 db '%s():Paged code called on IRQL %d',0


       我想说的是:不要紧,你喜欢记录多少,你应该移走这样的垃圾记录和垃圾代码在发布版中。越少的代码,越少的bug。也学下次蓝屏会刚好在那些糟糕测试并绑定调试信息的代码中。今年的首次揭幕是OnlineArmor防火墙。“Online Armor有一个非常好的机会,调者华尔兹就窃取了苏格兰时事通讯2008最佳软件防火墙的荣誉称号” 是的,在DriverVerifier下的首次测试就给我了一个蓝屏。真是很有趣,他在标准检查工具下挂掉了。 在里面你能发现IRP_MJ_DEVICE_CONTROL 句柄,那是处理所有与METHOD_NEITHER有关的IOCTLs。
        你知道ProbeForRead()/ProbeForWrite()?他们甚至不检查指针是否为空,这真是可笑,所有Windows用户的最好保护软件有如此多的问题。猜猜它能怎么样?一部分16进制的代码如下所示:

 int __stdcall DispatchDeviceControl(intDeviceObject, PIRP Irp)
{
  struct_IRP::$::$::$::$A02EC6A2CE86544F716F4825015773AC::_IO_STACK_LOCATION *Stack; //eax@1
  unsigned int Status; // edi@1
  PIRP _Irp; // esi@1
  void *InBuffer; // ecx@2
  int InBufferSize; // edi@2
  PVOID OutBuffer; // edx@2
  int OutBufferSize; // ebx@2
  int Length; // eax@3
  int ReturnLength; // [sp+8h][bp-4h]@1

  ReturnLength = 0;
  _Irp = Irp;
  Stack =Irp->Tail.Overlay.CurrentStackLocation;
  Status = 0xC00000BBu;
  if ( *(_BYTE *)Stack == 14 )
  {
    InBuffer = (void*)*((_DWORD *)Stack + 4);
    InBufferSize =*((_DWORD *)Stack + 2);
    OutBuffer =Irp->UserBuffer;
    OutBufferSize =*((_DWORD *)Stack + 1);
    Irp = (PIRP)*((_DWORD*)Stack + 3);
    Status =HandleRequest((int)Irp, InBuffer, InBufferSize, OutBuffer, OutBufferSize,&ReturnLength);
  }
  Length = ReturnLength;
  _Irp->IoStatus.Status =Status;
  _Irp->IoStatus.Information =Length;
  IofCompleteRequest(_Irp, 0);
  return Status;
}

int __stdcall HandleRequest(int Ioctl,void *InBuffer, int InBufferSize, void *OutBuffer, int OutBufferSize, int*ReturnLength)
{
  …
  if ( Ioctl == 0x830020EB )
  {
   sub_1484A((int)OutBuffer);
    *v6 = 28;
    return 0;
  }

在sub_1484A()里什么是如此的有趣?看看这里:
int __stdcall sub_1484A(int a1)
{
  int result; // eax@3
  CPPEH_RECORD ms_exc; // [sp+Ch][bp-18h]@1

  ms_exc.disabled = 0;
  if ( dword_16168 )
  {
    memcpy((void *)a1,(const void *)dword_161A8, 0x1Cu);
  }
  else
  {
    result = 0;
    memset((void *)a1, 0,0x1Cu);
  }
  return result;
}


       酷,在内核空间写些东西已经没有任何困难了,我们能制造一个DOS,甚至可以执行代码。我只是不想进一步发掘了,希望剩下的将被同道之一完成。如果我说的是真的话,似乎每个防火墙都能被绕过,没有东西能做到100%的保护。Rootkit,木马,蠕虫和其他恶意软件变的更加隐蔽、复杂,而且很难被发现。我不想给出任何关于选择哪款防火墙的建议,只是要确信,你用了一个功能强大的防火墙。

转载于:https://www.cnblogs.com/airoot/p/4131855.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值