为了提供一些上下文 - 正如这里提到的,我正在尝试制作一个可以利用网络监视器 API 的 rust 二进制文件。
我面临的当前问题与NmAddField
假设除了其他事情之外还考虑有效字段路径的功能有关。
示例中的一个是,http.request.uri
但我正在努力寻找这个值的来源,为了这样做,决定列出框架上的所有字段,因为函数文档中的备注部分指出,如果函数不是称为所有字段都附加到帧。我当前的测试文件如下所示:
#![allow(non_camel_case_types, non_snake_case)]
use cpp_xport::core_funcs::NMAPI::{NmCreateCaptureFile, NmOpenCaptureEngine, NmConfigAdapter, NmStopCapture, NmCloseHandle, NmAddFrame, NmStartCapture, NmGetAdapterCount, NmLoadNplParser, NmAddFilter, NmCreateFrameParserConfiguration, NmAddField, NmCreateFrameParser, NmParseFrame, NmEvaluateFilter, NmGetFieldValueString, NmGetFieldCount, NmGetParsedFieldInfo, NmGetFieldName};
use cpp_xport::shared::types::*;
use std::mem::zeroed;
use std::thread::sleep;
use std::time::{Duration, SystemTime};
use cpp_xport::util::WideString::{ToWide, FromWide};
use std::ptr::{null_mut, null};
use cpp_xport::shared::types::NmNplParserLoadingOption::NmAppendRegisteredNplSets;
use cpp_xport::shared::types::NmFrameParserOptimizeOption::NmParserOptimizeNone;
use std::ops::AddAssign;
use cpp_xport::shared::types::BOOL::{FALSE, TRUE};
use cpp_xport::shared::types::NmFrameParsingOption::all;
/// Wi-Fi network interface
pub const adapter_idx: ULONG = 4;
/// struct for passing handles to callback
pub struct HandleBundle {
pub frames_elapsed: ULONG,
pub integrity_check: &'static str,
pub cap_file: HANDLE,
pub frame_parser: HANDLE,
pub filter_id: ULONG,
pub field_id: ULONG,
}
/// on frame callback
pub unsafe extern "system" fn _MyFrameIndication(hCaptureEngine: HANDLE, adapterIndex: ULONG, pContext: LPVOID, hRawFrame: HANDLE) {
/// asserting the raw frame is not null
assert!(!hRawFrame.is_null());
/// getting the HandleBundle
let handle_bundle: &mut HandleBundle = (pContext as *mut HandleBundle).as_mut().unwrap();
println!("integrity check, handle bundle says: {}", handle_bundle.integrity_check);
/// frame preprocessing
let mut parsed_frame: HANDLE = unsafe {zeroed()};
let ret = unsafe { NmParseFrame(handle_bundle.frame_parser,
hRawFrame,
handle_bundle.frames_elapsed,
all,
&mut parsed_frame,
null_mut())
};
handle_bundle.frames_elapsed.add_assign(1); /// incrementing frame count by 1
println!("NmParseFrame: {}",ret);
assert_eq!(ret, 0);
/// getting total number of fields on frame
let mut total_fields: ULONG = 0;
let ret = unsafe {
NmGetFieldCount(parsed_frame, &mut total_fields)
};
println!("NmGetFieldCount: {}",ret);
assert_eq!(ret, 0);
println!("{} total fields on the frame", total_fields);
/// for every field attempting to read its path and name
// for idx in 1..total_fields {
// let mut path_buffer: Vec<u16> = vec![0_u16;128];
// let mut name_buffer: Vec<u16> = vec![0_u16;128];
// let ret = unsafe {
// NmGetFieldName(parsed_frame,
// idx,
// NmParsedFieldNames::NmFieldNamePath,
// path_buffer.as_mut_ptr(),
// 128,
// name_buffer.as_mut_ptr())
// };
// println!("NmGetFieldName: {}", ret);
// assert_eq!(ret, 0);
// println!("full field name: {}{}",
// FromWide(path_buffer.as_mut_ptr(), 128),
// FromWide(name_buffer.as_mut_ptr(), 128));
// }
/// using the filter added to evaluate the frame data
let mut passed: BOOL = FALSE;
let ret = unsafe {
NmEvaluateFilter(parsed_frame,
handle_bundle.filter_id,
&mut passed)
};
println!("NmEvaluateFilter: {}",ret);
assert_eq!(ret, 0);
/// if the frame data triggers our filter
if passed == TRUE {
/// extracting the value from the added field into string buffer
let mut string_buffer: Vec<u16> = vec![0_u16;256]; /// making a wide string buffer of known length
let ret = unsafe {
NmGetFieldValueString(parsed_frame,
handle_bundle.field_id,
255,
string_buffer.as_mut_ptr())
};
println!("NmGetFieldValueString: {}", ret);
assert_eq!(ret, 0);
/// outputting the value
println!("field value: {}", FromWide(string_buffer.as_mut_ptr(), 255));
}
/// releasing the parsed frame handle
unsafe {
NmCloseHandle(parsed_frame)
};
/// storing the raw frame in the capture file
let ret = unsafe {
NmAddFrame(handle_bundle.cap_file, hRawFrame)
};
println!("NmAddFrame: {}",ret);
assert_eq!(ret, 0);
/// releasing the raw frame handle
unsafe {
NmCloseHandle(hRawFrame)
};
}
/// build (on init) callback
pub unsafe extern "system" fn _onBuild(_: PVOID, _: ULONG, _: LPCWSTR, _: ULONG) {
println!("on init called");
}
fn main () {
/// opening a file to store the capture
let mut myCapFile: HANDLE = unsafe { zeroed() };
let mut CapSize: ULONG = unsafe { zeroed() };
let mut pname: Vec<u16> = ToWide("C:\\Users\\grass\\Desktop\\codes\\Rust\\cpp_xport\\res\\20sec.cap");
let ret = unsafe { NmCreateCaptureFile(pname.as_mut_ptr(), 2000,
0, &mut myCapFile as PHANDLE, &mut CapSize)
};
println!("NmCreateCaptureFile: {}", ret);
assert_eq!(ret, 0);
/// initializing the capture engine
let mut myCaptureEngine: HANDLE = unsafe { zeroed() };
let ret = unsafe { NmOpenCaptureEngine(&mut myCaptureEngine) };
println!("NmOpenCaptureEngine: {}", ret);
assert_eq!(ret, 0);
// =============================================================================================
/// loads configuration language parser
let mut parser: HANDLE = unsafe {zeroed()};
let ret = unsafe { NmLoadNplParser(null_mut(),
NmAppendRegisteredNplSets,
Some(_onBuild),
null_mut(), &mut parser) };
println!("NmLoadNplParser: {}",ret);
assert_eq!(ret, 0);
/// creates a frame parser config
let mut parser_config: HANDLE = unsafe {zeroed()};
let ret = unsafe { NmCreateFrameParserConfiguration(parser,
Some(_onBuild),
null_mut(),
&mut parser_config) };
println!("NmCreateFrameParserConfiguration: {}",ret);
assert_eq!(ret, 0);
/// adds a filtering rule to the frame parser config
let mut rule = ToWide("ProcessID == 16648");
let mut filter_id: ULONG = 0;
let ret = unsafe { NmAddFilter(parser_config,
rule.as_mut_ptr(),
&mut filter_id)
};
println!("NmAddFilter: {}",ret);
assert_eq!(ret, 0);
/// enables optimized access to the selected fields (http.request.uri in this case)
// let mut field_id: ULONG = 0;
// let ret = unsafe {
// let mut eq_string = ToWide("http.request.uri");
// NmAddField(parser_config,
// eq_string.as_mut_ptr(),
// &mut field_id)
//
// };
// println!("NmAddField: {}", ret);
// assert_eq!(ret, 0);
/// creates the frame parser
let mut frame_parser: HANDLE = unsafe {zeroed()};
let ret = unsafe {
NmCreateFrameParser(parser_config,
&mut frame_parser,
NmParserOptimizeNone)
};
println!("NmCreateFrameParser: {}", ret);
assert_eq!(ret, 0);
// =============================================================================================
/// getting the number of available network interfaces
let mut total_ifaces: ULONG = unsafe { zeroed() };
let ret = unsafe { NmGetAdapterCount(myCaptureEngine, &mut total_ifaces as PULONG) };
println!("NmGetAdapterCount: {}", ret);
assert_eq!(ret, 0);
println!("{} network interfaces are available", total_ifaces);
/// configuring network monitor to use certain adapter, and assign per frame callback
/// using pCallerContext to pass a bundle with handles
let mut handle_bundle: HandleBundle = HandleBundle {
frames_elapsed: 0,
integrity_check: "hewwo, warudo",
cap_file: myCapFile,
frame_parser: frame_parser,
filter_id: filter_id,
field_id: 0,
};
let ret = unsafe { NmConfigAdapter(myCaptureEngine,
adapter_idx,
Some(_MyFrameIndication),
&mut handle_bundle as *mut _ as _,
NmCaptureCallbackExitMode::DiscardRemainFrames)
};
println!("configuring adapter: code is {}", ret);
assert_eq!(ret, 0);
/// starting capture
let ret = unsafe {
NmStartCapture(myCaptureEngine,
adapter_idx,
NmAdapterCaptureMode::NmLocalOnly)
};
println!("starting capture: code is {}",ret);
assert_eq!(ret, 0);
// =============================================================================================
/// wasting time
let before = SystemTime::now();
while (SystemTime::now().duration_since(before).unwrap().as_secs() < 30) {
}
// =============================================================================================
println!("stopping capture");
/// closing the capture
unsafe {
NmStopCapture(myCaptureEngine, adapter_idx)
};
println!("releasing handles");
/// releasing the capture engine and file
unsafe {
NmCloseHandle(myCaptureEngine);
NmCloseHandle(myCapFile);
}
// =============================================================================================
}
它似乎部分起作用,因为字段的数量平均在 80 到 120 之间,很少有大约 1000 个字段的条目。但是,如果我在返回任何错误之前取消注释_MyFrameIndication
用于枚举它在函数中导致的字段的回调中的片段。STATUS_ACCESS_VIOLATION
我不确定它是否是由于无效的 id(因为我只是假设对于 N 个字段,有 ID 从 0 到 N 的字段),或者它是否与我传递的缓冲区有关,因为错误清楚地显示它更多的是内存问题,并且函数的文档指出,如果将传递无效的 id,则函数的返回码将表明这一点。另一件事是它可能是我不知道的一些 c++ 特定的,因为我是基于 c++ 示例和我自己制作的绑定编写的。
如果有人能阐明为什么会发生这种情况,我将不胜感激。
PS 由于我没有找到下面的任何在线文档是来自应用程序帮助窗口的屏幕截图,API dll 捆绑在一起(网络监视器 3.4)。
更新:
忘了提到我对指向数组的指针之间的区别感到非常困惑,WCHAR
因为LPWSTR
在这两种情况下它都想要一个指向 u16 buff 的指针,对吧?