如何从资源中加载DLL动态库

不得闲 2008-01-11 12:53:09

就是自己 使用 Brcc32命令制作一个包含DLL动态库的资源文件,然后我如何从程序中加载该动态库呢!
比如 有一个动态库 Test.dll,然后我在制作资源文件如下:

MyDll DLL Test.dll 保存为Test.rc
然后使用 Brcc32 test.rc命令生成 Brcc32.res

然后在程序中{$R Test.res}将该资源文件作为应用程序的一个资源编译到EXE文件中去

我就想问一下,当EXE文件在运行的过程中,我如何从它的资源文件中加载我编译进去的DLL动态库,
然后调用其中的函数

从磁盘加载用LoadLibrary就可以了,但是,此时动态库在程序的资源文件中,也就是说他在内存中。此时该如何加载呢?期待高手解答。
...全文
922 22 打赏 收藏 转发到动态 举报
写回复
用AI写文章
22 条回复
切换为时间正序
请发表友善的回复…
发表回复
liaoguobao 2010-09-06
  • 打赏
  • 举报
回复
我做过,下面是静态类头文件

//ResDll.h

#ifndef _RESDLL_H_
#define _RESDLL_H_

#pragma once

#include <winnt.h>

class CResDll
{
protected:
CResDll();
virtual ~CResDll();

static BOOL FinalizeSections(const PIMAGE_NT_HEADERS pInh);
static BOOL GetExportFun(const BYTE *p, const PIMAGE_NT_HEADERS pInh, void *pVoid);
static BOOL BuildImportTable(const BYTE *p, const PIMAGE_NT_HEADERS pNewInh, void *pVoid);
static BOOL CopySections(const PIMAGE_NT_HEADERS pNewInh, const BYTE *pSrcData, BYTE *pDesData);
static BOOL PerformBaseRelocation(const BYTE *p, const PIMAGE_NT_HEADERS pNewInh, DWORD dwOffset);

public:
static BOOL FreeLibraryFromRes(HMODULE hModule);
static FARPROC GetProcAddressFromRes(HMODULE hModule, const WCHAR *pszFunName);
static HMODULE LoadLibraryFromRes(HMODULE hResModule, WORD wDllResId, const WCHAR *szResType);
};

#endif
不得闲 2008-02-25
  • 打赏
  • 举报
回复
to ambush:
参数是如何进入的,你就要看看关于函数的参数传递的问题了,这里的从内存中加载资源DLL,其实不过是
找该DLL的函数在内存中的地址而已了,你使用普通的LoadLibrary也一样是把DLL加载到内存中,找到其中的
函数地址。所以总体说来就是找DLL的入口地址了。其他和LoadLibrary差不多
ambush 2008-02-23
  • 打赏
  • 举报
