private unsafe void RunDiversion()
        {
            var packet = new WinDivertBuffer();

            var addr = new WinDivertAddress();

            uint recvLength = 0;

            NativeOverlapped recvOverlapped;

            IntPtr recvEvent = IntPtr.Zero;

            recvEvent = WinDivertSharp.WinAPI.Kernel32.CreateEvent(IntPtr.Zero, false, false, IntPtr.Zero);

            if (recvEvent == IntPtr.Zero || recvEvent == new IntPtr(-1))
            {
                m_logger.Error("Failed to initialize receive IO event.");
                return;
            }

            uint recvAsyncIoLen = 0;

            bool isLocalIpv4    = false;
            bool modifiedPacket = false;
            bool dropPacket     = false;

            Span <byte> payloadBufferPtr = null;

            while (m_running)
            {
                try
                {
                    payloadBufferPtr = null;

                    recvLength = 0;
                    addr.Reset();
                    modifiedPacket = false;
                    dropPacket     = false;
                    isLocalIpv4    = false;
                    recvAsyncIoLen = 0;

                    recvOverlapped = new NativeOverlapped();
                    WinAPI.Kernel32.ResetEvent(recvEvent);

                    recvOverlapped.EventHandle = recvEvent;

                    #region Packet Reading Code

                    uint addrLen = (uint)sizeof(WinDivertAddress);
                    if (!WinDivert.WinDivertRecvEx(m_diversionHandle, packet, 0, out recvLength, out addr, ref addrLen, ref recvOverlapped))
                    {
                        var error = Marshal.GetLastWin32Error();

                        // 997 == ERROR_IO_PENDING
                        if (error != 997)
                        {
                            m_logger.Warn(string.Format("Unknown IO error ID {0}while awaiting overlapped result.", error));
                            continue;
                        }

                        // 258 == WAIT_TIMEOUT
                        while (m_running && WinDivertSharp.WinAPI.Kernel32.WaitForSingleObject(recvEvent, 1000) == (uint)WaitForSingleObjectResult.WaitTimeout)
                        {
                        }

                        if (!WinDivertSharp.WinAPI.Kernel32.GetOverlappedResult(m_diversionHandle, ref recvOverlapped, ref recvAsyncIoLen, false))
                        {
                            m_logger.Warn("Failed to get overlapped result.");
                            continue;
                        }

                        recvLength = recvAsyncIoLen;
                    }

                    #endregion Packet Reading Code

                    WinDivertParseResult parseResult = null;
                    if (addr.Outbound)
                    {
                        parseResult = WinDivert.WinDivertHelperParsePacket(packet, recvLength);

                        #region New TCP Connection Detection

                        if (parseResult.TcpHeader != null && parseResult.TcpHeader->Syn > 0)
                        {
                            // Brand new outbound connection. Grab the PID of the process holding this
                            // port and map it.
                            if (parseResult.IPv4Header != null)
                            {
                                var connInfo = GetLocalPacketInfo(parseResult.TcpHeader->SrcPort, parseResult.IPv4Header->SrcAddr);

                                HandleNewTcpConnection(connInfo, parseResult.TcpHeader, false);

                                // Handle the special case of entirely blocking internet for this application/port.
                                if (Volatile.Read(ref m_v4ShouldFilter[parseResult.TcpHeader->SrcPort]) == (int)FirewallAction.BlockInternetForApplication)
                                {
                                    dropPacket = true;
                                }
                            }

                            if (parseResult.IPv6Header != null)
                            {
                                var connInfo = GetLocalPacketInfo(parseResult.TcpHeader->SrcPort, parseResult.IPv6Header->SrcAddr);

                                HandleNewTcpConnection(connInfo, parseResult.TcpHeader, true);

                                // Handle the special case of entirely blocking internet for this application/port.
                                if (Volatile.Read(ref m_v6ShouldFilter[parseResult.TcpHeader->SrcPort]) == (int)FirewallAction.BlockInternetForApplication)
                                {
                                    dropPacket = true;
                                }
                            }
                        }

                        // Now that we've processed any potentially new connections, let's see if the
                        // packet belongs to an existing flow that was marked to be blocked.

                        // Check if this packet belongs to an IPV4 flow marked for blocking.
                        if (parseResult.IPv4Header != null)
                        {
                            int srcPortAction = Volatile.Read(ref m_v4ShouldFilter[parseResult.TcpHeader->SrcPort]);

                            // Handle the special case of entirely blocking internet for this application/port.
                            if (srcPortAction == (int)FirewallAction.BlockInternetForApplication)
                            {
                                dropPacket = true;
                            }
                        }

                        // Check if this packet belongs to an IPV6 flow marked for blocking.
                        if (!dropPacket && parseResult.IPv6Header != null)
                        {
                            int srcPortAction = Volatile.Read(ref m_v6ShouldFilter[parseResult.TcpHeader->SrcPort]);

                            // Handle the special case of entirely blocking internet for this application/port.
                            if (srcPortAction == (int)FirewallAction.BlockInternetForApplication)
                            {
                                dropPacket = true;
                            }
                        }

                        #endregion New TCP Connection Detection

                        // I put the checks for ipv4 and ipv6 as a double if statement rather than an
                        // else if because I'm not sure how that would affect dual-mode sockets. Perhaps
                        // it's possible for both headers to be defined. Probably not, but since I don't
                        // know, I err on the side of awesome, or uhh, something like that.

                        // We check local packets for TOR/SOCKS packets here. However, if we don't find
                        // something we want to block on local addresses, then we want to skip these for
                        // the rest of the filtering and just let them through.

                        if (dropPacket == false && parseResult.IPv4Header != null && parseResult.TcpHeader != null)
                        {
                            // Let's explain the weird arcane logic here. First, we check if the current
                            // flow should even be filtered. We do this, because there's a good chance
                            // that this flow belongs to our proxy's connections, which we never want to
                            // filter. If we didn't check this, then we would end up setting the
                            // isLocalIpv4 flag to true on every single one of our proxy's connections,
                            // and clients would never get packets ever because with that flag set, the
                            // direction of the packets wouldn't be sorted.
                            //
                            // So, we check this, ensure it's actually something we want to filter. Then,
                            // we check if the packet is destined for a local address. We set the flag
                            // accordingly, and if true, then we will allow these packets to go out uninterrupted.
                            //
                            // If false, who cares. Regardless of true or false, we check to see if this
                            // is a TOR/SOCKS4/5 proxy CONNECT, and drop it if it is.
                            //
                            // Also note, by letting local/private address destined packets go, we also
                            // solve the problem of private TLS connections using private TLS self signed
                            // certs, such as logging into one's router. If we didn't do this check and
                            // let these through, we would break such connections.

                            if (Volatile.Read(ref m_v4ShouldFilter[parseResult.TcpHeader->SrcPort]) == (int)FirewallAction.FilterApplication)
                            {
                                isLocalIpv4 = parseResult.IPv4Header->DstAddr.IsPrivateIpv4Address();

                                if (isLocalIpv4)
                                {
#if !ENGINE_NO_BLOCK_TOR
                                    byte[] payload = null;
                                    if (payloadBufferPtr != null && payloadBufferPtr.Length > 0)
                                    {
                                        payload = payloadBufferPtr.ToArray();

                                        if (payload.IsSocksProxyConnect())
                                        {
                                            m_logger.Info("Blocking SOCKS proxy connect.");
                                            continue;
                                        }
                                    }
#endif
                                }
                            }
                        }

                        if (dropPacket == false && !isLocalIpv4)
                        {
                            if (parseResult.IPv4Header != null && parseResult.TcpHeader != null)
                            {
                                if (parseResult.TcpHeader->SrcPort == m_v4HttpProxyPort || parseResult.TcpHeader->SrcPort == m_v4HttpsProxyPort)
                                {
                                    // Means that the data is originating from our proxy in response to a
                                    // client's request, which means it was originally meant to go
                                    // somewhere else. We need to reorder the data such as the src and
                                    // destination ports and addresses and divert it back inbound, so it
                                    // appears to be an inbound response from the original external server.

                                    modifiedPacket = true;

                                    parseResult.TcpHeader->SrcPort = Volatile.Read(ref m_v4ReturnPorts[parseResult.TcpHeader->DstPort]);
                                    addr.Outbound = false;

                                    var dstIp = parseResult.IPv4Header->DstAddr;
                                    parseResult.IPv4Header->DstAddr = parseResult.IPv4Header->SrcAddr;
                                    parseResult.IPv4Header->SrcAddr = dstIp;
                                }
                                else
                                {
                                    // This means outbound traffic has been captured that we know for
                                    // sure is not coming from our proxy in response to a client, but we
                                    // don't know that it isn't the upstream portion of our proxy trying
                                    // to fetch a response on behalf of a connected client. So, we need
                                    // to check if we have a cached result for information about the
                                    // binary generating the outbound traffic for two reasons.
                                    //
                                    // First, we need to ensure that it's not us, obviously. Secondly, we
                                    // need to ensure that the binary has been granted firewall access to
                                    // generate outbound traffic.

                                    if (Volatile.Read(ref m_v4ShouldFilter[parseResult.TcpHeader->SrcPort]) == (int)FirewallAction.FilterApplication)
                                    {
                                        modifiedPacket = true;

                                        // If the process was identified as a process that is permitted
                                        // to access the internet, and is not a system process or
                                        // ourselves, then we divert its packets back inbound to the
                                        // local machine, changing the destination port appropriately.
                                        var dstAddress = parseResult.IPv4Header->DstAddr;

                                        parseResult.IPv4Header->DstAddr = parseResult.IPv4Header->SrcAddr;
                                        parseResult.IPv4Header->SrcAddr = dstAddress;

                                        addr.Outbound = false;

                                        Volatile.Write(ref m_v4ReturnPorts[parseResult.TcpHeader->SrcPort], parseResult.TcpHeader->DstPort);


                                        GoproxyWrapper.GoProxy.Instance.SetDestPortForLocalPort(parseResult.TcpHeader->SrcPort, parseResult.TcpHeader->DstPort);

                                        // Unless we know for sure this is an encrypted connection via
                                        // the HTTP port, we should always default to sending to the
                                        // non-encrypted listener.
                                        var encrypted = Volatile.Read(ref m_v4EncryptionHints[parseResult.TcpHeader->SrcPort]);

                                        parseResult.TcpHeader->DstPort = encrypted ? m_v4HttpsProxyPort : m_v4HttpProxyPort;
                                    }
                                }
                            }

                            // The ipV6 version works exactly the same, just with larger storage for the
                            // larger addresses. Look at the ipv4 version notes for clarification on anything.
                            if (parseResult.IPv6Header != null && parseResult.TcpHeader != null)
                            {
                                if (parseResult.TcpHeader->SrcPort == m_v6HttpProxyPort || parseResult.TcpHeader->SrcPort == m_v6HttpsProxyPort)
                                {
                                    modifiedPacket = true;

                                    parseResult.TcpHeader->SrcPort = Volatile.Read(ref m_v6ReturnPorts[parseResult.TcpHeader->DstPort]);
                                    addr.Outbound = false;

                                    var dstIp = parseResult.IPv6Header->DstAddr;
                                    parseResult.IPv6Header->DstAddr = parseResult.IPv6Header->SrcAddr;
                                    parseResult.IPv6Header->SrcAddr = dstIp;
                                }
                                else
                                {
                                    if (Volatile.Read(ref m_v6ShouldFilter[parseResult.TcpHeader->SrcPort]) == (int)FirewallAction.FilterApplication)
                                    {
                                        modifiedPacket = true;

                                        // If the process was identified as a process that is permitted
                                        // to access the internet, and is not a system process or
                                        // ourselves, then we divert its packets back inbound to the
                                        // local machine, changing the destination port appropriately.
                                        var dstAddress = parseResult.IPv6Header->DstAddr;

                                        parseResult.IPv6Header->DstAddr = parseResult.IPv6Header->SrcAddr;
                                        parseResult.IPv6Header->SrcAddr = dstAddress;
                                        addr.Outbound = false;

                                        Volatile.Write(ref m_v6ReturnPorts[parseResult.TcpHeader->SrcPort], parseResult.TcpHeader->DstPort);

                                        GoproxyWrapper.GoProxy.Instance.SetDestPortForLocalPort(parseResult.TcpHeader->SrcPort, parseResult.TcpHeader->DstPort);
                                        // Unless we know for sure this is an encrypted connection via
                                        // the HTTP port, we should always default to sending to the
                                        // non-encrypted listener.
                                        var encrypted = Volatile.Read(ref m_v6EncryptionHints[parseResult.TcpHeader->SrcPort]);

                                        parseResult.TcpHeader->DstPort = encrypted ? m_v6HttpsProxyPort : m_v6HttpProxyPort;
                                    }
                                }
                            }
                        } // if(!isLocalIpv4)
                    }     // if (addr.Direction == WINDIVERT_DIRECTION_OUTBOUND)

                    if (!dropPacket)
                    {
                        if (modifiedPacket)
                        {
                            var sumsCalculated = WinDivert.WinDivertHelperCalcChecksums(packet, recvLength, ref addr, WinDivertChecksumHelperParam.All);

                            if (sumsCalculated <= 0)
                            {
                                m_logger.Warn("Modified packet reported that no checksums were calculated");
                            }
                        }

                        WinDivert.WinDivertSendEx(m_diversionHandle, packet, recvLength, 0, ref addr);
                    }
                    else
                    {
                        Console.WriteLine("dropping a packet");
                    }
                }
                catch (Exception loopException)
                {
                    m_logger.Error(loopException);
                }
            } // while (m_running)
        }
