微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

c – 如何修改运行时加载的DLL的导入地址表

我想在运行时挂钩从加载的DLL中调用函数,我使用了“ Windows Via C/C++”一书中的CAPIHook类(通过安装系统范围挂钩完成的DLL注入和通过修改IAT挂钩)但是这个只有在可执行文件的IAT中存在DLL名称/符号时,代码才有效. (即用于隐式DLL链接)

这是DLL代码

CAPIHook::CAPIHook(PSTR pszCalleeModName,PSTR pszFuncName,PROC pfnHook) {

   // Note: the function can be hooked only if the exporting module 
   //       is already loaded. A solution Could be to store the function
   //       name as a member; then,in the hooked LoadLibrary* handlers,parse
   //       the list of CAPIHook instances,check if pszCalleeModName
   //       is the name of the loaded module to hook its export table and 
   //       re-hook the import tables of all loaded modules.

   m_pNext  = sm_pHead;    // The next node was at the head
   sm_pHead = this;        // This node is Now at the head

   // Save information about this hooked function
   m_pszCalleeModName   = pszCalleeModName;
   m_pszFuncName        = pszFuncName;
   m_pfnHook            = pfnHook;
   m_pfnorig            =  GetProcAddressRaw(GetModuleHandleA(pszCalleeModName),m_pszFuncName);

   // If function does not exit,... bye bye
   // This happens when the module is not already loaded
   if (m_pfnorig == NULL)
   {
      wchar_t szPathname[MAX_PATH];
      GetmodulefileNameW(NULL,szPathname,_countof(szPathname));
      wchar_t sz[1024];
      StringCchPrintfW(sz,_countof(sz),TEXT("[%4u - %s] impossible to find %s\r\n"),GetCurrentProcessId(),pszFuncName);
      OutputDebugString(sz);
      return;
   }

   // Hook this function in all currently loaded modules
   ReplaceIATEntryInAllMods(m_pszCalleeModName,m_pfnorig,m_pfnHook);
}

这是钩子函数

HMODULE WINAPI CAPIHook::LoadLibraryA(PCSTR pszModulePath) {

   HMODULE hmod = ::LoadLibraryA(pszModulePath);
   FixupNewlyLoadedModule(hmod,0);
   return(hmod);
}

HMODULE WINAPI CAPIHook::LoadLibraryW(PCWSTR pszModulePath) {

   HMODULE hmod = ::LoadLibraryW(pszModulePath);
   FixupNewlyLoadedModule(hmod,0);
   return(hmod);
}

HMODULE WINAPI CAPIHook::LoadLibraryExA(PCSTR pszModulePath,HANDLE hFile,DWORD dwFlags) {

   HMODULE hmod = ::LoadLibraryExA(pszModulePath,hFile,dwFlags);
   FixupNewlyLoadedModule(hmod,dwFlags);
   return(hmod);
}

HMODULE WINAPI CAPIHook::LoadLibraryExW(PCWSTR pszModulePath,DWORD dwFlags) {

   HMODULE hmod = ::LoadLibraryExW(pszModulePath,dwFlags);
   return(hmod);
}

替换IAT的方法

