这实际上是可能的,但微软出于某种原因没有记录它。 NtQuerySection API 自 Windows NT 的早期版本就存在,并且在 Windows 10 中仍然存在。
以下是您的操作方式(显然,您需要自行承担依赖未记录内核 API 的风险):
HANDLE hFileMapping = ::OpenFileMapping(FILE_MAP_READ | FILE_MAP_WRITE, FALSE, strSharedMemName);
_ASSERT(hFileMapping);
ULONGLONG uicbSharedMemSize = 0;
//Get the handle returned by the CreateFileMapping function
//Assuming the same process here...
HANDLE hDupH;
if((::DuplicateHandle(
::GetCurrentProcess(), hFileMapping,
::GetCurrentProcess(), &hDupH,
DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS, FALSE, 0)))
{
hFileMapping = hDupH;
enum SECTION_INFORMATION_CLASS{
SectionBasicInformation,
SectionImageInformation
};
typedef struct _SECTION_BASIC_INFORMATION {
ULONG Unknown;
ULONG SectionAttributes;
LARGE_INTEGER SectionSize;
} SECTION_BASIC_INFORMATION, *PSECTION_BASIC_INFORMATION;
static NTSTATUS
(NTAPI
*pfnNtQuerySection)(
IN HANDLE SectionHandle,
IN SECTION_INFORMATION_CLASS InformationClass,
OUT PVOID InformationBuffer,
IN ULONG InformationBufferSize,
OUT PULONG ResultLength OPTIONAL ) = NULL;
if(!pfnNtQuerySection)
(FARPROC&)pfnNtQuerySection = ::GetProcAddress(::GetModuleHandle(L"ntdll.dll"), "NtQuerySection");
if(pfnNtQuerySection)
{
SECTION_BASIC_INFORMATION sbi = {0};
ULONG ucbRead = 0;
NTSTATUS stat = pfnNtQuerySection(hFileMapping, SectionBasicInformation, &sbi, sizeof(sbi), &ucbRead);
if(stat >= 0)
{
//The size returned will be rounded up to the page size (i.e. 4K in most cases)
uicbSharedMemSize = sbi.SectionSize.QuadPart;
}
}
}
首先,SECTION_BASIC_INFORMATION 的正确定义是:
typedef struct _SECTION_BASIC_INFORMATION
{
PVOID BaseAddress;
ULONG AllocationAttributes;
LARGE_INTEGER MaximumSize;
} SECTION_BASIC_INFORMATION, *PSECTION_BASIC_INFORMATION;
这么旧的定义(DWORD 第一个成员 - 错误,不适用于 64 位代码)。
在第二次调用 NtQuerySection 时,部分句柄必须具有 SECTION_QUERY 访问权限,否则将是 STATUS_ACCESS_DENIED - 所以行:
OpenFileMapping(FILE_MAP_READ | FILE_MAP_WRITE, FALSE, strSharedMemName);
错了。必须是
OpenFileMapping(SECTION_QUERY|FILE_MAP_READ|FILE_MAP_WRITE, FALSE, strSharedMemName);
或任何访问权限,包括SECTION_QUERY
注意,如果使用OpenFileMapping 并将dwDesiredAccess 设置为SECTION_QUERY,则OpenFileMapping 由于未知原因将其更改为SECTION_MAP_READ - 是此api 中的下一行代码。 if (dwDesiredAccess == SECTION_QUERY) dwDesiredAccess = SECTION_MAP_READ;
所以需要添加一些对SECTION_QUERY 的访问权限。当然,我们可以将SECTION_QUERY 与ZwOpenSection 完全匹配使用
下一个 - 什么叫DuplicateHandle ?!?这在任务上下文调用中是绝对没有意义的。我们通过OpenFileMappingW 或ZwOpenSection 处理了部分。
最后是什么GetModuleHandle + GetProcAddress 为ZwQuerySection ?例如,如果没有GetModuleHandle + GetProcAddress,我们如何调用OpenFileMappingW? GetProcAddress 怎么打电话?以同样的方式,我们可以调用ZwQuerySection - 只需通过每个 wdk lib 文件夹中存在的 ntdll.lib 与 ntdll.dll 链接。所以最终的代码必须是:
if (HANDLE hMap = OpenFileMappingW(SECTION_QUERY|SECTION_MAP_READ, FALSE, name))
{
SECTION_BASIC_INFORMATION sbi;
if (0 <= ZwQuerySection(hMap, SectionBasicInformation, &sbi, sizeof(sbi), 0))
{
DbgPrint("section size = %I64x\n", sbi.Size.QuadPart);
}
CloseHandle(hMap);
}
或
HANDLE hMap;
if (0 <= ZwOpenSection(&hMap, SECTION_QUERY, &oa))
{
SECTION_BASIC_INFORMATION sbi;
if (0 <= ZwQuerySection(hMap, SectionBasicInformation, &sbi, sizeof(sbi), 0))
{
DbgPrint("section size = %I64x\n", sbi.Size.QuadPart);
}
CloseHandle(hMap);
}