#include <iostream>
using namespace std;
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h> //PRIx64
#define BOOST_STATIC_ASSERT(x)
// #define _ULONGLONG_
// #if (!defined (_MAC) && (!defined(MIDL_PASS) || defined(__midl)) && (!defined(_M_IX86) || (defined(_INTEGRAL_MAX_BITS) && _INTEGRAL_MAX_BITS >= 64)))
// typedef __int64 LONGLONG;
// typedef unsigned __int64 ULONGLONG;
// #define MAXLONGLONG (0x7fffffffffffffff)
// #else
// #if defined(_MAC) && defined(_MAC_INT_64)
// typedef __int64 LONGLONG;
// typedef unsigned __int64 ULONGLONG;
// #define MAXLONGLONG (0x7fffffffffffffff)
// #else
// typedef double LONGLONG;
// typedef double ULONGLONG;
// #endif //_MAC and int64
// #endif
// #ifndef VOID
// #define VOID void
// typedef char CHAR;
// typedef short SHORT;
// typedef long LONG;
// #if !defined(MIDL_PASS)
// typedef int INT;
// #endif
// #endif
// typedef unsigned long DWORD;
// #if defined(MIDL_PASS)
// typedef struct _LARGE_INTEGER {
// #else // MIDL_PASS
// typedef union _LARGE_INTEGER {
// struct {
// DWORD LowPart;
// LONG HighPart;
// } DUMMYSTRUCTNAME;
// struct {
// DWORD LowPart;
// LONG HighPart;
// } u;
// #endif //MIDL_PASS
// LONGLONG QuadPart;
// } LARGE_INTEGER;
//typedef LARGE_INTEGER *PLARGE_INTEGER;
// /* BASETYPES is defined in ntdef.h if these types are already defined */
// #ifndef BASETYPES
// #define BASETYPES
// typedef unsigned long ULONG;
// typedef ULONG *PULONG;
// typedef unsigned short USHORT;
// typedef USHORT *PUSHORT;
// typedef unsigned char UCHAR;
// typedef UCHAR *PUCHAR;
// //typedef _Null_terminated_ char *PSZ;
// #endif /* !BASETYPES */
/* Basic system type definitions, taken from the BSD file sys/types.h. */
typedef unsigned char u_char;
typedef unsigned short u_short;
typedef unsigned int u_int;
typedef unsigned long u_long;
typedef char CCHAR;
// #ifndef _MAC
// typedef wchar_t WCHAR; // wc, 16-bit UNICODE character
// #else
// // some Macintosh compilers don't define wchar_t in a convenient location, or define it as a char
// typedef unsigned short WCHAR; // wc, 16-bit UNICODE character
// #endif
//typedef char32_t WCHAR;
typedef int16_t WCHAR;
typedef uint32_t ULONG;
typedef uint32_t DWORD;
typedef uint64_t LARGE_INTEGER;
#ifdef __cplusplus
# define STATIC_CAST(T, x) static_cast<T>(x)
# define REINTERPRET_CAST(T, x) reinterpret_cast<T>(x)
# define CONST_CAST(T, x) const_cast<T>(x)
#else
# define STATIC_CAST(T, x) ((T)(x))
# define REINTERPRET_CAST(T, x) ((T)(x))
# define CONST_CAST(T, x) ((T)(x))
#endif
#pragma pack(1)
/**
* [MS-SMB2] 2.2.33 SMB2 QUERY_DIRECTORY Request (CommandCode = 14 , BodySize = 33 )
* The SMB2 QUERY_DIRECTORY Request packet is sent by the client to obtain a directory enumeration on a directory open. This request consists of an SMB2 header, as specified in section 2.2.1, followed by this request structure:
*/
typedef struct {
/* StructureSize (2 bytes): The client MUST set this field to 33, indicating the size of the request structure, not including the header. The client MUST set this field to this value regardless of how long Buffer[] actually is in the request being sent. */
uint16_t StructureSize;
/**
* FileInformationClass (1 byte): The file information class describing the format that data MUST be returned in.
* Possible values are as specified in [MS-FSCC] section 2.4 File Information Classes. This field MUST contain
* one of the following values:
* * **FileDirectoryInformation** 0x01 Basic information about a file or directory. Basic information is defined
* as the file's name, time stamp, size and attributes. File attributes are as specified in [MS-FSCC] section
* 2.6 File Attributes.
* * **FileFullDirectoryInformation** 0x02 Full information about a file or directory. Full information is defined
* as all the basic information plus extended attribute size.
* * **FileIdFullDirectoryInformation** 0x26 Full information plus volume file ID about a file or directory. A
* volume file ID is defined as a number assigned by the underlying object store that uniquely identifies a file
* within a volume.
* * **FileBothDirectoryInformation** 0x03 Basic information plus extended attribute size and short name about a
* file or directory. See [MS-FSCC] 2.4.17 FileIdBothDirectoryInformation or FILE_ID_BOTH_DIR_INFORMATION structure in ntifs.h
* * **FileIdBothDirectoryInformation** 0x25 FileBothDirectoryInformation plus volume file ID about a file or directory.
* * **FileNamesInformation** 0x0C Detailed information on the names of files and directories in a directory.
* @see https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/4718fc40-e539-4014-8e33-b675af74e3e1#24-file-information-classes
* @see https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/content/wdm/ne-wdm-_file_information_class
*/
u_char FileInformationClass;
u_char Flags; /* Flags (1 byte): Flags indicating how the query directory operation MUST be processed. This field MUST be a logical OR of the following values, or zero if none are selected: */
/* FileIndex (4 bytes): The byte offset within the directory, indicating the position at which to resume the enumeration. If SMB2_INDEX_SPECIFIED is set in Flags, this value MUST be supplied and is based on the FileIndex value received in a previous enumeration response. Otherwise, it MUST be set to zero and the server MUST ignore it. */
uint32_t FileIndex;
/* FileId (16 bytes): An SMB2_FILEID identifier of the directory on which to perform the enumeration. This is returned from an SMB2 Create Request to open a directory on the server. */
u_char FileId[16];
/* FileNameOffset (2 bytes): The offset, in bytes, from the beginning of the SMB2 header to the search pattern to be used for the enumeration. This field MUST be 0 if no search pattern is provided. */
uint16_t FileNameOffset;
/* FileNameLength (2 bytes): The length, in bytes, of the search pattern. This field MUST be 0 if no search pattern is provided. */
uint16_t FileNameLength;
/* OutputBufferLength (4 bytes): The maximum number of bytes the server is allowed to return in the SMB2 QUERY_DIRECTORY Response. */
uint32_t OutputBufferLength;
/* Buffer (variable): A variable-length buffer containing the Unicode search pattern for the request, as described by the FileNameOffset and FileNameLength fields. The format, including wildcards and other conventions for this pattern, is specified in [MS-CIFS] section 2.2.1.1.3.<65> */
u_char Buffer[];
} smb2_query_directory_request_t;
BOOST_STATIC_ASSERT(32 == sizeof(smb2_query_directory_request_t));
/**
This information class differs from FileDirectoryInformation (section 2.4.10) in that it includes short names in the returns list.
@see https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/270df317-9ba5-4ccb-ba00-8d22be139bc5#248-filebothdirectoryinformation
@see https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/content/ntifs/ns-ntifs-_file_id_both_dir_information
*/
typedef struct smb2_FileBothDirectoryInformation {
/* NextEntryOffset (4 bytes): A 32-bit unsigned integer that contains the byte offset from the beginning of this entry, at which the next FILE_BOTH_DIR_INFORMATION entry is located, if multiple entries are present in a buffer. This member is zero if no other entries follow this one. An implementation MUST use this value to determine the location of the next entry (if multiple entries are present in a buffer). */
ULONG NextEntryOffset;
/* FileIndex (4 bytes): A 32-bit unsigned integer that contains the byte offset of the file within the parent directory. For file systems in which the position of a file within the parent directory is not fixed and can be changed at any time to maintain sort order, this field SHOULD be set to 0x00000000 and MUST be ignored.<89> */
ULONG FileIndex;
/* CreationTime (8 bytes): The time when the file was created; see section 2.1.1. This value MUST be greater than or equal to 0. */
LARGE_INTEGER CreationTime;
/* LastAccessTime (8 bytes): The last time the file was accessed; see section 2.1.1. This value MUST be greater than or equal to 0. */
LARGE_INTEGER LastAccessTime;
/* LastWriteTime (8 bytes): The last time information was written to the file; see section 2.1.1. This value MUST be greater than or equal to 0. */
LARGE_INTEGER LastWriteTime;
/* ChangeTime (8 bytes): The last time the file was changed; see section 2.1.1. This value MUST be greater than or equal to 0. */
LARGE_INTEGER ChangeTime;
/* EndOfFile (8 bytes): A 64-bit signed integer that contains the absolute new end-of-file position as a byte offset from the start of the file. EndOfFile specifies the offset to the byte immediately following the last valid byte in the file. Because this value is zero-based, it actually refers to the first free byte in the file. That is, it is the offset from the beginning of the file at which new bytes appended to the file will be written. The value of this field MUST be greater than or equal to 0. */
LARGE_INTEGER EndOfFile;
/* AllocationSize (8 bytes): A 64-bit signed integer that contains the file allocation size, in bytes. The value of this field MUST be an integer multiple of the cluster size. */
LARGE_INTEGER AllocationSize;
/* FileAttributes (4 bytes): A 32-bit unsigned integer that contains the file attributes. Valid file attributes are specified in section 2.6. */
ULONG FileAttributes;
/* FileNameLength (4 bytes): A 32-bit unsigned integer that specifies the length, in bytes, of the file name contained within the FileName member. */
ULONG FileNameLength;
/* EaSize (4 bytes): A 32-bit unsigned integer that contains the combined length, in bytes, of the extended attributes (EA) for the file. */
ULONG EaSize;
/* ShortNameLength (1 byte): An 8-bit signed integer that specifies the length, in bytes, of the file name contained in the ShortName member. This value MUST be greater than or equal to 0. */
CCHAR ShortNameLength;
/* Reserved (1 byte): Reserved for alignment. This field can contain any value and MUST be ignored. */
CCHAR Reserved;
/* ShortName (24 bytes): A sequence of Unicode characters containing the short (8.3) file name. When working with this field, use ShortNameLength to determine the length of the file name rather than assuming the presence of a trailing null delimiter. */
WCHAR ShortName[12];
/* The 8-byte file reference number for the file. This number is generated and assigned to the file by the file system. (Note that the FileId is not the same as the 16-byte "file object ID" that was added to NTFS for Microsoft Windows 2000.) */
LARGE_INTEGER FileId; // Missing in [MS-FSCC]: File System Control Codes - 2.4.8 FileBothDirectoryInformation
u_char Reserved2[2]; // Missing in [MS-FSCC]: File System Control Codes - 2.4.8 FileBothDirectoryInformation
/* FileName (variable): A sequence of Unicode characters containing the file name. When working with this field, use FileNameLength to determine the length of the file name rather than assuming the presence of a trailing null delimiter. Dot directory names are valid for this field. For more details, see section 2.1.5.1. */
WCHAR FileName[1];
} smb2_FileBothDirectoryInformation_t;
BOOST_STATIC_ASSERT(106 == sizeof(smb2_FileBothDirectoryInformation_t));
/**
* [MS-SMB2] 2.2.34 SMB2 QUERY_DIRECTORY Response (CommandCode = 14 , BodySize = 9 + variable)
* The SMB2 QUERY_DIRECTORY Response packet is sent by a server in response to an SMB2 QUERY_DIRECTORY Request (section 2.2.33). This response consists of an SMB2 header, as specified in section 2.2.1, followed by this response structure:
*/
typedef struct {
/*
StructureSize (2 bytes): The server MUST set this field to 9, indicating the size of the request structure, not including the header.
The server MUST set this field to this value regardless of how long Buffer[] actually is in the request.
*/
uint16_t StructureSize;
/* OutputBufferOffset (2 bytes): The offset, in bytes, from the beginning of the SMB2 header to the directory enumeration data being returned. */
uint16_t OutputBufferOffset;
/* OutputBufferLength (4 bytes): The length, in bytes, of the directory enumeration being returned. */
uint32_t OutputBufferLength;
/*
Buffer (variable): A variable-length buffer containing the directory enumeration being returned in the response,
as described by the OutputBufferOffset and OutputBufferLength. The format of this content is as specified in
[MS-FSCC] section 2.4 File Information Classes, within the topic for the specific file information class referenced
in the SMB2 QUERY_DIRECTORY Request. */
u_char Buffer[1];
} smb2_query_directory_response_t;
BOOST_STATIC_ASSERT(9 == sizeof(smb2_query_directory_response_t));
#pragma pack()
//https://stackoverflow.com/questions/15934111/portable-and-safe-way-to-add-byte-offset-to-any-pointer
template <typename T> inline void addOffset(std::ptrdiff_t offset, T *&ptr) {
if (!ptr) return;
ptr = (T*)((const unsigned char*)ptr + offset);
}
template <typename T> inline T* offset(std::ptrdiff_t offset, T *ptr) {
return (T*)((const unsigned char*)ptr + offset);
}
//SomeType* ptr; int offset = 12345; offset_ptr(offset, ptr);
template <typename T> inline void offset_ptr(std::ptrdiff_t byte_offset, const T* &ref_ptr) {
ref_ptr = (T*)((const unsigned char*)ref_ptr + byte_offset);
}
//If you use this marco like `typedef struct {} SomeType; SomeType* ptr; OFFSET_PTR(16, ptr);`
//IDE error: expression must be a modifiable value. Compile: error C2106: '=': left operand must be l-value.
#define OFFSET_PTR(byte_offset, ref_ptr) ((const unsigned char*)ref_ptr = (const unsigned char*)ref_ptr + byte_offset)
char packet_bytes[9] = {0};
int main(int argc, char* argv[]) {
printf("(int)sizeof(smb2_query_directory_response_t) = %d\n", (int)sizeof(smb2_query_directory_response_t));
printf("(int)sizeof(smb2_FileBothDirectoryInformation_t) = %d\n", (int)sizeof(smb2_FileBothDirectoryInformation_t));
const smb2_query_directory_response_t* pSMB2QueryDirectoryResponse = (smb2_query_directory_response_t*)packet_bytes;
const smb2_FileBothDirectoryInformation_t *pFileBothDirInfo = pSMB2QueryDirectoryResponse->OutputBufferLength ? REINTERPRET_CAST(const smb2_FileBothDirectoryInformation_t*, pSMB2QueryDirectoryResponse->Buffer) : NULL;
while (pFileBothDirInfo)
{
// ideone runs on linux with a compiler who consider wchar_t 4 bytes?
// https://stackoverflow.com/questions/16944750/c-unicode-characters-printing
//wprintf(L"%.*s|%.*s\n", pFileBothDirInfo->FileNameLength/2, pFileBothDirInfo->FileName, pFileBothDirInfo->ShortNameLength/2, pFileBothDirInfo->ShortName);
if (pFileBothDirInfo->NextEntryOffset)
{
offset_ptr(pFileBothDirInfo->NextEntryOffset, pFileBothDirInfo);
const unsigned char *ptrTemp;
ptrTemp = ((const unsigned char*)pFileBothDirInfo + 10);
//be equivalent to
//((const unsigned char*)pFileBothDirInfo) = ( (const unsigned char*)pFileBothDirInfo + 10 );
OFFSET_PTR(pFileBothDirInfo->NextEntryOffset, pFileBothDirInfo);
printf("ptrTemp = %p", ptrTemp);
}
else
{
break;
}
}
return 0;
}