Chinaunix首页 | 论坛 | 博客
  • 博客访问: 333362
  • 博文数量: 107
  • 博客积分: 2825
  • 博客等级: 少校
  • 技术积分: 795
  • 用 户 组: 普通用户
  • 注册时间: 2009-09-19 12:19
文章分类

全部博文(107)

文章存档

2013年(2)

2012年(31)

2011年(18)

2010年(12)

2009年(44)

我的朋友

分类: LINUX

2009-11-23 21:24:32

在PE映像的装入和启动过程中,DLL的装入和连接是一个重要的环节。读者在上一篇漫谈中看到,Windows的DLL装入(除ntdll.dll外)和连接是通过ntdll.dll中的一个函数LdrInitializeThunk()实现的。在Wine中,这个环节也是通过一个同名的函数实现的,只不过这个函数不在ntdll.dll中,而是wine-kthread里面的一个函数。在ReactOS中则同样也是LdrInitializeThunk(),同样也在ntdll.dll中。DLL的装入和连接当然离不开PE格式,但是本文的目的不在于完整、系统地介绍PE格式,而在于从LdrInitializeThunk()这个函数入手讲述DLL动态连接的过程,这个过程涉及PE格式中的什么成分,就讲解什么成分。这样,整个过程下来,PE格式中关键性的部件也就差不多都见到了。
    先对LdrInitializeThunk()这个函数名作些解释。“Ldr”显然是“Loader”的缩写。而“Thunk”意为“翻译”、“转换”、或者某种起着“桥梁”作用的东西。这个词在一般的字典中是查不到的,但却是个常见于微软的资料、文档中的术语。这个术语起源于编译技术,表示一小片旨在获取某个地址的代码,最初用于函数调用时“形参”和“实参”的结合。后来这个术语有了不少新的特殊含义和使用,但是DLL的动态连接与函数调用时的“形实结合”确实有着本质的相似。其实Unix/Linux也常常用到类似的技术,只是很少使用这个术语。例如,在Linux内核(i386版本)中,current是作为指针使用的,但实际上却是个宏操作:
CODE:
#define current get_current()
而get_current()是一个函数:
CODE:
static inline struct task_struct * get_current(void)
{
struct task_struct *current;
__asm__("andl %%esp,%0; ":"=r" (current) : "0" (~8191UL));
return current;
}
这显然就是一个Thunk。还有,ELF映像(与.so模块)的连接所用的“过程连接表”PLT和“全局位移表”GOT本质上也是Thunk。所以,Thunk就是“动态连接”的同义词。
    下面我们就来看LdrInitializeThunk()的代码。由于Windows不公开它的代码,而Wine需要处理PE和ELF两种格式的动态连接库,相比之下略为复杂一些,所以我们先看ReactOS代码中的这个函数,其代码在reactos/ib/ntdll\ldr/entry.S中:
CODE:
.globl
:
#if defined(_M_IX86)
nop   /* breakin overwrites this with "int 3" */
jmp
#elif defined(_M_ALPHA)
. . . . . . .
由于是汇编代码,所以在函数名前面加上了‘_’,而后缀@16则表示调用参数一共是16字节、即4个参数(不过下面的代码并未用到这4个参数)。其实这个函数的本身就是个Thunk,因为它起的只是桥梁、跳板的作用,真正起作用的是__true_LdrInitializeThunk()。
    在进入这个函数之前,目标EXE映像已经被映射到当前进程的用户空间,系统DLL ntdll.dll的映像也已经被映射,但是并没有在EXE映像与ntdll.dll映像之间建立连接(实际上EXE映像未必就直接调用ntdll.dll中的函数)。LdrInitializeThunk()是ntdll.dll中不经连接就可进入的函数,实质上就是ntdll.dll的入口。除ntdll.dll以外,别的DLL都还没有被装入(映射)。此外,当前进程(除内核中的“进程控制块”EPROCESS等数据结构外)在用户空间已经有了一个“进程环境块”PEB,以及该进程的第一个“线程环境块”TEB。这就是进入__true_LdrInitializeThunk()前的“当前形势”。
CODE:
VOID STDCALL
__true_LdrInitializeThunk (ULONG Unknown1, ULONG Unknown2,
                         ULONG Unknown3, ULONG Unknown4)
{
   . . . . . .
   DPRINT("LdrInitializeThunk()\n");
   if (NtCurrentPeb()->Ldr == NULL || NtCurrentPeb()->Ldr->Initialized == FALSE)
   {
       Peb = (PPEB)(PEB_BASE);
       DPRINT("Peb %x\n", Peb);
       ImageBase = Peb->ImageBaseAddress;
       . . . . . .
       /* Initialize NLS data */
       RtlInitNlsTables (Peb->AnsiCodePageData, Peb->OemCodePageData,
                         Peb->UnicodeCaseTableData, &NlsTable);
       RtlResetRtlTranslations (&NlsTable);
       NTHeaders = (PIMAGE_NT_HEADERS)(ImageBase + PEDosHeader->e_lfanew);
       . . . . . .
       /* create process heap */
       RtlInitializeHeapManager();
       Peb->ProcessHeap = RtlCreateHeap(HEAP_GROWABLE, NULL,
                            NTHeaders->OptionalHeader.SizeOfHeapReserve,
                            NTHeaders->OptionalHeader.SizeOfHeapCommit,
                            NULL, NULL);
       . . . . . .
       /* create loader information */
       Peb->Ldr = (PPEB_LDR_DATA)RtlAllocateHeap (Peb->ProcessHeap,
                                                  0,
                                                  sizeof(PEB_LDR_DATA));
       . . . . . .
       Peb->Ldr->Length = sizeof(PEB_LDR_DATA);
       Peb->Ldr->Initialized = FALSE;
       Peb->Ldr->SsHandle = NULL;
       InitializeListHead(&Peb->Ldr->InLoadOrderModuleList);
       InitializeListHead(&Peb->Ldr->InMemoryOrderModuleList);
       InitializeListHead(&Peb->Ldr->InInitializationOrderModuleList);
       . . . . . .
       /* add entry for ntdll */
       NtModule = (PLDR_MODULE)RtlAllocateHeap (Peb->ProcessHeap,
                                                        0,
                                                        sizeof(LDR_MODULE));
       . . . . . .
       InsertTailList(&Peb->Ldr->InLoadOrderModuleList,
                             &NtModule->InLoadOrderModuleList);
       InsertTailList(&Peb->Ldr->InInitializationOrderModuleList,
       
阅读(1123) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~