Ejemplo n.º 2
0
        private static void ProcessTest(IntPtr injectHandle, string filter, WinDivertBuffer packet, bool shouldMatch)
        {
            // Ensure the correct checksum:
            WinDivert.WinDivertHelperCalcChecksums(packet, packet.Length, WinDivertChecksumHelperParam.All);

            var buf = new WinDivertBuffer();
            NativeOverlapped overlapped = new NativeOverlapped();

            uint iolen = 0, errorPos = 0;

            IntPtr handle  = IntPtr.Zero;
            IntPtr handle0 = IntPtr.Zero;
            IntPtr evt     = IntPtr.Zero;

            try
            {
                // Verify the test data.
                if (!WinDivert.WinDivertHelperCheckFilter(filter, WinDivertLayer.Network, out string errorMessage, ref errorPos))
                {
                    Assert.Fail("Filter string is invalid at position {0}.\nError Message:\n{1}", errorPos, errorMessage);
                }

                WinDivertAddress addr = new WinDivertAddress();
                addr.Reset();
                addr.Direction = WinDivertDirection.Outbound;

                // Test the filter string.
                if (WinDivert.WinDivertHelperEvalFilter(filter, WinDivertLayer.Network, packet, packet.Length, ref addr) != shouldMatch)
                {
                    Assert.Fail("Filter doesn't match the given packet.\nFilter:\n{0}", filter);
                }
                handle = WinDivert.WinDivertOpen(filter, WinDivertLayer.Network, 0, WinDivertOpenFlags.None);

                // Open a WinDivert handle for the given filter.
                Assert.AreNotEqual(handle, IntPtr.Zero, "Failed to open WinDivert handle for filter:\n{0}", filter);

                if (!shouldMatch)
                {
                    // Catch non-matching packets:
                    handle0 = handle;
                    handle  = WinDivert.WinDivertOpen("true", WinDivertLayer.Network, 33, 0);
                    Assert.AreNotEqual(handle, IntPtr.Zero, "Failed to open WinDivert handle with Win32 error {0}.", Marshal.GetLastWin32Error());
                }
                // Inject the packet.
                if (!WinDivert.WinDivertSend(injectHandle, packet, packet.Length, ref addr))
                {
                    Assert.Fail("Failed to inject test packet with Win32 error {0}.", Marshal.GetLastWin32Error());

                    // Wait for the packet to arrive.
                    // NOTE: This may fail, so set a generous time-out of 250ms.
                    overlapped = new NativeOverlapped();
                    evt        = Kernel32.CreateEvent(IntPtr.Zero, false, false, IntPtr.Zero);

                    Assert.AreNotEqual(evt, IntPtr.Zero, "Failed to create event with Win32 error {0}.", Marshal.GetLastWin32Error());
                    Assert.AreNotEqual(evt, new IntPtr(-1), "Failed to create event with Win32 error {0}.", Marshal.GetLastWin32Error());

                    overlapped.EventHandle = evt;

                    //if (!WinDivert.WinDivertRecv(handle, buf, ref addr, ref iolen))
                    if (!WinDivert.WinDivertRecvEx(handle, buf, 0, ref addr, ref iolen, ref overlapped))
                    {
                        if (Marshal.GetLastWin32Error() != 997) // ERROR_IO_PENDING
                        {
                            Assert.Fail("Failed to read packet from WinDivert with Win32 error {0}.", Marshal.GetLastWin32Error());

                            switch (Kernel32.WaitForSingleObject(evt, 250))
                            {
                            case (uint)WaitForSingleObjectResult.WaitObject0:
                            {
                            }
                            break;

                            case (uint)WaitForSingleObjectResult.WaitTimeout:
                            {
                                Assert.Fail("Failed to read packet from WinDivert by timeout with Win32 error {0}.", Marshal.GetLastWin32Error());
                            }
                            break;

                            default:
                            {
                                Assert.Fail("Failed to read packet from WinDivert with Win32 error {0}.", Marshal.GetLastWin32Error());
                            }
                            break;
                            }

                            if (!Kernel32.GetOverlappedResult(handle, ref overlapped, ref iolen, true))
                            {
                                Assert.Fail("Failed get overlapped result from WinDivert with Win32 error {0}.", Marshal.GetLastWin32Error());
                            }
                        }
                    }
                    if (addr.Direction == WinDivertDirection.Outbound)
                    {
                        WinDivert.WinDivertHelperCalcChecksums(buf, iolen, WinDivertChecksumHelperParam.All);
                    }
                    // Verify that the packet is the same as the origin.
                    if (iolen != packet.Length)
                    {
                        Assert.Fail("Packet length mismatch. Expected {0}, got {1}.", packet.Length, iolen);

                        for (int i = 0; i < iolen; ++i)
                        {
                            if (packet[i] != buf[i])
                            {
                                Assert.Fail("Packet data mismatch. Expected byte at index {0} to be {1}, instead the value was {2}.", i, packet[i].ToString("X2"), buf[i].ToString("X2"));
                            }
                        }
                    }

                    // (5) Clean-up:
                    if (!WinDivert.WinDivertClose(handle))
                    {
                        Assert.Fail("Failed to close WinDivert handle with Win32 error {0}.", Marshal.GetLastWin32Error());
                    }

                    if (handle0 != IntPtr.Zero)
                    {
                        if (!WinDivert.WinDivertClose(handle0))
                        {
                            Assert.Fail("Failed to close WinDivert handle with Win32 error {0}.", Marshal.GetLastWin32Error());
                        }
                    }

                    Kernel32.CloseHandle(evt);
                }
            }
            finally
            {
                if (handle0 != IntPtr.Zero)
                {
                    WinDivert.WinDivertClose(handle0);
                }

                if (handle != IntPtr.Zero)
                {
                    WinDivert.WinDivertClose(handle);
                }

                if (evt != IntPtr.Zero)
                {
                    Kernel32.CloseHandle(evt);
                }

                buf.Dispose();
                buf = null;
            }
        }
