這段時間用到了SysinternalsSuite中的pipelist工具來查看使用的NamedPipe是什麼,用過之後就想自己瞭解下它是怎樣工作,於是就反組譯碼一下,沒想到卻意外的簡單。
下面是反組譯碼出的虛擬碼
int __cdecl main(int argc, const char **argv, const char **envp){ int result; // eax@2 HMODULE v4; // eax@3 HMODULE v5; // eax@6 HANDLE hHandle; // ebp@9 DWORD v7; // eax@10 FILE_DIRECTORY_INFORMATION *FileInformation; // edi@11 int v9; // eax@12 FILE_DIRECTORY_INFORMATION *i; // esi@13 int v11; // [sp+34h] [bp-94Ch]@12 int IoStatusBlock; // [sp+38h] [bp-948h]@12 char v13; // [sp+40h] [bp-940h]@14 char v14; // [sp+E0h] [bp-8A0h]@14 __int16 v15[1024]; // [sp+180h] [bp-800h]@14 LOBYTE(v11) = 1; printf("\nPipeList v1.01\n"); printf("by Mark Russinovich\n"); printf("http://www.sysinternals.com\n\n"); if ( EulaAccept((LPARAM)"PipeList") ) { v4 = GetModuleHandleA("ntdll.dll"); pfnNtQueryDirectoryFile = (int (__stdcall *)(_DWORD, _DWORD, _DWORD, _DWORD, _DWORD, _DWORD, _DWORD, _DWORD, _DWORD, _DWORD, _DWORD))GetProcAddress(v4, "NtQueryDirectoryFile"); if ( !pfnNtQueryDirectoryFile ) { printf("\nCould not find NtQueryDirectoryFile entry point in NTDLL.DLL\n"); exit(1); } v5 = GetModuleHandleA("ntdll.dll"); pfnRtlNtStatusToDosError = (int)GetProcAddress(v5, "RtlNtStatusToDosError"); if ( !pfnRtlNtStatusToDosError ) { printf("\nCould not find RtlNtStatusToDosError entry point in NTDLL.DLL\n"); exit(1); } hHandle = CreateFileA("\\\\.\\Pipe\\", 0x80000000u, 7u, 0, 3u, 0, 0); if ( hHandle == (HANDLE)-1 ) { v7 = GetLastError(); sub_401050((int)"Pipe error", v7); result = 0; } else { printf("%-40s%14s%20s\n", "Pipe Name", "Instances", "Max Instances"); printf("%-40s%14s%20s\n", "---------", "---------", "-------------"); FileInformation = (FILE_DIRECTORY_INFORMATION *)malloc(0x1000u); while ( 1 ) { v9 = pfnNtQueryDirectoryFile(hHandle, 0, 0, 0, &IoStatusBlock, FileInformation, 4096, 1, 0, 0, v11); if ( v9 < 0 ) break; for ( i = FileInformation; ; i = (FILE_DIRECTORY_INFORMATION *)((char *)i + i->NextEntryOffset) ) { swprintf((wchar_t *)&v14, (size_t)L"%d ", (const wchar_t *)i->EndOfFile.LowPart); swprintf((wchar_t *)&v13, (size_t)L"%d ", (const wchar_t *)i->AllocationSize.LowPart); wcsncpy((wchar_t *)v15, i->FileName, i->FileNameLength >> 1); v15[i->FileNameLength >> 1] = 0; wprintf(L"%-40s%14s%20s\n", v15, &v14, &v13); if ( !i->NextEntryOffset ) break; } LOBYTE(v11) = 0; } if ( v9 != -2147483642 ) sub_401000((int)"Error querying pipe directory:", v9); free(FileInformation); CloseHandle(hHandle); result = 0; } } else { result = 1; } return result;}
Named Pipes是一種簡單的處理序間通訊(IPC)機制。可在同一台電腦的不同進程之間,或在跨越一個網路的不同電腦的不同進程之間,支援可靠的、單向或雙向的資料通訊。具名管道是圍繞Windows檔案系統設計的一種機制,採用“具名管道檔案系統”(Named Pipe File System,NPFS)介面,客戶機和伺服器應用可利用標準的Win32檔案系統相關API函數。
具名管道的標識採用UNC格式的進行命名的:
\\server\pipe\[path]name
從上面反組譯碼出代碼可以看出,它是使用NtQueryDirectoryFile來查詢\\.\pipe\下的File Information。查看NtQueryDirectoryFile的聲明(在Window NT 2000 Native API這文檔中可以找到,叫做ZwQueryDirectoryFile)
ZwQueryDirectoryFile retrieves information about the contents of a directory.NTSYSAPINTSTATUSNTAPIZwQueryDirectoryFile(IN HANDLE FileHandle,IN HANDLE Event OPTIONAL,IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,IN PVOID ApcContext OPTIONAL,OUT PIO_STATUS_BLOCK IoStatusBlock,OUT PVOID FileInformation,IN ULONG FileInformationLength,IN FILE_INFORMATION_CLASS FileInformationClass,IN BOOLEAN ReturnSingleEntry,IN PUNICODE_STRING FileName OPTIONAL,IN BOOLEAN RestartScan);
這個功能的關鍵在於:
1、CreateFileA("\\\\.\\Pipe\\", GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, 0, OPEN_EXISTING, 0, 0);
2、NtQueryDirectoryFile(hHandle, 0, 0, 0, &IoStatusBlock, FileInformation, 4096, FileDirectoryInformation /*=1*/, 0, 0, v11);
當然除了枚舉本機電腦的Named Pipes,也可以枚舉其他機器的,只要把對應的伺服器名加到路徑中,如\ \ m y s e r v e r \ pipe \ ,這樣可枚舉出伺服器\ \ m y s e r v e r 的Named Pipes,當然要有許可權才行。