当前位置:首页 > c++ > 如何解决windows报无法定位程序输入点“xxxapi”于动态链接库“xxx.dll”上

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

xuwenyan3天前c++160

众所周知,从 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
    版权声明:本文为本站原创文章,转载请注明出处,非常感谢,如版权漏申明或您觉得任何有异议的地方欢迎与本站取得联系。
    标签: C++编程thunk

    相关文章

    排序算法-快速排序

    排序算法-快速排序

    排序算法的思想非常简单,在待排序的数列中,我们首先要找一个数字作为基准数(这只是个专用名词)。为了方便,我们一般选择第 1 个数字作为基准数(其实选择第几个并没有关系)。接下来我们需要把这个待排序的数...

    排序算法-冒泡排序

    排序算法-冒泡排序

    冒泡排序也是一种简单直观的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法...

    排序算法-选择排序

    排序算法-选择排序

    选择排序是一种简单直观的排序算法,无论什么数据进去都是 O(n²) 的时间复杂度。所以用到它的时候,数据规模越小越好。唯一的好处可能就是不占用额外的内存空间了吧。时间复杂度O(n²)最坏情况合适发生?...

    c++时间戳转年月日时分秒

    c++时间戳转年月日时分秒

    时间戳转年月日时分秒是比较常用的功能,调用api localtime_s把时间戳转成tm结构体,就可以通过tm结构体中的成员得到对应的年月日时分秒,需要注意的就是tm结构体部分成员的值不是真实的值,需...

    c++使用libcurl实现断点续传

    c++使用libcurl实现断点续传

    libcurl实现断点续传大致需要两个关键点:1:使用GetFileSize接口获取本地已缓存文件的大小。2:通过curl_easy_setopt接口的CURLOPT_RESUME_FROM_LARG...

    std::make_shared有什么好处?

    std::make_shared有什么好处?

    为什么使用std::make_shared,std::make_shared有什么好处?如下: 更美观的代码std::shared_ptr<Node> ptr(new Node);std...

    发表评论

    访客

    ◎欢迎参与讨论,请在这里发表您的看法和观点。