Skip to content

Commit

Permalink
Fea #66, 让.NET 8/9 支持XP,新增ThreadpoolIo支持
Browse files Browse the repository at this point in the history
  - 现有WaitForThreadpoolWorkCallbacks等函数添加Cancel支持
  - 添加 CreateThreadpoolIo
  - 添加 CloseThreadpoolIo
  - 添加 StartThreadpoolIo
  - 添加 CancelThreadpoolIo
  - 添加 WaitForThreadpoolIoCallbacks
  • Loading branch information
mingkuang-Chuyu committed May 19, 2024
1 parent 98dab91 commit 748419c
Show file tree
Hide file tree
Showing 7 changed files with 1,228 additions and 310 deletions.
45 changes: 27 additions & 18 deletions ThunksList.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,33 @@
| QueryInterruptTime | 不存在时,读取KUSER_SHARED_DATA::InterruptTime值。
| QueryInterruptTimePrecise | 不存在时,读取KUSER_SHARED_DATA::InterruptTime值。

## api-ms-win-core-threadpool-l1-2-0.dll
| 函数 | Fallback
| ---- | -----------
| CreateThreadpoolWork | 不存在时,内部实现。
| CloseThreadpoolWork | 不存在时,内部实现。
| TrySubmitThreadpoolCallback | 不存在时,调用QueueUserWorkItem。
| SubmitThreadpoolWork | 不存在时,调用QueueUserWorkItem。
| WaitForThreadpoolWorkCallbacks | 不存在时,内部实现。
| CreateThreadpoolTimer | 不存在时,内部实现。
| CloseThreadpoolTimer | 不存在时,调用DeleteTimerQueueTimer。
| SetThreadpoolTimer | 不存在时,调用CreateTimerQueueTimer。
| WaitForThreadpoolTimerCallbacks | 不存在时,调用WaitForSingleObject。
| SetEventWhenCallbackReturns | 不存在时,内部实现。
| ReleaseSemaphoreWhenCallbackReturns | 不存在时,内部实现。
| ReleaseMutexWhenCallbackReturns | 不存在时,内部实现。
| LeaveCriticalSectionWhenCallbackReturns | 不存在时,内部实现。
| FreeLibraryWhenCallbackReturns | 不存在时,内部实现。
| CreateThreadpoolWait | 不存在时,内部实现。
| CloseThreadpoolWait | 不存在时,调用UnregisterWait。
| SetThreadpoolWait | 不存在时,调用RegisterWaitForSingleObject。
| WaitForThreadpoolWaitCallbacks | 不存在时,调用WaitForSingleObject。
| CreateThreadpoolIo | 不存在时,调用BindIoCompletionCallback。
| CloseThreadpoolIo | 不存在时,内部实现。
| StartThreadpoolIo | 不存在时,内部实现。
| CancelThreadpoolIo | 不存在时,内部实现。
| WaitForThreadpoolIoCallbacks | 不存在时,调用WaitForSingleObject。

