본문 바로가기
개발/Windows

UNICODE_STRING 동적할당 하기 / 드라이버개발

by lucidmaj7 2020. 7. 24.
728x90
반응형

UNICODE_STRING 동적할당 하기 / 드라이버개발

드라이버 개발을 할때 주로 문자열은 UNICODE_STRING이라는 자료구조를 사용하게 된다. 하지만 익숙치 않은 구조때문인지 드라이버 개발 입문시 어려움을 겪는 부분이기도하다.
우선 UNICODE_STRING 구조체를 보겠다.

typedef struct _UNICODE_STRING {
  USHORT Length;
  USHORT MaximumLength;
  PWSTR  Buffer;
} UNICODE_STRING, *PUNICODE_STRING;

유저 모드 프로그램 개발시 char, wchar와 같이 단순 배열 형태가 아닌 것을 볼 수 있다.

첫번째 필드 Length는 문자열 버퍼의 길이를 바이트 단위로 나타낸다. 조심해야 한다. 문자의 갯수가 아니라 버퍼 바이트 길이이다. 이때, NULL문자를 제외한 크기이다. 또 주의 해야 할 점은 Length가 0이라도 버퍼에 NULL가 들어있을 수 있다.

두번째, MaxiumLengthBuffer에 할당된 총 메모리의 바이트 크기를 나타낸다.

마지막으로 Buffer는 실제 문자 데이터가 들어간 버퍼이다. Wide-Charactor를 가리킨다.

UNICODE_STRING은 문자열을 나타내는게 아니라 문자열의 버퍼와 길이등의 정보를 저장하고 있는 구조체라는 것을 알 수 있다.

UNICODE_STRING 동적할당/해제

다음은 UNICODE_STRING의 동적할당, 해제를 구현한 코드이다.

동적할당 시 MaxiumLength기준으로 버퍼크기를 할당받아 구조체를 체워주면된다.


NTSTATUS AllocUnicode(
    PUNICODE_STRING dst, 
    USHORT maxiumBufferLen
)
{
    dst->Buffer = (PWCH)ExAllocatePoolWithTag(NonPagedPool, maxiumBufferLen, POOL_TAG);
    if (dst->Buffer == NULL)
    {
        return STATUS_UNSUCCESSFUL;
    }
    RtlZeroMemory(dst->Buffer, maxiumBufferLen);

    dst->Length = 0;
    dst->MaximumLength = maxiumBufferLen;

    return STATUS_SUCCESS;

}

할당해제는 Buffer필드가 가리키고 있는 Wide Character 버퍼를 할당해제 한다.

VOID FreeUnicode(
    PUNICODE_STRING dst
)
{
    if (!dst->Buffer)
    {
        return;
    }

    ExFreePool(dst->Buffer);
    dst->Buffer = 0;
    dst->Length = 0;
    dst->MaximumLength = 0;

}

예제 코드

다음은 UNICODE_STRING을 동적할당하여 문자열을 복사하고 출력하는 예제 코드이다.

출력은 KdPrint함수를 이용하고 UNICODE_STRING의 Format String 식별자는 %wZ이다.

#include <ntddk.h>

#define POOL_TAG 'cw32'

NTSTATUS DriverEntry(
    PDRIVER_OBJECT pDriverObject,
    PUNICODE_STRING pRegistryPath
);

VOID DriverUnload(
    PDRIVER_OBJECT pDriverObject
);

NTSTATUS AllocUnicode(
    PUNICODE_STRING dst,
    USHORT maxiumBufferLen
);

VOID FreeUnicode(
    PUNICODE_STRING dst
);



const WCHAR gHello[] = L"hello~Driver!";

VOID FreeUnicode(
    PUNICODE_STRING dst
)
{
    if (!dst->Buffer)
    {
        return;
    }

    ExFreePool(dst->Buffer);
    dst->Buffer = 0;
    dst->Length = 0;
    dst->MaximumLength = 0;

}

NTSTATUS AllocUnicode(
    PUNICODE_STRING dst, 
    USHORT maxiumBufferLen
)
{
    dst->Buffer = (PWCH)ExAllocatePoolWithTag(NonPagedPool, maxiumBufferLen, POOL_TAG);
    if (dst->Buffer == NULL)
    {
        return STATUS_UNSUCCESSFUL;
    }
    RtlZeroMemory(dst->Buffer, maxiumBufferLen);

    dst->Length = 0;
    dst->MaximumLength = maxiumBufferLen;

    return STATUS_SUCCESS;

}

NTSTATUS DriverEntry(
    PDRIVER_OBJECT pDriverObject,
    PUNICODE_STRING pRegistryPath
)
{

    UNREFERENCED_PARAMETER(pDriverObject);
    UNREFERENCED_PARAMETER(pRegistryPath);

    pDriverObject->DriverUnload = DriverUnload;

    NTSTATUS status = STATUS_UNSUCCESSFUL;
    UNICODE_STRING helloUnicode;

    UNICODE_STRING helloUnicodeAlloc;

    RtlInitUnicodeString(&helloUnicode, gHello); //Unicode String 초기화
    KdPrint(("helloUnicode=%wZ Length=%d MaxiumLength=%d\n", &helloUnicode, helloUnicode.Length, helloUnicode.MaximumLength));

    AllocUnicode(&helloUnicodeAlloc, 100);

    RtlCopyUnicodeString(&helloUnicodeAlloc, &helloUnicode);
    KdPrint(("helloUnicodeAlloc=%wZ Length=%d MaxiumLength=%d\n", &helloUnicodeAlloc, helloUnicodeAlloc.Length, helloUnicodeAlloc.MaximumLength));

    FreeUnicode(&helloUnicodeAlloc);

    return status;

}


VOID DriverUnload(
    PDRIVER_OBJECT pDriverObject
)
{

    UNREFERENCED_PARAMETER(pDriverObject);
    KdPrint(("DriverUnload\n"));

}

 

참고

728x90
반응형

댓글