Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use QueueUserAPC to run NtCancelIoFile on each thread #125

8 changes: 5 additions & 3 deletions src/Thunks/api-ms-win-core-io.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,11 @@ namespace YY::Thunks
{
return pCancelIoEx(hFile, lpOverlapped);
}

//downlevel逻辑会把该文件所有IO动作给取消掉!凑合用吧。
return CancelIo(hFile);
// https://github.com/wine-mirror/wine/blob/100645ac4de77879f6a36181234f76794bcbecb2/dlls/kernelbase/file.c#L3005
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IO_STATUS_BLOCK io;
auto status = NtCancelIoFileEx(hFile, (PIO_STATUS_BLOCK)lpOverlapped, &io);
if (status) SetLastError(RtlNtStatusToDosError(status));
return !status;
}
#endif

Expand Down
74 changes: 58 additions & 16 deletions src/Thunks/ntdll.hpp
Original file line number Diff line number Diff line change
@@ -1,35 +1,77 @@
namespace YY::Thunks
#include <tlhelp32.h>
namespace YY::Thunks
{
#if (YY_Thunks_Target < __WindowsNT6)

// 最低受支持的客户端 Windows Vista [桌面应用|UWP 应用]
// 最低受支持的服务器 Windows Server 2008[桌面应用 | UWP 应用]
__DEFINE_THUNK(
ntdll,
12,
NTSTATUS,
NTAPI,
NtCancelIoFileEx,
ntdll,
12,
NTSTATUS,
NTAPI,
NtCancelIoFileEx,
HANDLE handle,
IO_STATUS_BLOCK* io,
IO_STATUS_BLOCK* io_status
)
)
{
if (const auto _pfnNtCancelIoFileEx = try_get_NtCancelIoFileEx())
{
return _pfnNtCancelIoFileEx(handle, io, io_status);
}

auto currentTid = GetCurrentThreadId();
HANDLE h = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, GetCurrentProcessId());
if (h != INVALID_HANDLE_VALUE) {
THREADENTRY32 te;
te.dwSize = sizeof(te);
if (Thread32First(h, &te)) {
do {
if (te.th32ThreadID == currentTid) {
continue;
}
HANDLE threadHandle = OpenThread(THREAD_SET_CONTEXT, FALSE, te.th32ThreadID);
if (threadHandle != INVALID_HANDLE_VALUE) {
struct CancelIoData {
HANDLE handle;
IO_STATUS_BLOCK* io_status;
};


QueueUserAPC([](ULONG_PTR param) {
auto data = (CancelIoData*)param;
#ifndef __USING_NTDLL_LIB
const auto NtCancelIoFile = try_get_NtCancelIoFile();
if (!NtCancelIoFile)
{
// 正常来说不应该走到这里
delete data;
return;
}
#endif

NtCancelIoFile(data->handle, data->io_status);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

delete data;
}, threadHandle, (ULONG_PTR) new CancelIoData {handle, io_status});
CloseHandle(threadHandle);
}
} while (Thread32Next(h, &te));
}
CloseHandle(h);
}


#ifndef __USING_NTDLL_LIB
const auto NtCancelIoFile = try_get_NtCancelIoFile();
if(!NtCancelIoFile)
if (!NtCancelIoFile)
{
// 正常来说不应该走到这里
return STATUS_NOT_SUPPORTED;
}
#endif
// 最坏打算,清除所有的调用
return NtCancelIoFile(handle, io_status);
return NtCancelIoFile(handle, io_status);
}
#endif

Expand All @@ -38,16 +80,16 @@

// 最低受支持的客户端 在 Windows 7 和更高版本的 Windows 中可用。
__DEFINE_THUNK(
ntdll,
16,
NTSTATUS,
NTAPI,
NtOpenKeyEx,
ntdll,
16,
NTSTATUS,
NTAPI,
NtOpenKeyEx,
__out PHANDLE _phKeyHandle,
__in ACCESS_MASK _fDesiredAccess,
__in POBJECT_ATTRIBUTES _pObjectAttributes,
__in ULONG _fOpenOptions
)
)
{
if (const auto _pfnNtOpenKeyEx = try_get_NtOpenKeyEx())
{
Expand Down Expand Up @@ -118,7 +160,7 @@
}
} while (false);

if(_hKey)
if (_hKey)
NtClose(_hKey);

return _Status;
Expand Down