WinDivert: Windows Packet Divert w/PureBasic samples.

Share your advanced PureBasic knowledge/code with the community.
User avatar
Thunder93
Addict
Addict
Posts: 1788
Joined: Tue Mar 21, 2006 12:31 am
Location: Canada

WinDivert: Windows Packet Divert w/PureBasic samples.

Post by Thunder93 »

JHPJHP recently posted topic here in 'Trick's 'n' Tip's' forum: PureBasic Interface to WinDivert

I don't want to confuse nor hijack his topic, so this reason I've created new one. Besides this more dedicated to conversions over from existing WinDivert sample applications sources .. like the one I'm posting today, netdump.

About WinDivert - http://reqrypt.org/windivert.html

WinDivert is a user-mode capture/sniffing/modification/blocking/re-injection package for Windows Vista, Windows Server 2008, Windows 7, and Windows 8. WinDivert can be used to implement user-mode packet filters, packet sniffers, firewalls, NAT, VPNs, tunneling applications, etc., without the need to write kernel-mode code.
  • The main features of the WinDivert are:
  • User-mode packet capture, sniffing, dropping, filtering, modification, re-injection, etc.
  • Simple, high-level, programming API.
  • Fully documented with sample programs.
  • Full IPv6 support.
  • Full loopback (localhost) support.
  • A modern WDF/WFP driver implementation.
  • Open source; Licensed under GNU Lesser General Public License (LGPL) version 3. See the License for more information.

WinDivert provides similar functionality to divert sockets from FreeBSD/MacOS, NETLINK sockets from Linux, and some commercial packages such as WinPkFilter for Windows. WinDivert also supports passive packet sniffing similar to Winpcap.



My PureBasic WinDivert sample package is available HERE.. PBWinDivert_samples.zip

Example utility source code... Netdump

Code: Select all

; /*
;  * DESCRIPTION:
;  * This is a simple traffic monitor.  It uses a WinDivert handle in SNIFF mode.
;  * The SNIFF mode copies packets And does Not block the original.
;  *
;  * usage: netdump.exe windivert-filter [priority]
;               netdump true         ; < -- Diverts all traffic (w/WINDIVERT_FLAG_SNIFF flag.)
;  */

IncludeFile "include\WinDivert_Header.pbi"
IncludeFile "include\WinDivert_Exit_Routine.pbi"
IncludeFile "include\Long2IP.pbi"
IncludeFile "include\IsPrint.pbi"

#MAXBUF  = $FFFF

