LoadDll详解----衔接于上篇的DLL装载

根据我们上次所讲,其大概流程是差不多理清了,但是还有具体的一些细节和一个Tls的大头还没阐述,先把LoadDll的具体细节讲完,这里推荐大家去看毛德操先生的著作《内核情景分析》,这本书对ReactOS(一种也是基于NT的内核,但是不同于Windows,它是完全开源的)的解析入木三分,我读完这个DLL的装载后大有所获,所以强烈推荐这本好书!!!

好了,接下来就是我们的正题了先复习下调用流程。
LdrInitializeThunk > LdrPEStartup() > LdrFixupImports()> LdrpProcessImportDirectory() > LdrpProcessImportDirectoryEntry()> LdrGetExportByOrdinal() > LdrFixupForward() 首先复习下LdrFixupForward的内容

LdrFixupForward(PCHAR ForwardName)
{
   
   CHAR NameBuffer[128];
   UNICODE_STRING DllName;
   NTSTATUS Status;
   PCHAR p;
   PLDR_DATA_TABLE_ENTRY Module;
   PVOID BaseAddress;
   strcpy(NameBuffer, ForwardName);
   p = strchr(NameBuffer, '.');//将转向DLL的dll模块名和转向函数分割
   if (p != NULL)
     {
   
        *p = 0;
        DPRINT("Dll: %s  Function: %sn", NameBuffer, p+1);
        RtlCreateUnicodeStringFromAsciiz (&DllName,
                                          NameBuffer);
        Status = LdrFindEntryForName (&DllName, &Module, FALSE);//先判断有无载入,假如加载了,就可以直接找了
        /* FIXME:
         *   The caller (or the image) is responsible for loading of the dll, where the function is forwarded.
         */
        if (!NT_SUCCESS(Status))//若未加载转向的DLL
          {
   
             Status = LdrLoadDll(NULL,//加载该DLL,及初始化其依赖的DLL
 								NULL,
                                 &DllName,
                                 &BaseAddress);
             if (NT_SUCCESS(Status))
               {
   
                 Status = LdrFindEntryForName (&DllName, &Module, FALSE);
               }
          }
        RtlFreeUnicodeString (&DllName);
        if (!NT_SUCCESS(Status))
          {
   
            DPRINT1("LdrFixupForward: failed to load %sn", NameBuffer);
            return NULL;
          }
        DPRINT("BaseAddress: %pn", Module->DllBase);
        return LdrGetExportByName(Module->DllBase, (PUCHAR)(p+1), -1);//递归调用依据函数名调用的过程
     }
   return NULL;
}

可以看到LdrFixupForward->LdrLoadDll 这才是我们今天的主角

/*
在LdrFixupForward里调用语句Status = LdrLoadDll(NULL,NULL,&DllName,&BaseAddress);
*/
NTSTATUS NTAPI
LdrLoadDll (IN PWSTR SearchPath OPTIONAL,
            IN PULONG LoadFlags OPTIONAL,
            IN PUNICODE_STRING Name,
            OUT PVOID *BaseAddress /* also known as HMODULE*, and PHANDLE 'DllHandle' */)
{
   
  NTSTATUS              Status;
  PLDR_DATA_TABLE_ENTRY Module;

  PPEB Peb = NtCurrentPeb();//获得peb指针
  TRACE_LDR("LdrLoadDll, loading %wZ%s%Sn",
            Name,
            SearchPath ? L" from " : L"",
            SearchPath ? SearchPath : L"");
  Status = LdrpLoadModule(SearchPath, LoadFlags ? *LoadFlags : 0, Name, &Module, BaseAddress);//下发给LdrpLoadModule
  if (NT_SUCCESS(Status) &&//若成功加载,并且不是映射为单纯的数据文件,因为我们这里是DLL文件,所以肯定进这个控制流
      (!LoadFlags || 0 == (*LoadFlags & LOAD_LIBRARY_AS_DATAFILE)))
    {
   
      if (!(Module->Flags & LDRP_PROCESS_ATTACH_CALLED))//模块并不是进程加载时被调用
        {
   
          RtlEnterCriticalSection(Peb->LoaderLock);
          Status = LdrpAttachProcess();
          RtlLeaveCriticalSection(Peb->LoaderLock);
        }
    }
 if ((!Module) && (NT_SUCCESS(Status)))//若模块
    return Status;
  *BaseAddress = NT_SUCCESS(Status) ? Module->DllBase : NULL;//返填充
  return Status;
}
/*
LdrpLoadModule   	//通过该函数装载模块和其依赖DLL
LdrpAttachProcess	//调用该函数的初始化函数
*/

