1

ドライバーから WinSock API を使用して別のコンピューターに接続しようとしています。問題は、WskSocketConnect(そしてWskConnect、そのルートをたどると) で失敗することSTATUS_INVALID_ADDRESSです。私のコードは次のとおりです。

#pragma warning(push)
#pragma warning(disable:4510)
#pragma warning(disable:4512)
#pragma warning(disable:4610)

#include <ntddk.h>
#include <wsk.h>

#pragma warning(pop)

const WSK_CLIENT_DISPATCH WskClientDispatch = {
    MAKE_WSK_VERSION(1, 0),
    0,
    NULL
};

WSK_REGISTRATION WskRegistration;

typedef struct _ASYNCHRONOUS_OPERATION_CONTEXT {
    KEVENT Event;
    PIRP Irp;
} ASYNCHRONOUS_OPERATION_CONTEXT, *PASYNCHRONOUS_OPERATION_CONTEXT;

extern "C" DRIVER_INITIALIZE DriverEntry;
extern "C" DRIVER_UNLOAD DriverUnload;
extern "C" KSTART_ROUTINE WorkerThread;
extern "C" IO_COMPLETION_ROUTINE SyncIrpCompletionRoutine;
extern "C" NTSTATUS WorkerThreadImpl();
extern "C" NTSTATUS InitializeAsynchronousOperationContext(PASYNCHRONOUS_OPERATION_CONTEXT Context);
extern "C" void FreeAsynchronousOperationContext(PASYNCHRONOUS_OPERATION_CONTEXT Context);
extern "C" void ReuseAsynchronousOperationContext(PASYNCHRONOUS_OPERATION_CONTEXT Context);
extern "C" NTSTATUS WaitForOperation(PASYNCHRONOUS_OPERATION_CONTEXT Context, NTSTATUS DispatchStatus);

NTSTATUS
    DriverEntry(
    __in PDRIVER_OBJECT DriverObject,
    __in PUNICODE_STRING RegistryPath
    );

VOID
    WorkerThread(
    __in PVOID Context
    );

VOID
    DriverUnload(
    __in PDRIVER_OBJECT DriverObject
    );

#ifdef ALLOC_PRAGMA

#pragma alloc_text(INIT, DriverEntry)
#pragma alloc_text(PAGE, DriverUnload)
#pragma alloc_text(PAGE, WorkerThread)
#pragma alloc_text(PAGE, WorkerThreadImpl)
#pragma alloc_text(PAGE, InitializeAsynchronousOperationContext)
#pragma alloc_text(PAGE, FreeAsynchronousOperationContext)
#pragma alloc_text(PAGE, ReuseAsynchronousOperationContext)
#pragma alloc_text(PAGE, WaitForOperation)

#endif

#define DATA_BUFFER_POOL_TAG 'wskt'

NTSTATUS
    DriverEntry(
    __in PDRIVER_OBJECT DriverObject,
    __in PUNICODE_STRING RegistryPath
    )
{
    NTSTATUS status;
    HANDLE threadHandle;
    WSK_CLIENT_NPI wskClientNpi;

    UNREFERENCED_PARAMETER(RegistryPath);

    PAGED_CODE();

    DbgPrint("Loading");

    wskClientNpi.ClientContext = NULL;
    wskClientNpi.Dispatch = &WskClientDispatch;
    status = WskRegister(&wskClientNpi, &WskRegistration);

    if (!NT_SUCCESS(status)) {
        return status;
    }

    status = PsCreateSystemThread(
        &threadHandle, THREAD_ALL_ACCESS, NULL, NULL, NULL,
        WorkerThread, NULL);

    if (!NT_SUCCESS(status)) {
        WskDeregister(&WskRegistration);
        return status;
    }

    ZwClose(threadHandle);

    DriverObject->DriverUnload = DriverUnload;

    DbgPrint("Loaded");

    return STATUS_SUCCESS;
}

VOID
    DriverUnload(
    __in PDRIVER_OBJECT DriverObject
    )
{  
    UNREFERENCED_PARAMETER(DriverObject);

    PAGED_CODE();

    DbgPrint("Unloading");
    WskDeregister(&WskRegistration);
    DbgPrint("Unloaded");
}

