从内存中加载DLL指南.docx
- 文档编号:25347725
- 上传时间:2023-06-07
- 格式:DOCX
- 页数:18
- 大小:21.37KB
从内存中加载DLL指南.docx
《从内存中加载DLL指南.docx》由会员分享,可在线阅读,更多相关《从内存中加载DLL指南.docx(18页珍藏版)》请在冰豆网上搜索。
从内存中加载DLL指南
从内存中加载DLL指南
从内存中加载DLL指南..................................................................................................................1前言...............................................................................................................................................2内容提纲.......................................................................................................................................2简介...............................................................................................................................................2PE文件格式..................................................................................................................................2DOSheader/DOSstub格式......................................................................................................3PEheader.........................................................................................................................3格式
Sectionheader...................................................................................................................6格式
加载LIBRARY................................................................................................................................6
Section..................................................................................................................7拷贝的内容
............................................................................................................................7基地址重定位
............................................................................................................................8处理导入信息
内存访问权限设置....................................................................................................................9通知library被进程加载............................................................................................................9调用导出函数..........................................................................................................................10释放library.............................................................................................................................10MEMORYMODULE工具包.............................................................................................................11
.................................................................................................................................11下载位置
已知的问题..............................................................................................................................11License.....................................................................................................................................11版本移植.................................................................................................................................11版权声明.................................................................................................................................12
前言
本篇指南是讲解如何不借助文件系统的帮助来加载内存中载入DLL的技术。
作者:
JoachimBauch
联系方式:
mail◎joachim-bauch.de
版权:
CreativeCommonsLicense(by-sa)内容提纲
简介
PE文件格式
DOSheader/DOSstub格式
PEheader格式
Sectionheader格式
加载library
分配内存空间
拷贝Section内容到目标位置
基址重定位
内存访问权限设置
通知library被进程加载
调用导出函数
释放library
MemoryModule工具包
下载地址
已知的问题
License
移植版本
版权声明
简介
Windows平台提供的加载library的API(LoadLibarary,LoadLibraryEx)只能加载文件系统中的Library.没有体哦那个从内存中加载Dll的功能。
但是,有些情况下又需要这样的功能。
譬如,你不想在发布包中包含很多文件,又或者你想给那些逆向工作者一些苦头吃。
这时一个常见的做法是先把dll文件写到一个临时文件中,然后从临时文件中导入它。
当程序终止时把临时文件删除。
PE文件格式
绝大多数包含执行代码的二进制文件(.exe、.dll、.sys)都有相同的文件格式。
这种文件格式包括下面几个部分:
DOSheader
DOSstub
PEheader
Sectionheader
Section1
Section2
…
Sectionn
下面将简单描述各个组成部分。
(注:
在头文件winnt.h中可以找到下面要介绍的所有
数据结构)
DOSheader/DOSstub格式
DOS格式部分有两部分组成。
分别是DOSheader和DOSstub
DOS头部存在的作用仅仅是为了向后兼容的目的。
跟在DOSheader后面的是DOSStub
数据,DOSstub用来显示一条错误信息来告诉用户该文件不能在DOS模式下运行。
微软对DOSHeader的声明如下:
typedefstruct_IMAGE_DOS_HEADER{//DOS.EXEheader
WORDe_magic;//Magicnumber
WORDe_cblp;//Bytesonlastpageoffile
WORDe_cp;//Pagesinfile
WORDe_crlc;//Relocations
WORDe_cparhdr;//Sizeofheaderinparagraphs
WORDe_minalloc;//Minimumextraparagraphsneeded
WORDe_maxalloc;//Maximumextraparagraphsneeded
WORDe_ss;//Initial(relative)SSvalue
WORDe_sp;//InitialSPvalue
WORDe_csum;//Checksum
WORDe_ip;//InitialIPvalue
WORDe_cs;//Initial(relative)CSvalue
WORDe_lfarlc;//Fileaddressofrelocationtable
WORDe_ovno;//Overlaynumber
WORDe_res[4];//Reservedwords
WORDe_oemid;//OEMidentifier(fore_oeminfo)
WORDe_oeminfo;//OEMinformation;e_oemidspecific
WORDe_res2[10];//Reservedwords
LONGe_lfanew;//Fileaddressofnewexeheader
}IMAGE_DOS_HEADER,*PIMAGE_DOS_HEADER;
PEheader格式
PEHeader用来描述和section相关的信息。
可执行文件用section来保存执行代码和数
据,以及从其他模块导入的函数的信息和本模块导出的函数信息等。
PEHeader的定义如下:
typedefstruct_IMAGE_NT_HEADERS{
DWORDSignature;
IMAGE_FILE_HEADERFileHeader;
IMAGE_OPTIONAL_HEADER32OptionalHeader;
}IMAGE_NT_HEADERS32,*PIMAGE_NT_HEADERS32;
FileHeader字段描述了文件的物理格式,如目录信息、Symbols的信息等。
typedefstruct_IMAGE_FILE_HEADER{
WORDMachine;
WORDNumberOfSections;
DWORDTimeDateStamp;
DWORDPointerToSymbolTable;
DWORDNumberOfSymbols;
WORDSizeOfOptionalHeader;
WORDCharacteristics;}IMAGE_FILE_HEADER,*PIMAGE_FILE_HEADER;
字段OptionalHeader保存模块的逻辑信息,这些信息包括需要的操作系统版本,需要的
内存大小和入口点信息。
typedefstruct_IMAGE_OPTIONAL_HEADER{
//
//Standardfields.
//
WORDMagic;
BYTEMajorLinkerVersion;
BYTEMinorLinkerVersion;
DWORDSizeOfCode;
DWORDSizeOfInitializedData;
DWORDSizeOfUninitializedData;
DWORDAddressOfEntryPoint;
DWORDBaseOfCode;
DWORDBaseOfData;
//
//NTadditionalfields.
//
DWORDImageBase;
DWORDSectionAlignment;
DWORDFileAlignment;
WORDMajorOperatingSystemVersion;
WORDMinorOperatingSystemVersion;
WORDMajorImageVersion;
WORDMinorImageVersion;
WORDMajorSubsystemVersion;
WORDMinorSubsystemVersion;
DWORDWin32VersionValue;
DWORDSizeOfImage;
DWORDSizeOfHeaders;
DWORDCheckSum;
WORDSubsystem;
WORDDllCharacteristics;
DWORDSizeOfStackReserve;
DWORDSizeOfStackCommit;
DWORDSizeOfHeapReserve;
DWORDSizeOfHeapCommit;
DWORDLoaderFlags;
DWORDNumberOfRvaAndSizes;
IMAGE_DATA_DIRECTORY
DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
}IMAGE_OPTIONAL_HEADER32,*PIMAGE_OPTIONAL_HEADER32;
字段DataDirectory保存着模块中定义的(IMAGE_NUMBEROF_DIRECTORY_ENTRIES)个逻辑项(Conpontents)的入口:
IndexDesription
0导出函数块
1导入函数块
2资源块
4异常信息块
5基地址重定位表块
6调试信息块
7架构(Architecture)特定的数据块8全局指针块
9线程本地存储块
10载入配置块
11Boundimports
12导入地址表块
13延迟加载导入块
14COM运行时描述块
对于只是加载DLL的任务来说,我们仅仅用到导入块和基地址重定位表块。
不过为了调用导出的函数,我们还需要用到导出函数块。
Sectionheader格式
这一部分数据保存在PEheader部分的OPtionalHeader字段后面。
为了方便定位sectionheader的位置,微软提供了一个宏定义IMAGE_FIRST_SECTION,它的值等于SectionHeader的开始地址相对于PEHeader基地址的位移。
Sectionheader实际上是一个存储着文件中每一个Section的信息的列表:
typedefstruct_IMAGE_SECTION_HEADER{
BYTEName[IMAGE_SIZEOF_SHORT_NAME];
union{
DWORDPhysicalAddress;
DWORDVirtualSize;
}Misc;
DWORDVirtualAddress;
DWORDSizeOfRawData;
DWORDPointerToRawData;
DWORDPointerToRelocations;
DWORDPointerToLinenumbers;
WORDNumberOfRelocations;
WORDNumberOfLinenumbers;
DWORDCharacteristics;
}IMAGE_SECTION_HEADER,*PIMAGE_SECTION_HEADER;
而一个Section中可以包含代码,数据,重定位信息,资源,导出导入函数等信息。
加载Library
为了模拟PEloader的过程,我们首先必须弄清楚从把文件读入内存中开始到准备好可以被程序使用为止,都需要执行那些步骤。
当我们调用LoadLibrary时,Windows主要做了了以下工作:
1.打开指定的文件并检查DOS和PE头部。
2.在PEHeader.OptionalHeader.ImageBase处分配PEHeader.Optionalheader.SizeOfImage
个字节的内存。
3.分析sectionheader,从IMAGE_SECTION_HEADER结构中的VirtualAddress属性中获取
每个section的开始地址相对与ImageBase的位移。
把section中的内容拷贝到正确
的位置。
4.如果分配的地址不同于ImageBase,代码和数据块中的参数必须做相应的调整。
这
一步就是传说中的relocation.
5.Library中用到的导入信息也必须通过加载相应的模块来解决。
6.各个section对应的内存区必须根据各个Section的特征来进行访问限制。
这时那些
标记为可以丢弃的section占用的内存可以被释放。
这些section通常保存都是导入
时需要用到的临时数据(例如基地址重定位信息)的。
7.现在library已经被成功的加载了,现在可以使用Dll_PROCESS_ATTACH标志来调用
library的入口函数通知library正在被进程加载。
下面我们将详细的描述各个步骤。
分配内存
为了利用window提供了设置内存块访问限制的功能,必须使用VirtualAlloc来预订(或分配)library需要的所有内存。
因为我们需要约束对这些内存的访问。
例如我们应该阻止对代码区和常量区的写操作。
OptionalHeader中保存有Library需要的内存块的大小。
如果可能,我们必须预订ImageBase中指定的内存。
Memory=VirtualAlloc((LPVOID)(PEHeader->OptionalHeader.ImageBase),
PEHeader->OptionalHeader.SizeOfImage,
MEM_RESERVE,PAGE_READWRITE);
如果预订到的地址不是ImageBase中指定的地址,那么必须执行后面描述的基地址重定位步骤。
拷贝Section的内容
分配内存以后,就可以把section中的内容拷贝到系统中了。
这时需要通过分析SectionHeader中的数据来找到section部分的数据在文件中的位置和在内存中的目标位置。
在数据拷贝之前,需要先提交要使用的内存块。
Dest=VirtualAlloc(baseAddress+section->VirtualAddress,
Section->SizeOfRawData,
MEM_COMMIT,
PAGE_READWRITE);
对于没有在文件中保存数据(如保存运行中用到的参数的section)的区块,SizeOfRawData字段的值为0.这时你可以用OptionalHeader字段中的SizeOfInitializedData或SizeOfUninitializedData字段。
具体选用那个字段取决于section的Characteristics字段中IMAGE_SCN_CNT_INITIALIZED_DATA和IMAGE_SCN_CNT_UNINITIALIZED_DATA标志位的值。
基地址重定位
Library中的代码/数据section中的用到的所有内存地址都以一种相对于基地址位移的方式进行保存。
而基地址则保存在OptionalHeader的ImageBase字段中。
如果library不能被加载到指定的基地址,那么这些内存地址的地址都必须进行调整,术语称之为重定位。
PE文件中的基地址重定位表保存这些需要重定位的内存地址。
我们可以在OptionalHeader的DataDirectory字段中保存的第5个字典入口处找到基地址重定位表。
这个表由一系列的IMAGE_BASE_RELOCATION数据结构组成。
typedefstruct_IMAGE_BASE_RELOCATION{
DWORDVirtualAddress;
DWORDSizeOfBlock;
//WORDTypeOffset[1];
}IMAGE_BASE_RELOCATION;
重定位表包含(SizeOfBlock–IMAGE_SIZEOF_BASE_RELOCATION)/2个项,每个项
由16位bit组成。
其中高4位bit定义了重定位的类型,低12位定义了相对于
VirtualAddress的位移。
在DLL文件中仅有以下类型有效
IMAGE_REL_BASED_ABSOLUTE
没有重定位操作,仅用作填充
IMAGE_REL_BASED_HIGHLOW
用分配到的地址与ImageBase的差值再加上offset处的32位地址的和作为重
定位后的地址。
.
处理导入信息
OptionalHeader中DataDirectory字段中的第一个(基于0开始)选项(entry)中包含了一组
library列表,保存着本library需要用到的所有library.列表中的选项的格式定义如下:
typedefstruct_IMAGE_IMPORT_DESCRIPTOR{
union{
DWORDCharacteristics;//0fort
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 内存 加载 DLL 指南