## api-ms-win-core-winrt-l1-1-0.dll
| 函数 | Fallback
| ---- | -----------
Expand Down Expand Up @@ -296,24 +323,6 @@
| UnmapViewOfFileEx | 不存在时,调用 UnmapViewOfFile 。
| VirtualProtectFromApp | 不存在时,调用 VirtualProtect 。
| OpenFileMappingFromApp | 不存在时,调用 OpenFileMappingW 。
| CreateThreadpoolWork | 不存在时,内部实现。警告,此函数请勿跨模块使用!!!
| CloseThreadpoolWork | 不存在时,内部实现。警告,此函数请勿跨模块使用!!!
| SubmitThreadpoolWork | 不存在时,调用QueueUserWorkItem。警告,此函数请勿跨模块使用!!!
| WaitForThreadpoolWorkCallbacks | 不存在时,内部实现。警告,此函数请勿跨模块使用!!!
| CreateThreadpoolTimer | 不存在时,内部实现。警告,此函数请勿跨模块使用!!!
| CloseThreadpoolTimer | 不存在时,内部实现。警告,此函数请勿跨模块使用!!!
| SetThreadpoolTimer | 不存在时,调用QueueTimer。警告,此函数请勿跨模块使用!!!
| SetEventWhenCallbackReturns | 不存在时,内部实现。警告,此函数请勿跨模块使用!!!
| ReleaseSemaphoreWhenCallbackReturns | 不存在时,内部实现。警告,此函数请勿跨模块使用!!!
| ReleaseMutexWhenCallbackReturns | 不存在时,内部实现。警告,此函数请勿跨模块使用!!!
| LeaveCriticalSectionWhenCallbackReturns | 不存在时,内部实现。警告,此函数请勿跨模块使用!!!
| FreeLibraryWhenCallbackReturns | 不存在时,内部实现。警告,此函数请勿跨模块使用!!!
| WaitForThreadpoolTimerCallbacks | 不存在时,内部实现。警告,此函数请勿跨模块使用!!!
| TrySubmitThreadpoolCallback | 不存在时,内部实现。警告,此函数请勿跨模块使用!!!
| CreateThreadpoolWait | 不存在时,内部实现。警告,此函数请勿跨模块使用!!!
| CloseThreadpoolWait | 不存在时,内部实现。警告,此函数请勿跨模块使用!!!
| SetThreadpoolWait | 不存在时,调用RegisterWaitForSingleObject。警告,此函数请勿跨模块使用!!!
| WaitForThreadpoolWaitCallbacks | 不存在时,内部实现。警告,此函数请勿跨模块使用!!!
| FlushProcessWriteBuffers | 不存在时,调用VirtualProtect。
| FlsAlloc | 不存在时,使用Tls实现。警告,此函数请勿跨模块使用!!!
| FlsFree | 不存在时,使用Tls实现。警告,此函数请勿跨模块使用!!!
Expand Down
146 changes: 146 additions & 0 deletions src/Shared/HookThunk.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
#pragma once

/*
跨模块ABI兼容的Thunk逻辑。
*/

