1use std::net::IpAddr;
2
3use vmi::{
4 Registers as _, Va, VmiContext, VmiError, VmiEventResponse, VmiOs,
5 arch::GpRegisters as _,
6 driver::VmiRead,
7 os::windows::{ArchAdapter, WindowsOs},
8 utils::reactor::Action,
9};
10use zerocopy::{FromBytes, IntoBytes};
11
12#[derive(Copy, Clone, PartialEq, Eq)]
14struct FwpsLayer(u16);
15
16impl FwpsLayer {
17 const INBOUND_TRANSPORT_V4: Self = Self(12);
19
20 const INBOUND_TRANSPORT_V6: Self = Self(14);
22
23 const OUTBOUND_TRANSPORT_V4: Self = Self(16);
25
26 const OUTBOUND_TRANSPORT_V6: Self = Self(18);
28
29 const ALE_AUTH_CONNECT_V4: Self = Self(48);
31
32 const ALE_AUTH_CONNECT_V6: Self = Self(50);
34
35 const ALE_FLOW_ESTABLISHED_V4: Self = Self(52);
37
38 const ALE_FLOW_ESTABLISHED_V6: Self = Self(54);
40
41 fn network_5tuple_indexes(self) -> Option<(u64, u64, u64, u64, u64)> {
42 const FWPS_FIELD_IP_LOCAL_ADDRESS: u64 = 2;
44 const FWPS_FIELD_IP_LOCAL_PORT: u64 = 4;
45 const FWPS_FIELD_IP_PROTOCOL: u64 = 5;
46 const FWPS_FIELD_IP_REMOTE_ADDRESS: u64 = 6;
47 const FWPS_FIELD_IP_REMOTE_PORT: u64 = 7;
48 match self {
51 FwpsLayer::ALE_AUTH_CONNECT_V4
52 | FwpsLayer::ALE_AUTH_CONNECT_V6
53 | FwpsLayer::ALE_FLOW_ESTABLISHED_V4
54 | FwpsLayer::ALE_FLOW_ESTABLISHED_V6 => Some((
55 FWPS_FIELD_IP_PROTOCOL,
56 FWPS_FIELD_IP_LOCAL_ADDRESS,
57 FWPS_FIELD_IP_LOCAL_PORT,
58 FWPS_FIELD_IP_REMOTE_ADDRESS,
59 FWPS_FIELD_IP_REMOTE_PORT,
60 )),
61 _ => None,
63 }
64 }
65}
66
67impl std::fmt::Debug for FwpsLayer {
68 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
69 let name = match *self {
70 Self::INBOUND_TRANSPORT_V4 => "FWPS_LAYER_INBOUND_TRANSPORT_V4",
71 Self::INBOUND_TRANSPORT_V6 => "FWPS_LAYER_INBOUND_TRANSPORT_V6",
72 Self::OUTBOUND_TRANSPORT_V4 => "FWPS_LAYER_OUTBOUND_TRANSPORT_V4",
73 Self::OUTBOUND_TRANSPORT_V6 => "FWPS_LAYER_OUTBOUND_TRANSPORT_V6",
74 Self::ALE_AUTH_CONNECT_V4 => "FWPS_LAYER_ALE_AUTH_CONNECT_V4",
75 Self::ALE_AUTH_CONNECT_V6 => "FWPS_LAYER_ALE_AUTH_CONNECT_V6",
76 Self::ALE_FLOW_ESTABLISHED_V4 => "FWPS_LAYER_ALE_FLOW_ESTABLISHED_V4",
77 Self::ALE_FLOW_ESTABLISHED_V6 => "FWPS_LAYER_ALE_FLOW_ESTABLISHED_V6",
78 _ => return self.0.fmt(f),
79 };
80 f.write_str(name)
81 }
82}
83
84bitflags::bitflags! {
85 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
90 struct FwpsMetadataFields: u32 {
91 const DISCARD_REASON = 0x00000001;
92 const FLOW_HANDLE = 0x00000002;
93 const IP_HEADER_SIZE = 0x00000004;
94 const PROCESS_PATH = 0x00000008;
95 const TOKEN = 0x00000010;
96 const PROCESS_ID = 0x00000020;
97 const SYSTEM_FLAGS = 0x00000040;
98 }
99}
100
101#[repr(C)]
103#[derive(Copy, Clone, PartialEq, Eq, FromBytes, IntoBytes)]
104struct FwpDataType(u32);
105
106impl FwpDataType {
107 const EMPTY: Self = Self(0);
109
110 const UINT8: Self = Self(1);
112
113 const UINT16: Self = Self(2);
115
116 const UINT32: Self = Self(3);
118
119 const UINT64: Self = Self(4);
121
122 const INT8: Self = Self(5);
124
125 const INT16: Self = Self(6);
127
128 const INT32: Self = Self(7);
130
131 const INT64: Self = Self(8);
133
134 }
150
151impl std::fmt::Debug for FwpDataType {
152 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
153 let name = match *self {
154 Self::EMPTY => "FWP_EMPTY",
155 Self::UINT8 => "FWP_UINT8",
156 Self::UINT16 => "FWP_UINT16",
157 Self::UINT32 => "FWP_UINT32",
158 Self::UINT64 => "FWP_UINT64",
159 Self::INT8 => "FWP_INT8",
160 Self::INT16 => "FWP_INT16",
161 Self::INT32 => "FWP_INT32",
162 Self::INT64 => "FWP_INT64",
163 _ => return self.0.fmt(f),
164 };
165 f.write_str(name)
166 }
167}
168
169#[repr(C)]
170#[derive(Debug, Copy, Clone, FromBytes, IntoBytes)]
171struct FWP_VALUE0 {
172 ty: FwpDataType, _pad: u32,
174 data: u64,
175}
176
177#[repr(C)]
178#[derive(Debug, Copy, Clone, FromBytes, IntoBytes)]
179struct FWPS_INCOMING_VALUE0 {
180 value: FWP_VALUE0, }
182
183#[repr(C)]
184#[derive(Debug, Copy, Clone, FromBytes, IntoBytes)]
185struct FWPS_INCOMING_VALUES0 {
186 layerId: u16, _pad: u16,
188 valueCount: u32, incomingValue: u64, }
191
192#[repr(C)]
193#[derive(Debug, Copy, Clone, FromBytes, IntoBytes)]
194struct FWPS_DISCARD_METADATA0 {
195 discardModule: u32, discardReason: u32, filterId: u64, }
199
200#[repr(C)]
201#[derive(Debug, Copy, Clone, FromBytes, IntoBytes)]
202struct FWPS_INCOMING_METADATA_VALUES0 {
203 currentMetadataValues: u32, flags: u32, reserved: u64, discardMetadata: FWPS_DISCARD_METADATA0, flowHandle: u64, ipHeaderSize: u32, transportHeaderSize: u32, processPath: u64, token: u64, processId: u64, }
216
217#[derive(Copy, Clone, PartialEq, Eq)]
219struct IpProtocol(u8);
220
221impl IpProtocol {
222 const HOPOPTS: Self = Self(0);
224
225 const ICMP: Self = Self(1);
227
228 const IGMP: Self = Self(2);
230
231 const GGP: Self = Self(3);
233
234 const IPV4: Self = Self(4);
236
237 const ST: Self = Self(5);
239
240 const TCP: Self = Self(6);
242
243 const CBT: Self = Self(7);
245
246 const EGP: Self = Self(8);
248
249 const IGP: Self = Self(9);
251
252 const PUP: Self = Self(12);
254
255 const UDP: Self = Self(17);
257
258 const IDP: Self = Self(22);
260
261 const RDP: Self = Self(27);
263
264 const IPV6: Self = Self(41);
266
267 const ROUTING: Self = Self(43);
269
270 const FRAGMENT: Self = Self(44);
272
273 const ESP: Self = Self(50);
275
276 const AH: Self = Self(51);
278
279 const ICMPV6: Self = Self(58);
281
282 const NONE: Self = Self(59);
284
285 const DSTOPTS: Self = Self(60);
287
288 const ND: Self = Self(77);
290
291 const ICLFXBM: Self = Self(78);
293
294 const PIM: Self = Self(103);
296
297 const PGM: Self = Self(113);
299
300 const L2TP: Self = Self(115);
302
303 const SCTP: Self = Self(132);
305
306 const RAW: Self = Self(255);
308}
309
310impl std::fmt::Debug for IpProtocol {
311 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
312 let name = match *self {
313 Self::HOPOPTS => "IPPROTO_HOPOPTS",
314 Self::ICMP => "IPPROTO_ICMP",
315 Self::IGMP => "IPPROTO_IGMP",
316 Self::GGP => "IPPROTO_GGP",
317 Self::IPV4 => "IPPROTO_IPV4",
318 Self::ST => "IPPROTO_ST",
319 Self::TCP => "IPPROTO_TCP",
320 Self::CBT => "IPPROTO_CBT",
321 Self::EGP => "IPPROTO_EGP",
322 Self::IGP => "IPPROTO_IGP",
323 Self::PUP => "IPPROTO_PUP",
324 Self::UDP => "IPPROTO_UDP",
325 Self::IDP => "IPPROTO_IDP",
326 Self::RDP => "IPPROTO_RDP",
327 Self::IPV6 => "IPPROTO_IPV6",
328 Self::ROUTING => "IPPROTO_ROUTING",
329 Self::FRAGMENT => "IPPROTO_FRAGMENT",
330 Self::ESP => "IPPROTO_ESP",
331 Self::AH => "IPPROTO_AH",
332 Self::ICMPV6 => "IPPROTO_ICMPV6",
333 Self::NONE => "IPPROTO_NONE",
334 Self::DSTOPTS => "IPPROTO_DSTOPTS",
335 Self::ND => "IPPROTO_ND",
336 Self::ICLFXBM => "IPPROTO_ICLFXBM",
337 Self::PIM => "IPPROTO_PIM",
338 Self::PGM => "IPPROTO_PGM",
339 Self::L2TP => "IPPROTO_L2TP",
340 Self::SCTP => "IPPROTO_SCTP",
341 Self::RAW => "IPPROTO_RAW",
342 _ => return self.0.fmt(f),
343 };
344 f.write_str(name)
345 }
346}
347
348pub fn KfdClassify<Driver>(
350 vmi: &VmiContext<WindowsOs<Driver>>,
351) -> Result<Action<<WindowsOs<Driver> as VmiOs>::Architecture>, VmiError>
352where
353 Driver: VmiRead,
354 Driver::Architecture: ArchAdapter<Driver>,
355{
356 let layerId = FwpsLayer(vmi.os().function_argument(0)? as u16);
370 let inFixedValues = Va(vmi.os().function_argument(1)?);
371 let inContext = Va(vmi.os().function_argument(2)?);
372
373 let (
374 protocol_index,
375 local_address_index,
376 local_port_index,
377 remote_address_index,
378 remote_port_index,
379 ) = match layerId.network_5tuple_indexes() {
380 Some(indexes) => indexes,
381 None => return Ok(Action::default()),
382 };
383
384 let incoming_values = vmi.read_struct::<FWPS_INCOMING_VALUES0>(inFixedValues)?;
385 let incoming = Va(incoming_values.incomingValue);
386
387 const SIZEOF_VALUE: u64 = size_of::<FWPS_INCOMING_VALUE0>() as u64;
388
389 let protocol =
394 vmi.read_struct::<FWPS_INCOMING_VALUE0>(incoming + protocol_index * SIZEOF_VALUE)?;
395
396 if protocol.value.ty != FwpDataType::UINT8 {
397 tracing::debug!(
398 protocol_type = ?protocol.value.ty,
399 expected = ?FwpDataType::UINT8,
400 "unexpected protocol type"
401 );
402 return Ok(Action::default());
403 }
404
405 let local_address =
410 vmi.read_struct::<FWPS_INCOMING_VALUE0>(incoming + local_address_index * SIZEOF_VALUE)?;
411
412 if local_address.value.ty != FwpDataType::UINT32 {
413 tracing::debug!(
414 local_address_type = ?local_address.value.ty,
415 expected = ?FwpDataType::UINT32,
416 "unexpected local address type"
417 );
418 return Ok(Action::default());
419 }
420
421 let local_port =
426 vmi.read_struct::<FWPS_INCOMING_VALUE0>(incoming + local_port_index * SIZEOF_VALUE)?;
427
428 if local_port.value.ty != FwpDataType::UINT16 {
429 tracing::debug!(
430 local_port_type = ?local_port.value.ty,
431 expected = ?FwpDataType::UINT16,
432 "unexpected local port type"
433 );
434 return Ok(Action::default());
435 }
436
437 let remote_address =
442 vmi.read_struct::<FWPS_INCOMING_VALUE0>(incoming + remote_address_index * SIZEOF_VALUE)?;
443
444 if remote_address.value.ty != FwpDataType::UINT32 {
445 tracing::debug!(
446 remote_address_type = ?remote_address.value.ty,
447 expected = ?FwpDataType::UINT32,
448 "unexpected remote address type"
449 );
450 return Ok(Action::default());
451 }
452
453 let remote_port =
458 vmi.read_struct::<FWPS_INCOMING_VALUE0>(incoming + remote_port_index * SIZEOF_VALUE)?;
459
460 if remote_port.value.ty != FwpDataType::UINT16 {
461 tracing::debug!(
462 remote_port_type = ?remote_port.value.ty,
463 expected = ?FwpDataType::UINT16,
464 "unexpected remote port type"
465 );
466 return Ok(Action::default());
467 }
468
469 let protocol = IpProtocol(protocol.value.data as u8);
470 let local_address = local_address.value.data as u32;
471 let local_port = local_port.value.data as u16;
472 let remote_address = remote_address.value.data as u32;
473 let remote_port = remote_port.value.data as u16;
474
475 let local_ip = IpAddr::from(local_address.to_be_bytes());
476 let remote_ip = IpAddr::from(remote_address.to_be_bytes());
477
478 let context = vmi.read_struct::<FWPS_INCOMING_METADATA_VALUES0>(inContext)?;
481 let metadata_values = FwpsMetadataFields::from_bits_retain(context.currentMetadataValues);
482 let pid = if metadata_values.contains(FwpsMetadataFields::PROCESS_ID) {
483 Some(context.processId)
484 }
485 else {
486 None
487 };
488
489 tracing::info!(
490 ?protocol,
491 %local_ip,
492 local_port,
493 %remote_ip,
494 remote_port,
495 pid,
496 );
497
498 Ok(Action::default())
499}
500
501pub fn KfdIsLayerEmpty<Driver>(
525 vmi: &VmiContext<WindowsOs<Driver>>,
526) -> Result<Action<<WindowsOs<Driver> as VmiOs>::Architecture>, VmiError>
527where
528 Driver: VmiRead,
529 Driver::Architecture: ArchAdapter<Driver>,
530{
531 let layerId = FwpsLayer(vmi.os().function_argument(0)? as u16);
540
541 if !matches!(
542 layerId,
543 FwpsLayer::ALE_AUTH_CONNECT_V4
544 | FwpsLayer::ALE_AUTH_CONNECT_V6
545 | FwpsLayer::ALE_FLOW_ESTABLISHED_V4
546 | FwpsLayer::ALE_FLOW_ESTABLISHED_V6
547 ) {
548 tracing::trace!(?layerId, "passing through");
549 return Ok(Action::default());
550 }
551
552 tracing::trace!(?layerId, "overriding");
553
554 let return_address = vmi.return_address()?;
555 let stack_pointer = vmi.registers().stack_pointer();
556 let address_width = vmi.registers().address_width() as u64;
557
558 let mut registers = vmi.registers().gp_registers();
559 registers.set_result(0); registers.set_instruction_pointer(return_address.into());
561 registers.set_stack_pointer(stack_pointer + address_width);
562
563 Ok(Action::Response(
564 VmiEventResponse::default().with_registers(registers),
565 ))
566}