从内存资源中加载DLL 模拟PE加载器
- 格式:doc
- 大小:309.50 KB
- 文档页数:42
dll加载原理DLL加载原理概述•DLL(动态链接库)是一种可执行文件格式,用于存储和共享程序代码和数据。
•DLL加载是将DLL文件加载到内存并解析其导出函数的过程。
DLL的分类•内核模式DLL:运行在操作系统内核空间中,提供给操作系统使用。
•用户模式DLL:运行在应用程序进程的用户空间中,为应用程序提供功能支持。
DLL的加载方式1.隐式加载:在应用程序启动时由操作系统自动加载所需的DLL文件。
–应用程序代码中使用函数,操作系统自动在加载应用程序的同时加载其依赖的DLL。
–应用程序代码需要将DLL的路径告知操作系统,操作系统根据路径找到DLL并加载。
2.显式加载:在应用程序运行时手动加载所需的DLL文件。
–应用程序通过调用加载函数(如LoadLibrary函数)手动加载DLL。
–调用GetProcAdress函数获取DLL中函数的入口地址,从而调用DLL中的函数。
DLL的加载过程1.读取DLL文件:–操作系统通过文件系统读取DLL文件的内容。
2.根据DLL文件的导入表(Import Table)解析DLL的依赖:–导入表记录了DLL所依赖的其他DLL,以及导出函数的名称和地址。
3.加载DLL依赖的其他DLL:–递归地加载DLL所依赖的其他DLL文件。
4.解析DLL导出函数:–根据导入表中记录的函数名称,找到导出函数的入口地址。
5.将DLL文件映射到进程空间:–将DLL文件映射到进程的虚拟内存空间中,以便能够访问DLL中的代码和数据。
6.更新进程的导入表:–更新进程的导入表,将DLL中导出函数的地址填入相应的入口地址。
DLL的卸载•当不再需要某个DLL时,可以将其从内存中卸载。
•DLL卸载的条件通常是没有其他模块依赖该DLL,或者由操作系统决定。
总结•DLL加载是将DLL文件加载到内存并解析导出函数的过程。
•DLL可以通过隐式加载或显式加载的方式加载。
•DLL的加载过程包括读取DLL文件、解析依赖、加载其他DLL、解析导出函数等步骤。
从内存中加载DLL指南从内存中加载DLL指南 ..................................................................... ............................................. 1 前言 ..................................................................... ........................................................................ .. 2 内容提纲 ..................................................................... .................................................................. 2 简介 ..................................................................... ........................................................................ .. 2 PE文件格式 ..................................................................... ............................................................. 2 DOS header /DOS stub 格式...................................................................... ................................ 3 PEheader ................................................................. ........................................................ 3 格式Sectionheader ................................................................. .................................................. 6 格式加载LIBRARY ................................................................ . (6)Section ............................................................ ...................................................... 7 拷贝的内容.................................................................... ........................................................ 7 基地址重定位.................................................................... ........................................................ 8 处理导入信息内存访问权限设置 ..................................................................... ............................................... 9 通知library被进程加载...................................................................... ...................................... 9 调用导出函数 ..................................................................... ..................................................... 10 释放library ................................................................ . (10)MEMORYMODULE工具包...................................................................... (11).................................................................... ............................................................. 11 下载位置已知的问题...................................................................... .. (11)License ................................................................ (11)版本移植 ..................................................................... ............................................................ 11 版权声明 ..................................................................... (12)前言本篇指南是讲解如何不借助文件系统的帮助来加载内存中载入DLL的技术。
开机提示找不到 *.dll 解决小结。
最近这个问题很多,把这个也总结一下吧,欢迎大家提出其它意见供大家参考:首先查一下是哪个.dll无法加载,试着手动regsvr32 *.dll加载试试1、开始-运行,输入msconfig,在“启动”中把相关自启动的选项都去掉。
2、关闭系统还原。
(我的电脑-属性-系统还原,选择“在所有的驱动器上关闭系统还原”)3、把C:\Documents and Settings\用户名\Local Settings\Temp和C:\Documents and Settings\用户名\Local Settings\Temporary Internet Files文件夹下的所有文件都删除。
(如果看不到此文件夹,工具-文件夹选项,在“查看”中有一项是“隐藏文件和文件夹”,选择“显示所有文件和文件夹”)4、把C:\WINDOWS\Prefetch文件夹下的所有文件都删除。
5、控制面板-服务,把你认为不需要的服务都改为“手动”并停用。
6、关闭各种视觉效果(我的电脑-属性,弹出的窗口里选择“高级”标签,性能的设置,选择最佳性能,或者只保留倒数第二项、倒数第三项和在窗口和按钮上保持视觉样式。
)7、关闭远程协助(我的电脑-属性,弹出的窗口里选择“远程”标签,然后取消下面两个选项的选择。
)8、安装优化软件(二者选一即可) TuneUp Utilities 或者 Windows 优化大师或者其它的......可能是这个dll因为某些原因(最大的可能是因为它是个病毒或流氓软件的dll 文件,被杀软删除了)丢失了,但其相关的注册信息却还在,导致系统开机时还加载它,却又找不到它的文件,所以报错。
如果你点击“确定”后,系统没有什么不正常,并且可以正常运行的话,你可以用这个软件清理掉这个开机加载项,以后开机就不会出现这个信息了。
Autoruns:开机启动项管理DLL文件即动态链接库文件,是一种可执行文件,它允许程序共享执行特殊任务所必需的代码和其他资源。
C#实现动态加载dll的⽅法本⽂实例讲述了C#实现动态加载dll的⽅法。
分享给⼤家供⼤家参考。
具体实现⽅法如下:复制代码代码如下:using System;using System.Collections.Generic;using System.Text;using System.Reflection;using System.IO;namespace monAPI.DynamicLoadAssembly{public class AssemblyDynamicLoader<T>{private AppDomain appDomain;private DynamicRemoteLoadAssembly<T> remoteLoader;public T InvokeMethod(string assemblyName, string assemblyPath, string assemblyConfigFilePath, string fullClassName, string methodName, params object[] args){AppDomainSetup setup = new AppDomainSetup();setup.ApplicationName = "ApplicationLoader";setup.ApplicationBase = AppDomain.CurrentDomain.BaseDirectory + @"bin\";//setup.PrivateBinPath = bine(AppDomain.CurrentDomain.BaseDirectory, "private");setup.CachePath = setup.ApplicationBase;setup.ShadowCopyFiles = "true";if (assemblyConfigFilePath != string.Empty){setup.ConfigurationFile = AppDomain.CurrentDomain.BaseDirectory + assemblyConfigFilePath;}setup.ShadowCopyDirectories = setup.ApplicationBase;setup.LoaderOptimization = LoaderOptimization.SingleDomain;this.appDomain = AppDomain.CreateDomain("ApplicationLoaderDomain", null, setup);String name = Assembly.GetExecutingAssembly().GetName().FullName;this.remoteLoader = (DynamicRemoteLoadAssembly<T>)this.appDomain.CreateInstanceAndUnwrap(name, typeof(DynamicRemoteLoadAssembly<T>).FullName);assemblyName = AppDomain.CurrentDomain.BaseDirectory + assemblyPath + assemblyName;return this.remoteLoader.InvokeMethod(assemblyName, fullClassName, methodName, args);}/// <summary>////// </summary>public void Unload(){try{AppDomain.Unload(this.appDomain);this.appDomain = null;}catch (CannotUnloadAppDomainException ex){}}}}复制代码代码如下:using System;using System.Collections.Generic;using System.Text;using System.Reflection;using System.Globalization;namespace monAPI.DynamicLoadAssembly{public class DynamicRemoteLoadAssembly<T> : MarshalByRefObject{private Assembly assembly = null;public T InvokeMethod(string assemblyPath, string fullClassName, string methodName, params object[] args){this.assembly = null;T result = default(T);try{this.assembly = Assembly.LoadFile(assemblyPath);Type pgmType = null;if (this.assembly != null){pgmType = this.assembly.GetType(fullClassName, true, true);}else{pgmType = Type.GetType(fullClassName, true, true);}BindingFlags defaultBinding = BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.IgnoreCase | BindingFlags.InvokeMethod | BindingFlags.Static;CultureInfo cultureInfo = new CultureInfo("es-ES", false);try{MethodInfo methisInfo = assembly.GetType(fullClassName, true, true).GetMethod(methodName);if (methisInfo == null){new Exception("EMethod does not exist!");}if (methisInfo.IsStatic){if (methisInfo.GetParameters().Length == 0){if (methisInfo.ReturnType == typeof(void)){pgmType.InvokeMember(methodName, defaultBinding, null, null, null, cultureInfo);}else{result = (T)pgmType.InvokeMember(methodName, defaultBinding, null, null, null, cultureInfo);}}else{if (methisInfo.ReturnType == typeof(void)){pgmType.InvokeMember(methodName, defaultBinding, null, null, args, cultureInfo);}else{result = (T)pgmType.InvokeMember(methodName, defaultBinding, null, null, args, cultureInfo);}}}else{if (methisInfo.GetParameters().Length == 0){object pgmClass = Activator.CreateInstance(pgmType);if (methisInfo.ReturnType == typeof(void)){pgmType.InvokeMember(methodName, defaultBinding, null, pgmClass, null, cultureInfo);}else{result = (T)pgmType.InvokeMember(methodName, defaultBinding, null, pgmClass, null, cultureInfo); }}else{object pgmClass = Activator.CreateInstance(pgmType);if (methisInfo.ReturnType == typeof(void)){pgmType.InvokeMember(methodName, defaultBinding, null, pgmClass, args, cultureInfo);}else{result = (T)pgmType.InvokeMember(methodName, defaultBinding, null, pgmClass, args, cultureInfo); }}}}catch (Exception e){result = (T)pgmType.InvokeMember(methodName, defaultBinding, null, null, null, cultureInfo);}return result;}catch (Exception ee){return result;}}}}希望本⽂所述对⼤家的C#程序设计有所帮助。
调用DLL,首先需要将DLL文件映像到用户进程的地址空间中,然后才能进行函数调用,这个函数和进程内部一般函数的调用方法相同。
Windows提供了两种将DLL映像到进程地址空间的方法:1. 隐式的加载时链接这种方法需要DLL工程经编译产生的LIB文件,此文件中包含了DLL允许应用程序调用的所有函数的列表,当链接器发现应用程序调用了LIB文件列出的某个函数,就会在应用程序的可执行文件的文件映像中加入一些信息,这些信息指出了包含这个函数的DLL文件的名字。
当这个应用程序运行时,也就是它的可执行文件被操作系统产生映像文件时,系统会查看这个映像文件中关于DLL的信息,然后将这个DLL文件映像到进程的地址空间。
系统通过DLL文件的名称,试图加载这个文件到进程地址空间时,它寻找DLL 文件的路径按照先后顺序如下:·程序运行时的目录,即可执行文件所在的目录;·当前程序工作目录·系统目录:对于Windows95/98来说,可以调用GetSystemDirectory函数来得到,对于WindowsNT/2000 来说,指的是32位Windows的系统目录,也可以调用GetSystemDirectory函数来得到,得到的值为SYSTEM32。
·Windows目录·列在PATH环境变量中的所有目录VC中加载DLL的LIB文件的方法有以下三种:①LIB文件直接加入到工程文件列表中在VC中打开File View一页,选中工程名,单击鼠标右键,然后选中“Add Files to Project”菜单,在弹出的文件对话框中选中要加入DLL的LIB文件即可。
②设置工程的 Project Settings来加载DLL的LIB文件打开工程的 Project Settings菜单,选中Link,然后在Object/library modules 下的文本框中输入DLL的LIB文件。
③通过程序代码的方式加入预编译指令#pragma comment (lib,”*.lib”),这种方法优点是可以利用条件预编译指令链接不同版本的LIB文件。
如何从资源中加载DLL动态库就是自己使用Brcc32命令制作一个包含DLL动态库的资源文件,然后我如何从程序中加载该动态库呢!比如有一个动态库 Test.dll,然后我在制作资源文件如下:MyDll DLL Test.dll 保存为T est.rc然后使用 Brcc32 test.rc命令生成 Brcc32.res然后在程序中{$R Test.res}将该资源文件作为应用程序的一个资源编译到EXE文件中去我就想问一下,当EXE文件在运行的过程中,我如何从它的资源文件中加载我编译进去的DLL动态库,然后调用其中的函数从磁盘加载用LoadLibrary就可以了,但是,此时动态库在程序的资源文件中,也就是说他在内存中。
此时该如何加载呢?期待高手解答。
{不支持用ASPACK压缩过的DLL}{DLL Loader by Aphex************************************************function xLoadLibrary(Src: Pointer; Imports: array ofTImportItem): TLibInfo;procedure xFreeLibrary(hModule: TLibInfo);}unit DLLUnit;interfaceusesWindows;typeTImportItem = recordName: string;PProcVar: PPointer;end;TwordArr = array[0..0] of word;PwordArr = ^TwordArr;TdwordArr = array[0..0] of dword;PdwordArr = ^TdwordArr;PImageImportDescriptor = ^TImageImportDescriptor;TImageImportDescriptor = packed recordOriginalFirstThunk: dword;TimeDateStamp: dword;ForwarderChain: dword;Name: dword;FirstThunk: dword;end;PImageBaseRelocation = ^TImageBaseRelocation;TImageBaseRelocation = packed recordVirtualAddress: cardinal;SizeOfBlock: cardinal;end;TDllEntryProc = function(hinstDLL: HMODULE; dwReason: dword; lpvReserved: Pointer): Boolean; stdcall;TStringArray = array of string;TLibInfo = recordImageBase: Pointer;DllProc: TDllEntryProc;LibsUsed: TStringArray;end;PLibInfo = ^TLibInfo;PPointer = ^Pointer;TSections = array[0..100000] of TImageSectionHeader;constIMPORTED_NAME_OFFSET = $00000002;IMAGE_ORDINAL_FLAG32 = $80000000;IMAGE_ORDINAL_MASK32 = $0000FFFF;function xLoadLibrary(Src: Pointer; Imports: array of TImportItem): TLibInfo;function xFreeLibrary(LoadedLib: TLibInfo): boolean;implementationfunction xFreeLibrary(LoadedLib: TLibInfo): boolean;varObjectLoop: integer;beginResult := False;with LoadedLib dobeginif @DllProc <> nil thenbeginDllProc(HModule(LoadedLib.ImageBase),DLL_PROCESS_DETACH, nil);end;for ObjectLoop := 0 to Length(LibsUsed) - 1 dobeginif ObjectLoop >= Length(LibsUsed) thenExit;FreeLibrary(GetModuleHandle(pchar(LibsUsed[ObjectLoop]) ));end;SetLength(LibsUsed, 0);end;VirtualFree(LoadedLib.ImageBase, 0, MEM_RELEASE);Result := True;end;function xLoadLibrary(Src: Pointer; Imports: array ofTImportItem): TLibInfo;var ImageBase: pointer;ImageBaseDelta: integer;ImageNtHeaders: PImageNtHeaders;PSections: ^TSections;SectionLoop: integer;SectionBase: pointer;VirtualSectionSize, RawSectionSize: cardinal;OldProtect: cardinal;NewLibInfo: TLibInfo;function StrT oInt(S: string): integer;beginVal(S, Result, Result);end;procedure Add(Strings: TStringArray; Text: string);beginSetLength(Strings, Length(Strings) + 1); Strings[Length(Strings) - 1] := Text;end;function Find(Strings: array of string; Text: string; var Index: integer): boolean;var StringLoop: integer;beginResult := False;for StringLoop := 0 to Length(Strings) - 1 do beginif lstrcmpi(pchar(Strings[StringLoop]), pchar(T ext)) = 0 then begin Index := StringLoop; Result := True;end;end;end;function GetSectionProtection(ImageScn: cardinal): cardinal;beginResult := 0;if (ImageScn and IMAGE_SCN_MEM_NOT_CACHED) <> 0 then beginResult := Result or PAGE_NOCACHE;end;if (ImageScn and IMAGE_SCN_MEM_EXECUTE) <> 0 then beginif (ImageScn and IMAGE_SCN_MEM_READ) <> 0 then begin if (ImageScn and IMAGE_SCN_MEM_WRITE) <> 0 then begin Result := Result or PAGE_EXECUTE_READWRITEend else beginResult := Result or PAGE_EXECUTE_READend;end else if (ImageScn and IMAGE_SCN_MEM_WRITE) <> 0 then beginResult := Result or PAGE_EXECUTE_WRITECOPYend else beginResult := Result or PAGE_EXECUTEend;end else if (ImageScn and IMAGE_SCN_MEM_READ) <> 0 then beginif (ImageScn and IMAGE_SCN_MEM_WRITE) <> 0 then begin Result := Result or PAGE_READWRITEend else begin Result := Result or PAGE_READONLY endend else if (ImageScn and IMAGE_SCN_MEM_WRITE) <> 0 then beginResult := Result or PAGE_WRITECOPYend else beginResult := Result or PAGE_NOACCESS;end;end;procedure ProcessExports(PExports: PImageExportDirectory; BlockSize: cardinal);varExportLoop: byte;ImportedFn: cardinal;PFnName: pchar;FnIndex: dword;function IsForwarderString(Data: pchar): boolean;beginResult := Data > PExports;if Result thenResult := cardinal(Data - PExports) < BlockSize;end;function GetForwardedSymbol(ForwarderString: pchar): pointer;varsForwarderString, DllName: string;ForwarderLoop: integer;LibHandle: HModule;beginsForwarderString := ForwarderString;while ForwarderString^ <> '.' do beginInc(ForwarderString);end;DllName := Copy(sForwarderString, 1, pos('.', sForwarderString) - 1);if not Find(NewLibInfo.LibsUsed, DllName, ForwarderLoop) then beginLibHandle := LoadLibrary(pchar(DllName));Add(NewLibInfo.LibsUsed, DllName);end else begin LibHandle := cardinal(NewLibInfo.LibsUsed[ForwarderLoop]);end;if ForwarderString^ = '#' thenForwarderString := pointer(StrToInt((ForwarderString + 1)));Result := GetProcAddress(LibHandle, ForwarderString);end;beginfor ExportLoop := 0 to PExports.NumberOfNames - 1 do beginPFnName := pchar(PdwordArr(cardinal(PExports.AddressOfNames) + cardinal(ImageBase))^[ExportLoop] + cardinal(ImageBase));for ImportedFn := low(Imports) to high(Imports) do begin if Imports[ImportedFn].Name = PFnName then beginFnIndex := PwordArr(cardinal(PExports.AddressOfNameOrdinals) + cardinal(ImageBase))^[ExportLoop];Imports[ImportedFn].PProcVar^ := pointer(PdwordArr(cardinal(PExports.AddressOfFunctions) + cardinal(ImageBase))^[FnIndex] + cardinal(ImageBase));if IsForwarderString(Imports[ImportedFn].PProcVar^) thenbegin Imports[ImportedFn].PProcVar^ := GetForwardedSymbol(Imports[ImportedFn].PProcVar^);end;end;end;end;end;procedure ProcessRelocs(PRelocs: PImageBaseRelocation);varPReloc: PImageBaseRelocation;RelocsSize: cardinal;Reloc: PWord;ModCount: cardinal;RelocLoop: cardinal;beginPReloc := PRelocs;RelocsSize := ImageNtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECT ORY_ENTRY_BASERELOC].Size;while cardinal(PReloc) - cardinal(PRelocs) < RelocsSize do beginModCount := (PReloc.SizeOfBlock - Sizeof(PReloc^)) div 2;Reloc := pointer(cardinal(PReloc) + sizeof(PReloc^));for RelocLoop := 0 to ModCount - 1 dobegin if Reloc^ and $F000 <> 0 thenInc(pdword(cardinal(ImageBase) + PReloc.VirtualAddress + (Reloc^ and $0FFF))^, ImageBaseDelta);Inc(Reloc);end;PReloc := pointer(Reloc);end;end;procedure ProcessImports(PImports: PImageImportDescriptor);varPImport: PImageImportDescriptor;Import: LPDword;PImportedName: pchar;LibHandle: HModule;ProcAddress: pointer;PLibName: pchar; ImportLoop: integer;function IsImportByOrdinal(ImportDescriptor: dword; HLib: THandle): boolean;beginResult := (ImportDescriptor and IMAGE_ORDINAL_FLAG32) <> 0;end;beginPImport := PImports;while <> 0 do beginPLibName := pchar(cardinal() + cardinal(ImageBase));if not Find(NewLibInfo.LibsUsed, PLibName, ImportLoop) thenbegin LibHandle := LoadLibrary(PLibName);Add(NewLibInfo.LibsUsed, PLibName);end else begin LibHandle :=cardinal(NewLibInfo.LibsUsed[ImportLoop]);end; if PImport.TimeDateStamp = 0 then beginImport := LPDword(pImport.FirstThunk + cardinal(ImageBase))end else beginImport := LPDword(pImport.OriginalFirstThunk + cardinal(ImageBase));end;while Import^ <> 0 do beginif IsImportByOrdinal(Import^, LibHandle) then beginProcAddress := GetProcAddress(LibHandle, pchar(Import^ and $FFFF))end else beginPImportedName := pchar(Import^ + cardinal(ImageBase) + IMPORTED_NAME_OFFSET);ProcAddress := GetProcAddress(LibHandle, PImportedName);end;PPointer(Import)^ := ProcAddress;Inc(Import);end;Inc(PImport);end;end;beginImageNtHeaders := pointer(int64(cardinal(Src)) + PImageDosHeader(Src)._lfanew);ImageBase := VirtualAlloc(nil, ImageNtHeaders.OptionalHeader.SizeOfImage, MEM_RESERVE,PAGE_NOACCESS);ImageBaseDelta := cardinal(ImageBase) - ImageNtHeaders.OptionalHeader.ImageBase;SectionBase := VirtualAlloc(ImageBase, ImageNtHeaders.OptionalHeader.SizeOfHeaders,MEM_COMMIT, PAGE_READWRITE);Move(Src^, SectionBase^, ImageNtHeaders.OptionalHeader.SizeOfHeaders);VirtualProtect(SectionBase,ImageNtHeaders.OptionalHeader.SizeOfHeaders,PAGE_READONLY, OldProtect);PSections := pointer(pchar(@(ImageNtHeaders.OptionalHeader)) + ImageNtHeaders.FileHeader.SizeOfOptionalHeader);for SectionLoop := 0 to ImageNtHeaders.FileHeader.NumberOfSections - 1 do beginVirtualSectionSize := PSections[SectionLoop].Misc.VirtualSize;RawSectionSize := PSections[SectionLoop].SizeOfRawData;if VirtualSectionSize < RawSectionSize thenbeginVirtualSectionSize := VirtualSectionSize xor RawSectionSize;RawSectionSize := VirtualSectionSize xor RawSectionSize;VirtualSectionSize := VirtualSectionSize xor RawSectionSize;end;SectionBase := VirtualAlloc(PSections[SectionLoop].VirtualAddress + pchar(ImageBase), VirtualSectionSize, MEM_COMMIT, PAGE_READWRITE);FillChar(SectionBase^, VirtualSectionSize, 0);Move((pchar(src) + PSections[SectionLoop].PointerToRawData)^, SectionBase^, RawSectionSize);end;NewLibInfo.DllProc := TDllEntryProc(ImageNtHeaders.OptionalHeader.AddressOfEntry Point + cardinal(ImageBase));NewLibInfo.ImageBase := ImageBase;SetLength(NewLibInfo.LibsUsed, 0);ifImageNtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECT ORY_ENTRY_BASERELOC].VirtualAddress <> 0 thenProcessRelocs(pointer(ImageNtHeaders.OptionalHeader.Dat aDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddr ess + cardinal(ImageBase)));ifImageNtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECT ORY_ENTRY_IMPORT].VirtualAddress <> 0 thenProcessImports(pointer(ImageNtHeaders.OptionalHeader.D ataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddres s + cardinal(ImageBase)));for SectionLoop := 0 to ImageNtHeaders.FileHeader.NumberOfSections - 1 do beginVirtualProtect(PSections[SectionLoop].VirtualAddress + pchar(ImageBase), PSections[SectionLoop].Misc.VirtualSize, GetSectionProtection(PSections[SectionLoop].Characteristics), OldProtect);end;*********************<>nilthenbeginif not NewLibInfo.DllProc(cardinal(ImageBase), DLL_PROCESS_ATTACH, nil) thenbeginNewLibInfo.DllProc := nil;xFreeLibrary(Result);end;end;ifImageNtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECT ORY_ENTRY_EXPORT].VirtualAddress <> 0 thenProcessExports(pointer(ImageNtHeaders.OptionalHeader.D ataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddres s + cardinal(ImageBase)), ImageNtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECT ORY_ENTRY_EXPORT].Size);Result := NewLibInfo;end;{//调用示例program test;UsesWindows, DLLUnit;varResourceLocation: HRSRC;ResourceSize: LongWord;ResourceHandle: THandle;ResourcePointer: Pointer;TestFunction: procedure;MyImports: array [0..0] of TImportItem =((Name: 'TestFunction'; PProcVar: @@TestFunction));MyLibrary: TLibInfo;beginResourceLocation := FindResource(HInstance, pchar('a01'), RT_RCDATA);if ResourceLocation <> 0 thenbeginResourceSize := SizeofResource(HInstance, ResourceLocation);if ResourceSize <> 0 thenbeginResourceHandle := LoadResource(HInstance, ResourceLocation);if ResourceHandle <> 0 thenbeginResourcePointer := LockResource(ResourceHandle);if ResourcePointer <> nil thenbeginMyLibrary := xLoadLibrary(ResourcePointer, MyImports);TestFunction;end;end;end;end;xFreeLibrary(MyLibrary);end.//===================================== ========================================= varFLibrary: TLibInfo;test: function(const i : Integer):integer; stdcall;constDllImports: array [0..0] of TImportItem =((Name: 'test'; PProcVar: @@test));procedure LoadLib;varBuf : Pointer;Size : DWORD;ProcessId: Cardinal;ResHandle:Cardinal;beginResHandle := FindResource(hInstance, 'testdll', 'DLL');if ResHandle > 0 thenbeginSize := SizeofResource(hInstance, ResHandle);Buf := LockResource(LoadResource(hInstance, ResHandle));FLibrary := xLoadLibrary(Buf, DllImports);end;end;procedure FreeLib;beginif FLibrary.ImageBase <> nil then beginif xFreeLibrary(FLibrary) then FLibrary.ImageBase := nil; end;end;//}end.。
通过资源文件方式打包exe、脚本、dll文件为单个exe文件的解决方案想将Lua和脚本文件打包成一个exe文件,以便发布,从网上查了N多资源,终于搞定了^-^主要实现方案是通过将Lua解释器和脚本文件以资源文件中RCDATA类型打包进exe文件中,在运行文件时再进行释放,然后在临时目录中执行。
大概步骤为:1、编写相应的rc文件,添加想打包的所有文件2、通过FindResource\SizeofResource\LoadResource\LockResource四个函数查找定位exe打包文件中对应的各个资源文件,并创建至临时目录中3、用CreateProcess\WaitForSingleObject\CloseHandle三个函数实现run and wait功能(好像 GetExitCodeProcess的方式也行)4、等程序执行完毕,删除临时文件(5、LoadLibrary\GetProcAddress\CallWindowProc\FreeLibrary四个函数实现ActiveX dll的注册)该方案一个缺点是可能容易被杀软认为是病毒-_-||实现该功能的一个简单方案为使用专业软件,如PEBundle。
更新历史:2008-11-4: 改动较多,目前可以释放到"temp","current","system","windows"和指定目录下了,并且解决了运行脚本时工作目录不一定为当前exe文件所在目录的问题。
增加了部分目录处理函数和字符串处理函数。
2008-11-3: 看了一位大大的blog,其使用pe文件的形式实现了动态加载到内存中执行,等有时间时好好研究研究,/lisunlin0/2008-11-1: 添加ActiveX dll的注册函数DllRegister的实现;将RunWait中的GetT empFilePath提取出来,以便通用;在一个字符串前添加一个空格写为函数。
彻底告别加载dll出错开机加载项大揭秘提到开机加载(load)项,大家不要以为就是系统启动(run)项。
最简单的例子是,杀毒软件或者用户手动删除病毒文件后,注册表中的自动加载信息仍在,登陆系统时就会提示“加载*dll出错,系统找不到指定的模块”,这些dll就是病毒寄生在系统进程之下的加载项。
加载dll出错病毒本身被阻止运行,却“挟系统以令用户”,辗转藏在系统进程后面继续狐假虎威,大行其道;它们被发现并删除后,下次系统登陆、启动服务、初始化用户配置、启动外壳explorer.exe时,依然会按注册表的指示运行rundll32.exe调用这些加载项,这时系统找不到文件实体,就会提示加载失败。
虽然不影响使用,但那“嗡”的一声,有如晴天霹雳,让人一开机就憋得慌!点击确定后也一直如坐针毡,总感觉自己中毒了。
其实,只要在注册表中搜索这个dll删掉,一般就能就地解决。
问题是,很多dll在注册表中根本搜索不到,但开机时它就是要弹框!别慌,只要去注册表中如下固定位置扫荡一遍,疏而不漏,总能找到蛛丝马迹。
以下位置最前四字母均为首字母缩写,在注册表利器Registry Workshop的地址栏中通用,可直接粘贴回车转到,并加入收藏,收藏还可分类哦~Let's Go!(1)WinLoadHKCU\Software\Microsoft\Windows NT\CurrentVersion\Windows\loadWindows_load如图,这项原本不存在,或者默认为空。
如果病毒将自己的dll添加到这里,可想而知系统启动时就会自动加载它。
(2)NotifyHKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\NotifyWinlogon_notify这里是windows登陆“通知”,图中的项都是正常项。
以前Windows 正版增值计划通知(WGA)提示Windows不是正版,就是通过wgalogon.dll在这里添加了一个项,登陆时通知调用WgaTray.exe,在托盘弹出提示的。
一种保护应用程序的方法模拟Windows PE加载器,从内存资源中加载DLL1、前言目前很多敏感和重要的DLL(Dynamic-link library) 都没有提供静态版本供编译器进行静态连接(.lib文件),即使提供了静态版本也因为兼容性问题导致无法使用,而只提供DLL版本,并且很多专业软件的授权部分的API,都是单独提供一个DLL来完成,而主模块通过调用DLL中的接口来完成授权功能。
虽然这些软件一般都采用了加壳和反调试等保护,但是一旦这些功能失去作用,比如脱壳,反反调试,HOOK API或者干脆写一个仿真的授权DLL (模拟授权DLL的所有导出函数接口),然后仿真的DLL再调用授权DLL,这样所有的输入首先被仿真DLL截获再传递给授权DLL,而授权DLL的输出也首先传递给仿真DLL再传递给主程序,这样就可以轻易的监视二者之间的输入输出之间的关系,从而轻易的截获DLL中的授权信息进行修改再返回给主程序。
2、目前隐式调用敏感DLL中可能存在的安全隐患以下通过两个软件的授权DLL来说明这种问题的严重性。
如下是两个软件中授权DLL的部分信息,如下图所示:(图1)通过工具OllyICE可以轻易的看出IoMonitor.exe调用授权DLL(XKeyAPI.DLL),这样就很容易在调用这些API的地方设置断点,然后判断输入输出的关系,从而达到破解的目的。
(图2)通过工具OllyICE可以轻易的看出sfeng.DLL中导出了很多函数,其中含义也很明显。
GetHDID获取硬盘的ID,GetCpuId获取cpu的ID,WinAntiDebug反调试接口。
而这些都是主程序需要调用的,比如:主程序通过GetHDID 来获取硬盘编码,以这个硬盘ID的伪码来生成授权码,破解者很容易修改这些接口的输出值或者干脆写一个sfeng.DLL来导出跟目标sfeng.DLL一模一样的导出函数,而主程序却完全不知晓。
只要用户有一套授权码就可以让GetHDID不管什么机器都返回一样的值,从而达到任何机器都可以使用同一套授权码。
(图3)如上图所示,直接修改DLL中函数GetHDID(RVA地址:0093FF3C开始)的实现,让它直接返回固定的硬盘ID就可以达到一个授权到处使用的目的。
其中:‖WD-Z=AM9N086529ksaiy‖为需要返回的已经授权的硬盘ID,我们直接返回这个值即可。
把原来0093FF3C 部分的代码用nop替换掉,添加Call 008FFF60,后面添加字符串‖WD-Z=AM9N086529ksaiy‖,Call 008FFF60之后,ESP=Call后的返回地址(Call指令的下一行),也就是字符串‖WD-Z=AM9N086529ksaiy‖的首地址,然后pop EAX 后,返回值就是字符串的首地址,通过这种简单的修改就可以达到破解的目的,说明这种隐式的调用是非常危险的。
3、模拟Windows PE加载器,从资源中加载DLL本文主要介绍将DLL文件进行加密压缩后存放在程序的资源段,然后在程序中读取资源段数据进行解压和解密工作后,从内存中加载这个DLL,然后模拟PE加载器完成DLL的加载过程。
本文主要以Visual C++ 6.0为工具进行介绍,其它开发工具实现过程与此类似。
这样作的好处也很明显,DLL文件存放在主程序的资源段,而且经过了加密压缩处理,破解者很难找到下断点的地方,也不能轻易修改资源DLL,因为只有主程序完成解压和解密工作,完成PE加载工作后此DLL才开始工作。
我们知道,要显式加载一个DLL,并取得其中导出的函数地址一般是通过如下步骤:(1) 用LoadLibrary加载DLL文件,获得该DLL的模块句柄;(2) 定义一个函数指针类型,并声明一个变量;(3) 用GetProcAddress取得该DLL中目标函数的地址,赋值给函数指针变量;(4) 调用函数指针变量。
这个方法要求DLL文件位于硬盘上面,而我们的DLL现在在内存中。
现在假设我们的DLL已经位于内存中,比如通过脱壳、解密或者解压缩得到,能不能不把它写入硬盘文件,而直接从内存加载呢?答案是肯定的,方法就是完成跟Windows PE加载器同样的工作即可。
加载过程大致包括以下几个部分:1、调用API读取DLL资源数据拷贝到内存中2、调用解压和解密函数对内存中的DLL进行处理3、检查DOS头和PE头判断是否为合法的PE格式4、计算加载该DLL所需的虚拟地址空间大小5、向操作系统申请指定大小的虚拟地址空间并提交6、将DLL数据复制到所分配的虚拟内存块中,注意文件段对齐方式和内存段对齐方式7、对每个 DLL文件来说都存在一个重定位节(.reloc),用于记录DLL文件的重定位信息,需要处理重定位信息8、读取DLL的引入表部分,加载引入表部分需要的DLL,并填充需要的函数入口的真实地址9、根据DLL每个节的属性设置其对应内存页的读写属性10、调用入口函数DLLMain,完成初始化工作11、保存DLL的基地址(即分配的内存块起始地址),用于查找DLL的导出函数12、不需要DLL的时候,释放所分配的虚拟内存,释放所有动态申请的内存以下部分分别介绍这几个步骤,以改造过的网上下载的CMemLoadDLL类为例程(原类存在几个错误的地方)A. 调用API读取DLL资源数据拷贝到内存中//加载资源DLL#define strKey (char)0x15char DLLty pe[4]={'D' ^ strKey ,'l'^ strKey,'l'^ strKey,0x00};HINSTANCE hinst=AfxGetInstanceHandle();HRSRC hr=NULL;HGLOBAL hg=NULL;//对资源名称字符串进行简单的异或操作,达到不能通过外部字符串参考下断点for(int i=0;i<sizeof(DLLty pe)-1;i++){DLLty pe[i]^=strKey;}hr=FindResource(hinst,MAKEINTRESOURCE(IDR_DLL),TEXT(DLLty pe));if (NULL == hr) return FALSE;//获取资源的大小DWORD dwSize = SizeofResource(hinst, hr);if (0 == dwSize) return FALSE;hg=LoadResource(hinst,hr);if (NULL == hg) return FALSE;//锁定资源LPVOID pBuffer =(LPSTR)LockResource(hg);if (NULL == pBuffer) return FALSE;FreeResource(hg); //在资源使用完毕后我们不需要使用UnlockResource和FreeResource来手动地释放资源,因为它们都是16位Windows遗留下来的,在Win32中,在使用完毕后系统会自动回收B. 调用解压和解密函数对内存总的DLL进行处理对于上面获取的pBuffer可以进行解压和解密操作,算法应该跟你加入的资源采取的算法进行逆变换即可,具体算法可以自己选择,此处省略。
C. 检查DOS头和PE头判断是否为合法的PE格式//CheckDataValide函数用于检查缓冲区中的数据是否有效的DLL文件//返回值:是一个可执行的DLL则返回TRUE,否则返回FALSE。
//lpFileData: 存放DLL数据的内存缓冲区//DataLength: DLL文件的长度BOOL CMemLoadDLL::CheckDataValide(void* lpFileData, int DataLength){//检查长度if(DataLength < sizeof(IMAGE_DOS_HEADER)) return FALSE;pDosHeader = (PIMAGE_DOS_HEADER)lpFileData; // DOS头//检查dos头的标记if(pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) return FALSE; //0*5A4D : MZ//检查长度if((DWORD)DataLength < (pDosHeader->e_lfanew + sizeof(IMAGE_NT_HEADERS)) ) return FALSE;//取得pe头pNTHeader = (PIMAGE_NT_HEADERS)( (unsigned long)lpFileData + pDosHeader->e_lfanew); // PE头//检查pe头的合法性if(pNTHeader->Signature != IMAGE_NT_SIGNATURE) return FALSE; //0*00004550 : PE00if((pNTHeader->FileHeader.Characteristics & IMAGE_FILE_DLL) == 0) //0*2000 : File is a DLLreturn FALSE;if((pNTHeader->FileHeader.Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE) == 0) //0*0002 : 指出文件可以运行return FALSE;if(pNTHeader->FileHeader.SizeOfOptionalHeader != sizeof(IMAGE_OPTIONAL_HEADER)) return FALSE;//取得节表(段表)pSectionHeader = (PIMAGE_SECTION_HEADER)((int)pNTHeader + sizeof(IMAGE_NT_HEADERS));//验证每个节表的空间for(int i=0; i< pNTHeader->FileHeader.NumberOfSections; i++){if((pSectionHeader[i].PointerToRawData + pSectionHeader[i].SizeOfRawData) > (DWORD)DataLength)return FALSE;}return TRUE;}D. 计算加载该DLL所需的虚拟地址空间大小计算整个DLL映像文件的尺寸,最大映像尺寸应该为VOffset最大的一个段的VOffset+VSize,然后补齐段对齐即可。