namespace YY
{
namespace Thunks
{
namespace internal
{
union HookThunkData
{
private:
static HookThunkData* volatile pFreeRoot;
// Windows最小地址管理粒度是64K,所以我们就直接申请一个64K
static constexpr size_t kAllocBufferBytesCount = 64 * 1024;

public:
HookThunkData* volatile pNext;
// 可以供内存执行权限的一段区域
struct
{
unsigned char ShellCode[60];
// 内存块的引用计数。
// 1. 如果是Buffer第一块内存的引用计数,那么引用归零时彻底释放整个缓冲区。
// 2. 如果不是Buffer第一块内存的引用计数,引用归零时减少一次该缓冲区第一块内存的引用计数。
ULONG uRef;
};

static HookThunkData* __fastcall Alloc()
{
__declspec(allocate(".YYThr$AAB")) static void* s_FreeAllHookThunkData = reinterpret_cast<void*>(&HookThunkData::FreeAll);
__foreinclude(s_FreeAllHookThunkData);

for (auto _pLast = pFreeRoot; _pLast;)
{
auto _pNext = _pLast->pNext;

auto _pResult = (HookThunkData*)InterlockedCompareExchange((volatile uintptr_t*)&pFreeRoot, (uintptr_t)_pNext, (uintptr_t)_pLast);
if (_pResult == _pLast)
{
_pResult->pNext = nullptr;

InterlockedIncrement(&_pResult->uRef);
return _pResult;
}
_pLast = _pResult;
}

// 缓存区域已经耗尽,申请新的内存。
auto _pResult = (HookThunkData*)VirtualAlloc(nullptr, kAllocBufferBytesCount, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (!_pResult)
return nullptr;

// 因为当前需要返回 _pResult,所以引用计数额外 + 1
_pResult->uRef = kAllocBufferBytesCount / sizeof(HookThunkData) + 1;

static_assert(kAllocBufferBytesCount % sizeof(HookThunkData) == 0, "");
// 因为等会需要返回一块内存,所以第一快内存我们就需要跳过,不添加到pFreeRoot了。
const auto _pFirstBuffer = _pResult + 1;
const auto _pLastBuffer = reinterpret_cast<HookThunkData*>((uintptr_t)_pResult + kAllocBufferBytesCount - sizeof(HookThunkData));

for (auto _pItem = _pFirstBuffer; ;)
{
_pItem->uRef = 1;
if (_pItem == _pLastBuffer)
break;
auto _pNext = _pItem + 1;
_pItem->pNext = _pNext;
_pItem = _pNext;
}

for (auto _pLast = pFreeRoot; ;)
{
_pLastBuffer->pNext = _pLast;
auto _pResult = (HookThunkData*)InterlockedCompareExchange((volatile uintptr_t*)&pFreeRoot, (uintptr_t)_pFirstBuffer, (uintptr_t)_pLast);
if (_pResult == _pLast)
{
break;
}
_pLast = _pResult;
}
return _pResult;
}

void __fastcall Free()
{
// 防止内存执行区域被人利用,数据全部清除!!
memset(ShellCode, 0, sizeof(ShellCode));

if (Release() == 0)
return;

// 重新将内存加入缓存区域。
for (auto _pLast = pFreeRoot; ;)
{
pNext = _pLast;
auto _pResult = (HookThunkData*)InterlockedCompareExchange((volatile uintptr_t*)&pFreeRoot, (uintptr_t)this, (uintptr_t)_pLast);
if (_pResult == _pLast)
{
return;
}
_pLast = _pResult;
}
}

private:
static void __cdecl FreeAll() noexcept
{
HookThunkData* _pRoot = (HookThunkData*)InterlockedExchange((volatile uintptr_t*)&pFreeRoot, (uintptr_t)nullptr);
for (auto _pItem = _pRoot; _pItem; )
{
auto _pNext = _pItem->pNext;
_pItem->Release();

_pItem = _pNext;
}
}

/// <summary>
/// 减少一次内存引用。
/// </summary>
/// <returns>返回新的引用计数。</returns>
ULONG __fastcall Release() noexcept
{
const auto _uNewRef = InterlockedDecrement(&uRef);
if (_uNewRef == 0)
{
// 引用归0,这块内存可能来自于其他模块,并且目标模块已经释放。
auto _pFirstBlock = reinterpret_cast<HookThunkData*>(uintptr_t(this) & (~(kAllocBufferBytesCount - 1)));
if (_pFirstBlock == this || InterlockedDecrement(&_pFirstBlock->uRef) == 0)
{
VirtualFree(_pFirstBlock, 0, MEM_RELEASE);
}
}

return _uNewRef;
}
};

HookThunkData* volatile HookThunkData::pFreeRoot = nullptr;
}
}
}
6 changes: 4 additions & 2 deletions src/Thunks/YY_Thunks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,8 @@ RtlCutoverTimeToSystemTime(
#pragma comment(lib, "User32.lib")
#endif

#include <HookThunk.h>

//展开函数的所有的 声明 以及 try_get_ 函数
#define __DEFINE_THUNK(_MODULE, _SIZE, _RETURN_, _CONVENTION_, _FUNCTION, ...) \
__APPLY_UNIT_TEST_BOOL(_FUNCTION); \
Expand Down Expand Up @@ -217,9 +219,9 @@ namespace YY
_Check_return_
_Ret_maybenull_
_Post_writable_byte_size_(_cbBytes)
static void* __fastcall Alloc(_In_ size_t _cbBytes)
static void* __fastcall Alloc(_In_ size_t _cbBytes, DWORD _fFlags = 0)
{
return HeapAlloc(((TEB*)NtCurrentTeb())->ProcessEnvironmentBlock->ProcessHeap, 0, _cbBytes);
return HeapAlloc(((TEB*)NtCurrentTeb())->ProcessEnvironmentBlock->ProcessHeap, _fFlags, _cbBytes);
}

_Check_return_
Expand Down
Loading

0 comments on commit 748419c

Please sign in to comment.