Procedure mainTask()  
  Protected.i Handle, Console
  Protected.l I, packet_len
  Protected.w Priority = 0   
  Protected.s tcpSrcPort, tcpDstPort, tcpSeqNum, tcpAckNum, tcpHdrLength, tcpRSRV, tcpNS
  Protected.s tcpCWR, tcpECE, tcpURG, tcpACK, tcpPSH, tcpRST, tcpSYN, tcpFIN, tcpWin, tcpChksum, tcpUrgPtr
  Protected.s udpSrcPort, udpDstPort, udpHdrLength, udpChksum, pData1.a
  
  Protected.s IP_ver, IP_hdrlength, IP_tos, IP_length, IP_id, IP_fragResv, IP_fragsDF
  Protected.s IP_fragsMF, IP_fragOffset, IP_TTL, IP_Protocol, IP_chksum
  Protected.s IPv6_ver, IPv6_TrafficClass, IPv6_FlowLabel, IPv6_Length, IPv6_NextHdr.s, IPv6_HopLimit
  Protected.u IPv6_SrcAddr, IPv6_dstAddr
  
  Protected.s ICMP_Type, ICMP_Code, ICMP_Chksum, ICMP_Body
  Protected.s ICMPv6_Type, ICMPv6_Code, ICMPv6_Chksum, ICMPv6_Body  
  
  
  *Packet = AllocateMemory(#MAXBUF)
  SafeExit\Packet = *Packet
  
  addr.WINDIVERT_ADDRESS
  *ip_header.WINDIVERT_IPHDR
  *ipv6_header.WINDIVERT_IPV6HDR
  *icmp_header.WINDIVERT_ICMPHDR
  *icmpv6_header.WINDIVERT_ICMPV6HDR
  *tcp_header.WINDIVERT_TCPHDR
  *udp_header.WINDIVERT_UDPHDR
  
  If Not OpenConsole()
    MessageRequester("netdump", "Unable to open Console, program will now close", #PB_MessageRequester_Ok)
    End
  EndIf
  
  Select CountProgramParameters()
    Case 1
      filter$ + ProgramParameter(0)
    Case 2
      Priority = Val(ProgramParameter(1))      
    Default
      PrintN("Usage: netdump windivert-filter [priority]"+#CRLF$+#CRLF$+
             "Examples:"+#CRLF$+
             "    netdump true"+#CRLF$+
             "    netdump "+#DQUOTE$+"outbound and tcp.DstPort == 80"+#DQUOTE$+" 1000"+#CRLF$+
             "    netdump "+#DQUOTE$+"inbound and tcp.Syn"+#DQUOTE$+" -4000")
      ;filter$ = "outbound and tcp.DstPort == 80"
      Exit()      
  EndSelect
  
  ; // Get console For pretty colors.
  Console = GetStdHandle_(#STD_OUTPUT_HANDLE)
  SafeExit\Console = Console
  
  ; // Divert traffic matching the filter:    
  handle = WinDivertOpen(filter$, #WINDIVERT_LAYER_NETWORK, priority, #WINDIVERT_FLAG_SNIFF)
  SafeExit\hWndDivert = handle
  
  If handle = #INVALID_HANDLE_VALUE
    If GetLastError_() = #ERROR_INVALID_PARAMETER
      PrintN("error: filter syntax error")
      Exit()   
    Else          
      PrintN("error: failed To open the WinDivert device ("+Str(GetLastError_())+")")
      Exit()
    EndIf
  EndIf
  
  ; // Max-out the packet queue:  
  If Not WinDivertSetParam(handle, #WINDIVERT_PARAM_QUEUE_LEN, 8192)    
    PrintN("error: failed to set packet queue length ("+Str(GetLastError_())+")")
    Exit()
  ElseIf Not WinDivertSetParam(handle, #WINDIVERT_PARAM_QUEUE_TIME, 2048)
    PrintN("error: failed to set packet queue time ("+Str(GetLastError_())+")")
    Exit()
  EndIf  
  
  PrintN("Now waiting for network activity."+#CRLF$)
  
  ; Main Loop:
  Repeat   
    
    ;  // Read a matching packet.
    If Not WinDivertRecv(handle, *packet, MemorySize(*packet), @addr, @packet_len)
      PrintN("warning: failed to read packet ("+Str(GetLastError_())+")")
      Continue
    EndIf
    
    ; // Print info about the matching packet.    
    WinDivertHelperParsePacket(*packet, packet_len, @*ip_header, @*ipv6_header, @*icmp_header, @*icmpv6_header, @*tcp_header, @*udp_header, #Null, #Null)
    If Not *ip_header And Not *ipv6_header
      PrintN("warning: junk packet")
    EndIf
    
    ; // Dump packet info:    
    SetConsoleTextAttribute_(Console, #FOREGROUND_RED)
    PrintN(#CRLF$+"Packet [Direction="+Str(addr\Direction)+" IfIdx="+Str(addr\IfIdx)+" SubIfIdx="+Str(addr\SubIfIdx))
    If *ip_header
      IP_ver = Str(GET_ipVERSION(*ip_header))
      IP_hdrlength = Str(GET_ipHDRLENGTH(*ip_header))
      IP_tos = Str(ntohs_(PeekA(@*ip_header\TOS)))
      IP_length = Str(ntohs_(PeekU(@*ip_header\Length)))
      IP_id = RSet(Hex(ntohs_(PeekU(@*ip_header\Id))), 4, "0")
      IP_fragResv  = Str(WINDIVERT_IPHDR_GET_RESERVED(*ip_header))
      IP_fragsDF = Str(WINDIVERT_IPHDR_GET_DF(*ip_header))
      IP_fragsMF = Str(WINDIVERT_IPHDR_GET_MF(*ip_header))
      IP_fragOffset = Str(WINDIVERT_IPHDR_GET_FRAGOFF(*ip_header))
      IP_TTL = Str(PeekA(@*ip_header\TTL))
      IP_Protocol = Str(PeekA(@*ip_header\Protocol))
      IP_chksum = Hex(ntohs_(PeekU(@*ip_header\Checksum)))
      
      IP_srcAddr$ = Long2IP(ntohl_(PeekL(@*ip_header\SrcAddr)))
      IP_dstAddr$ = Long2IP(ntohl_(PeekL(@*ip_header\DstAddr)))
      
      SetConsoleTextAttribute_(Console, #FOREGROUND_GREEN | #FOREGROUND_RED)
      
      PrintN("IPv4 [Version=" + IP_ver + " HdrLength=" + IP_hdrlength +
             " TOS=" + IP_tos + " Length=" + IP_length + " Id=0x" + IP_id +
             " Reserved=" + IP_fragResv + " DF=" + IP_fragsDF + " MF=" + IP_fragsMF +
             " FragOff=" + IP_fragOffset + " TTL=" + IP_TTL + " Protocol=" + IP_Protocol +             
             " Checksum=0x" + IP_chksum +" SrcAddr="+IP_srcAddr$+" DstAddr="+IP_dstAddr$ + "]")
    EndIf
    
    If *ipv6_header
      IPv6_ver = Str(GET_IPv6VERSION(*ipv6_header))
      IPv6_TrafficClass = Str(WINDIVERT_IPV6HDR_GET_TRAFFICCLASS(*ipv6_header))
      IPv6_FlowLabel = Str(WINDIVERT_IPV6HDR_GET_FLOWLABEL(*ipv6_header))
      IPv6_Length = Str(ntohs_(PeekU(@*ipv6_header\Length)))
      IPv6_NextHdr = Str(PeekA(@*ipv6_header\NextHdr))
      IPv6_HopLimit = Str(PeekA(@*ipv6_header\HopLimit))      
      
      IPv6_srcAddr$ = "" : IPv6_dstAddr$ = ""
      For k = 0 To 7
        IPv6_srcAddr = PeekU(@*ipv6_header\SrcAddr[k])
        IPv6_dstAddr = PeekU(@*ipv6_header\DstAddr[k])
        
        If IPv6_srcAddr : IPv6_srcAddr$ + LCase(Hex(ntohs_(IPv6_srcAddr))) : EndIf
        If IPv6_dstAddr : IPv6_dstAddr$ + LCase(Hex(ntohs_(IPv6_dstAddr))) : EndIf
        
        If k = 0 : IPv6_srcAddr$ + "::" : IPv6_dstAddr$ + "::"
        ElseIf k < 7
          If IPv6_srcAddr : IPv6_srcAddr$ + ":" : EndIf
          If IPv6_dstAddr : IPv6_dstAddr$ + ":" : EndIf  
        EndIf
      Next
      
      SetConsoleTextAttribute_(Console, #FOREGROUND_GREEN | #FOREGROUND_RED)
      PrintN("IPv6 [Version=" + IPv6_ver + " TrafficClass=" + IPv6_TrafficClass + "  FlowLabel=" + IPv6_FlowLabel + 
             " Length=" + IPv6_length + " NextHdr=" + IPv6_NextHdr + " HopLimit=" + IPv6_HopLimit + " SrcAddr=" + IPv6_srcAddr$ +
             " DstAddr=" + IPv6_dstAddr$ + "]")
    EndIf
    
    If *icmp_header
      ICMP_Type = Str(PeekA(@*icmp_header\Type))
      ICMP_Code = Str(PeekA(@*icmp_header\Code))
      ICMP_Chksum = Hex(ntohs_(PeekU(@*icmp_header\Checksum)))
      ICMP_Body = Str(ntohl_(PeekL(@*icmp_header\Body)))      
      
      SetConsoleTextAttribute_(Console, #FOREGROUND_RED)
      PrintN("ICMP [Type=" + ICMP_Type + " Code=" + ICMP_Code + " Checksum=0x" + ICMP_Chksum + " Body=0x" + ICMP_Body + "]")
    EndIf
    
    If *icmpv6_header      
      ICMPv6_Type = Str(PeekA(@*icmpv6_header\Type))
      ICMPv6_Code = Str(PeekA(@*icmpv6_header\Code))
      ICMPv6_Chksum = Hex(ntohs_(PeekU(@*icmpv6_header\Checksum)))
      ICMPv6_Body = Str(ntohl_(PeekL(@*icmpv6_header\Body)))      
      
      SetConsoleTextAttribute_(Console, #FOREGROUND_RED)
      PrintN("ICMPV6 [Type=" + ICMPv6_Type + " Code=" + ICMPv6_Code + " Checksum=0x" + ICMPv6_Chksum + " Body=0x" + ICMPv6_Body + "]")
    EndIf
    
    If *tcp_header
      tcpSrcPort = Str(ntohs_(PeekU(@*tcp_header\SrcPort)))
      tcpDstPort = Str(ntohs_(PeekU(@*tcp_header\DstPort)))
      tcpSeqNum = Str(ntohl_(PeekL(@*tcp_header\SeqNum)) & $FFFFFFFF)
      tcpAckNum = Str(ntohl_(PeekL(@*tcp_header\AckNum)) & $FFFFFFFF)
      tcpHdrLength = Str(GET_tcpHDRLENGTH(*tcp_header))
      tcpRSRV = Str(GET_tcpRESERVED(*tcp_header))
      
      tcpNS = Str(GET_tcpNS(*tcp_header))
      tcpCWR = Str(GET_tcpCWR(*tcp_header))
      tcpECE = Str(GET_tcpECE(*tcp_header))
      tcpURG = Str(GET_tcpURG(*tcp_header))
      tcpACK = Str(GET_tcpACK(*tcp_header))
      tcpPSH = Str(GET_tcpPSH(*tcp_header))
      tcpRST = Str(GET_tcpRST(*tcp_header))
      tcpSYN = Str(GET_tcpSYN(*tcp_header))
      tcpFIN = Str(GET_tcpFIN(*tcp_header))
      tcpWin = Str(ntohs_(PeekU(@*tcp_header\Window)))
      tcpChksum = Hex(ntohs_(PeekU(@*tcp_header\Checksum)))
      tcpUrgPtr = Str(ntohs_(PeekU(@*tcp_header\UrgPtr)))
      
      SetConsoleTextAttribute_(Console, #FOREGROUND_GREEN)
      PrintN("TCP [SrcPort=" + tcpSrcPort + " DstPort=" + tcpDstPort + " SeqNum=" + tcpSeqNum + " AckNum=" + tcpAckNum +
             " HdrLength=" + tcpHdrLength + " Reserved=" + tcpRSRV + " Flags:[NS="+tcpNS + " CWR=" + tcpCWR + " ECE=" + tcpECE + " URG=" + tcpURG +
             " ACK=" + tcpACK + " PSH=" + tcpPSH + " RST=" + tcpRST + " SYN=" + tcpSYN + " FIN=" + tcpFIN +
             "] Window=" + tcpWin + " Checksum=0x" + tcpChksum + " UrgPtr=" + tcpUrgPtr + "]")      
    EndIf
    
    If *udp_header
      udpSrcPort = Str(ntohs_(PeekU(@*udp_header\SrcPort)))
      udpDstPort = Str(ntohs_(PeekU(@*udp_header\DstPort)))
      udpHdrLength = Str(ntohs_(PeekU(@*udp_header\Length)))
      udpChksum = Hex(ntohs_(PeekU(@*udp_header\Checksum)))
      
      SetConsoleTextAttribute_(Console, #FOREGROUND_GREEN)
      PrintN("UDP [SrcPort=" + udpSrcPort + " DstPort=" + udpDstPort + " Length=" + udpHdrLength + " Checksum=0x" + udpChksum + "]")
    EndIf    
    
    SetConsoleTextAttribute_(Console, #FOREGROUND_GREEN | #FOREGROUND_BLUE)
    
    pData$ = ""
    For i = 0 To packet_len-1
      If (i % 20) = 0
        pData$ + #CRLF$ + "          "
      EndIf
      pData$ + RSet(Hex(PeekA(*Packet+i)), 2, "0")
    Next
    PrintN(pData$)
    
    SetConsoleTextAttribute_(Console, #FOREGROUND_RED | #FOREGROUND_BLUE)
    
    pData$ = "" : pData = 0
    For i = 0 To packet_len-1
      If (i % 40) = 0
        pData$ + #CRLF$ + "          "
      EndIf
      pData = PeekA(*Packet+i)
      
      If IsPrint(pData) : pData$ + Chr(PeekA(*Packet+i))
      Else
        pData$ + "."
      EndIf
      
    Next    
    PrintN(pData$+#CRLF$)
    
  ForEver
EndProcedure

mainTask()

Changelog

Code: Select all

Rev #5 (Updated on Tuesday Dec 2, 2014)

* Added netfilter.pb   (Credits to the PureBasic community. Special thanks to infratec & JHPJHP for the aid.)
* Tweaks to existing projects.

-----------
Rev #4  (Updated on Sunday Nov 23, 2014)

* netdump.pb (location: parent)
     - More code beautification.

* GetTCPFlags_.pbi (formely known as GetTCPFlags_STR.pbi, Location: \Include\)
     - Revamped the old procedure.


-----------
Rev #3  (Updated on Friday Nov 21, 2014)

* Updated to WinDivert 1.1.7 Library and required driver files. (Enhancements to IPv6 support)

* WinDivert_Header.pbi (location: \Includes\)
     - Updated existing PB-Specific Macros labelling.
     - PureBasic - Specific Macros additions (e.g, .. GET_tcpSYN(), SET_tcpSYN, UNSET_tcpSYN.)
     - Particular WINDIVERT_TCPHDR Structure Field names been changed.

* netdump.pb (location: parent)
     - Match changes made in WinDivert_Header.pbi file.
     - Beautified the code.
     - TCP Header logging now defines three more tcp flags (NS, CWR, ECE)


-----------
Rev #2  (Updated on Wed Nov 19, 2014

* WinDivert_Header.pbi
     - Added two additional PureBasic - Specific Macros.
        ..WINDIVERT_IPHDR_SET_VERSION(), INDIVERT_IPHDR_SET_HDRLENGTH()

* netdump.pb
     - N/A


-----------
Rev #1  (Updated on Wed Nov 16, 2014)

* WinDivert_Header.pbi
     - Updates to the Macros labelling. Couple still was using the old WinDivert Macro names.
     - Added two additional PureBasic - Specific Macro.
        ..WINDIVERT_IPHDR_GET_VERSION(), WINDIVERT_IPHDR_GET_HDRLENGTH()

* netdump.pb
     - Now using the two new WinDivert Header file Macros additions.
         ..WINDIVERT_IPHDR_GET_VERSION(), WINDIVERT_IPHDR_GET_HDRLENGTH()
     - Adjustment to RSet() on IP Header ID retrieval, showing couple extra characters.
Last edited by Thunder93 on Tue Dec 02, 2014 8:31 am, edited 6 times in total.
ʽʽSuccess is almost totally dependent upon drive and persistence. The extra energy required to make another effort or try another approach is the secret of winning.ʾʾ --Dennis Waitley
User avatar
Thunder93
Addict
Addict
Posts: 1788
Joined: Tue Mar 21, 2006 12:31 am
Location: Canada

Re: WinDivert: Windows Packet Divert

Post by Thunder93 »

[reserved thread]
Last edited by Thunder93 on Sun Nov 23, 2014 4:25 am, edited 7 times in total.
ʽʽSuccess is almost totally dependent upon drive and persistence. The extra energy required to make another effort or try another approach is the secret of winning.ʾʾ --Dennis Waitley
User avatar
Thunder93
Addict
Addict
Posts: 1788
Joined: Tue Mar 21, 2006 12:31 am
Location: Canada

Re: WinDivert: Windows Packet Divert

Post by Thunder93 »

[reserved thread]
Last edited by Thunder93 on Sun Nov 23, 2014 4:25 am, edited 1 time in total.
ʽʽSuccess is almost totally dependent upon drive and persistence. The extra energy required to make another effort or try another approach is the secret of winning.ʾʾ --Dennis Waitley
User avatar
Thunder93
Addict
Addict
Posts: 1788
Joined: Tue Mar 21, 2006 12:31 am
Location: Canada

Re: WinDivert: Windows Packet Divert

Post by Thunder93 »

When time permits, I'll do the other two WinDivert sample applications. If someone wants to do the other two and post it here.. that's also alright. Keeping in mind I'm focusing on keeping conversion as close as possible with the original samples. :wink:

If you have created different applications, posting the source codes here for those is also welcome. :)
ʽʽSuccess is almost totally dependent upon drive and persistence. The extra energy required to make another effort or try another approach is the secret of winning.ʾʾ --Dennis Waitley
JHPJHP
Addict
Addict
Posts: 2129
Joined: Sat Oct 09, 2010 3:47 am
Contact:

Re: WinDivert: Windows Packet Divert

Post by JHPJHP »

Hi Thunder93,

I'm glad you've taken your own advice to continue this project, we'd both agreed it's worthwhile.

Best of luck.
User avatar
Thunder93
Addict
Addict
Posts: 1788
Joined: Tue Mar 21, 2006 12:31 am
Location: Canada

Re: WinDivert: Windows Packet Divert

Post by Thunder93 »

Thanks JHPJHP.

I have always seen great potential with WinDivert for the PB community, like you have. I'm interested and really enjoy messing with WinDivert. :mrgreen:
ʽʽSuccess is almost totally dependent upon drive and persistence. The extra energy required to make another effort or try another approach is the secret of winning.ʾʾ --Dennis Waitley
User avatar
Thunder93
Addict
Addict
Posts: 1788
Joined: Tue Mar 21, 2006 12:31 am
Location: Canada

Re: WinDivert: Windows Packet Divert w/PureBasic samples.

Post by Thunder93 »

I have updated my PureBasic WinDivert samples, including WinDivert Lib and two required driver files. Now is available through maintained download, zip archived.. for people's convenience. Information included via original post.
ʽʽSuccess is almost totally dependent upon drive and persistence. The extra energy required to make another effort or try another approach is the secret of winning.ʾʾ --Dennis Waitley
JHPJHP
Addict
Addict
Posts: 2129
Joined: Sat Oct 09, 2010 3:47 am
Contact:

Re: WinDivert: Windows Packet Divert w/PureBasic samples.

Post by JHPJHP »

Great job Thunder93, you're really knocking this one out of the park.
User avatar
Thunder93
Addict
Addict
Posts: 1788
Joined: Tue Mar 21, 2006 12:31 am
Location: Canada

Re: WinDivert: Windows Packet Divert w/PureBasic samples.

Post by Thunder93 »

Thanks JHPJHP! :mrgreen:
ʽʽSuccess is almost totally dependent upon drive and persistence. The extra energy required to make another effort or try another approach is the secret of winning.ʾʾ --Dennis Waitley
User avatar
Thunder93
Addict
Addict
Posts: 1788
Joined: Tue Mar 21, 2006 12:31 am
Location: Canada

Re: WinDivert: Windows Packet Divert w/PureBasic samples.

Post by Thunder93 »

Updated package. Mainly to include the converted netfilter.c
ʽʽSuccess is almost totally dependent upon drive and persistence. The extra energy required to make another effort or try another approach is the secret of winning.ʾʾ --Dennis Waitley
LinXP
New User
New User
Posts: 7
Joined: Mon May 07, 2018 9:58 am

Re: WinDivert: Windows Packet Divert w/PureBasic samples.

Post by LinXP »

Please reupload PBWinDivert_samples.zip
User avatar
Techie42
User
User
Posts: 58
Joined: Sun Oct 30, 2005 12:28 pm
Location: UK (Berkshire)

Re: WinDivert: Windows Packet Divert w/PureBasic samples.

Post by Techie42 »

Does anyone have the original files mentioned in the top item for this post please?
If the temperature today was 0 degrees, how can it be twice as cold tomorrow?
User avatar
Zebuddi123
Enthusiast
Enthusiast
Posts: 794
Joined: Wed Feb 01, 2012 3:30 pm
Location: Nottinghamshire UK
Contact:

Re: WinDivert: Windows Packet Divert w/PureBasic samples.

Post by Zebuddi123 »

malleo, caput, bang. Ego, comprehendunt in tempore
User avatar
Techie42
User
User
Posts: 58
Joined: Sun Oct 30, 2005 12:28 pm
Location: UK (Berkshire)

Re: WinDivert: Windows Packet Divert w/PureBasic samples.

Post by Techie42 »

Zebuddi123 wrote:@ Techie42 https://www.dropbox.com/s/ghov81cik70y1 ... s.zip?dl=0
Zebuddi. :)
Thank you very much :D (sorry for my tardiness - better late than never :wink: )
If the temperature today was 0 degrees, how can it be twice as cold tomorrow?
Post Reply