如何在类中挂钩 Windows 上的 fopen()

How to hook fopen() on Windows inside a class

提问人:Caty 提问时间:6/4/2023 最后编辑:Caty 更新时间:6/5/2023 访问量:135

问:

我需要在 Windows 上挂钩 fopen() 作为类的成员。我测试了这段代码:

void **IATfind(const char *function, HMODULE module);

// Define the function pointer type for the original function
typedef FILE*(__cdecl* popen)(const char* filename, const char* mode);

struct Hook {
  // Declare the original function pointer
  popen orig_fopen;
  // Define the detoured function
  FILE* __cdecl hook_fopen(const char* filename, const char* mode) {
    printf("Rewrite fopen: %s\n", filename); // need to know here which module make fopen() call
    return orig_fopen("hook_test.txt", mode);
  }
  void DetourIATptr(const char *function, void *newfunction, HMODULE module) {
    void **funcptr = IATfind(function, module);
    if (funcptr == 0) {
      printf("cannot find function address\n");
      return;
    }

    DWORD oldrights, newrights = PAGE_READWRITE;
    //Update the protection to READWRITE
    VirtualProtect(funcptr, sizeof(LPVOID), newrights, &oldrights);

    orig_fopen = (popen)*funcptr;
    *funcptr = (void*)&Hook::hook_fopen;

    //Restore the old memory protection flags.
    VirtualProtect(funcptr, sizeof(LPVOID), oldrights, &newrights);
  }
  void Do() {
    //DetourIATptr("fopen", (void*)hook_fopen, 0);
  }
};
int main(int argc, CHAR *argv[]) {
  Hook hk;
  hk.Do();
  printf("main\n");
  fopen("myfile.txt", "w");

  return 0;
}
void **IATfind(const char *function, HMODULE module) { //Find the IAT (Import Address Table) entry specific to the given function.
  if (module == 0)
    module = GetModuleHandle(0);
  PIMAGE_DOS_HEADER pImgDosHeaders = (PIMAGE_DOS_HEADER)module;
  PIMAGE_NT_HEADERS pImgNTHeaders = (PIMAGE_NT_HEADERS)((LPBYTE)pImgDosHeaders + pImgDosHeaders->e_lfanew);
  PIMAGE_IMPORT_DESCRIPTOR pImgImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)((LPBYTE)pImgDosHeaders + pImgNTHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);

  if (pImgDosHeaders->e_magic != IMAGE_DOS_SIGNATURE) {
    printf("libPE Error : e_magic is no valid DOS signature\n");
    return 0;
  }
  for (IMAGE_IMPORT_DESCRIPTOR *iid = pImgImportDesc; iid->Name != NULL; iid++) {
    for (int funcIdx = 0; *(funcIdx + (LPVOID*)(iid->FirstThunk + (SIZE_T)module)) != NULL; funcIdx++) {
      char *modFuncName = (char*)(*(funcIdx + (SIZE_T*)(iid->OriginalFirstThunk + (SIZE_T)module)) + (SIZE_T)module + 2);
      const uintptr_t nModFuncName = (uintptr_t)modFuncName;
      bool isString = !(nModFuncName & (sizeof(nModFuncName) == 4 ? 0x80000000 : 0x8000000000000000));
      if (isString) {
        if (!_stricmp(function, modFuncName)) {
          printf("address finded\n");
          return funcIdx + (LPVOID*)(iid->FirstThunk + (SIZE_T)module);
        }
      }
    }
  }
  return 0;
}

我得到这个:错误 C2440:“类型转换”:无法从“FILE (__cdecl Hook::)(const char *,const char *)” 转换为“void *”

如果我从 Hook 结构中定义 hook_fopen(),代码工作正常,但我需要使用类才能在多个 dll 模块中挂钩 fopen()。

替代解决方案:可以避免使用类,但需要知道哪个模块进行 fopen() 调用,因此必须在 hook_fopen() 中识别 hmodule,我需要它用于加载更多 dll 模块并检查此模块是否充当恶意软件的应用程序。

C++ Windows 挂钩 fopen

评论

2赞 john 6/4/2023
hook 函数必须与 hooked 函数具有相同的签名。类内的非静态函数与类外的函数具有不同的签名。这是C++的一个基本事实。因此,您似乎唯一的选择是使静态。当然,这意味着你不能再访问,除非你也把它变成静态的。hook_fopenorig_fopenhook_fopen
0赞 john 6/4/2023
由于您可能无法接受静态化,您能否解释一下为什么使用类可以帮助您在多个模块中使用此代码。这部分还不清楚(至少对我来说是这样)。hook_fopen
0赞 Caty 6/4/2023
我怎么说,需要在多个dll模块中挂钩fopen()。当一个模块调用 fopen() 时,实际上会调用 hook_fopen(),但我需要知道哪个模块进行 fopen() 调用。我需要它用于加载更多模块并检查此模块是否充当恶意软件的应用程序。
0赞 john 6/4/2023
因此,您正在尝试向 fopen 调用添加上下文。这在任何直接的方式都是不可能的。
0赞 RbMm 6/4/2023
hook_fopen不能是 member 或 class/struct。 是错误的。必须根本不需要(我已经没有说它是如何实现的)popen orig_fopen;extern "C" { extern PVOID __imp_fopen;}IATfind

答: 暂无答案