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

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

xuwenyan1周前 (08-05)c++290

众所周知,从 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

    相关文章

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

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

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

    c++函数模板参数类型限定

    c++函数模板参数类型限定

    函数模板函数模板可以实现对不同数据类型做统一操作,比如比较两个数据的大小:template<typename T> bool compare(T& ...

    排序算法-快速排序

    排序算法-快速排序

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

    排序算法-冒泡排序

    排序算法-冒泡排序

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

    排序算法-选择排序

    排序算法-选择排序

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

    大端模式和小端模式的区别以及如何判断大小端

    大端模式和小端模式的区别以及如何判断大小端

    在计算中,字节顺序是指数字的二进制表示内的字节(或有时是位)的顺序。它也可以更普遍地用于指代任何表示的内部排序,例如数字系统中的数字或日期的部分。在最常见的用法中,字节顺序表示多字节数字内的字节顺序,...

    发表评论

    访客

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