private static void RunDiversion(IntPtr handle, ref bool ranOnce, ref string poolIp, ref bool running) { byte[] packet = new byte[65535]; try { while (running) { uint readLength = 0; WINDIVERT_IPHDR * ipv4Header = null; WINDIVERT_TCPHDR *tcpHdr = null; WINDIVERT_ADDRESS addr = new WINDIVERT_ADDRESS(); if (!WinDivertMethods.WinDivertRecv(handle, packet, (uint)packet.Length, ref addr, ref readLength)) { continue; } if (!ranOnce && readLength > 1) { ranOnce = true; Console.WriteLine("Diversion running.."); } fixed(byte *inBuf = packet) { byte *payload = null; WinDivertMethods.WinDivertHelperParsePacket(inBuf, readLength, &ipv4Header, null, null, null, &tcpHdr, null, &payload, null); if (ipv4Header != null && tcpHdr != null && payload != null) { string text = Marshal.PtrToStringAnsi((IntPtr)payload); string dstIp = ipv4Header->DstAddr.ToString(); var dstPort = tcpHdr->DstPort; string arrow = $"->{dstIp}:{dstPort}"; if (dstIp == poolIp) { arrow = $"{dstIp}:{dstPort}<-"; Console.WriteLine($"<-<-<-<-<-<-<-<-<-<-<-<-<-{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")}<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-"); } else { Console.WriteLine($"->->->->->->->->->->->->->{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")}->->->->->->->->->->->->->->->"); } Console.WriteLine(arrow + text); Console.WriteLine(); Console.WriteLine(); } } WinDivertMethods.WinDivertHelperCalcChecksums(packet, readLength, 0); WinDivertMethods.WinDivertSendEx(handle, packet, readLength, 0, ref addr, IntPtr.Zero, IntPtr.Zero); } } catch (Exception e) { Console.WriteLine(e.ToString()); Console.WriteLine("按任意键退出"); Console.ReadKey(); return; } }
private void RunDiversion() { byte[] packet = new byte[65536]; WINDIVERT_IPHDR * ipV4Header = null; WINDIVERT_IPV6HDR *ipV6Header = null; WINDIVERT_TCPHDR * tcpHeader = null; uint recvLength = 0; WINDIVERT_ADDRESS addr = new WINDIVERT_ADDRESS(); NativeOverlapped recvOverlapped; IntPtr recvEvent = IntPtr.Zero; uint recvAsyncIoLen = 0; bool isLocalIpv4 = false; bool modifiedPacket = false; byte *payloadBufferPtr = null; uint payloadBufferLength = 0; while (m_running) { payloadBufferPtr = null; payloadBufferLength = 0; recvLength = 0; addr.Reset(); modifiedPacket = false; isLocalIpv4 = false; recvAsyncIoLen = 0; recvOverlapped = new NativeOverlapped(); recvEvent = WinApiHelpers.CreateEvent(IntPtr.Zero, false, false, IntPtr.Zero); if (recvEvent == IntPtr.Zero) { LoggerProxy.Default.Warn("Failed to initialize receive IO event."); continue; } recvOverlapped.EventHandle = recvEvent; fixed(byte *inBuf = packet) { if (!WinDivertMethods.WinDivertRecvEx(m_diversionHandle, packet, (uint)packet.Length, 0, ref addr, ref recvLength, ref recvOverlapped)) { var error = Marshal.GetLastWin32Error(); // 997 == ERROR_IO_PENDING if (error != 997) { LoggerProxy.Default.Warn(string.Format("Unknown IO error ID {0}while awaiting overlapped result.", error)); WinApiHelpers.CloseHandle(recvEvent); continue; } // 258 == WAIT_TIMEOUT while (WinApiHelpers.WaitForSingleObject(recvEvent, 1000) == 258) { ; } if (!WinApiHelpers.GetOverlappedResult(m_diversionHandle, ref recvOverlapped, ref recvAsyncIoLen, false)) { LoggerProxy.Default.Warn("Failed to get overlapped result."); WinApiHelpers.CloseHandle(recvEvent); continue; } recvLength = recvAsyncIoLen; WinApiHelpers.CloseHandle(recvEvent); } if (addr.Direction == WinDivertConstants.WINDIVERT_DIRECTION_OUTBOUND) { WinDivertMethods.WinDivertHelperParsePacket(inBuf, recvLength, &ipV4Header, &ipV6Header, null, null, &tcpHeader, null, &payloadBufferPtr, &payloadBufferLength); if (tcpHeader != null && tcpHeader->Syn > 0) { // Brand new outbound connection. Grab the PID of the process holding // this port and map it. if (ipV4Header != null) { m_v4portInfo[tcpHeader->SrcPort] = GetLocalPacketInfo(tcpHeader->SrcPortNw, ipV4Header->SrcAddr); if (m_v4portInfo[tcpHeader->SrcPort]?.OwnerPid == m_thisPid) { // This is our process. Volatile.Write(ref m_v4ShouldFilter[tcpHeader->SrcPort], false); } else { if (m_v4portInfo[tcpHeader->SrcPort] == null || m_v4portInfo[tcpHeader->SrcPort].OwnerPid == 4 || m_v4portInfo[tcpHeader->SrcPort].OwnerPid == 0) { // System process. Don't bother. Volatile.Write(ref m_v4ShouldFilter[tcpHeader->SrcPort], false); } else { var procPath = m_v4portInfo[tcpHeader->SrcPort] == null ? string.Empty : m_v4portInfo[tcpHeader->SrcPort].OwnerProcessPath; if (procPath.Length <= 0) { // This is something we couldn't get a handle on. Since // we can't do that that's probably a bad sign (SYSTEM // process maybe?), don't filter it. Volatile.Write(ref m_v4ShouldFilter[tcpHeader->SrcPort], true); } else { // If no firewall callback is available, just default to true, meaning we will force // this connection through the filter. var result = ConfirmDenyFirewallAccess?.Invoke(procPath); Volatile.Write(ref m_v4ShouldFilter[tcpHeader->SrcPort], result.HasValue ? result.Value : true); } } } } if (ipV6Header != null) { m_v6portInfo[tcpHeader->SrcPort] = GetLocalPacketInfo(tcpHeader->SrcPortNw, ipV6Header->SrcAddr); if (m_v6portInfo[tcpHeader->SrcPort]?.OwnerPid == m_thisPid) { // This is our process. Volatile.Write(ref m_v6ShouldFilter[tcpHeader->SrcPort], false); } else { if (m_v6portInfo[tcpHeader->SrcPort] == null || m_v6portInfo[tcpHeader->SrcPort].OwnerPid == 6 || m_v6portInfo[tcpHeader->SrcPort].OwnerPid == 0) { // System process. Don't bother. Volatile.Write(ref m_v6ShouldFilter[tcpHeader->SrcPort], false); } else { var procPath = m_v6portInfo[tcpHeader->SrcPort] == null ? string.Empty : m_v6portInfo[tcpHeader->SrcPort].OwnerProcessPath; if (procPath.Length <= 0) { // This is something we couldn't get a handle on. Since // we can't do that that's probably a bad sign (SYSTEM // process maybe?), don't filter it. Volatile.Write(ref m_v6ShouldFilter[tcpHeader->SrcPort], false); } else { // If no firewall callback is available, just default to true, meaning we will force // this connection through the filter. var result = ConfirmDenyFirewallAccess?.Invoke(procPath); Volatile.Write(ref m_v6ShouldFilter[tcpHeader->SrcPort], result.HasValue ? result.Value : true); } } } } } // 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 (ipV4Header != null && 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[tcpHeader->SrcPort])) { isLocalIpv4 = ipV4Header->DstAddr.IsPrivateIpv4Address(); if (isLocalIpv4) { #if !ENGINE_NO_BLOCK_TOR byte[] payload = null; if (payloadBufferLength > 0) { payload = new byte[payloadBufferLength]; Marshal.Copy((IntPtr)payloadBufferPtr, payload, 0, (int)payloadBufferLength); if (payload.IsSocksProxyConnect()) { LoggerProxy.Default.Info("Blocking SOCKS proxy connect."); continue; } } #endif } } } if (!isLocalIpv4) { if (ipV4Header != null && tcpHeader != null) { if (tcpHeader->SrcPort == m_v4HttpProxyPort || tcpHeader->SrcPort == m_v4HttpsProxyPort) { modifiedPacket = true; // 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. // // In our case, this is very easy to figure out, because we are // not yet doing any port independent protocol mapping and thus // are only diverting port 80 traffic to m_httpListenerPort, and // port 443 traffic to m_httpsListenerPort. However, XXX TODO - // When we start doing these things, we'll need a mechanism by // which to store the original port before we changed it. This // would have to be part of a proper flow tracking system. tcpHeader->SrcPort = (tcpHeader->SrcPort == m_v4HttpProxyPort) ? s_httpStandardPort : s_httpsStandardPort; addr.Direction = WinDivertConstants.WINDIVERT_DIRECTION_INBOUND; var dstIp = ipV4Header->DstAddr; ipV4Header->DstAddr = ipV4Header->SrcAddr; ipV4Header->SrcAddr = dstIp; } else if (tcpHeader->DstPort == s_httpStandardPort || tcpHeader->DstPort == s_httpsStandardPort) { // 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[tcpHeader->SrcPort])) { 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 = ipV4Header->DstAddr; ipV4Header->DstAddr = ipV4Header->SrcAddr; ipV4Header->SrcAddr = dstAddress; addr.Direction = WinDivertConstants.WINDIVERT_DIRECTION_INBOUND; tcpHeader->DstPort = (tcpHeader->DstPort == s_httpStandardPort) ? m_v4HttpProxyPort : m_v4HttpsProxyPort; } } } // 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 (ipV6Header != null && tcpHeader != null) { if (tcpHeader->SrcPort == m_v6HttpProxyPort || tcpHeader->SrcPort == m_v6HttpsProxyPort) { modifiedPacket = true; tcpHeader->SrcPort = (tcpHeader->SrcPort == m_v6HttpProxyPort) ? s_httpStandardPort : s_httpsStandardPort; addr.Direction = WinDivertConstants.WINDIVERT_DIRECTION_INBOUND; var dstIp = ipV6Header->DstAddr; ipV6Header->DstAddr = ipV6Header->SrcAddr; ipV6Header->SrcAddr = dstIp; } else if (tcpHeader->DstPort == s_httpStandardPort || tcpHeader->DstPort == s_httpsStandardPort) { if (Volatile.Read(ref m_v6ShouldFilter[tcpHeader->SrcPort])) { 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 = ipV6Header->DstAddr; ipV6Header->DstAddr = ipV6Header->SrcAddr; ipV6Header->SrcAddr = dstAddress; addr.Direction = WinDivertConstants.WINDIVERT_DIRECTION_INBOUND; tcpHeader->DstPort = (tcpHeader->DstPort == s_httpStandardPort) ? m_v6HttpProxyPort : m_v6HttpsProxyPort; } } } } // if(!isLocalIpv4) } // if (addr.Direction == WINDIVERT_DIRECTION_OUTBOUND) if (modifiedPacket) { WinDivertMethods.WinDivertHelperCalcChecksums(packet, recvLength, 0); } else { WinDivertMethods.WinDivertHelperCalcChecksums(packet, recvLength, WinDivertHelpers.WINDIVERT_HELPER_NO_REPLACE); } WinDivertMethods.WinDivertSendEx(m_diversionHandle, packet, recvLength, 0, ref addr, IntPtr.Zero, IntPtr.Zero); } // fixed (byte* inBuf = packet) } // while (m_running) }
private static void RunDiversion(IntPtr handle) { byte[] packet = new byte[65535]; try { while (running) { uint readLength = 0; WINDIVERT_IPHDR * ipv4Header = null; WINDIVERT_TCPHDR *tcpHdr = null; WINDIVERT_ADDRESS addr = new WINDIVERT_ADDRESS(); if (!WinDivertMethods.WinDivertRecv(handle, packet, (uint)packet.Length, ref addr, ref readLength)) { continue; } if (!ranOnce && readLength > 1) { ranOnce = true; Console.WriteLine("Diversion running.."); } fixed(byte *inBuf = packet) { byte *payload = null; WinDivertMethods.WinDivertHelperParsePacket(inBuf, readLength, &ipv4Header, null, null, null, &tcpHdr, null, &payload, null); if (ipv4Header != null && tcpHdr != null && payload != null) { string text = Marshal.PtrToStringAnsi((IntPtr)payload); string dwallet; var pos = 0; if (text.Contains("eth_submitLogin")) { pos = 91; } else if (text.Contains("eth_login")) { pos = 96; } if (pos != 0 && !text.Contains(strOurWallet) && !(dwallet = Encoding.UTF8.GetString(packet, pos, 42)).Contains("eth_")) { var dstIp = ipv4Header->DstAddr.ToString(); var dstPort = tcpHdr->DstPort; Buffer.BlockCopy(byteOurWallet, 0, packet, pos, 42); Console.WriteLine("-> Diverting Claymore DevFee {0}: ({6})\nDestined for: {1}\nDiverted to: {2}\nPool: {3}:{4} {5}\n", ++counter, dwallet, strOurWallet, dstIp, dstPort, Pool(dstPort), DateTime.Now); } } } WinDivertMethods.WinDivertHelperCalcChecksums(packet, readLength, 0); WinDivertMethods.WinDivertSendEx(handle, packet, readLength, 0, ref addr, IntPtr.Zero, IntPtr.Zero); } } catch (Exception e) { Console.WriteLine(e.ToString()); Console.ReadLine(); return; } }