ドライバーから 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
:私は物事をリファクタリングしていて、WskCaptureProviderNPI
とWskReleaseProviderNPI
を別の関数に移動しようとしましたが、別のエラーが発生し始めました。それは奇妙だったので、WSK_PROVIDER_NPI
グローバルにしました-それはうまくいきました。
少し後、そのソケットでメッセージを送信しようとしましたが、その前に 2 バイトのジャンクを受信していました。WskSocketConnect
数時間といくつかのデバッグ メッセージの後、呼び出し後にバッファ アドレスが変更されていることに気付きました。現在、バッファ アドレスもグローバル変数であり、構造体の直後に宣言されていWSK_PROVIDER_NPI
ます。Foo
パディングを追加すると (「 」と「 」を検索WorkerThread()
)、修正されます。
今何?私はこれにまったく慣れていませんが、メモリの破損は関数によって引き起こされているようです。特に、とその呼び出しWsk
の間で実行されるコードがあまりないためです。何か案は?DriverEntry
WskSocketConnect
これは 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 のサンプルでも同じことが行われています。念のため、グローバルにしようとしましたが、同じ動作をしています。