void CAPIHook::ReplaceIATEntryInOneMod(PCSTR pszCalleeModName,PROC pfnCurrent,PROC pfnNew,HMODULE hmodCaller) {

   // Get the address of the module's import section
   ULONG ulSize;

   // An exception was triggered by Explorer (when browsing the content of 
   // a folder) into imagehlp.dll. It looks like one module was unloaded...
   // Maybe some threading problem: the list of modules from Toolhelp might 
   // not be accurate if FreeLibrary is called during the enumeration.
   PIMAGE_IMPORT_DESCRIPTOR pImportDesc = NULL;
   __try {
      pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR) ImageDirectoryEntryToData(
         hmodCaller,TRUE,IMAGE_DIRECTORY_ENTRY_IMPORT,&ulSize);
   } 
   __except (InvalidReadExceptionFilter(GetExceptioninformation())) {
      // nothing to do in here,thread continues to run normally
      // with NULL for pImportDesc 
   }

   if (pImportDesc == NULL)
      return;  // This module has no import section or is no longer loaded


   // Find the import descriptor containing references to callee's functions
   for (; pImportDesc->Name; pImportDesc++) {
      PSTR pszModName = (PSTR) ((PBYTE) hmodCaller + pImportDesc->Name);
      if (lstrcmpiA(pszModName,pszCalleeModName) == 0) {

         // Get caller's import address table (IAT) for the callee's functions
         PIMAGE_THUNK_DATA pThunk = (PIMAGE_THUNK_DATA) 
            ((PBYTE) hmodCaller + pImportDesc->FirstThunk);

         // Replace current function address with new function address
         for (; pThunk->u1.Function; pThunk++) {

            // Get the address of the function address
            PROC* ppfn = (PROC*) &pThunk->u1.Function;

            // Is this the function we're looking for?
            BOOL bFound = (*ppfn == pfnCurrent);
            if (bFound) {
               if (!WriteProcessMemory(GetCurrentProcess(),ppfn,&pfnNew,sizeof(pfnNew),NULL) && (ERROR_NOACCESS == GetLastError())) {
                  DWORD dwOldProtect;
                  if (VirtualProtect(ppfn,PAGE_WRITEcopY,&dwOldProtect)) {

                     WriteProcessMemory(GetCurrentProcess(),NULL);
                     VirtualProtect(ppfn,dwOldProtect,&dwOldProtect);
                  }
               }
               return;  // We did it,get out
            }
         }
      }  // Each import section is parsed until the right entry is found and patched
   }
}

作者添加评论添加功能,但我不知道该怎么做

Note: the function can be hooked only if the exporting module
is already loaded. A solution Could be to store the function
name as a member; then,parse
the list of CAPIHook instances,check if pszCalleeModName
is the name of the loaded module to hook its export table and
re-hook the import tables of all loaded modules.

他也在书上写了这个,但我又不知道该怎么做

A possible solution is to use the hooked LoadLibrary* functions to
detect when a module is exporting an unpatched hooked function and
then execute two actions:

Hook again the import table of the module already loaded because it is
Now possible to call GetProcAddress and get a pointer to the original
implementation of the function to hook. Notice that the name of the
function needs to be stored as a class member and set in the
constructor.

Directly update this hooked function in the Export Address Table of
the exporting module as shown by the implementation of the
ReplaceEATEntryInOneMod function. That way,all new modules calling
the hooked function will call our handler

我尝试在加载DLL后修改IAT,但我的钩子函数没有被调用

HMODULE WINAPI CAPIHook::LoadLibraryW(PCWSTR pszModulePath) {

   HMODULE hmod = ::LoadLibraryW(pszModulePath);

   if (StrCmpIW(pszModulePath,myDLLUnicodeName.c_str()) == 0 ) {
        PROC proc =  GetProcAddressRaw(GetModuleHandleA(myDLLName.c_str()),myFunctionName.c_str());

        if ( proc != NULL ) {
            for (CAPIHook* p = sm_pHead; p != NULL; p = p->m_pNext) {
                 if (StrCmpIA(p->m_pszCalleeModName,myDLLName.c_str()) == 0) {
                    MessageBox(NULL,L"This is the New Dynamic DLL",L"Test!",0);
                    ReplaceIATEntryInAllMods(p->m_pszCalleeModName,proc,p->m_pfnHook);  
                 }
            }
        }
    }

   FixupNewlyLoadedModule(hmod,0);
   return(hmod);
}

那么,如何修改代码来处理动态加载情况?

解决方法

我之前做过这个.
你想要的是EAT挂钩而不是IAT.此外,挂钩:: LoadLibrary API本身,以便您知道何时加载DLL,并在加载后从DLL挂钩所请求的api.

