打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
如何从资源中加载DLL动态库
就是自己 使用 Brcc32命令制作一个包含DLL动态库的资源文件,然后我如何从程序中加载该动态库呢!
  比如 有一个动态库 Test.dll,然后我在制作资源文件如下:
   
  MyDll DLL Test.dll 保存为Test.rc
  然后使用 Brcc32 test.rc命令生成 Brcc32.res

  然后在程序中{$R Test.res}将该资源文件作为应用程序的一个资源编译到EXE文件中去 
  
  我就想问一下,当EXE文件在运行的过程中,我如何从它的资源文件中加载我编译进去的DLL动态库,
  然后调用其中的函数

  从磁盘加载用LoadLibrary就可以了,但是,此时动态库在程序的资源文件中,也就是说他在内存中。此时该如何加载呢?期待高手解答。

{不支持用ASPACK压缩过的DLL}

{
  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;

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;

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.




本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
【Delphi】内存加载并运行EXE程序
从内存中加载DLL DELPHI版
Kendy--从内存中加载并启动一个exe
EXE文件内存加载
谈谈 Delphi 的类型与指针[2]
调用外部 DLL 中的函数(1. 早绑定)
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服