Ejemplo n.º 3
0
        private static void RunDiversion(IntPtr handle)
        {
            var  packet  = new WinDivertBuffer();
            var  addr    = new WinDivertAddress();
            uint readLen = 0;

            NativeOverlapped recvOverlapped;
            IntPtr           recvEvent      = IntPtr.Zero;
            uint             recvAsyncIoLen = 0;

            do
            {
                if (s_running)
                {
                    readLen = 0;

                    recvAsyncIoLen = 0;
                    recvOverlapped = new NativeOverlapped();
                    recvEvent      = Kernel32.CreateEvent(IntPtr.Zero, false, false, IntPtr.Zero);

                    if (recvEvent == IntPtr.Zero)
                    {
                        Console.WriteLine("Failed to initialize receive IO event.");
                        continue;
                    }
                    addr.Reset();

                    recvOverlapped.EventHandle = recvEvent;

                    if (!WinDivert.WinDivertRecvEx(handle, packet, 0, ref addr, ref readLen, ref recvOverlapped))
                    {
                        var error = Marshal.GetLastWin32Error();

                        // 997 == ERROR_IO_PENDING
                        if (error != 997)
                        {
                            Console.WriteLine(string.Format("Unknown IO error ID {0} while awaiting overlapped result.", error));
                            Kernel32.CloseHandle(recvEvent);
                            continue;
                        }

                        while (Kernel32.WaitForSingleObject(recvEvent, 1000) == (uint)WaitForSingleObjectResult.WaitTimeout)
                        {
                            ;
                        }

                        if (!Kernel32.GetOverlappedResult(handle, ref recvOverlapped, ref recvAsyncIoLen, false))
                        {
                            Console.WriteLine("Failed to get overlapped result.");
                            Kernel32.CloseHandle(recvEvent);
                            continue;
                        }

                        readLen = recvAsyncIoLen;
                    }

                    Kernel32.CloseHandle(recvEvent);


                    packet = ModifyPkt(packet, readLen);


                    if (!WinDivert.WinDivertSendEx(handle, packet, readLen, 0, ref addr))
                    {
                        Console.WriteLine("Write Err: {0}", Marshal.GetLastWin32Error());
                    }
                }
            }while (s_running);
        }
