SSブログ

Filter Manager APIを使ってボリュームを列挙する例 [CodeTips]

年明け最初に上げようと思って、昨年末に用意していた内容を上げておきます。
ということは、「あけましておめでとうございます」ですね。明日から5月だというのに…(^^;


GitHubの説明などで 'FltMgr' (Filter Manager) APIと書いていますが、正確には"Filter Manager Support for Minifilter Drivers"の”User-Mode Library” (FltLib.dll) のAPI を使用しています。

Windowsにfltmcというコマンドがありますが、このサンプルではfltmcの instancesやvolumesオプションで表示される様な内容を取得する例を示します。fltmcがコマンド目的上フィルタドライバを中心にした情報の見せ方なのに対し、サンプルではボリュームを中心とした見せ方となってします。

なお、このサンプルは管理者モードで実行してください。

あと、すっかり当たり前に公開してしまったのですが、コード中、print_string()でUNICODE_STRINGを使用している箇所があります(どさくさに紛れて__based変数も)。ここは当然ながらUNICODE_STRINGは必ずしも必須ではありません(使用しない場合はこの部分を適切なC文字列の処理に変更してください)。表示したい内容がポインタとオフセット、レングスで与えられるため、手軽に処理する例としてこの様な使い方をしています。

Visual Studio 2010プロジェクト,Windows 7 WDK用 sourcesを含むすべての内容は GitHubに公開しています。

GitHub レポジトリ:
https://github.com/katsu-y/fsfltview

//
// fsfltview
//
// Sample: Using the filter manager for volume and filter instance enumeration.
//
// Note:   This code is need to run under administrator mode.
//
// Author: YAMASHITA Katsuhiro
//
#include <SDKDDKVer.h>

#include <stdio.h>
#include <stdlib.h>

#include <windows.h>
#include <fltuser.h>  // for FltMgr

#if 0
#include <winternl.h> // for UNICODE_STRING
#else
typedef struct _UNICODE_STRING {
    USHORT Length;
    USHORT MaximumLength;
    PWSTR  Buffer;
} UNICODE_STRING;
typedef UNICODE_STRING *PUNICODE_STRING;
#endif

#define _VOLUME_NAME_LENGTH 256

WORD g_wVersion = 0;

HRESULT
_FindFirst_VolumeInstance(
    PCWSTR pszVolumeName,
    INSTANCE_INFORMATION_CLASS dwInformationClass,
    LPVOID  *lpReturnedBuffer,
    LPHANDLE  lpVolumeInstanceFind
    )
{
    HRESULT hr;
    HANDLE hVolumeInstanceFind;
    DWORD BytesReturned;

    PVOID lpBuffer = NULL;
    DWORD dwBufferSize = 0;

    for(;;)
    {
        hr = FilterVolumeInstanceFindFirst(
                pszVolumeName,
                dwInformationClass,
                lpBuffer,
                dwBufferSize,
                &BytesReturned,
                &hVolumeInstanceFind
                );

        if( HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER )
        {
            if( lpBuffer )
                free(lpBuffer);
            lpBuffer = malloc(BytesReturned);
            if( lpBuffer == NULL )
            {
                hr = E_OUTOFMEMORY;
                break;
            }
            dwBufferSize = BytesReturned;

            continue;
        }
        else
        {
            break;
        }
    }

    if( hr == S_OK && lpBuffer != NULL )
    {
        *lpReturnedBuffer = lpBuffer;
        *lpVolumeInstanceFind = hVolumeInstanceFind;
    }
    else
    {
        *lpReturnedBuffer = NULL;
        *lpVolumeInstanceFind = NULL;

        if( lpBuffer != NULL )
            free(lpBuffer);
    }

    return hr;
}

HRESULT
_FindNext_VolumeInstance(
    HANDLE  hVolumeInstanceFind,
    INSTANCE_INFORMATION_CLASS dwInformationClass,
    LPVOID  *lpReturnedBuffer
    )
{
    HRESULT hr;
    DWORD BytesReturned;

    PVOID lpBuffer = NULL;
    DWORD dwBufferSize = 0;

    for(;;)
    {
        hr = FilterVolumeInstanceFindNext(
                hVolumeInstanceFind,
                dwInformationClass,
                lpBuffer,
                dwBufferSize,
                &BytesReturned
                );

        if( HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER )
        {
            if( lpBuffer )
                free(lpBuffer);
            lpBuffer = malloc(BytesReturned);
            if( lpBuffer == NULL )
            {
                hr = E_OUTOFMEMORY;
                break;
            }
            dwBufferSize = BytesReturned;

            continue;
        }
        else
        {
            break;
        }
    }

    if( hr == S_OK && lpBuffer != NULL )
    {
        *lpReturnedBuffer = lpBuffer;
    }
    else
    {
        *lpReturnedBuffer = NULL;

        if( lpBuffer != NULL )
            free(lpBuffer);
    }
    return hr;
}

void print_string(PCSTR Title,PVOID pBuffer,USHORT offset,USHORT len)
{
    BYTE __based(pBuffer) *pBased = 0;
    UNICODE_STRING us;
    us.Length = len;
    us.MaximumLength = us.Length;
    us.Buffer = (PWSTR)(pBased + offset);
    printf("%s%wZ\n",Title,&us);
}

void EnumVolumeInstance(PCWSTR pszVolumeName)
{
    HRESULT hr;
    HANDLE hVolumeInstanceFind;
    INSTANCE_INFORMATION_CLASS InfoClass;
    PVOID pBuffer;

    if( g_wVersion >= _WIN32_WINNT_VISTA )
        InfoClass = InstanceAggregateStandardInformation;
    else
        InfoClass = InstanceFullInformation;

    hr = _FindFirst_VolumeInstance(pszVolumeName,InfoClass,
                (PVOID *)&pBuffer,&hVolumeInstanceFind);

    if( hr == S_OK )
    {
        do
        {
            if( g_wVersion >= _WIN32_WINNT_VISTA )
            {
                INSTANCE_AGGREGATE_STANDARD_INFORMATION *piasi 
                    = (INSTANCE_AGGREGATE_STANDARD_INFORMATION *)pBuffer;

                if( piasi->Flags == FLTFL_IASI_IS_MINIFILTER )
                {
                    print_string("\tInstance Name: ",piasi,
                        piasi->Type.MiniFilter.InstanceNameBufferOffset,
                        piasi->Type.MiniFilter.InstanceNameLength);

                    print_string("\tFilter Name  : ",piasi,
                        piasi->Type.MiniFilter.FilterNameBufferOffset,
                        piasi->Type.MiniFilter.FilterNameLength);

                    print_string("\tAltitude     : ",piasi,
                        piasi->Type.MiniFilter.AltitudeBufferOffset,
                        piasi->Type.MiniFilter.AltitudeLength);

                    printf("\n");
                }
                else if( piasi->Flags == FLTFL_IASI_IS_LEGACYFILTER )
                {
                    print_string("\tFilter Name  : ",piasi,
                        piasi->Type.LegacyFilter.FilterNameBufferOffset,
                        piasi->Type.LegacyFilter.FilterNameLength);

                    print_string("\tAltitude     : ",piasi,
                        piasi->Type.LegacyFilter.AltitudeBufferOffset,
                        piasi->Type.LegacyFilter.AltitudeLength);

                    printf("\n");
                }
            }
            else
            {
                INSTANCE_FULL_INFORMATION *pifi
                    = (INSTANCE_FULL_INFORMATION *)pBuffer;

                print_string("\tInstance Name: ",pifi,
                    pifi->InstanceNameBufferOffset,
                    pifi->InstanceNameLength);

                print_string("\tFilter Name  : ",pifi,
                    pifi->FilterNameBufferOffset,
                    pifi->FilterNameLength);

                print_string("\tAltitude     : ",pifi,
                    pifi->AltitudeBufferOffset,
                    pifi->AltitudeLength);

                printf("\n");
            }
            free(pBuffer);

            hr = _FindNext_VolumeInstance(hVolumeInstanceFind,
							InfoClass,(PVOID *)&pBuffer);
        }
        while( hr == S_OK );
    }
    else
    {
        printf("\tenum volume instance error: 0x%08X\n\n",hr);
    }
}

int __cdecl wmain(int /*argc*/, WCHAR* /*argv*/[])
{
    HRESULT hr;
    HANDLE hFilterFind;
    DWORD BytesReturned;

    WORD wVersion = LOWORD(GetVersion());
    g_wVersion = MAKEWORD(HIBYTE(wVersion),LOBYTE(wVersion));

    DWORD dwBufferSize = sizeof(FILTER_VOLUME_STANDARD_INFORMATION)
						 + (sizeof(WCHAR) * _VOLUME_NAME_LENGTH);
    FILTER_VOLUME_STANDARD_INFORMATION *lpBuffer =
						 (FILTER_VOLUME_STANDARD_INFORMATION *)malloc(dwBufferSize);
    if( lpBuffer == NULL )
        return -1;

    hr = FilterVolumeFindFirst(
                FilterVolumeStandardInformation,
                lpBuffer,
                dwBufferSize,
                &BytesReturned,
                &hFilterFind
                ); 

    if( hr == S_OK )
    {
        do
        {
            WCHAR sz[_VOLUME_NAME_LENGTH+1];
            WCHAR szDosDrive[MAX_PATH];

            memcpy(sz,lpBuffer->FilterVolumeName,lpBuffer->FilterVolumeNameLength);
            sz[ lpBuffer->FilterVolumeNameLength/sizeof(WCHAR) ] = UNICODE_NULL;

            if( FilterGetDosName(sz,szDosDrive,MAX_PATH) != S_OK )
            {
                szDosDrive[0] = 0;
            }

            if( szDosDrive[0] != L'\0' )
                printf("%S (%s:)\n",sz,szDosDrive);
            else
                printf("%S\n",sz);

            EnumVolumeInstance(sz);

            hr = FilterVolumeFindNext(
                        hFilterFind,
                        FilterVolumeStandardInformation,
                        lpBuffer,
                        dwBufferSize,
                        &BytesReturned
                        ); 
        }
        while( hr == S_OK );
    }
    else
    {
        printf("error: 0x%08X\n",hr);
    }

    free(lpBuffer);

    return 0;
}






SetupAPIを使ってディスクドライブを列挙する [CodeTips]

前回の記事は8月だったので、約四ヶ月!間が空いてしまいました。
でも、ここは思い出したようにやっていきます。

さて、今回はWindows Setup API を使って、ディスクドライブデバイスを列挙する例です。

#include <stdio.h>
#include <windows.h>
#include <setupapi.h>
#include <devguid.h>
#define INITGUID
#include <devpkey.h>

int wmain(int argc, WCHAR* argv[])
{
    HDEVINFO hDevInfo;

    hDevInfo = SetupDiGetClassDevsEx(&GUID_DEVCLASS_DISKDRIVE,NULL,NULL,
                                     DIGCF_PROFILE,NULL,NULL,NULL);
    if( hDevInfo != INVALID_HANDLE_VALUE )
    {
        SP_DEVINFO_DATA DevInfoData = {0};
        DevInfoData.cbSize = sizeof(DevInfoData);

        BYTE Buffer[4096];

        DWORD Index = 0;

        while( SetupDiEnumDeviceInfo(hDevInfo,Index,&DevInfoData) )
        {
            DEVPROPTYPE PropertyType;

            if( SetupDiGetDeviceProperty(hDevInfo,&DevInfoData,
                    &DEVPKEY_Device_FriendlyName,&PropertyType,
                    Buffer,sizeof(Buffer),NULL,0) )
            {
                if( PropertyType == DEVPROP_TYPE_STRING )
                {
                    wprintf(L"%s\n",(PWSTR)Buffer);
                }
            }			
            Index++;
        }
        SetupDiDestroyDeviceInfoList(hDevInfo);
    }
    return 0;
}

この例は、SetupAPIのDevice Installation Function(SetupDiのプリフィクスを持つ)を使って、ディスクドライブクラスに登録されているデバイスを列挙して表示します。

SetupDiGetClassDevsEx関数にGUID_DEVCLASS_DISKDRIVEを指定してディスクドライブのみを列挙する様に指定し、同時にDIGCF_PROFILEを指定して現在のハードウェアプロファイルすべてを列挙する様にしています。

GUID_DEVCLASS_DISKDRIVEは、ディスクドライブ(DiskDrive)クラスを示すGUIDで、そのデバイスの列挙を指示します。一般的には内蔵ハードディスクやUSBの外付けディスク、SDカード、メモリスティックなどや仮想ディスクなども含め「ディスク」として認識され、通常エクスプローラ上でドライブが割り当てられるデバイスを指します。

フラグにDIGCF_PROFILEを指定する(0でも可。その場合はすべてのハードウェアプロファイルが対象になる)と面白い情報を得ることができます。アクティブなディスクデバイス以外に非アクティブなデバイスも列挙することができるのです。このサンプルを実行すると、例えば過去にPCに接続して、その時点でそうはたUSBメモリなども表示されます。私も長期間使っているPCに試したところ、いろいろ懐かしいUSBメモリや今は手元に無いデジカメや携帯プレーヤーなどが表示され感慨深いものがありました。

ただ、この例は対象をディスクデバイスクラスのみとしているため、DVD/CD-ROMドライブやフロッピーディスクなどディスクドライブ以外のクラスに属するデバイスは表示されません(恐らくスマートフォンもポータブルデバイス扱いで表示できません。ただ、モバイルデバイスに詳しくないので判りませんが、ものによってはソフトのインストールの為CD-ROMクラスデバイスを登録する機種ある様です。なので、ディスクドライブで表示するものもあるかもしれません)。しかし、これらのクラスを含めるのは簡単でGUID_DEVCLASS_DISKDRIVEの部分をそれぞれのクラスGUID(GUID_DEVCLASS_CDROMなど)に置き換えれば同じ様に列挙できます(もちろんGUIDを指定せず、すべてのデバイスクラス、デバイスを列挙することも可能です)。デバイスクラスはdevguid.hに記述されています。

SetupDiGetClassDevsEx関数が成功したら、後は返されたHDEVINFO を使ってSetupDiEnumDeviceInfo関数でデバイスを列挙します。デバイス情報がSP_DEVINFO_DATAに返されるので、それを使ってSetupDiGetDeviceProperty関数を呼び出し、デバイスのプロパティを得ます。取得したいプロパティの種類は引数で指定できます。ここでは単純にDEVPKEY_Device_FriendlyNameのみを取得しています。フレンドリ名とはその名の通り人間が読む為のデバイス名や商品名で構成されます。

プロパティには型があるので、一応PropertyTypeに返されるプロパティタイプをチェックし、文字列(DEVPROP_TYPE_STRING)の場合のみ表示しています。このPropertyTypeにはいろいろな型があるので、より多くのプロパティを取得したい場合には、それぞれきちんと確認する必要があります。

SetupDiGetDevicePropertyはWindows Vista以降で登場したAPIなので、Windows XP以前では使えません。もし、Windows XPで実行したい場合はSetupDiGetDevicePropertyの部分を以下の様に書き換えます。

ULONG ulRegDataType;
ULONG cbBuffer = sizeof(Buffer);
if( CM_Get_DevNode_Registry_Property(DevInfoData.DevInst,CM_DRP_FRIENDLYNAME,
                            &ulRegDataType,Buffer,&cbBuffer,0) == CR_SUCCESS )
{
    wprintf(L"%s\n",(PWSTR)Buffer);
}


この様にコンフィグレーションマネージャのAPIを使用するため、cfgmgr32.hのインクルードも追加してください。

#include <cfgmgr32.h>


こうやって多数のデバイスが列挙されたら、不要なものを削除したくなるかもしれません。その様な場合はデバイスマネージャやDeviceWalkerなどで削除すると良いでしょう。

今回、この例の様なフレンドリ名に加え、もう少しだけ表示するプロパティを追加した「完全版」サンプルをGitHubに上げておきました。以下はその一部(mainのみ)です。このサンプルもディスクドライブクラスのみ列挙しています。

int wmain(int /*argc*/, WCHAR* /*argv[]*/)
{
    _wsetlocale(LC_ALL, L"");

    CSimpleArray devProps; 

    HDEVINFO hDevInfo;
    hDevInfo = SetupDiGetClassDevsEx(&GUID_DEVCLASS_DISKDRIVE,NULL,NULL,DIGCF_PROFILE,NULL,NULL,NULL);

    if( hDevInfo != INVALID_HANDLE_VALUE )
    {
        SP_DEVINFO_DATA DevInfoData = {0};
        DevInfoData.cbSize = sizeof(DevInfoData);

        DWORD dwIndex = 0;
        while( SetupDiEnumDeviceInfo(hDevInfo,dwIndex,&DevInfoData) )
        {
            CDevicePropertySet *set = new CDevicePropertySet;

            if( set != NULL )
            {
                if( !set->FriendlyName.GetProperty(hDevInfo, DevInfoData, DEVPKEY_Device_FriendlyName) )
                {
                    // When could not acquire friendly name, instead get the Instance ID as a friendly name.
                    // Possible cause is the target device deleted after call SetupDiEnumDeviceInfo().
                    //
                    set->FriendlyName.GetProperty(hDevInfo, DevInfoData, DEVPKEY_Device_InstanceId);
                }

                if( set->FriendlyName.IsValidData() )
                {
                    set->FriendlyName.GetProperty(hDevInfo, DevInfoData, DEVPKEY_Device_FriendlyName);
                    set->DevNodeStatus.GetProperty(hDevInfo,DevInfoData,DEVPKEY_Device_DevNodeStatus);
                    set->FriendlyName.GetProperty(hDevInfo,DevInfoData,DEVPKEY_Device_FriendlyName);
                    set->InstallDate.GetProperty(hDevInfo,DevInfoData,DEVPKEY_Device_InstallDate);
                    set->FirstInstallDate.GetProperty(hDevInfo,DevInfoData,DEVPKEY_Device_FirstInstallDate);
                    set->RemovalRelations.GetProperty(hDevInfo,DevInfoData,DEVPKEY_Device_RemovalRelations);

                    devProps.Add( set );
                }
                else
                {
                    // When could not make friendly name, free an object.
                    // But it normally does not occurs.
                    //
                    delete set;
                }
            }

            dwIndex++;
        }

        SetupDiDestroyDeviceInfoList(hDevInfo);
    }
    else
    {
        return -1; // error
    }

    // sort by friendly name
    //
    qsort(devProps.GetData(),devProps.GetSize(),sizeof(CDevicePropertySet *),_compare);

    // print information
    //
    int i,c;
    c = devProps.GetSize();
    for(i = 0; i < c; i++)
    {
        PrintFriendlyName(*devProps[i]);

        PrintDateTime(devProps[i]->InstallDate);

        PrintRelationVolumes(devProps[i]->RemovalRelations);

        printf("\n");
    }

    // frees object memory
    //
    c = devProps.GetSize();
    for(i = 0; i < c; i++)
    {
        delete devProps[i];
    }

    // frees pointer array
    //
    devProps.RemoveAll();

    return 0;
}


すべてのソースコードを以下に載せましたので、興味のある方はどうぞ。

GitHub レポジトリ:
https://github.com/katsu-y/fsstoragedevice


NtDisplayString/NtDelayExecution [CodeTips]

今回はWindows ネイティブの実行ファイルを作成します。
Win32の実行ファイルではないので、エクスプローラなどからは実行できません。後述する様にレジストリを編集してPC起動時に実行する様にします。

ソースファイル名 'ntdisplay.cpp'
#include <ntddk.h>

EXTERN_C
NTSTATUS
NTAPI
NtDisplayString(
    PUNICODE_STRING String
    );

EXTERN_C
NTSTATUS
NTAPI
NtDelayExecution( 
    BOOLEAN Alertable,
    PLARGE_INTEGER Interval
    );

void __cdecl main()
{
    UNICODE_STRING s;

    RtlInitUnicodeString(&s,L"Hello world!\n");
    NtDisplayString( &s );

    LARGE_INTEGER li;
    li.QuadPart = -(10 * 10000000); // wait for relative 10 sec
    NtDelayExecution( FALSE, &li );
}

作成するのがネイティブ実行ファイルなので、WDKは必須といえます。今回も使い慣れたWindows 7のWDKを使用します。

Windows Driver Kit Version 7.1.0

(もちろん、コンパイルやリンカの設定を自前で行えば、VisualStudioなどに添付された開発環境でもバイナリを生成できる筈です)

WDKでビルドする為に必要なsourcesファイルとmakefileも示しておきます。これらをソースファイルと同じディレクトリに置き、buildコマンドでビルドします。

ファイル名 'sources'
TARGETTYPE=PROGRAM
TARGETNAME=ntdisplay
TARGETPATH=obj
UMTYPE=nt

_NT_TARGET_VERSION=$(_NT_TARGET_VERSION_WINXP)

MINWIN_SDK_LIB_PATH=$(DDK_LIB_PATH)

INCLUDES=$(DDK_INC_PATH)

SOURCES=ntdisplay.cpp

LINKLIBS=$(DDK_LIB_PATH)\ntdll.lib

ファイル名 'makefile'
!INCLUDE $(NTMAKEENV)\makefile.def


このプログラムは特に何もしません。PCを起動(再起動)すると、画面に10秒間"Hello World!"と表示して終了します。

    RtlInitUnicodeString(&s,L"Hello world!\n");
    NtDisplayString( &s );
画面にテキストを表示する部分です。

    LARGE_INTEGER li;
    li.QuadPart = -(10 * 10000000); // wait for relative 10 sec
    NtDelayExecution( FALSE, &li );
10秒間待機する部分です。 li.QuadPartに指定する値は100ns単位で、負の値だと呼び出し時点からの相対時間を意味します。

注:大きな値を与えると、長時間PCが立ち上がらないことになりますので注意してください。


前述の通り、エクスプローラなどからは実行できないので、PC起動時に実行されるプログラムとして登録します。それには以下の手順で行ってください。

1. ビルドしたntdisplay.exeを %systemroot% (例えばC:\Windows)にコピーします。

2.レジストリエディタで以下のレジストリ値を編集します。
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager
BootExecute (REG_MULTI_SZ)


rg.png
上図の様に実行ファイル名である"ntdisplay"を追加します。
通常、"autocheck autochk *"が記述されていると思いますが、その次の行に追加するとよいでしょう。

3.[OK]を選択して値を保存し、レジストリエディタを終了して、PCを再起動します。

PC起動時にテキストで"Hello World!"と表示されたでしょうか?

今回はサンプルプログラムですので意味のある処理はしていませんが、実際にはchkdskの様なタスクを実行します。私のサイトでも、このプログラムと同じくPC起動時にファイルのコピーをするプログラムを公開していますので、興味のある方は参照してみてください。

FSNtCopy

NtOpenFile [CodeTips]

今回はWindows ネイティブAPIのNtOpenFile関数を使ってファイルをオープンする処理の例です。

ネイティブAPIを呼び出すので、WDK(Windows Driver Kit)を使って、コマンドプロンプトで実行できるモジュールを作成します。今ではVisualStudioと結合されているWDKですが、ここではスタンドアロンで環境を用意できるWindows 7のWDKを使います。

Windows Driver Kit Version 7.1.0

ソースファイル名 'ntopen.cpp'
// ntopen.cpp
// This sample code is opens file using native api function.
// I have built using the Windows 7 WDK (7600.16385.1).
//
#include <ntifs.h>
#include <stdio.h>
#include <locale.h>

// undefined native APIs
EXTERN_C
VOID
NTAPI
RtlSetLastWin32Error(
    ULONG ErrorCode
    );

EXTERN_C
ULONG
NTAPI
RtlGetLastWin32Error(
    VOID
    );

//
// open file by NT namespace
//
HANDLE _open_file(HANDLE hRoot,LPCWSTR FilePath,
            ULONG DesiredAccess,ULONG ShareAccess,ULONG OpenOptions)
{
    OBJECT_ATTRIBUTES ObjectAttributes;
    IO_STATUS_BLOCK IoStatus = {0};
    UNICODE_STRING NtPathName;
    NTSTATUS Status;
    HANDLE hFile = NULL;

    RtlInitUnicodeString(&NtPathName,FilePath);

    InitializeObjectAttributes(&ObjectAttributes,&NtPathName,0,hRoot,NULL);

    Status = NtOpenFile(
                    &hFile,
                    DesiredAccess,
                    &ObjectAttributes,
                    &IoStatus,
                    ShareAccess,
                    OpenOptions
                    );

    // Substitute from Win32 error code mechanism.
    RtlSetLastWin32Error(Status);

    return hFile;
}

//
// wmain()
//
int __cdecl wmain(int argc, WCHAR* argv[]) 
{
    _wsetlocale(LC_ALL,L"");

    if( argc < 2 )
    {
        wprintf(L"parameter required.\n");
        return -1;
    }

    HANDLE hFile;
    hFile = _open_file(NULL,argv[1],
                FILE_READ_DATA|FILE_READ_ATTRIBUTES|SYNCHRONIZE,
                FILE_SHARE_READ|FILE_SHARE_WRITE,
                FILE_NON_DIRECTORY_FILE|FILE_SYNCHRONOUS_IO_ALERT);

    if( hFile != NULL ) 
    {
        // To do something...
        wprintf(L"open succeeded.\n");

        NtClose(hFile);
    }
    else
    {
        wprintf(L"error : 0x%08X\n",RtlGetLastWin32Error());
    }

    return 0;
}

WDKでビルドする為に必要なsourcesファイルとmakefileも示しておきます。これらをソースファイルと同じディレクトリに置き、buildコマンドでビルドします。

ファイル名 'sources'
TARGETTYPE=PROGRAM
TARGETNAME=ntopen
TARGETPATH=obj
UMTYPE=console
UMENTRY=wmain

_NT_TARGET_VERSION=$(_NT_TARGET_VERSION_WINXP)

INCLUDES=$(DDK_INC_PATH)

USE_MSVCRT=1

SOURCES=\
	ntopen.cpp

LINKLIBS=\
	$(DDK_LIB_PATH)\ntdll.lib


ファイル名 'makefile'
!INCLUDE $(NTMAKEENV)\makefile.def


実行例
C:>ntopen \Device\HarddiskVolume2\windows\system32\notepad.exe
open succeeded.

C:>ntopen \??\C:\windows\system32\notepad.exe
open succeeded.


実行時にオープンするファイルの完全のパスをパラメータとして指定します。

NtOpenFileを使っているので、パスはWin32形式やMS-DOSドライブではなく、NTのオブジェクトネームスペースを使います。ドライブ名が割り当てられている場合は、ドライブパスのプリフィックスに'\??\'を付ける書式が指定し易いでしょう。

この例はオープンするだけで何もしません。取得できたファイルハンドルを使ってファイルを読み書きしたり情報を取得したりしてみてください。また、NtOpenFileの引数の詳細はmsdnなどで公開されていますので、いろいろ試すこともできます(ドキュメントではカーネルモードでの名称ZwOpenFileとして公開されています)。

msdn : ZwOpenFile

CryptBinaryToString/CryptStringToBinary [CodeTips]

このブログは放置しておくと「荒れ野」になってしまうので(^^;、それを回避するために備忘録的なコードを載せておくことにします。

今回はCryptAPIのCryptBinaryToString/CryptStringToBinary関数です。

// 'cl -DUNICODE <sourcefilename>'
#ifndef UNICODE
#define UNICODE
#endif

#include <stdio.h>
#include <windows.h>
#include <wincrypt.h>

#pragma comment(lib, "crypt32.lib") 
    
void wmain()
{
    WCHAR wszString[4096];
    DWORD cchString;

    /* test sample data (this data is nonsensical) */
    UCHAR data[] = "\xA1\x23\x1C\x56\x4f\x48\x06\x71\x01\x39\xCC\x55\xAA\x01\x02\x03\xac\xde\xff\xa9";

    /* encode */
    BYTE *pbBinary = data; 
    DWORD cbBinary = sizeof(data) - 1; // exclude termination null
    cchString = ARRAYSIZE(wszString);
    CryptBinaryToString(pbBinary,cbBinary,CRYPT_STRING_BASE64|CRYPT_STRING_NOCRLF,wszString,&cchString);

    printf("\nbase64:\n%S\n",wszString);
    
    /* decode */
    BYTE bufDecode[4096];
    DWORD cbDecode = ARRAYSIZE(bufDecode);
    CryptStringToBinary(wszString,cchString,CRYPT_STRING_BASE64,bufDecode,&cbDecode,NULL,NULL);

    /* print */
    cchString = ARRAYSIZE(wszString);
    CryptBinaryToString(bufDecode,cbDecode,CRYPT_STRING_HEXASCIIADDR,wszString,&cchString);
    
    printf("\nhex dump:\n%S\n",wszString);
}

使用法を示す事が目的の為、エラー処理は一切省いてあります。バッファも単純に扱っています。実際には出力データの長さを問い合わせるなどの処理が必要となるでしょう。
コンパイルし、実行すると以下の結果になります。今回はtest.cppというソースに落とし、test.exeという実行ファイルを作成しました。

C:\Test\code>cl -DUNICODE test.cpp


C:\Test\code>test

base64:
oSMcVk9IBnEBOcxVqgECA6ze/6k=

hex dump:
0000    a1 23 1c 56 4f 48 06 71  01 39 cc 55 aa 01 02 03   .#.VOH.q.9.U....
0010    ac de ff a9                                        ....


この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。