Adversarial C2 Protocol Implemented in Zig
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at dev 131 lines 3.9 kB view raw
1// Copyright 2026 Robby Zambito 2// 3// This file is part of zaprus. 4// 5// Zaprus is free software: you can redistribute it and/or modify it under the 6// terms of the GNU General Public License as published by the Free Software 7// Foundation, either version 3 of the License, or (at your option) any later 8// version. 9// 10// Zaprus is distributed in the hope that it will be useful, but WITHOUT ANY 11// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 12// A PARTICULAR PURPOSE. See the GNU General Public License for more details. 13// 14// You should have received a copy of the GNU General Public License along with 15// Zaprus. If not, see <https://www.gnu.org/licenses/>. 16 17pub const IpAddr = packed struct { 18 int: I, 19 20 const V = @Vector(4, u8); 21 const I = u32; 22 23 pub fn fromBytes(s: V) IpAddr { 24 return .{ .int = @bitCast(s) }; 25 } 26}; 27 28pub const MacAddr = packed struct { 29 int: I, 30 31 const V = @Vector(6, u8); 32 const I = @Int(.unsigned, @bitSizeOf(V)); 33 34 pub fn fromBytes(s: V) MacAddr { 35 return .{ .int = @bitCast(s) }; 36 } 37}; 38 39pub const EthIpUdp = packed struct(u336) { // 42 bytes * 8 bits = 336 40 // --- UDP (Last in memory, defined first for LSB->MSB) --- 41 udp: packed struct { 42 checksum: u16 = 0, 43 len: u16, 44 dst_port: u16, 45 src_port: u16, 46 }, 47 48 // --- IP --- 49 ip: packed struct { 50 dst_addr: IpAddr, 51 src_addr: IpAddr, 52 header_checksum: u16 = 0, 53 protocol: u8 = 17, // udp 54 ttl: u8 = 0x40, 55 56 // fragment_offset (13 bits) + flags (3 bits) = 16 bits 57 // In Big Endian, flags are the high bits of the first byte. 58 // To have flags appear first in the stream, define them last here. 59 fragment_offset: u13 = 0, 60 flags: packed struct(u3) { 61 reserved: u1 = 0, 62 dont_fragment: u1 = 1, 63 more_fragments: u1 = 0, 64 } = .{}, 65 66 id: u16, 67 len: u16, 68 tos: u8 = undefined, 69 70 // ip_version (4 bits) + ihl (4 bits) = 8 bits 71 // To have version appear first (high nibble), define it last. 72 ihl: u4 = 5, 73 ip_version: u4 = 4, 74 }, 75 76 // --- Ethernet --- 77 eth_type: u16 = std.os.linux.ETH.P.IP, 78 src_mac: MacAddr, 79 dst_mac: MacAddr = .fromBytes(@splat(0xff)), 80 81 pub fn toBytes(self: @This()) [336 / 8]u8 { 82 var res: [336 / 8]u8 = undefined; 83 var w: Writer = .fixed(&res); 84 w.writeStruct(self, .big) catch unreachable; 85 return res; 86 } 87 88 pub fn setPayloadLen(self: *@This(), len: usize) void { 89 self.ip.len = @intCast(len + (@bitSizeOf(@TypeOf(self.udp)) / 8) + (@bitSizeOf(@TypeOf(self.ip)) / 8)); 90 91 // Zero the checksum field before calculation 92 self.ip.header_checksum = 0; 93 94 // Serialize IP header to big-endian bytes 95 var ip_bytes: [@bitSizeOf(@TypeOf(self.ip)) / 8]u8 = undefined; 96 var w: Writer = .fixed(&ip_bytes); 97 w.writeStruct(self.ip, .big) catch unreachable; 98 99 // Calculate checksum over serialized bytes 100 self.ip.header_checksum = onesComplement16(&ip_bytes); 101 102 self.udp.len = @intCast(len + (@bitSizeOf(@TypeOf(self.udp)) / 8)); 103 } 104}; 105 106fn onesComplement16(data: []const u8) u16 { 107 var sum: u32 = 0; 108 109 // Process pairs of bytes as 16-bit words 110 var i: usize = 0; 111 while (i + 1 < data.len) : (i += 2) { 112 const word: u16 = (@as(u16, data[i]) << 8) | data[i + 1]; 113 sum += word; 114 } 115 116 // Handle odd byte if present 117 if (data.len % 2 == 1) { 118 sum += @as(u32, data[data.len - 1]) << 8; 119 } 120 121 // Fold 32-bit sum to 16 bits 122 while (sum >> 16 != 0) { 123 sum = (sum & 0xFFFF) + (sum >> 16); 124 } 125 126 // Return ones' complement 127 return ~@as(u16, @truncate(sum)); 128} 129 130const std = @import("std"); 131const Writer = std.Io.Writer;