WSK_PROVIDER_NPI wskProviderNpi;
//CHAR Foo[10]; // padding
PCHAR DataBuffer;

USHORT htons(USHORT value)
{
    return value >> 8 | ((value & 0xff) << 8);
}

NTSTATUS InitializeAsynchronousOperationContext(PASYNCHRONOUS_OPERATION_CONTEXT Context)
{
    PAGED_CODE();

    Context->Irp = IoAllocateIrp(1, FALSE);
    if (Context->Irp == NULL) {
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    KeInitializeEvent(&Context->Event, SynchronizationEvent, FALSE);

    IoSetCompletionRoutine(Context->Irp,
        SyncIrpCompletionRoutine,
        &Context->Event, TRUE, TRUE, TRUE);

    return STATUS_SUCCESS;
}

void FreeAsynchronousOperationContext(PASYNCHRONOUS_OPERATION_CONTEXT Context)
{
    PAGED_CODE();

    IoFreeIrp(Context->Irp);
}

void ReuseAsynchronousOperationContext(PASYNCHRONOUS_OPERATION_CONTEXT Context)
{
    PAGED_CODE();

    IoReuseIrp(Context->Irp, STATUS_UNSUCCESSFUL);
    IoSetCompletionRoutine(Context->Irp,
        SyncIrpCompletionRoutine,
        &Context->Event, TRUE, TRUE, TRUE);
}

NTSTATUS WaitForOperation(PASYNCHRONOUS_OPERATION_CONTEXT Context, NTSTATUS DispatchStatus)
{
    PAGED_CODE();

    if (DispatchStatus == STATUS_PENDING) {
        KeWaitForSingleObject(&Context->Event, Executive, KernelMode, FALSE, NULL);
    }

    return Context->Irp->IoStatus.Status;
}

NTSTATUS WorkerThreadImpl()
{
    PAGED_CODE();

    NTSTATUS status;

    status = WskCaptureProviderNPI(
        &WskRegistration, 
        WSK_INFINITE_WAIT,
        &wskProviderNpi);

    if (!NT_SUCCESS(status)) {
        DbgPrint("WskCaptureProviderNPI FAIL");
        return status;
    }

    DataBuffer = (PCHAR) ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE, DATA_BUFFER_POOL_TAG);
    if (DataBuffer == NULL) {
        WskReleaseProviderNPI(&WskRegistration);
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    ASYNCHRONOUS_OPERATION_CONTEXT OperationContext;
    status = InitializeAsynchronousOperationContext(&OperationContext);
    if (!NT_SUCCESS(status)) {
        WskReleaseProviderNPI(&WskRegistration);
        ExFreePoolWithTag(DataBuffer, DATA_BUFFER_POOL_TAG);
        return status;
    }

    SOCKADDR_IN localAddr  = { AF_INET, 0, IN4ADDR_ANY_INIT };
    SOCKADDR_IN remoteAddr = { AF_INET, htons(7777), IN4ADDR_LOOPBACK_INIT };
    DbgPrint("%p", DataBuffer);

    status = wskProviderNpi.Dispatch->WskSocketConnect(&wskProviderNpi.Client,
        SOCK_STREAM, IPPROTO_TCP,
        (PSOCKADDR) &localAddr, (PSOCKADDR) &remoteAddr, 0,
        NULL, NULL, NULL, NULL, NULL,
        OperationContext.Irp);
    // BUGBUG here, DataBuffer has changed since the previous DbgPrint()
    DbgPrint("%p", DataBuffer);
    status = WaitForOperation(&OperationContext, status);

    if (NT_SUCCESS(status)) {
        PWSK_SOCKET socket = (PWSK_SOCKET) OperationContext.Irp->IoStatus.Information;
        PWSK_PROVIDER_CONNECTION_DISPATCH connectionDispatch = (PWSK_PROVIDER_CONNECTION_DISPATCH) socket->Dispatch;
        ReuseAsynchronousOperationContext(&OperationContext);
        status = connectionDispatch->Basic.WskCloseSocket(socket, OperationContext.Irp);
        status = WaitForOperation(&OperationContext, status);
    }

    FreeAsynchronousOperationContext(&OperationContext);

    WskReleaseProviderNPI(&WskRegistration);
    ExFreePoolWithTag(DataBuffer, DATA_BUFFER_POOL_TAG);
    return STATUS_SUCCESS;
}

VOID
    WorkerThread(
    __in PVOID Context
    )
{
    UNREFERENCED_PARAMETER(Context);

    PAGED_CODE();

    PsTerminateSystemThread(WorkerThreadImpl());
}

NTSTATUS
    SyncIrpCompletionRoutine(
    __in PDEVICE_OBJECT Reserved,
    __in PIRP Irp,
    _In_reads_opt_(_Inexpressible_("varies")) PVOID Context
    )
{    
    UNREFERENCED_PARAMETER(Reserved);
    UNREFERENCED_PARAMETER(Irp);

    ASSERT(Context != NULL);

    if (Irp->PendingReturned) {
        KeSetEvent((PKEVENT) Context, 2, FALSE);
    }

    return STATUS_MORE_PROCESSING_REQUIRED;
}

0xc0000141呼び出しは( )と同期して失敗しますSTATUS_INVALID_ADDRESS。localhost のそのポートでリッスンしているアプリケーションがあり、リモート コンピューターと同じように動作しています。

ヒントをいただければ幸いです。

編集今、物事は奇妙になっています。完全なファイルでソース コードを更新しました。

私は問題を発見しましたWskSocketConnect:私は物事をリファクタリングしていて、WskCaptureProviderNPIWskReleaseProviderNPIを別の関数に移動しようとしましたが、別のエラーが発生し始めました。それは奇妙だったので、WSK_PROVIDER_NPIグローバルにしました-それはうまくいきました。

少し後、そのソケットでメッセージを送信しようとしましたが、その前に 2 バイトのジャンクを受信して​​いました。WskSocketConnect数時間といくつかのデバッグ メッセージの後、呼び出し後にバッファ アドレスが変更されていることに気付きました。現在、バッファ アドレスもグローバル変数であり、構造体の直後に宣言されていWSK_PROVIDER_NPIます。Fooパディングを追加すると (「 」と「 」を検索WorkerThread())、修正されます。

今何?私はこれにまったく慣れていませんが、メモリの破損は関数によって引き起こされているようです。特に、とその呼び出しWskの間で実行されるコードがあまりないためです。何か案は?DriverEntryWskSocketConnect

これは Windows 7 x64 上にあります。

更新 2 コードの先頭で無効にしているコンパイル警告は次のとおりです。

warning C4510: '_WSK_TDI_MAP_INFO' : default constructor could not be generated
warning C4512: '_WSK_TDI_MAP_INFO' : assignment operator could not be generated
warning C4610: struct '_WSK_TDI_MAP_INFO' can never be instantiated - user defined constructor required

ファイルをCとしてコンパイルすると修正されると思います。

my に関してはWSK_CLIENT_NPI、 のドキュメントでWskRegisterは、有効なままにしておく必要があるとは言及されておらず (他の引数の場合と同様) echosrv、DDK のサンプルでも同じことが行われています。念のため、グローバルにしようとしましたが、同じ動作をしています。

4

1 に答える 1

0

警告を無視したり無効にしたりすることはお勧めしません. 誇りを持って警告を誇示してください。標準的な方法で警告を削除するお手伝いをします。警告メッセージだけでなく、警告が表示されている行も表示してください。未定義の動作を呼び出している可能性があり、警告がそれを強調しているように思えます。

この形式は OS API、コンパイラ、および標準ライブラリ用に予約されているため、アンダースコアが先頭にある識別子も問題になる可能性があります。_ASYNCHRONOUS_OPERATION_CONTEXT の名前を変更してください。

%p は、(printf 書式指定子を使用する) DbgPrint にどの種類のポインターを期待するように指示しますか? 空所 *。printf が問題を引き起こしているというまれなケースに対処するために、いくつかのキャストを行うことをお勧めします。

&wskProviderNpi.Client は、&wskClientNpi と同じオブジェクトを参照することを意図しているようです。ここでの問題は、DriverEntry が返されたときに wskClientNpi が破棄され、あなたが言及した「STATUS_INVALID_ADDRESS」エラーが発生することです (一種の際どい方法で)。wskRegistration 宣言のすぐ下に wskClientNpi 宣言を入れてみましたか?

于 2013-01-23T10:10:48.040 に答える