当前位置:首页 > c++ > 正文内容

如何解决windows报无法定位程序输入点“xxxapi”于动态链接库“xxx.dll”上

xuwenyan8个月前 (08-05)c++581

众所周知,从 Windows 的每次更新又会新增大量 API,这使得兼容不同版本的 Windows 需要花费很大精力。导致现在大量开源项目已经不再兼容一些早期的 Windows 版本,比如 Windows XP RTM。

难道就没有一种快速高效的方案解决无法定位程序输入点的问题吗?

有!!!使用Chuyu Team开源的YY-Thunks即可快速解决兼容性问题,已经处理了几乎所有存在兼容性问题的api。

原理

使用 LoadLibrary 以及 GetProcAddress 动态加载 API,不存在时做出补偿措施, 最大限度模拟原始 API 行为,让你的程序正常运行。

亮点

  • 更快!更安全!鸭船内建2级缓存以及按需加载机制,同时自动加密所有函数指针, 防止内存爆破攻击。最大程度减少不需要和不必要的 LoadLibrary 以及 GetProcAddress 调用以及潜在安全风险。

  • 轻松兼容 Windows XP,让你安心专注于业务逻辑。

  • 完全开源。 


使用

  1. 下载 YY-Thunks-Binary, 然后解压到你的工程目录。

  2. 【链接器】-【输入】-【附加依赖项】,添加 objs\$(PlatformShortName)\YY_Thunks_for_WinXP.obj

  3. 重新编译代码。

以上内容全部来至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系统下运行效果

image.png

可以看出win10系统下没有任何问题,再来看一下xp系统的效果

image.png

这就是因为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系统的效果

image.png

可以看到调用的是CreateEventEx函数,再看看xp系统

image.png

没有报错,但是调用的是替代的CreateEvent函数

大概实现的原理演示完了,要一个一个实现还是非常麻烦的,所以还是直接使用YY-Thunks吧~~

    文章作者:xuwenyan
    版权声明:本文为本站原创文章,转载请注明出处,非常感谢,如版权漏申明或您觉得任何有异议的地方欢迎与本站取得联系。

    扫描二维码推送至手机访问。

    版权声明:本文由艺文笔记发布,如需转载请注明出处。

    本文链接:https://www.xuwenyan.com/archives/2806

    标签: C++编程thunk
    分享给朋友:

    “如何解决windows报无法定位程序输入点“xxxapi”于动态链接库“xxx.dll”上” 的相关文章

    C++生成windows转储文件

    C++生成windows转储文件

    C++生成windows转储文件,代码如下: #include <Windows.h> #include <Dbghelp.h> void MakeMinidump(EXCEPTION_POINTERS* e) { auto hDbgHelp = Lo...

    C++如何获取控制台程序的输出内容?

    C++如何获取控制台程序的输出内容?

    很多工具程序(如ffmpeg)的进度显示往往都是以控制台字符显示的方法,我们可能需要调用这种控制台工具去完成工作,但同时又希望以友好的ui界面去显示当前的工作状态(如进度)。此时我们能想到的就是运行控制台程序,然后以某种方式去获取到控制台程序的输出,然后转换到我们的ui界面上去显示。 有多种...

    VC的ATL工程向导同时生成一个PS工程是做什么的?可以不要吗?

    VC的ATL工程向导同时生成一个PS工程是做什么的?可以不要吗?

    例如,我用VC2015的工程向导新建一个ATL的工程名字叫myAtl,那么VC会同时给我生成一个叫做myAtlPS的工程。这个myAtlPS工程是做什么的?什么情况下可以不需要它?什么情况下它又是必须存在的? PS工程是什么?可以不要吗? 这个PS工程叫做代理与存根(proxy&nbs...

    解决程序在xp系统总是莫名奇妙的崩溃问题(/Zc:threadSafeInit- )

    解决程序在xp系统总是莫名奇妙的崩溃问题(/Zc:threadSafeInit- )

    现象:程序在xp系统上面总是莫名其妙的崩溃,检查代码看不出任何问题,感觉代码都很好。即使你远程调试,找到了崩溃的点,当你注释了崩溃点之后,还是会崩溃到别的地方。当你遇到了这种情况的时候,不妨参照一下下面的方法看看,说不定可以解决问题。如何解决?将崩溃程序相关的所有工程代码全部关闭全局变量的线程安全检...

    uafxcwd.lib(afxmem.obj) : error LNK2005:

    uafxcwd.lib(afxmem.obj) : error LNK2005: "void * __cdecl operator new(unsigned int)"解决办法

    如果在编译MFC程序的时候出现下列及类似的错误: 1˃uafxcwd.lib(afxmem.obj) : error LNK2005: "void * __cdecl operator new(unsigned int)" (??2@YAPAXI@Z) 已经在 LIBCMTD.lib(new...

    C++ 获取进程所在目录(进程全路径)

    C++ 获取进程所在目录(进程全路径)

    打开windows任务管理器,会看到很多的进程在运行,随机挑选一个,如何通过c++代码获取某一个进程的所在全路径呢?这也是在windows软件开发中经常遇到的需求。通过进程名获取进程全路径由于可能很多进程叫同一个名字,所以获得的结果也有可能是多个#include <windows.h...