回复
to ysai:
源码:
{//调用示例
program test;

Uses
Windows, DLLUnit;

var
ResourceLocation: HRSRC;
ResourceSize: LongWord;
ResourceHandle: THandle;
ResourcePointer: Pointer;

TestFunction: procedure;
MyImports: array [0..0] of TImportItem =(
(Name: 'TestFunction'; PProcVar: @@TestFunction)
);
MyLibrary: TLibInfo;

begin
ResourceLocation := FindResource(HInstance, pchar('a01'), RT_RCDATA);
if ResourceLocation <> 0 then
begin
ResourceSize := SizeofResource(HInstance, ResourceLocation);
if ResourceSize <> 0 then
begin
ResourceHandle := LoadResource(HInstance, ResourceLocation);
if ResourceHandle <> 0 then
begin
ResourcePointer := LockResource(ResourceHandle);
if ResourcePointer <> nil then
begin
MyLibrary := xLoadLibrary(ResourcePointer, MyImports);
TestFunction;
end;
end;
end;
end;
xFreeLibrary(MyLibrary);
end.

我在WIN XP下测试了,我写的DLL中的showmessage('OK')被正常调用了。
但有个问题想请教,该动态库中函数的入参是如何进入TestFunction的?并且如何使用返回参数?
ambush 2008-02-23
  • 打赏
  • 举报
回复
其实资源文件还有其它用法。比如说在你的程序携带其它文件,要用的时候释放出来。


例如: myexe exefile 'ha1.exe'//脚本文件

下面是自定义释放函数ExtractRes,本例中使用如下: 软件开发网 www.mscto.com

ExtractRes('exefile','myexe','c:\new.exe');


就把ha1.exe以new.exe为名字保存到C盘根目录下了. 软件开发网 www.mscto.com

function TForm1.ExtractRes(ResType, ResName, ResNewName: string): boolean;



var

软件开发网 www.mscto.com


Res: TResourceStream;

软件开发网 http://bbs.mscto.com

begin

软件开发网 www.mscto.com

try

Res := TResourceStream.Create(Hinstance, Resname, Pchar(ResType));

try

软件开发网 http://bbs.mscto.com

Res.SavetoFile(ResNewName);

Result := true;



finally 软件开发网 http://bbs.mscto.com

Res.Free;

end;

软件开发网 http://bbs.mscto.com

except

Result := false;

end;

end;

不得闲 2008-01-28
  • 打赏
  • 举报
回复
to mwy654321 :
自然可以,上面的是通过PE文件在内存中的位置进行加载的,那么EXE也是PE文件,只要找到他在内存中的位置,一样操作
不得闲 2008-01-28
  • 打赏
  • 举报
回复
呵呵,不会跳出来的.
fox1999 2008-01-28
  • 打赏
  • 举报
回复
APHE 的個代碼,卡巴可能會跳出來
不得闲 2008-01-25
  • 打赏
  • 举报
回复
结贴了!呵呵,估计没有简单的了,要分析PE文件的话都是很麻烦的。
不得闲 2008-01-25
  • 打赏
  • 举报
回复
to ysai:
这个代码,我看到过,就是没有收集下来,这次大哥共享出来了,实在感激!呵呵!接分了。我也做了一个不过有问题,有时候喜欢出错!。可是难道就没有比这个代码更简单的吗?
to mwy654321 :
不是不行,只能说是你不会而已呵呵。
无条件为你 2008-01-25
  • 打赏
  • 举报
回复
问一下,EXE有没有办法动态加载?
ysai 2008-01-23
  • 打赏
  • 举报
回复
PS:不支持用ASPACK压缩过的DLL
ysai 2008-01-23
  • 打赏
  • 举报
回复
begin
ImageNtHeaders := 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
begin
VirtualSectionSize := PSections[SectionLoop].Misc.VirtualSize;
RawSectionSize := PSections[SectionLoop].SizeOfRawData;
if VirtualSectionSize < RawSectionSize then
begin
VirtualSectionSize := 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.AddressOfEntryPoint + cardinal(ImageBase));
NewLibInfo.ImageBase := ImageBase;
SetLength(NewLibInfo.LibsUsed, 0);
if ImageNtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress <> 0 then
ProcessRelocs(pointer(ImageNtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress + cardinal(ImageBase)));
if ImageNtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress <> 0 then
ProcessImports(pointer(ImageNtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress + cardinal(ImageBase)));
for SectionLoop := 0 to ImageNtHeaders.FileHeader.NumberOfSections - 1 do
begin
VirtualProtect(PSections[SectionLoop].VirtualAddress + pchar(ImageBase), PSections[SectionLoop].Misc.VirtualSize, GetSectionProtection(PSections[SectionLoop].Characteristics), OldProtect);
end;
if @NewLibInfo.DllProc <> nil then
begin
if not NewLibInfo.DllProc(cardinal(ImageBase), DLL_PROCESS_ATTACH, nil) then
begin
NewLibInfo.DllProc := nil;
xFreeLibrary(Result);
end;
end;
if ImageNtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress <> 0 then
ProcessExports(pointer(ImageNtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress + cardinal(ImageBase)), ImageNtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size);
Result := NewLibInfo;
end;

