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

本文详细介绍了DLL加载的过程,从LdrFixupForward到LdrLoadDll,再到LdrpLoadModule。重点讨论了LdrpMapKnownDll和LdrpMapDllImageFile的实现,包括DLL的搜索路径、PE文件检测以及内存映射。最后提到了LdrpCallDllEntry在DLL初始化中的作用,包括调用Tls回调函数和DllMain。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

根据我们上次所讲,其大概流程是差不多理清了,但是还有具体的一些细节和一个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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值