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, верно?

0 ответов

Другие вопросы по тегам