{//调用示例
program test;

Uses
Windows, DLLUnit;

var
ResourceLocation: HRSRC;
ResourceSize: LongWord;
ResourceHandle: THandle;
ResourcePointer: Pointer;

TestFunction: procedure;
MyImports: array [0..0] of TImportItem =(
(Name: 'TestFunction'; PProcVar: @@TestFunction)
);
MyLibrary: TLibInfo;

begin
ResourceLocation := FindResource(HInstance, pchar('a01'), RT_RCDATA);
if ResourceLocation <> 0 then
begin
ResourceSize := SizeofResource(HInstance, ResourceLocation);
if ResourceSize <> 0 then
begin
ResourceHandle := LoadResource(HInstance, ResourceLocation);
if ResourceHandle <> 0 then
begin
ResourcePointer := LockResource(ResourceHandle);
if ResourcePointer <> nil then
begin
MyLibrary := xLoadLibrary(ResourcePointer, MyImports);
TestFunction;
end;
end;
end;
end;
xFreeLibrary(MyLibrary);
end.

//==============================================================================
var
FLibrary: TLibInfo;
test: function(const i : Integer):integer; stdcall;

const
DllImports: array [0..0] of TImportItem =(
(Name: 'test'; PProcVar: @@test)
);

procedure LoadLib;
var
Buf : Pointer;
Size : DWORD;
ProcessId: Cardinal;
ResHandle:Cardinal;
begin
ResHandle := FindResource(hInstance, 'testdll', 'DLL');
if ResHandle > 0 then
begin
Size := SizeofResource(hInstance, ResHandle);
Buf := LockResource(LoadResource(hInstance, ResHandle));
FLibrary := xLoadLibrary(Buf, DllImports);
end;
end;

procedure FreeLib;
begin
if FLibrary.ImageBase <> nil then
begin
if xFreeLibrary(FLibrary) then
FLibrary.ImageBase := nil;
end;
end;
//}

end.
ysai 2008-01-23
  • 打赏
  • 举报
回复
function xLoadLibrary(Src: Pointer; Imports: array of TImportItem): TLibInfo;
var
ImageBase: pointer;
ImageBaseDelta: integer;
ImageNtHeaders: PImageNtHeaders;
PSections: ^TSections;
SectionLoop: integer;
SectionBase: pointer;
VirtualSectionSize, RawSectionSize: cardinal;
OldProtect: cardinal;
NewLibInfo: TLibInfo;

function StrToInt(S: string): integer;
begin
Val(S, Result, Result);
end;

procedure Add(Strings: TStringArray; Text: string);
begin
SetLength(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;
begin
Result := False;
for StringLoop := 0 to Length(Strings) - 1 do
begin
if lstrcmpi(pchar(Strings[StringLoop]), pchar(Text)) = 0 then
begin
Index := StringLoop;
Result := True;
end;
end;
end;

function GetSectionProtection(ImageScn: cardinal): cardinal;
begin
Result := 0;
if (ImageScn and IMAGE_SCN_MEM_NOT_CACHED) <> 0 then
begin
Result := Result or PAGE_NOCACHE;
end;
if (ImageScn and IMAGE_SCN_MEM_EXECUTE) <> 0 then
begin
if (ImageScn and IMAGE_SCN_MEM_READ) <> 0 then
begin
if (ImageScn and IMAGE_SCN_MEM_WRITE) <> 0 then
begin
Result := Result or PAGE_EXECUTE_READWRITE
end
else
begin
Result := Result or PAGE_EXECUTE_READ
end;
end
else if (ImageScn and IMAGE_SCN_MEM_WRITE) <> 0 then
begin
Result := Result or PAGE_EXECUTE_WRITECOPY
end
else
begin
Result := Result or PAGE_EXECUTE
end;
end
else if (ImageScn and IMAGE_SCN_MEM_READ) <> 0 then
begin
if (ImageScn and IMAGE_SCN_MEM_WRITE) <> 0 then
begin
Result := Result or PAGE_READWRITE
end
else
begin
Result := Result or PAGE_READONLY
end
end
else if (ImageScn and IMAGE_SCN_MEM_WRITE) <> 0 then
begin
Result := Result or PAGE_WRITECOPY
end
else
begin
Result := Result or PAGE_NOACCESS;
end;
end;

procedure ProcessExports(PExports: PImageExportDirectory; BlockSize: cardinal);
var
ExportLoop: byte;
ImportedFn: cardinal;
PFnName: pchar;
FnIndex: dword;

function IsForwarderString(Data: pchar): boolean;
begin
Result := Data > PExports;
if Result then
Result := cardinal(Data - PExports) < BlockSize;
end;

function GetForwardedSymbol(ForwarderString: pchar): pointer;
var
sForwarderString, DllName: string;
ForwarderLoop: integer;
LibHandle: HModule;
begin
sForwarderString := ForwarderString;
while ForwarderString^ <> '.' do
begin
Inc(ForwarderString);
end;
DllName := Copy(sForwarderString, 1, pos('.', sForwarderString) - 1);
if not Find(NewLibInfo.LibsUsed, DllName, ForwarderLoop) then
begin
LibHandle := LoadLibrary(pchar(DllName));
Add(NewLibInfo.LibsUsed, DllName);
end
else
begin
LibHandle := cardinal(NewLibInfo.LibsUsed[ForwarderLoop]);
end;
if ForwarderString^ = '#' then
ForwarderString := pointer(StrToInt((ForwarderString + 1)));
Result := GetProcAddress(LibHandle, ForwarderString);
end;

begin
for ExportLoop := 0 to PExports.NumberOfNames - 1 do
begin
PFnName := 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
begin
FnIndex := 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^) then
begin
Imports[ImportedFn].PProcVar^ := GetForwardedSymbol(Imports[ImportedFn].PProcVar^);
end;
end;
end;
end;
end;

procedure ProcessRelocs(PRelocs: PImageBaseRelocation);
var
PReloc: PImageBaseRelocation;
RelocsSize: cardinal;
Reloc: PWord;
ModCount: cardinal;
RelocLoop: cardinal;
begin
PReloc := PRelocs;
RelocsSize := ImageNtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size;
while cardinal(PReloc) - cardinal(PRelocs) < RelocsSize do
begin
ModCount := (PReloc.SizeOfBlock - Sizeof(PReloc^)) div 2;
Reloc := pointer(cardinal(PReloc) + sizeof(PReloc^));
for RelocLoop := 0 to ModCount - 1 do
begin
if Reloc^ and $F000 <> 0 then
Inc(pdword(cardinal(ImageBase) + PReloc.VirtualAddress + (Reloc^ and $0FFF))^, ImageBaseDelta);
Inc(Reloc);
end;
PReloc := pointer(Reloc);
end;
end;

procedure ProcessImports(PImports: PImageImportDescriptor);
var
PImport: PImageImportDescriptor;
Import: LPDword;
PImportedName: pchar;
LibHandle: HModule;
ProcAddress: pointer;
PLibName: pchar;
ImportLoop: integer;

function IsImportByOrdinal(ImportDescriptor: dword; HLib: THandle): boolean;
begin
Result := (ImportDescriptor and IMAGE_ORDINAL_FLAG32) <> 0;
end;

begin
PImport := PImports;
while PImport.Name <> 0 do
begin
PLibName := pchar(cardinal(PImport.Name) + cardinal(ImageBase));
if not Find(NewLibInfo.LibsUsed, PLibName, ImportLoop) then
begin
LibHandle := LoadLibrary(PLibName);
Add(NewLibInfo.LibsUsed, PLibName);
end
else
begin
LibHandle := cardinal(NewLibInfo.LibsUsed[ImportLoop]);
end;
if PImport.TimeDateStamp = 0 then
begin
Import := LPDword(pImport.FirstThunk + cardinal(ImageBase))
end
else
begin
Import := LPDword(pImport.OriginalFirstThunk + cardinal(ImageBase));
end;
while Import^ <> 0 do
begin
if IsImportByOrdinal(Import^, LibHandle) then
begin
ProcAddress := GetProcAddress(LibHandle, pchar(Import^ and $FFFF))
end
else
begin
PImportedName := pchar(Import^ + cardinal(ImageBase) + IMPORTED_NAME_OFFSET);
ProcAddress := GetProcAddress(LibHandle, PImportedName);
end;
PPointer(Import)^ := ProcAddress;
Inc(Import);
end;
Inc(PImport);
end;
end;
ysai 2008-01-23
  • 打赏
  • 举报
回复
{
DLL Loader by Aphex
http://www.iamaphex.cjb.net
unremote@knology.net

Based on code from gmm@ufacom.ru

function xLoadLibrary(Src: Pointer; Imports: array of TImportItem): TLibInfo;
procedure xFreeLibrary(hModule: TLibInfo);
}

unit DLLUnit;

interface

uses
Windows;

type
TImportItem = record
Name: string;
PProcVar: PPointer;
end;

TwordArr = array[0..0] of word;
PwordArr = ^TwordArr;
TdwordArr = array[0..0] of dword;
PdwordArr = ^TdwordArr;

PImageImportDescriptor = ^TImageImportDescriptor;
TImageImportDescriptor = packed record
OriginalFirstThunk: dword;
TimeDateStamp: dword;
ForwarderChain: dword;
Name: dword;
FirstThunk: dword;
end;

PImageBaseRelocation = ^TImageBaseRelocation;
TImageBaseRelocation = packed record
VirtualAddress: cardinal;
SizeOfBlock: cardinal;
end;

TDllEntryProc = function(hinstDLL: HMODULE; dwReason: dword; lpvReserved: Pointer): Boolean; stdcall;

TStringArray = array of string;

TLibInfo = record
ImageBase: Pointer;
DllProc: TDllEntryProc;
LibsUsed: TStringArray;
end;

PLibInfo = ^TLibInfo;
PPointer = ^Pointer;

TSections = array[0..100000] of TImageSectionHeader;

const
IMPORTED_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;

implementation

function xFreeLibrary(LoadedLib: TLibInfo): boolean;
var
ObjectLoop: integer;
begin
Result := False;
with LoadedLib do
begin
if @DllProc <> nil then
begin
DllProc(HModule(LoadedLib.ImageBase), DLL_PROCESS_DETACH, nil);
end;
for ObjectLoop := 0 to Length(LibsUsed) - 1 do
begin
if ObjectLoop >= Length(LibsUsed) then
Exit;
FreeLibrary(GetModuleHandle(pchar(LibsUsed[ObjectLoop])));
end;
SetLength(LibsUsed, 0);
end;
VirtualFree(LoadedLib.ImageBase, 0, MEM_RELEASE);
Result := True;
end;
无条件为你 2008-01-23
  • 打赏
  • 举报
回复
并不是所有的文件都支持流操作。

你的意思我明白,要求直接读资源里面的文件嘛,如果是图片当然可以读到Image里面,如果是EXE或者DLL文件,不释放出来,根本不可以用。但你要求不释放到硬盘中,那是不可能的。

建议你释放后,加载,程序关闭后再删除。

另外,你为什么要做成DLL呢,如果你有DLL这个文件的源代码,可以直接把源代码做到EXE里面。
不得闲 2008-01-23
  • 打赏
  • 举报
回复
似乎无人问津啊!
分数可以加上去,希望有知道的人,告之。
rock1001 2008-01-14
  • 打赏
  • 举报
回复
需要自己实现LoadLibrary,主要是代码重定位问题,以前做过,应为编译器太多,不太稳定,也没做下去
蒋晟 2008-01-14
  • 打赏
  • 举报
回复
不行
不过你可以在内存里面注入数据之后创建远程线程,然后自己手动调整函数导入表
不得闲 2008-01-14
  • 打赏
  • 举报
回复
其实,我想了一个,只是很复杂麻烦我还没有去实现他,想问一下有没有简单的办法了

我的方法是 先使用 FindResource找到DLL资源,然后使用LoadResource装载资源,然后是使用LockResource锁定
资源得到资源数据,然后通过内存影象来查找对应的函数指针,进行调用。
不得闲 2008-01-12
  • 打赏
  • 举报
回复
我的目的是通过内存中加载,不要在系统上生成文件。
加载更多回复(2)

1,183

社区成员

发帖
与我相关
我的任务
社区描述
Delphi Windows SDK/API
社区管理员
  • Windows SDK/API社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