Skip to content

Commit 1149c82

Browse files
Fea #80,使用APC模拟 NtCancelIoFileEx已更好支持rust(PR #125
1 parent f081454 commit 1149c82

File tree

2 files changed

+83
-17
lines changed

2 files changed

+83
-17
lines changed

src/Thunks/api-ms-win-core-io.hpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,15 @@ namespace YY::Thunks
2121
return pCancelIoEx(hFile, lpOverlapped);
2222
}
2323

24-
//downlevel逻辑会把该文件所有IO动作给取消掉!凑合用吧。
25-
return CancelIo(hFile);
24+
IO_STATUS_BLOCK _IoStatusBlock;
25+
// 没有CancelIoEx那么也必然没有NtCancelIoFileEx,所以直接调用 Fallback系列即可。
26+
auto _Status = Fallback::NtCancelIoFileEx(hFile, reinterpret_cast<IO_STATUS_BLOCK*>(lpOverlapped), &_IoStatusBlock);
27+
if (_Status < 0)
28+
{
29+
SetLastError(internal::NtStatusToDosError(_Status));
30+
return FALSE;
31+
}
32+
return TRUE;
2633
}
2734
#endif
2835

src/Thunks/ntdll.hpp

Lines changed: 74 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,72 @@
1-
namespace YY::Thunks
1+
2+
3+
#if defined(YY_Thunks_Implemented) && (YY_Thunks_Target < __WindowsNT6)
4+
namespace YY::Thunks::Fallback
5+
{
6+
static NTSTATUS NTAPI NtCancelIoFileEx(
7+
HANDLE _hHandle,
8+
IO_STATUS_BLOCK* _pIo,
9+
IO_STATUS_BLOCK* _pIoStatus
10+
)
11+
{
12+
// NtCancelIoFile无法模拟特定的IO取消工作,因此需要取消特定IO时立即失败处理
13+
if (_pIo != nullptr)
14+
{
15+
// Not supported
16+
return STATUS_NOT_FOUND;
17+
}
18+
19+
#ifndef __USING_NTDLL_LIB
20+
const auto NtCancelIoFile = try_get_NtCancelIoFile();
21+
if (!NtCancelIoFile)
22+
{
23+
// 正常来说不应该走到这里
24+
return STATUS_NOT_SUPPORTED;
25+
}
26+
#endif
27+
28+
auto _Status = NtCancelIoFile(_hHandle, _pIoStatus);
29+
if (_Status < 0)
30+
return _Status;
31+
32+
internal::StringBuffer<char> _Buffer;
33+
auto _pProcessInfo = internal::GetCurrentProcessInfo(_Buffer);
34+
if (!_pProcessInfo)
35+
return _Status;
36+
37+
const auto _uCurrentThreadId = GetCurrentThreadId();
38+
for (ULONG i = 0; i != _pProcessInfo->ThreadCount; ++i)
39+
{
40+
auto& _Thread = _pProcessInfo->Threads[i];
41+
42+
if (_uCurrentThreadId == static_cast<DWORD>(reinterpret_cast<UINT_PTR>(_Thread.ClientId.UniqueThread)))
43+
continue;
44+
45+
auto _hThread = OpenThread(THREAD_SET_CONTEXT, FALSE, static_cast<DWORD>(reinterpret_cast<UINT_PTR>(_Thread.ClientId.UniqueThread)));
46+
if (!_hThread)
47+
continue;
48+
49+
QueueUserAPC(
50+
[](ULONG_PTR _hHandle)
51+
{
52+
#ifndef __USING_NTDLL_LIB
53+
const auto NtCancelIoFile = try_get_NtCancelIoFile();
54+
#endif
55+
IO_STATUS_BLOCK _IoStatus;
56+
// 故意不判断空指针,NtCancelIoFileEx开头已经判断过了。
57+
// 如果真的崩溃,那么说明内存被改坏了。
58+
NtCancelIoFile(reinterpret_cast<HANDLE>(_hHandle), &_IoStatus);
59+
}, _hThread, (ULONG_PTR)_hHandle);
60+
CloseHandle(_hThread);
61+
}
62+
63+
return _Status;
64+
}
65+
}
66+
#endif
67+
68+
69+
namespace YY::Thunks
270
{
371
#if (YY_Thunks_Target < __WindowsNT6)
472

@@ -10,26 +78,17 @@
1078
NTSTATUS,
1179
NTAPI,
1280
NtCancelIoFileEx,
13-
HANDLE handle,
14-
IO_STATUS_BLOCK* io,
15-
IO_STATUS_BLOCK* io_status
81+
HANDLE _hHandle,
82+
IO_STATUS_BLOCK* _pIo,
83+
IO_STATUS_BLOCK* _pIoStatus
1684
)
1785
{
1886
if (const auto _pfnNtCancelIoFileEx = try_get_NtCancelIoFileEx())
1987
{
20-
return _pfnNtCancelIoFileEx(handle, io, io_status);
88+
return _pfnNtCancelIoFileEx(_hHandle, _pIo, _pIoStatus);
2189
}
2290

23-
#ifndef __USING_NTDLL_LIB
24-
const auto NtCancelIoFile = try_get_NtCancelIoFile();
25-
if(!NtCancelIoFile)
26-
{
27-
// 正常来说不应该走到这里
28-
return STATUS_NOT_SUPPORTED;
29-
}
30-
#endif
31-
// 最坏打算,清除所有的调用
32-
return NtCancelIoFile(handle, io_status);
91+
return Fallback::NtCancelIoFileEx(_hHandle, _pIo, _pIoStatus);
3392
}
3493
#endif
3594

0 commit comments

Comments
 (0)