如何解决windows报无法定位程序输入点“xxxapi”于动态链接库“xxx.dll”上
众所周知,从 Windows 的每次更新又会新增大量 API,这使得兼容不同版本的 Windows 需要花费很大精力。导致现在大量开源项目已经不再兼容一些早期的 Windows 版本,比如 Windows XP RTM。
难道就没有一种快速高效的方案解决无法定位程序输入点的问题吗?
有!!!使用Chuyu Team开源的YY-Thunks即可快速解决兼容性问题,已经处理了几乎所有存在兼容性问题的api。
原理
使用 LoadLibrary 以及 GetProcAddress 动态加载 API,不存在时做出补偿措施, 最大限度模拟原始 API 行为,让你的程序正常运行。
亮点
更快!更安全!鸭船内建2级缓存以及按需加载机制,同时自动加密所有函数指针, 防止内存爆破攻击。最大程度减少不需要和不必要的 LoadLibrary 以及 GetProcAddress 调用以及潜在安全风险。
轻松兼容 Windows XP,让你安心专注于业务逻辑。
完全开源。
使用
下载 YY-Thunks-Binary, 然后解压到你的工程目录。
【链接器】-【输入】-【附加依赖项】,添加
objs\$(PlatformShortName)\YY_Thunks_for_WinXP.obj
。重新编译代码。
以上内容全部来至YY-Thunks项目的ReadMe.md文件。
错误效果演示
以使用CreateEventEx为例
int main() { HANDLE hEvent = ::CreateEventEx(nullptr, L"test-event", CREATE_EVENT_INITIAL_SET, EVENT_ALL_ACCESS); if (hEvent) ::CloseHandle(hEvent); system("pause"); return 0; }
先看win10系统下运行效果
可以看出win10系统下没有任何问题,再来看一下xp系统的效果
这就是因为xp系统下面是没有CreateEventEx这个api的,下面看看YY-Thunks是如何解决。
YY-Thunks如何解决的
#if defined(_M_IX86) //x86的符号存在@ 我们使用 identifier 特性解决 #define _LCRT_DEFINE_IAT_SYMBOL(_FUNCTION, _SIZE) \ __pragma(warning(suppress:4483)) \ extern "C" __declspec(selectany) void const* const __identifier(_CRT_STRINGIZE_(_imp__ ## _FUNCTION ## @ ## _SIZE)) \ = reinterpret_cast<void const*>(_FUNCTION) #else #define _LCRT_DEFINE_IAT_SYMBOL(_FUNCTION, _SIZE) \ extern "C" __declspec(selectany) void const* const _LCRT_DEFINE_IAT_SYMBOL_MAKE_NAME(_FUNCTION, _SIZE) \ = reinterpret_cast<void const*>(_FUNCTION) #endif #define __DEFINE_THUNK(_MODULE, _SIZE, _RETURN_, _CONVENTION_, _FUNCTION, ...) \ _LCRT_DEFINE_IAT_SYMBOL(_FUNCTION, _SIZE); \ EXTERN_C _RETURN_ _CONVENTION_ _FUNCTION(__VA_ARGS__) /** * 由于会默认链接到这些函数,把这些函数一次覆盖了吧 * 只是为了演示,所以并未实现这些函数 */ #if (YY_Thunks_Support_Version < NTDDI_WIN6) //Windows Vista, Windows Server 2008 __DEFINE_THUNK( kernel32, 12, BOOL, WINAPI, InitializeCriticalSectionEx, _Out_ LPCRITICAL_SECTION lpCriticalSection, _In_ DWORD dwSpinCount, _In_ DWORD Flags ) { return FALSE; } #endif #if (YY_Thunks_Support_Version < NTDDI_WIN6) //Minimum supported client Windows Vista [desktop apps | UWP apps] //Minimum supported server Windows Server 2008 [desktop apps | UWP apps] __DEFINE_THUNK( kernel32, 36, int, WINAPI, LCMapStringEx, _In_opt_ LPCWSTR lpLocaleName, _In_ DWORD dwMapFlags, _In_reads_(cchSrc) LPCWSTR lpSrcStr, _In_ int cchSrc, _Out_writes_opt_(cchDest) LPWSTR lpDestStr, _In_ int cchDest, _In_opt_ LPNLSVERSIONINFO lpVersionInformation, _In_opt_ LPVOID lpReserved, _In_opt_ LPARAM sortHandle ) { return 0; } #endif #if (YY_Thunks_Support_Version < NTDDI_WIN6) //Windows Vista, Windows Server 2008 __DEFINE_THUNK( kernel32, 8, LCID, WINAPI, LocaleNameToLCID, _In_ LPCWSTR lpName, _In_ DWORD dwFlags ) { return 0; } #endif #if (YY_Thunks_Support_Version < NTDDI_WIN6) //Windows Vista [desktop apps | UWP apps] //Windows Server 2008 [desktop apps | UWP apps] __DEFINE_THUNK( kernel32, 16, HANDLE, WINAPI, CreateEventExW, _In_opt_ LPSECURITY_ATTRIBUTES lpEventAttributes, _In_opt_ LPCWSTR lpName, _In_ DWORD dwFlags, _In_ DWORD dwDesiredAccess ) { /*if (auto pCreateEventExW = try_get_CreateEventExW()) { return pCreateEventExW(lpEventAttributes, lpName, dwFlags, dwDesiredAccess); }*/ using CreateEventExFunc = HANDLE (*) ( LPSECURITY_ATTRIBUTES lpEventAttributes, LPCWSTR lpName, DWORD dwFlags, DWORD dwDesiredAccess ); HMODULE hModule = ::GetModuleHandle(L"Kernel32.dll"); if (hModule) { CreateEventExFunc CreateEventExFunc_ = (CreateEventExFunc)::GetProcAddress(hModule, "CreateEventExW"); if (CreateEventExFunc_) { std::cout << "调用:CreateEventExW" << std::endl; return CreateEventExFunc_(lpEventAttributes, lpName, dwFlags, dwDesiredAccess); } } std::cout << "调用:CreateEventW" << std::endl; return ::CreateEventW(lpEventAttributes, dwFlags & CREATE_EVENT_MANUAL_RESET, dwFlags & CREATE_EVENT_INITIAL_SET, lpName); } #endif int main() { HANDLE hEvent = ::CreateEventEx(nullptr, L"test-event", CREATE_EVENT_INITIAL_SET, EVENT_ALL_ACCESS); if (hEvent) ::CloseHandle(hEvent); system("pause"); return 0; }
实现代码参考于YY-Thunks,可以看出,使用上没有任何改变,只是额外重新定义了系统api的实现。
先看看win10系统的效果
可以看到调用的是CreateEventEx函数,再看看xp系统
没有报错,但是调用的是替代的CreateEvent函数
大概实现的原理演示完了,要一个一个实现还是非常麻烦的,所以还是直接使用YY-Thunks吧~~