记录一次运行时重定向Windows系统API的操作

众所周知Windows API GetWindowText/GetWindowTextLength有点坑,可能会耗时久以及造成当前进程卡死。最近调查客户卡死问题,唯一可疑的线程就在调用GetWindowText,于是决定先重定向这个系统API到自己实现的不卡顿的版本。思路是在客户用的自己DLL被加载时,直接修改进程的内存中的代码即可~不再赘述,上代码

int WINAPI internalGetWindowTextLengthA(HWND hWnd) { return 50; }

int WINAPI internalGetWindowTextLengthW(HWND hWnd) { return 50; }

int WINAPI internalGetWindowTextA(HWND hWnd, LPSTR lpString, int nMaxCount) {
  if (!lpString || !nMaxCount) return 0;

  LPWSTR lpWString = (LPWSTR) malloc(nMaxCount * sizeof(WCHAR));
  if (!lpWString) return 0;

  int textLength = InternalGetWindowText(hWnd, lpWString, nMaxCount);
  if (!textLength) {
    free(lpWString);
    return 0;
  }

  int ansiTextLength =
      WideCharToMultiByte(CP_ACP, 0, lpWString, -1, NULL, 0, NULL, NULL);
  ansiTextLength =
      WideCharToMultiByte(CP_ACP, 0, lpWString, textLength, lpString,
                          min(nMaxCount, ansiTextLength), NULL, NULL);
  free(lpWString);

  return ansiTextLength;
}

int WINAPI internalGetWindowTextW(HWND hWnd, LPWSTR lpString, int nMaxCount) {
  return InternalGetWindowText(hWnd, lpString, nMaxCount);
}

// This will use ::GetProcAddress to get the original function and then use jmp to redirect the call to the new function
bool hookSysFunctions(HMODULE hModule, LPCSTR lpProcName, FARPROC func) {
  FARPROC pfnOrig = GetProcAddress(hModule, lpProcName);
  if (!pfnOrig) return 0;
#ifdef _WIN64
  DWORD oldProtect;
  VirtualProtect(pfnOrig, 14, PAGE_EXECUTE_READWRITE, &oldProtect);
  *(BYTE *) pfnOrig = 0x48;
  *(BYTE *) ((DWORD_PTR) pfnOrig + 1) = 0xB8;
  *(DWORD_PTR *) ((DWORD_PTR) pfnOrig + 2) = (DWORD_PTR) func;
  *(BYTE *) ((DWORD_PTR) pfnOrig + 10) = 0xFF;
  *(BYTE *) ((DWORD_PTR) pfnOrig + 11) = 0xE0;
  VirtualProtect(pfnOrig, 14, oldProtect, &oldProtect);
  return true;
#else
  DWORD oldProtect;
  VirtualProtect(pfnOrig, 5, PAGE_EXECUTE_READWRITE, &oldProtect);
  *(BYTE *) pfnOrig = 0xE9;
  *(DWORD *) ((DWORD_PTR) pfnOrig + 1) =
      (DWORD_PTR) func - (DWORD_PTR) pfnOrig - 5;
  VirtualProtect(pfnOrig, 5, oldProtect, &oldProtect);
  return true;
#endif
}

BOOL WINAPI DllMain(HINSTANCE hinstDLL,// handle to DLL module
                    DWORD fdwReason,   // reason for calling function
                    LPVOID lpvReserved)// reserved
{
  // Perform actions based on the reason for calling.
  switch (fdwReason) {
    case DLL_PROCESS_ATTACH:
      // Initialize once for each new process.
      // Return FALSE to fail DLL load.
      {
        std::vector<std::pair<std::string, FARPROC>> internalFunctions = {
            {"GetWindowTextLengthA", (FARPROC) internalGetWindowTextLengthA},
            {"GetWindowTextLengthW", (FARPROC) internalGetWindowTextLengthW},
            {"GetWindowTextA", (FARPROC) internalGetWindowTextA},
            {"GetWindowTextW", (FARPROC) internalGetWindowTextW}};

        HMODULE hModule = GetModuleHandleW(L"user32");

        for (auto &func : internalFunctions) {
          hookSysFunctions(hModule, func.first.c_str(), func.second);
        }
      }
      break;

    case DLL_THREAD_ATTACH:
      // Do thread-specific initialization.
      break;

    case DLL_THREAD_DETACH:
      // Do thread-specific cleanup.
      break;

    case DLL_PROCESS_DETACH:

      if (lpvReserved != nullptr) {
        break;// do not do cleanup if process termination scenario
      }

      // Perform any necessary cleanup.
      break;
  }
  return TRUE;// Successful DLL_PROCESS_ATTACH.
}

验证下来果然不卡了,而且调试发现这个线程就是客户flutter application的ui线程,使用了win32这个flutter的库。一般团队不建议用这几个函数去枚举窗口获取窗口信息,坑比较多。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值