可以看到,LdrLoadDll只是起到一个类似于stub的功能,主要实现下发给了LdrpLoadModule用以加载该模块及其依赖的DLL。而对于LdrpAttachProcess而言,则是调用这些DLL的初始化函数(dwReason == DLL_PROCESS_ATTACH),这个之后再讲,先把加载捋清了。

LdrFixupForward->LdrLoadDll->LdrpLoadModule

static NTSTATUS
LdrpLoadModule(IN PWSTR SearchPath OPTIONAL,
               IN ULONG LoadFlags,
               IN PUNICODE_STRING Name,		//模块名
               PLDR_DATA_TABLE_ENTRY *Module,//模块信息
               PVOID *BaseAddress OPTIONAL)
{
   
    UNICODE_STRING AdjustedName;
    UNICODE_STRING FullDosName;
    NTSTATUS Status;
    PLDR_DATA_TABLE_ENTRY tmpModule;
    HANDLE SectionHandle;
    SIZE_T ViewSize;
    PVOID ImageBase;
    PIMAGE_NT_HEADERS NtHeaders;
    BOOLEAN MappedAsDataFile;
    PVOID ArbitraryUserPointer;

    if (Module == NULL)
      {
   
        Module = &tmpModule;
      }
    /* adjust the full dll name */
    LdrAdjustDllName(&AdjustedName, Name, FALSE);//调节全路径至BaseDllName
    DPRINT(
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Qt控制台应用程序中调用DLL,你可以按照以下步骤进行操作: 1. 将DLL文件放置在Qt项目的文件夹中,或者指定其绝对路径。 2. 在Qt项目中创建一个头文件(例如,dllwrapper.h),用于声明要调用的DLL函数的函数指针和相关数据结构。 3. 在dllwrapper.h文件中,使用`#include`指令包含DLL的头文件。如果DLL没有提供头文件,则需要自己编写函数的声明。 4. 在dllwrapper.h文件中,声明函数指针来存储DLL函数的地址。例如,如果要调用名为`MyFunction`的函数,则可以使用以下代码声明函数指针: ```cpp typedef int (*MyFunctionType)(int); ``` 5. 在dllwrapper.h文件中,创建一个类或命名空间来管理DLL函数的加载和调用。在类或命名空间中,添加一个静态成员函数用于加载DLL并获取函数地址。例如: ```cpp class DLLWrapper { public: static bool loadDLL(); static MyFunctionType myFunction; }; ``` 6. 在dllwrapper.cpp文件中实现`loadDLL`和其他函数。`loadDLL`函数中,使用`QLibrary`类来加载DLL并获取函数地址。例如: ```cpp bool DLLWrapper::loadDLL() { QLibrary dll("your_dll_name.dll"); if (dll.load()) { myFunction = (MyFunctionType)dll.resolve("MyFunction"); if (myFunction) { return true; } } return false; } ``` 7. 在主函数或其他需要调用DLL函数的地方,调用`loadDLL`函数来加载DLL。例如: ```cpp if (DLLWrapper::loadDLL()) { int result = DLLWrapper::myFunction(42); // 处理DLL函数的返回值 } else { // 处理加载DLL失败的情况 } ``` 这样,你就可以在Qt控制台应用程序中成功调用DLL函数了。请注意,上述示例代码仅作为演示,你需要根据实际情况进行修改和适配。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值