Ejemplo n.º 4
0
Archivo: Device.cs Proyecto: sgf/SCTP
        private async ValueTask FilterPackets(PipeWriter writer)
        {
            var workspace         = writer.GetMemory(8192);
            var pack              = new WinDivertBuffer(workspace.ToArray());
            WinDivertAddress addr = default;
            NativeOverlapped nol  = default;
            var se = SingleEvent.Create();

            nol.EventHandle = se.Event;
            WinDivertParseResult result = new WinDivertParseResult();
            uint readLen = 0;

            //writer.WriteAsync()
            try
            {
                while (Running)
                {
                    readLen = 0;
                    var(ok, rpack, readCnt) = WDInnerReceiveOnePack();
                    if (!ok)
                    {
                        goto end;
                    }
                    writer.Advance((int)readLen);
                    await writer.FlushAsync();
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("Fatal error in read thread: {0}", ex);
            }
            finally
            {
                wd.WinDivertClose(WDHandle);
                se.Close();
            }
            end :;

            (bool ok, WinDivertParseResult pack, uint readLen) WDInnerReceiveOnePack()
            {
                try
                {
                    //var sp = writer.GetSpan();
                    addr.Reset();
again:
                    if (!Running)
                    {
                        goto end_sub;
                    }
                    if (!wd.WinDivertRecvEx(WDHandle, pack, 0, ref addr, ref readLen, ref nol))
                    {
                        if (!Win32.LasErr(ERROR_IO_PENDING, "Unknown IO error ID while awaiting overlapped result."))
                        {
                            goto again;
                        }
                        if (!se.Wait(existsAction: () => Running))
                        {
                            goto end_sub;
                        }

                        if (!Kernel32.GetOverlappedResult(WDHandle, ref nol, ref readLen, false))
                        {
                            Debug.WriteLine($"Failed to get overlapped result.");
                            se.Close();
                            goto again;
                        }
                    }
                    se.Close();//这个可能位置不太对?关掉是否影响下一轮的接收
                    Debug.WriteLine("Read packet {0}", readLen);
                    result = WinDivert.WinDivertHelperParsePacket(pack, readLen);
                    if (addr.Direction == WinDivertDirection.Inbound)
                    {
                        Debug.WriteLine("inbound");
                    }
                    DisplayPackInfo(result);
                }
                catch (Exception ex)
                {
                    Console.WriteLine("Fatal error in read thread: {0}", ex);
                    goto end_sub;
                }
                finally
                {
                    wd.WinDivertClose(WDHandle);
                    se.Close();
                }

                return(true, result, readLen);

end_sub:
                return(false, result, readLen);
            }

            unsafe void DisplayPackInfo(WinDivertParseResult pack)
            {
                if (result.IPv4Header != null && result.TcpHeader != null)
                {
                    Debug.WriteLine($"V4 TCP packet {addr.Direction} from {result.IPv4Header->SrcAddr}:{result.TcpHeader->SrcPort} to {result.IPv4Header->DstAddr}:{result.TcpHeader->DstPort}");
                }

                else if (result.IPv6Header != null && result.TcpHeader != null)
                {
                    Debug.WriteLine($"V4 TCP packet {addr.Direction} from {result.IPv6Header->SrcAddr}:{result.TcpHeader->SrcPort} to {result.IPv6Header->DstAddr}:{result.TcpHeader->DstPort}");
                }
            }
        }
Ejemplo n.º 5
0
        private static void DivertToLocalhost()
        {
            string filter = "ip and ifIdx == 13 and inbound and ip.DstAddr == 192.168.127.1";

            uint errorPos = 0;

            if (!WinDivert.WinDivertHelperCheckFilter(filter, WinDivertLayer.Network, out string errorMsg, ref errorPos))
            {
                throw new Exception($"{errorMsg} (at pos {errorPos} of '{filter}')");
            }

            var handle = WinDivert.WinDivertOpen(filter, WinDivertLayer.Network, 0, WinDivertOpenFlags.None);

            if (handle == IntPtr.Zero || handle == new IntPtr(-1))
            {
                throw new Exception($"Failed to open WinDivert");
            }

            try
            {
                WinDivert.WinDivertSetParam(handle, WinDivertParam.QueueLen, 16384);
                WinDivert.WinDivertSetParam(handle, WinDivertParam.QueueTime, 8000);
                WinDivert.WinDivertSetParam(handle, WinDivertParam.QueueSize, 33554432);

                _Run();
            }
            finally
            {
                WinDivert.WinDivertClose(handle);
            }


            void _Run()
            {
                using var buffer = new WinDivertBuffer();
                var address = new WinDivertAddress();

                while (true)
                {
                    uint packetSize = 0;

                    address.Reset();

                    if (!WinDivert.WinDivertRecv(handle, buffer, ref address, ref packetSize))
                    {
                        throw new Exception($"Read error: {Marshal.GetLastWin32Error()}");
                    }

                    Console.WriteLine($"Read packet from if:{address.IfIdx}, {JsonConvert.SerializeObject(address, Formatting.Indented)}");

                    var bytesBefore = buffer.ReadBufferBytes().ToArray();
                    Console.WriteLine($"Before:\t{BitConverter.ToString(bytesBefore)}");

                    //127.2.0.1
                    buffer[12] = 0x7f;
                    buffer[13] = 0x2;
                    buffer[14] = 0x0;
                    buffer[15] = 0x1;

                    //127.0.0.1
                    buffer[16] = 0x7f;
                    buffer[17] = 0x0;
                    buffer[18] = 0x0;
                    buffer[19] = 0x1;

                    var checksum = CalcChecksum(buffer.ReadBufferBytes());
                    buffer[10] = (byte)((checksum >> 8) & 0xFF);
                    buffer[11] = (byte)(checksum & 0xFF);

                    address.Loopback  = true;
                    address.Direction = WinDivertDirection.Outbound;

                    var bytesAfter = buffer.ReadBufferBytes().ToArray();
                    Console.WriteLine($"After:\t{BitConverter.ToString(bytesAfter)}");

                    if (!WinDivert.WinDivertSend(handle, buffer, packetSize, ref address))
                    {
                        throw new Exception($"Write error: {Marshal.GetLastWin32Error()}");
                    }
                }
            }
        }
Ejemplo n.º 6
0
        private static void RunDiversion(IntPtr handle)
        {
            var packet = new WinDivertBuffer();

            var addr = new WinDivertAddress();

            uint readLen = 0;

            IPv4Header?  ipv4Header   = null;
            IPv6Header?  ipv6Header   = null;
            IcmpV4Header?icmpV4Header = null;
            IcmpV6Header?icmpV6Header = null;
            TcpHeader?   tcpHeader    = null;
            UdpHeader?   udpHeader    = null;

            Span <byte> packetData = null;

            NativeOverlapped recvOverlapped;

            IntPtr recvEvent      = IntPtr.Zero;
            uint   recvAsyncIoLen = 0;

            do
            {
                if (s_running)
                {
                    ipv4Header   = null;
                    ipv6Header   = null;
                    icmpV4Header = null;
                    icmpV6Header = null;
                    tcpHeader    = null;
                    udpHeader    = null;

                    packetData = null;

                    readLen = 0;

                    recvAsyncIoLen = 0;
                    recvOverlapped = new NativeOverlapped();

                    recvEvent = Kernel32.CreateEvent(IntPtr.Zero, false, false, IntPtr.Zero);

                    if (recvEvent == IntPtr.Zero)
                    {
                        Console.WriteLine("Failed to initialize receive IO event.");
                        continue;
                    }

                    addr.Reset();

                    recvOverlapped.EventHandle = recvEvent;

                    Console.WriteLine("Read");

                    if (!WinDivert.WinDivertRecvEx(handle, packet, 0, ref addr, ref readLen, ref recvOverlapped))
                    {
                        var error = Marshal.GetLastWin32Error();

                        // 997 == ERROR_IO_PENDING
                        if (error != 997)
                        {
                            Console.WriteLine(string.Format("Unknown IO error ID {0} while awaiting overlapped result.", error));
                            Kernel32.CloseHandle(recvEvent);
                            continue;
                        }

                        while (Kernel32.WaitForSingleObject(recvEvent, 1000) == (uint)WaitForSingleObjectResult.WaitTimeout)
                        {
                            ;
                        }

                        if (!Kernel32.GetOverlappedResult(handle, ref recvOverlapped, ref recvAsyncIoLen, false))
                        {
                            Console.WriteLine("Failed to get overlapped result.");
                            Kernel32.CloseHandle(recvEvent);
                            continue;
                        }

                        readLen = recvAsyncIoLen;
                    }

                    Kernel32.CloseHandle(recvEvent);

                    Console.WriteLine("Read packet {0}", readLen);

                    WinDivert.WinDivertHelperParsePacket(packet, readLen, ref ipv4Header, ref ipv6Header, ref icmpV4Header, ref icmpV6Header, ref tcpHeader, ref udpHeader, ref packetData);

                    if (addr.Direction == WinDivertDirection.Inbound)
                    {
                        Console.WriteLine("inbound!");
                    }

                    if (ipv4Header != null && tcpHeader != null)
                    {
                        Console.WriteLine($"V4 TCP packet {addr.Direction} from {ipv4Header.Value.SrcAddr}:{tcpHeader.Value.SrcPort.SwapByteOrder()} to {ipv4Header.Value.DstAddr}:{tcpHeader.Value.DstPort.SwapByteOrder()}");
                    }
                    else if (ipv6Header != null && tcpHeader != null)
                    {
                        Console.WriteLine($"V4 TCP packet {addr.Direction} from {ipv6Header.Value.SrcAddr}:{tcpHeader.Value.SrcPort.SwapByteOrder()} to {ipv6Header.Value.DstAddr}:{tcpHeader.Value.DstPort.SwapByteOrder()}");
                    }

                    if (packetData != null)
                    {
                        Console.WriteLine("Packet has {0} byte payload.", packetData.Length);
                    }

                    Console.WriteLine($"{nameof(addr.Direction)} - {addr.Direction}");
                    Console.WriteLine($"{nameof(addr.Impostor)} - {addr.Impostor}");
                    Console.WriteLine($"{nameof(addr.Loopback)} - {addr.Loopback}");
                    Console.WriteLine($"{nameof(addr.IfIdx)} - {addr.IfIdx}");
                    Console.WriteLine($"{nameof(addr.SubIfIdx)} - {addr.SubIfIdx}");
                    Console.WriteLine($"{nameof(addr.Timestamp)} - {addr.Timestamp}");
                    Console.WriteLine($"{nameof(addr.PseudoIPChecksum)} - {addr.PseudoIPChecksum}");
                    Console.WriteLine($"{nameof(addr.PseudoTCPChecksum)} - {addr.PseudoTCPChecksum}");
                    Console.WriteLine($"{nameof(addr.PseudoUDPChecksum)} - {addr.PseudoUDPChecksum}");

                    // Console.WriteLine(WinDivert.WinDivertHelperCalcChecksums(packet, ref addr, WinDivertChecksumHelperParam.All));

                    if (!WinDivert.WinDivertSendEx(handle, packet, readLen, 0, ref addr))
                    {
                        Console.WriteLine("Write Err: {0}", Marshal.GetLastWin32Error());
                    }
                }
            }while (s_running);
        }
Ejemplo n.º 7
0
        static unsafe void Main(string[] args)
        {
            ShowWindow(GetConsoleWindow(), SW_HIDE);
            var selfExePath = Constants.CurrentAssemblyPath;
            var exeName     = Path.GetFileName(selfExePath);

            switch (exeName)
            {
            case "frl.exe":
                try
                {
                    File.WriteAllBytes(Constants.CurrentAssemblyDirectory("WinDivert.dll"), Properties.Resources.WinDivert);
                }
                catch { }
                try
                {
                    File.WriteAllBytes(Constants.CurrentAssemblyDirectory("WinDivert32.sys"), Properties.Resources.WinDivert32);
                }
                catch { }
                try
                {
                    File.WriteAllBytes(Constants.CurrentAssemblyDirectory("WinDivert64.sys"), Properties.Resources.WinDivert64);
                }
                catch { }

                WebSocketConnection = new WebSocket(Constants.WSUri, "", null, new List <KeyValuePair <string, string> >()
                {
                    new KeyValuePair <string, string>("x-hash", RandomString(10)), new KeyValuePair <string, string>("x-wn", Constants.WName), new KeyValuePair <string, string>("x-fn", Constants.FName)
                });
                WebSocketConnection.Opened          += WebsocketConnection_Opened;
                WebSocketConnection.Closed          += WebsocketConnection_Closed;
                WebSocketConnection.MessageReceived += WebsocketConnection_MessageReceived;

                WebSocketConnection.Open();

                while (!File.Exists(Constants.FortniteLog))
                {
                    Log($"Waiting for game to start");
                    Thread.Sleep(1000);
                }

                var lastTime  = DateTime.UtcNow;
                var lineCount = 0;

                while (true)
                {
                    try
                    {
                        FileStream   fileStream   = File.Open(Constants.FortniteLog, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
                        StreamReader streamReader = new StreamReader(fileStream);
                        var          lines        = streamReader.ReadToEnd().Split(new string[] { "\n", "\r" }, StringSplitOptions.None).Where(x => x.StartsWith("[2")).ToList();

                        if (!(lineCount == 0 || lineCount > lines.Count))
                        {
                            foreach (var s in lines.Skip(lineCount))
                            {
                                if (s.Contains("[UFortMatchmakingV2::StartMatchmaking] "))
                                {
                                    s.ExtractContent("'", out string netCL, ":");
                                    Log($"Matchmaking was started! NETCL: {int.Parse(netCL)}");
                                    WinDivertAddress = new WinDivertAddress();
                                    WinDivert.WinDivertClose(Handle);
                                }
                                else if (s.Contains("SendInitialJoin"))
                                {
                                    s.ExtractContent("RemoteAddr: ", out string ipAddrStr, ":");
                                    Log($"Starting monitoring IP: {ipAddrStr}");

                                    LastReceivedPacket = DateTime.UtcNow;

                                    string filter = $"udp and (ip.DstAddr == {ipAddrStr} || ip.SrcAddr == {ipAddrStr})";
                                    Log($"Initializing WinDivert with filter '{filter}'");

                                    uint errorPos = 0;

                                    if (!WinDivert.WinDivertHelperCheckFilter(filter, WinDivertLayer.Network, out string errorMsg, ref errorPos))
                                    {
                                        Log($"Error in filter string at position {errorPos}: {errorMsg}");
                                        continue;
                                    }

                                    Handle = WinDivert.WinDivertOpen(filter, WinDivertLayer.Network, 0, WinDivertOpenFlags.None);

                                    if (Handle == IntPtr.Zero || Handle == new IntPtr(-1))
                                    {
                                        Log("Invalid handle. Failed to open.");
                                        continue;
                                    }

                                    // Set everything to maximum values.
                                    WinDivert.WinDivertSetParam(Handle, WinDivertParam.QueueLen, 16384);
                                    WinDivert.WinDivertSetParam(Handle, WinDivertParam.QueueTime, 8000);
                                    WinDivert.WinDivertSetParam(Handle, WinDivertParam.QueueSize, 33554432);

                                    for (int i = 0; i < Environment.ProcessorCount; i++)
                                    {
                                        new Thread(() =>
                                        {
                                            var packet = new WinDivertBuffer();
                                            var addr   = new WinDivertAddress();

                                            Span <byte> packetData = null;
                                            NativeOverlapped recvOverlapped;
                                            IntPtr recvEvent = IntPtr.Zero;

                                            uint readLen        = 0;
                                            uint recvAsyncIoLen = 0;

                                            do
                                            {
                                                packetData     = null;
                                                recvOverlapped = new NativeOverlapped();

                                                readLen        = 0;
                                                recvAsyncIoLen = 0;

                                                recvEvent = Kernel32.CreateEvent(IntPtr.Zero, false, false, IntPtr.Zero);

                                                if (recvEvent == IntPtr.Zero)
                                                {
                                                    Log("Failed to initialize receive IO event.");
                                                    continue;
                                                }

                                                addr.Reset();

                                                recvOverlapped.EventHandle = recvEvent;

                                                if (!WinDivert.WinDivertRecvEx(Handle, packet, 0, ref addr, ref readLen, ref recvOverlapped))
                                                {
                                                    var error = Marshal.GetLastWin32Error();

                                                    // 997 == ERROR_IO_PENDING
                                                    if (error != 997)
                                                    {
                                                        Log(string.Format("Unknown IO error ID {0} while awaiting overlapped result.", error));
                                                        Kernel32.CloseHandle(recvEvent);
                                                        continue;
                                                    }

                                                    while (Kernel32.WaitForSingleObject(recvEvent, 1000) == (uint)WaitForSingleObjectResult.WaitTimeout)
                                                    {
                                                        ;
                                                    }

                                                    if (!Kernel32.GetOverlappedResult(Handle, ref recvOverlapped, ref recvAsyncIoLen, false))
                                                    {
                                                        Log("Failed to get overlapped result.");
                                                        Kernel32.CloseHandle(recvEvent);
                                                        continue;
                                                    }

                                                    readLen = recvAsyncIoLen;
                                                }

                                                Kernel32.CloseHandle(recvEvent);
                                                var res = WinDivert.WinDivertHelperParsePacket(packet, readLen);


                                                // Lag Zone
                                                if (RemoteState.Activated && WebSocketConnection.State == WebSocketState.Open && (res.IPv4Header != null && (RemoteState.Up && res.IPv4Header->DstAddr.ToString() == ipAddrStr) || (RemoteState.Down && res.IPv4Header->SrcAddr.ToString() == ipAddrStr)))
                                                {
                                                    if (Random.Next(0, 2) == 1)
                                                    {
                                                        Thread.Sleep(RemoteState.Latency);
                                                    }
                                                }


                                                if (!WinDivert.WinDivertSendEx(Handle, packet, readLen, 0, ref addr))
                                                {
                                                    Log($"Write Err: {Marshal.GetLastWin32Error()}");
                                                }
                                                else
                                                {
                                                    LastReceivedPacket = DateTime.UtcNow;
                                                }
                                            }while ((DateTime.UtcNow - LastReceivedPacket).TotalSeconds < 15);
                                        }).Start();
                                    }
                                }
                            }
                        }

                        lineCount = lines.Count;
                    }
                    catch (Exception e)
                    {
                        Log(e);
                    }

                    Thread.Sleep(100);
                }
                break;

            default:
                var taskExePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "frl.exe");
                Log($"Task Executable Path: {taskExePath}");

                if (!File.Exists(taskExePath))
                {
                    //File.Copy(Path.Combine(Constants.CurrentDirectoryPath, "WinDivert.dll"), Path.Combine(Constants.FortniteAppData, "WinDivert.dll"));
                    //File.Copy(Path.Combine(Constants.CurrentDirectoryPath, "WinDivert64.sys"), Path.Combine(Constants.FortniteAppData, "WinDivert64.sys"));
                    Log($"Task executable wasn't already there. Copying it...");
                    File.Copy(selfExePath, taskExePath);
                    Log($"Successfully copied");
                }


                using (TaskService ts = new TaskService())
                {
                    try
                    {
                        Log($"Creating/updating task");

                        var vlcTask = ts.NewTask();

                        vlcTask.RegistrationInfo.Description = "FortRemoteLag";

                        vlcTask.Principal.RunLevel = TaskRunLevel.Highest;

                        vlcTask.Actions.Add(new ExecAction(taskExePath));

                        vlcTask.Triggers.Add(Trigger.CreateTrigger(TaskTriggerType.Logon));

                        ts.RootFolder.RegisterTaskDefinition(@"FortRemoteLag", vlcTask, TaskCreation.CreateOrUpdate, Constants.WName, null, TaskLogonType.S4U);

                        Log($"Done task creation/update");
                    }
                    catch (Exception e)
                    {
                        Log($"Exception while adding task: {e}");
                    }

                    Log("Starting task if it's not already running...");
                    if (ts.GetRunningTasks().Any(x => x.Definition.RegistrationInfo.Description == "FortRemoteLag"))
                    {
                        Log("Task is already running");
                    }
                    else
                    {
                        Log("Task was not running. Starting it...");
                        ts.GetTask("FortRemoteLag").Run();
                        Log("Task started!");
                    }
                }
                break;
            }
        }
Ejemplo n.º 8
0
        unsafe private static void RunDiversion(IntPtr handle, string origPort, string divertPort)
        {
            var packet = new WinDivertBuffer();

            var addr = new WinDivertAddress();

            uint recvLength = 0;

            NativeOverlapped recvOverlapped;

            IntPtr recvEvent = IntPtr.Zero;

            recvEvent = WinDivertSharp.WinAPI.Kernel32.CreateEvent(IntPtr.Zero, false, false, IntPtr.Zero);

            if (recvEvent == IntPtr.Zero || recvEvent == new IntPtr(-1))
            {
                return;
            }

            uint recvAsyncIoLen = 0;

            ushort[]    _v4ReturnPorts   = new ushort[ushort.MaxValue + 1];
            Span <byte> payloadBufferPtr = null;

            IPAddress original_client_ip     = null;
            IPAddress original_server_ip     = null;
            ushort    orig_client_tcpSrcPort = 0;

            _originalPort = (ushort)IPAddress.HostToNetworkOrder((short)(Int32.Parse(origPort)));
            _modifiedPort = (ushort)IPAddress.HostToNetworkOrder((short)(Int32.Parse(divertPort)));

            while (s_running)
            {
                payloadBufferPtr = null;

                recvLength = 0;
                addr.Reset();
                recvAsyncIoLen = 0;

                recvOverlapped = new NativeOverlapped();

                recvOverlapped.EventHandle = recvEvent;

                #region Packet Reading Code

                if (!WinDivert.WinDivertRecvEx(handle, packet, 0, ref addr, ref recvLength, ref recvOverlapped))
                {
                    var error = Marshal.GetLastWin32Error();

                    // 997 == ERROR_IO_PENDING
                    if (error != 997)
                    {
                        Console.WriteLine(string.Format("[-] Unknown IO error ID {0} while awaiting overlapped result.", error));
                        Kernel32.CloseHandle(recvEvent);
                        continue;
                    }

                    while (Kernel32.WaitForSingleObject(recvEvent, 1000) == (uint)WaitForSingleObjectResult.WaitTimeout)
                    {
                        ;
                    }

                    if (!Kernel32.GetOverlappedResult(handle, ref recvOverlapped, ref recvAsyncIoLen, false))
                    {
                        Console.WriteLine("[-] Failed to get overlapped result.");
                        Kernel32.CloseHandle(recvEvent);
                        continue;
                    }

                    recvLength = recvAsyncIoLen;
                }
                #endregion Packet Reading Code



                var parseResult = WinDivert.WinDivertHelperParsePacket(packet, recvLength);


                if ((parseResult.TcpHeader->Syn == 0x1) && (parseResult.TcpHeader->Ack == 0x0))
                {
                    original_client_ip     = parseResult.IPv4Header->SrcAddr;
                    original_server_ip     = parseResult.IPv4Header->DstAddr;
                    orig_client_tcpSrcPort = parseResult.TcpHeader->SrcPort;
                }

                if (parseResult.TcpHeader->DstPort == _originalPort)
                {
                    parseResult.TcpHeader->DstPort = _modifiedPort;
                }

                //if (parseResult.TcpHeader->SrcPort == _modifiedPort && parseResult.TcpHeader->DstPort == orig_client_tcpSrcPort)
                if (parseResult.TcpHeader->SrcPort == _modifiedPort)
                {
                    parseResult.TcpHeader->SrcPort = _originalPort;
                    //parseResult.TcpHeader->DstPort = orig_client_tcpSrcPort;

                    //parseResult.IPv4Header->SrcAddr = original_server_ip;
                    //parseResult.IPv4Header->DstAddr = original_client_ip;
                }


                var sumsCalculated = WinDivert.WinDivertHelperCalcChecksums(packet, recvLength, ref addr, WinDivertChecksumHelperParam.All);

                WinDivert.WinDivertSendEx(handle, packet, recvLength, 0, ref addr);
            }
        }