STATUS_ACCESS_VIOLATION вызвано NmGetFieldName (API сетевого монитора)
Чтобы дать немного контекста - как упоминалось здесь, я пытаюсь создать двоичный файл ржавчины, который может использовать API сетевого монитора.
Текущая проблема, с которой я сталкиваюсь, связана с
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
внутри функции перед возвратом какой-либо ошибки.
Я не уверен, связано ли это с недопустимым идентификатором (поскольку я просто предположил, что для полей N есть поля с идентификаторами от 0 до N), или это связано с буферами, которые я передаю, поскольку ошибка ясно показывает что это скорее проблема с памятью, и в документации для функции указано, что, если будет передан недопустимый идентификатор, код возврата функции будет указывать на это. Другое дело, что это может быть какая-то специфика С ++, о которой я не знаю, поскольку я пишу ее на основе примера С ++ с привязками, которые я сделал сам.
Если кто-нибудь сможет пролить свет на то, почему это может происходить, я был бы очень признателен.
PS Поскольку я не нашел никакой интерактивной документации, ниже приведены снимки экрана из окна справки приложения, с которым поставляется API dll (Network Monitor 3.4).
Обновление: забыл упомянуть, что меня очень смущает разница между указателем на массив
WCHAR
а также
LPWSTR
ведь в обоих случаях ему нужен указатель на бафф u16, верно?