互联网上有一些关于如何做到这一点的例子.这是我刚才发现的一个
http://board.cheat-project.com/showthread.php?t=10633

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


对象的传值与返回说起函数,就不免要谈谈函数的参数和返回值。一般的,我们习惯把函数看作一个处理的封装(比如黑箱),而参数和返回值一般对应着处理过程的输入和输出。这种情况下,参数和返回值都是值类型的,也就是说,函数和它的调用者的信息交流方式是用过数据的拷贝来完成,即我们习惯上称呼的“值传递”。但是自从引
从实现装饰者模式中思考C++指针和引用的选择最近在看设计模式的内容,偶然间手痒就写了一个“装饰者”模式的一个实例。该实例来源于风雪涟漪的博客,我对它做了简化。作为一个经典的设计模式,本身并没有太多要说的内容。但是在我尝试使用C++去实现这个模式的实例的时候,出现了一些看似无关紧要但是却引人深思的问题
关于vtordisp知多少?我相信不少人看到这篇文章,多半是来自于对标题中“vtordisp”的好奇。其实这个关键词也是来源于我最近查看对象模型的时候偶然发现的。我是一个喜欢深究问题根源的人(有点牛角尖吧),所以当我第一次发现vtordisp的时候,我也是很自然的把它输进google查找相关资料,但
那些陌生的C++关键字学过程序语言的人相信对关键字并不陌生。偶然间翻起了《C++ Primer》这本书,书中列举了所有C++的关键字。我认真核对了一下,竟然发现有若干个从未使用过的关键字。一时间对一个学了六年C++的自己狠狠鄙视了一番,下决心一定要把它们搞明白!图1红色字体给出的是我个人感觉一般大家
命令行下的树形打印最近在处理代码分析问题时,需要将代码的作用域按照树形结构输出。问题的原型大概是下边这个样子的。图中给了一个简化的代码片段,该代码片段包含5个作用域:全局作用域0、函数fun作用域1、if语句作用域2、else语句作用域3和函数main作用域4。代码作用域有个显著的特点就是具有树形结
虚函数与虚继承寻踪封装、继承、多态是面向对象语言的三大特性,熟悉C++的人对此应该不会有太多异议。C语言提供的struct,顶多算得上对数据的简单封装,而C++的引入把struct“升级”为class,使得面向对象的概念更加强大。继承机制解决了对象复用的问题,然而多重继承又会产生成员冲突的问题,虚继
不要被C++“自动生成”所蒙骗C++对象可以使用两种方式进行创建:构造函数和复制构造函数。假如我们定义了类A,并使用它创建对象。Aa,b;Ac=a;Ad(b);对象a和b使用编译器提供的默认构造函数A::A()创建出来,我们称这种创建方式为对象的定义(包含声明的含义)。对象c和d则是使用已有的对象,
printf背后的故事 说起编程语言,C语言大家再熟悉不过。说起最简单的代码,Helloworld更是众所周知。一条简单的printf语句便可以完成这个简单的功能,可是printf背后到底做了什么事情呢?可能很多人不曾在意,也或许你比我还要好奇!那我们就聊聊printf背后的故事。 一、printf
定义 浮点数就是小数点位置不固定的数,也就是说与定点数不一样,浮点数的小数点后的小数位数可以是任意的,根据IEEE754-1985(也叫IEEE Standard for Binary Floating-Point Arithmetic)的定义,浮点数的类型有两种:单精度类型(用4字节存储)和双精度
在《从汇编看c++的引用和指针》一文中,虽然谈到了引用,但是只是为了将两者进行比较。这里将对引用做进一步的分析。1 引用的实现方式在介绍有关引用的c++书中,很多都说引用只是其引用变量的一个别名。我自己不是很喜欢这种解释,因为觉得这种解释会给人误解,好像引用和变量就是一回事,而且,书中也没有给出,为