powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Загрузка dll-ресурса из памяти для x64
6 сообщений из 6, страница 1 из 1
Загрузка dll-ресурса из памяти для x64
    #39422772
kopiev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Всем привет,
проблема с загрузкой dll-библиотеки в ресурсах проекта из памяти для x64 сборки. Нашел в интернете пример, немного адаптировал для x64:
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
192.
193.
194.
195.
196.
197.
198.
199.
200.
201.
202.
203.
204.
205.
206.
207.
208.
209.
210.
211.
212.
213.
214.
215.
216.
217.
218.
219.
220.
221.
222.
223.
224.
225.
226.
227.
228.
229.
230.
231.
232.
233.
234.
235.
236.
237.
238.
239.
240.
241.
242.
243.
244.
245.
246.
247.
248.
249.
250.
251.
252.
253.
254.
255.
256.
257.
258.
259.
260.
261.
262.
263.
264.
265.
266.
267.
268.
269.
270.
271.
272.
273.
274.
275.
276.
277.
278.
279.
280.
281.
282.
283.
284.
285.
286.
287.
288.
289.
290.
291.
292.
293.
294.
295.
296.
297.
298.
299.
300.
301.
302.
303.
304.
305.
306.
307.
308.
309.
310.
311.
312.
313.
314.
315.
316.
317.
318.
319.
320.
321.
322.
323.
324.
325.
326.
327.
328.
329.
330.
331.
332.
333.
334.
335.
336.
337.
338.
339.
340.
341.
342.
343.
344.
345.
346.
347.
348.
349.
350.
351.
352.
353.
354.
355.
356.
357.
358.
359.
360.
361.
362.
363.
364.
365.
366.
367.
368.
369.
370.
371.
372.
373.
374.
375.
376.
377.
378.
379.
380.
381.
382.
383.
384.
385.
386.
387.
388.
389.
390.
391.
392.
393.
394.
395.
396.
397.
398.
399.
400.
401.
402.
403.
404.
405.
406.
407.
408.
409.
410.
411.
412.
413.
414.
415.
416.
417.
418.
419.
420.
421.
422.
423.
424.
425.
426.
427.
428.
429.
430.
431.
432.
433.
434.
435.
436.
437.
438.
439.
440.
441.
442.
443.
444.
445.
446.
447.
448.
449.
450.
451.
452.
453.
454.
455.
456.
457.
458.
459.
460.
461.
462.
463.
464.
465.
466.
467.
468.
469.
470.
471.
472.
473.
474.
475.
476.
477.
478.
479.
480.
481.
482.
483.
484.
485.
486.
487.
488.
489.
490.
491.
492.
493.
494.
495.
496.
497.
498.
499.
500.
501.
502.
503.
504.
505.
506.
507.
508.
509.
510.
511.
512.
513.
514.
515.
516.
517.
518.
519.
520.
521.
522.
523.
524.
525.
526.
527.
528.
529.
530.
531.
532.
533.
534.
535.
536.
537.
538.
539.
540.
541.
542.
543.
544.
545.
546.
547.
548.
549.
550.
551.
552.
553.
554.
555.
556.
557.
558.
559.
560.
561.
562.
563.
564.
565.
566.
567.
568.
569.
570.
571.
572.
573.
574.
575.
576.
577.
578.
579.
580.
581.
582.
583.
584.
585.
586.
587.
588.
589.
590.
591.
592.
593.
594.
595.
596.
597.
598.
599.
600.
601.
602.
603.
604.
605.
606.
607.
608.
609.
610.
611.
612.
613.
614.
615.
616.
617.
618.
619.
620.
621.
622.
623.
624.
625.
626.
627.
628.
629.
630.
631.
632.
633.
634.
635.
636.
637.
638.
639.
640.
641.
642.
643.
644.
645.
646.
647.
648.
649.
650.
651.
652.
653.
654.
655.
656.
657.
658.
659.
660.
661.
662.
663.
664.
665.
666.
667.
668.
669.
670.
671.
672.
673.
674.
675.
676.
677.
678.
679.
680.
681.
682.
683.
684.
unit MW_MemoryDll;

interface

{$REGION 'Documentation'}
// =================================================================================================
// Memory DLL 32 Bit functions
//
// Loads and calls DLL functions and methods from memory from a resource within the EXE.
// Replaces typical use whereby the DLL is compiled as a resource and at runtime is saved
// to a file, then loaded and executed.
// Works in a similar fashion to Delphi LoadLibrary(),GetProcAddress() and FreeLibrary()
// functions except the DLL is loaded from resource to memory.
// It is best to call the functions in a try..except structure
//
// Mike Heydon 2010
//
// =================================================================================================

// The original unit sample is taken from
//  http://delphi.cjcsoft.net//viewthread.php?tid=48024
// This instance of helper unit contains minor corrections, auto formatted.
{$ENDREGION}

uses Windows, SysUtils, Classes;

// Prototype Definitions
function MemoryLoadLibrary(const ADllResName: string): Pointer;

function MemoryGetProcAddress(AModule: Pointer; const AName: string;
  ACaseSensitive: boolean = false): Pointer; stdcall;

procedure MemoryFreeLibrary(AModule: Pointer); stdcall;

// ------------------------------------------------------------------------------------------------
implementation

{$REGION 'Types and Constants'}
// -------------------------------------------------------------------------------------------------

type
  TDllEntryProc = function(hinstdll: THandle; fdwReason: DWORD;
    lpReserved: Pointer): BOOL; stdcall;
  PBTMemoryModule = ^TBTMemoryModule;

  _BT_MEMORY_MODULE = packed record
    Headers: PImageNtHeaders;
    CodeBase: Pointer;
    Modules: Pointer;
    NumModules: integer;
    Initialized: boolean;
  end;

{$EXTERNALSYM _BT_MEMORY_MODULE}

  TBTMemoryModule = _BT_MEMORY_MODULE;
  BT_MEMORY_MODULE = _BT_MEMORY_MODULE;
{$EXTERNALSYM BT_MEMORY_MODULE}

  // Missing Windows API Definitions

  PImageBaseRelocation = ^TImageBaseRelocation;

  _IMAGE_BASE_RELOCATION = packed record
    VirtualAddress: DWORD;
    SizeOfBlock: DWORD;
  end;

{$EXTERNALSYM _IMAGE_BASE_RELOCATION}

  TImageBaseRelocation = _IMAGE_BASE_RELOCATION;
  IMAGE_BASE_RELOCATION = _IMAGE_BASE_RELOCATION;
{$EXTERNALSYM IMAGE_BASE_RELOCATION}
  PImageImportDescriptor = ^TImageImportDescriptor;

  _IMAGE_IMPORT_DESCRIPTOR = packed record
    OriginalFirstThunk: DWORD;
    TimeDateStamp: DWORD;
    ForwarderChain: DWORD;
    Name: DWORD;
    FirstThunk: DWORD;
  end;

{$EXTERNALSYM _IMAGE_IMPORT_DESCRIPTOR}

  TImageImportDescriptor = _IMAGE_IMPORT_DESCRIPTOR;
  IMAGE_IMPORT_DESCRIPTOR = _IMAGE_IMPORT_DESCRIPTOR;
{$EXTERNALSYM IMAGE_IMPORT_DESCRIPTOR}
  PImageImportByName = ^TImageImportByName;

  _IMAGE_IMPORT_BY_NAME = packed record
    Hint: Word;
    Name: array [0 .. 255] of byte;
  end;

{$EXTERNALSYM _IMAGE_IMPORT_BY_NAME}

  TImageImportByName = _IMAGE_IMPORT_BY_NAME;
  IMAGE_IMPORT_BY_NAME = _IMAGE_IMPORT_BY_NAME;
{$EXTERNALSYM IMAGE_IMPORT_BY_NAME}

const
  IMAGE_SIZEOF_BASE_RELOCATION = 8;
{$EXTERNALSYM IMAGE_SIZEOF_BASE_RELOCATION}
  IMAGE_REL_BASED_HIGHLOW = 3;
{$EXTERNALSYM IMAGE_REL_BASED_HIGHLOW}
  IMAGE_ORDINAL_FLAG32 = DWORD($80000000);
{$EXTERNALSYM IMAGE_ORDINAL_FLAG32}
{$ENDREGION}
{$REGION 'Internal Calls'}
  // -------------------------------------------------------------------------------------------------

function _GetFieldOffset(const AStruc; const AField): NativeUInt; stdcall; inline;
begin
  Result := NativeUInt(@AField) - NativeUInt(@AStruc);
end;

function _GetImageFirstSection(ANtHeader: PImageNtHeaders): PImageSectionHeader;
  stdcall; inline;
begin
  Result := PImageSectionHeader(NativeUInt(ANtHeader) +
    _GetFieldOffset(ANtHeader^, ANtHeader^.OptionalHeader) +
    ANtHeader^.FileHeader.SizeOfOptionalHeader);
end;

function _GetHeaderDictionary(AModule: PBTMemoryModule; AIdx: integer)
  : PImageDataDirectory; stdcall; inline;
begin
  Result := PImageDataDirectory
    (@(AModule.Headers.OptionalHeader.DataDirectory[AIdx]));
end;

function _GetImageOrdinal(AOrdinal: DWORD): Word; stdcall; inline;
begin
  Result := AOrdinal and $FFFF;
end;

function _GetImageSnapByOrdinal(AOrdinal: DWORD): boolean; stdcall; inline;
begin
  Result := (AOrdinal and IMAGE_ORDINAL_FLAG32) <> 0
end;

procedure _CopySections(const AData: Pointer;
  const AOldHeaders: TImageNtHeaders; AModule: PBTMemoryModule); stdcall;
var
  iSize, i: integer;
  pCodebase, pDest: Pointer;
  pSection: PImageSectionHeader;
begin
  pCodebase := AModule.CodeBase;
  pSection := _GetImageFirstSection(AModule.Headers);

  for i := 0 to AModule.Headers.FileHeader.NumberOfSections - 1 do
  begin
    // Section doesn't contain data in the dll itself, but may define uninitialized data
    if (pSection.SizeOfRawData = 0) then
    begin
      iSize := AOldHeaders.OptionalHeader.SectionAlignment;

      if iSize > 0 then
      begin
        pDest := VirtualAlloc
          (Pointer(NativeUInt(pCodebase) + pSection.VirtualAddress), iSize,
          MEM_COMMIT, PAGE_READWRITE);
        pSection.Misc.PhysicalAddress := NativeUInt(pDest);
        ZeroMemory(pDest, iSize);
      end;

      Inc(NativeUInt(pSection), sizeof(TImageSectionHeader));
      Continue;
    end;

    // Commit memory block and copy data from DLL
    pDest := VirtualAlloc(Pointer(NativeUInt(pCodebase) +
      pSection.VirtualAddress), pSection.SizeOfRawData, MEM_COMMIT,
      PAGE_READWRITE);
    CopyMemory(pDest, Pointer(NativeUInt(AData) + pSection.pointerToRawData),
      pSection.SizeOfRawData);
    pSection.Misc.PhysicalAddress := NativeUInt(pDest);
    // IMAGE_SIZEOF_SECTION_HEADER
    Inc(NativeUInt(pSection), sizeof(TImageSectionHeader));
  end;
end;

procedure _PerformBaseRelocation(AModule: PBTMemoryModule;
  ADelta: NativeUInt); stdcall;
var
  i: cardinal;
  pCodebase, pDest: Pointer;
  pDirectory: PImageDataDirectory;
  pRelocation: PImageBaseRelocation;
  pRelInfo: ^Word;
  pPatchAddrHL: ^DWORD;
  iType, iOffset: NativeInt;
begin
  pCodebase := AModule.CodeBase;
  pDirectory := _GetHeaderDictionary(AModule, IMAGE_DIRECTORY_ENTRY_BASERELOC);

  if pDirectory.Size > 0 then
  begin
    pRelocation := PImageBaseRelocation(NativeUInt(pCodebase) +
      pDirectory.VirtualAddress);

    while pRelocation.VirtualAddress > 0 do
    begin
      pDest := Pointer((NativeUInt(pCodebase) + pRelocation.VirtualAddress));
      pRelInfo := Pointer(NativeUInt(pRelocation) + IMAGE_SIZEOF_BASE_RELOCATION);

      for i := 0 to
        (trunc(((pRelocation.SizeOfBlock - IMAGE_SIZEOF_BASE_RELOCATION) /
        2)) - 1) do
      begin
        // Upper 4 bits define the type of relocation
        iType := (pRelInfo^ shr 12);
        // Lower 12 bits define the offset
        iOffset := pRelInfo^ and $FFF;

        if iType = IMAGE_REL_BASED_HIGHLOW then
        begin
          // Change complete 32 bit address
          pPatchAddrHL := Pointer(NativeUInt(pDest) + NativeUInt(iOffset));
          pPatchAddrHL^ := pPatchAddrHL^ + ADelta;
        end;

        Inc(pRelInfo);
      end;

      pRelocation := Pointer(NativeUInt(pRelocation) + pRelocation.SizeOfBlock);
    end;
  end;
end;

function _BuildImportTable(AModule: PBTMemoryModule; out AErrStr: string)
  : boolean; stdcall;
var
  pCodebase: Pointer;
  pDirectory: PImageDataDirectory;
  pImportDesc: PImageImportDescriptor;
  pThunkRef, pFuncRef: ^NativeUInt;
  iHandle: HMODULE;
  iTemp: integer;
  rThunkData: TImageImportByName;
begin
  Result := true;
  pCodebase := AModule.CodeBase;
  pDirectory := _GetHeaderDictionary(AModule, IMAGE_DIRECTORY_ENTRY_IMPORT);

  if (pDirectory.Size > 0) then
  begin
    pImportDesc := PImageImportDescriptor(NativeUInt(pCodebase) +
      pDirectory.VirtualAddress);

    while (not IsBadReadPtr(pImportDesc, sizeof(TImageImportDescriptor))) and
      (pImportDesc.Name > 0) do
    begin
      iHandle := LoadLibraryA
        (PAnsiChar(NativeUInt(pCodebase) + pImportDesc.Name));

      if (iHandle = INVALID_HANDLE_VALUE) or (iHandle = 0) then
      begin
        AErrStr := 'BuildImportTable: can''t load library: ' +
          PAnsiChar(NativeUInt(pCodebase) + pImportDesc.Name);
        Result := false;
        exit;
      end;

      // ReallocMemory crashes if "AModule.Modules = nil"
      if AModule.Modules = nil then
        AModule.Modules := AllocMem(1);
      AModule.Modules := ReallocMemory(AModule.Modules,
        ((AModule.NumModules + 1) * (sizeof(HMODULE))));

      if AModule.Modules = nil then
      begin
        AErrStr := 'BuildImportTable: ReallocMemory failed';
        Result := false;
        exit;
      end;

      iTemp := (sizeof(NativeUInt) * (AModule.NumModules));
      Inc(NativeUInt(AModule.Modules), iTemp);
      NativeUInt(AModule.Modules^) := iHandle;
      Dec(NativeUInt(AModule.Modules), iTemp);
      AModule.NumModules := AModule.NumModules + 1;

      if pImportDesc.OriginalFirstThunk > 0 then
      begin
        pThunkRef := Pointer(NativeUInt(pCodebase) +
          pImportDesc.OriginalFirstThunk);
        pFuncRef := Pointer(NativeUInt(pCodebase) + pImportDesc.FirstThunk);
      end
      else
      begin
        // No hint table
        pThunkRef := Pointer(NativeUInt(pCodebase) + pImportDesc.FirstThunk);
        pFuncRef := Pointer(NativeUInt(pCodebase) + pImportDesc.FirstThunk);
      end;

      while pThunkRef^ <> 0 do
      begin
        if _GetImageSnapByOrdinal(pThunkRef^) then
          pFuncRef^ := NativeUInt(GetProcAddress(iHandle,
            PAnsiChar(_GetImageOrdinal(pThunkRef^))))
        else
        begin
          CopyMemory(@rThunkData, Pointer(NativeUInt(pCodebase) + pThunkRef^),
            sizeof(TImageImportByName));
          pFuncRef^ := NativeUInt(GetProcAddress(iHandle,
            PAnsiChar(@(rThunkData.Name))));
        end;

        if pFuncRef^ = 0 then
        begin
          AErrStr := 'BuildImportTable: GetProcAddress failed';
          Result := false;
          break;
        end;

        Inc(pFuncRef);
        Inc(pThunkRef);
      end;

      Inc(NativeUInt(pImportDesc), sizeof(TImageImportDescriptor));
    end;
  end;
end;

function _GetSectionProtection(ASectionHeader: cardinal): cardinal; stdcall;
var
  iResult: cardinal;
begin
  iResult := 0;
  if (ASectionHeader and IMAGE_SCN_MEM_NOT_CACHED) > 0 then
    iResult := iResult or PAGE_NOCACHE;

  // E - Execute, R - Read , W - Write
  if (ASectionHeader and IMAGE_SCN_MEM_EXECUTE) > 0 // E ?
  then
    if (ASectionHeader and IMAGE_SCN_MEM_READ) > 0 // ER ?
    then
      if (ASectionHeader and IMAGE_SCN_MEM_WRITE) > 0 // ERW ?
      then
        iResult := iResult or PAGE_EXECUTE_READWRITE
      else
        iResult := iResult or PAGE_EXECUTE_READ
    else if (ASectionHeader and IMAGE_SCN_MEM_WRITE) > 0 // EW?
    then
      iResult := iResult or PAGE_EXECUTE_WRITECOPY
    else
      iResult := iResult or PAGE_EXECUTE
  else if (ASectionHeader and IMAGE_SCN_MEM_READ) > 0 // R?
  then
    if (ASectionHeader and IMAGE_SCN_MEM_WRITE) > 0 // RW?
    then
      iResult := iResult or PAGE_READWRITE
    else
      iResult := iResult or PAGE_READONLY
  else if (ASectionHeader and IMAGE_SCN_MEM_WRITE) > 0 // W?
  then
    iResult := iResult or PAGE_WRITECOPY
  else
    iResult := iResult or PAGE_NOACCESS;

  Result := iResult;
end;

procedure _FinalizeSections(AModule: PBTMemoryModule); stdcall;
var
  i: integer;
  pSection: PImageSectionHeader;
  iProtect, iOldProtect, iSize: cardinal;
begin
  pSection := _GetImageFirstSection(AModule.Headers);

  for i := 0 to AModule.Headers.FileHeader.NumberOfSections - 1 do
  begin

    if (pSection.Characteristics and IMAGE_SCN_MEM_DISCARDABLE) > 0 then
    begin
      // Section is not needed any more and can safely be freed
      VirtualFree(Pointer(pSection.Misc.PhysicalAddress),
        pSection.SizeOfRawData, MEM_DECOMMIT);
      Inc(NativeUInt(pSection), sizeof(TImageSectionHeader));
      Continue;
    end;

    iProtect := _GetSectionProtection(pSection.Characteristics);
    if (pSection.Characteristics and IMAGE_SCN_MEM_NOT_CACHED) > 0 then
      iProtect := (iProtect or PAGE_NOCACHE);

    // Determine size of region
    iSize := pSection.SizeOfRawData;

    if iSize = 0 then
    begin
      if (pSection.Characteristics and IMAGE_SCN_CNT_INITIALIZED_DATA) > 0 then
        iSize := AModule.Headers.OptionalHeader.SizeOfInitializedData
      else
      begin
        if (pSection.Characteristics and IMAGE_SCN_CNT_UNINITIALIZED_DATA) > 0 then
          iSize := AModule.Headers.OptionalHeader.SizeOfUninitializedData;
      end;
      if iSize > 0 then
      begin
        if not VirtualProtect(Pointer(pSection.Misc.PhysicalAddress),
          pSection.SizeOfRawData, iProtect, @iOldProtect) then
          raise Exception.Create('FinalizeSections: VirtualProtect failed');
      end;
    end;

    Inc(NativeUInt(pSection), sizeof(TImageSectionHeader));
  end;
end;

// ========================================
// Load Library into memory structure
// ========================================

function _MemoryLoadLibary(AData: Pointer): PBTMemoryModule; stdcall;
var
  sErrStr: string;
  pResult: PBTMemoryModule;
  rDosHeader: TImageDosHeader;
  rOldHeader: TImageNtHeaders;
  pCode, pHeaders: Pointer;
  iLocationDelta: NativeUInt;
  rDllEntry: TDllEntryProc;
  bSuccessfull: boolean;
begin
  sErrStr := '';
  pResult := nil;

  try
    CopyMemory(@rDosHeader, AData, sizeof(_IMAGE_DOS_HEADER));

    if (rDosHeader.e_magic > IMAGE_DOS_SIGNATURE) then
      raise Exception.Create('MemoryLoadLibary: DLL DOS header is not valid');

    CopyMemory(@rOldHeader, Pointer(NativeUInt(AData) + rDosHeader._lfanew),
      sizeof(_IMAGE_NT_HEADERS));

    if rOldHeader.Signature > IMAGE_NT_SIGNATURE then
      raise Exception.Create
        ('MemoryLoadLibary: IMAGE_NT_SIGNATURE is not valid');

    // Reserve memory for image of library
    pCode := VirtualAlloc(Pointer(rOldHeader.OptionalHeader.ImageBase),
      rOldHeader.OptionalHeader.SizeOfImage, MEM_RESERVE, PAGE_READWRITE);

    // Try to allocate memory at arbitrary position
    if pCode = nil then
      pCode := VirtualAlloc(nil, rOldHeader.OptionalHeader.SizeOfImage,
        MEM_RESERVE, PAGE_READWRITE);

    if pCode = nil then
      raise Exception.Create('MemoryLoadLibary: VirtualAlloc failed');

    // Alloc space for the result record
    pResult := PBTMemoryModule(HeapAlloc(GetProcessHeap(), 0,
      sizeof(TBTMemoryModule)));
    pResult.CodeBase := pCode;
    pResult.NumModules := 0;
    pResult.Modules := nil;
    pResult.Initialized := false;
    // xy: is it correct to commit the complete memory region at once?
    // Calling DllEntry raises an exception if we don't...
    VirtualAlloc(pCode, rOldHeader.OptionalHeader.SizeOfImage, MEM_COMMIT,
      PAGE_READWRITE);
    // Commit memory for headers
    pHeaders := VirtualAlloc(pCode, rOldHeader.OptionalHeader.SizeOfHeaders,
      MEM_COMMIT, PAGE_READWRITE);
    // Copy PE header to code
    CopyMemory(pHeaders, AData,
      (cardinal(rDosHeader._lfanew) + rOldHeader.OptionalHeader.SizeOfHeaders));
    pResult.Headers := PImageNtHeaders(NativeUInt(pHeaders) + rDosHeader._lfanew);
    // Update position
    pResult.Headers.OptionalHeader.ImageBase := NativeUInt(pCode);
    // Copy sections from DLL file block to new memory location
    _CopySections(AData, rOldHeader, pResult);
    // Adjust base address of imported data
    iLocationDelta := NativeUInt(NativeUInt(pCode) -
      rOldHeader.OptionalHeader.ImageBase);
    if iLocationDelta > 0 then
      _PerformBaseRelocation(pResult, iLocationDelta);

    // Load required dlls and adjust function table of imports
    if not _BuildImportTable(pResult, sErrStr) then
      raise Exception.Create
        (sErrStr + ' MemoryLoadLibary: BuildImportTable failed');

    // Mark memory pages depending on section headers and release
    // sections that are marked as "discardable"
    _FinalizeSections(pResult);

    // Get entry point of loaded library
    if (pResult.Headers.OptionalHeader.AddressOfEntryPoint) > 0 then
    begin
      @rDllEntry := Pointer(NativeUInt(pCode) +
        pResult.Headers.OptionalHeader.AddressOfEntryPoint);

      if @rDllEntry = nil then
        raise Exception.Create('MemoryLoadLibary: Get DLLEntyPoint failed');

      bSuccessfull := rDllEntry(NativeUInt(pCode), DLL_PROCESS_ATTACH, nil); // <---  Не может присоединиться для x64

      if not bSuccessfull then
        raise Exception.Create('MemoryLoadLibary: Can''t attach library');

      pResult.Initialized := true;
    end;
  except
    MemoryFreeLibrary(pResult);
    raise;
  end;

  Result := pResult;
end;

{$ENDREGION}
{$REGION 'User Calls'}
// -------------------------------------------------------------------------------------------------

// ========================================================
// Load the library from RESOURCE NAME in EXE into memory
// ========================================================

function MemoryLoadLibrary(const ADllResName: string): Pointer;
var
  oMs: TMemoryStream;
  oRs: TResourceStream;
  iDllDataSize: int64;
  pDllData: Pointer;
  pResult: PBTMemoryModule;
begin
  pResult := nil;

  if FindResource(hInstance, PWideChar(ADllResName), RT_RCDATA) > 0 then
  begin
    oRs := TResourceStream.Create(hInstance, ADllResName, RT_RCDATA);
    oMs := TMemoryStream.Create;
    try
      oMs.LoadFromStream(oRs);
      oMs.Position := 0;
      iDllDataSize := oMs.Size;
      pDllData := GetMemory(iDllDataSize);
      oMs.Read(pDllData^, iDllDataSize);
      pResult := Pointer(_MemoryLoadLibary(pDllData));
    finally
      oMs.Free;
      oRs.Free;
    end;
  end;

  Result := pResult;
end;


// ===============================================
// Find the Funcion/Procedure Entry point
// ===============================================

function MemoryGetProcAddress(AModule: Pointer; const AName: string;
  ACaseSensitive: boolean = false): Pointer; stdcall;
var
  sName: AnsiString;
  pFoundName, pName: PAnsiChar;
  sFoundName: string;
  pCodebase: Pointer;
  iIdx: integer;
  i: DWORD;
  pNameRef, pTemp: ^DWORD;
  pOrdinal: ^Word;
  pExports: PImageExportDirectory;
  pDirectory: PImageDataDirectory;
  pModule: PBTMemoryModule;
begin
  pModule := PBTMemoryModule(AModule);
  pCodebase := pModule.CodeBase;
  iIdx := -1;
  pDirectory := _GetHeaderDictionary(pModule, IMAGE_DIRECTORY_ENTRY_EXPORT);

  if pDirectory.Size = 0 then
    raise Exception.Create('MemoryGetProcAddress: no export table found');

  pExports := PImageExportDirectory(NativeUInt(pCodebase) +
    pDirectory.VirtualAddress);

  if ((pExports.NumberOfNames = 0) or (pExports.NumberOfFunctions = 0)) then
    raise Exception.Create
      ('MemoryGetProcAddress: DLL doesn''t export anything');

  // Search function name in list of exported names
  pNameRef := Pointer(NativeUInt(pCodebase) + NativeUInt(pExports.AddressOfNames));
  pOrdinal := Pointer(NativeUInt(pCodebase) +
    NativeUInt(pExports.AddressOfNameOrdinals));

  for i := 0 to pExports.NumberOfNames - 1 do
  begin
    if not ACaseSensitive then
    begin
      // Ignore Case
      pFoundName := PAnsiChar(NativeUInt(pCodebase) + pNameRef^);
      sFoundName := string(pFoundName);

      if SameText(AName, sFoundName) then
      begin
        iIdx := pOrdinal^;
        break;
      end;
    end
    else
    begin
      // Match Case
      sName := AnsiString(AName);
      pName := @sName[1];

      if StrComp(pName, PAnsiChar(NativeUInt(pCodebase) + pNameRef^)) = 0 then
      begin
        iIdx := pOrdinal^;
        break;
      end;
    end;

    Inc(pNameRef);
    Inc(pOrdinal);
  end;

  if (iIdx = -1) then
    raise Exception.Create('MemoryGetProcAddress: exported symbol not found');

  if (cardinal(iIdx) > pExports.NumberOfFunctions - 1) then
    raise Exception.Create
      ('MemoryGetProcAddress: name - ordinal number don''t match');

  // AddressOfFunctions contains the RVAs to the "real" functions
  pTemp := Pointer(NativeUInt(pCodebase) + NativeUInt(pExports.AddressOfFunctions) +
    NativeUInt((iIdx * 4)));
  Result := Pointer(NativeUInt(pCodebase) + pTemp^);
end;


// ======================================
// Free the Library if allocated
// ======================================

procedure MemoryFreeLibrary(AModule: Pointer); stdcall;
var
  pModule1, pModule2: PBTMemoryModule;
  i: integer;
  iTemp: integer;
  rDllEntry: TDllEntryProc;
begin
  pModule1 := PBTMemoryModule(AModule);
  pModule2 := PBTMemoryModule(AModule);

  if pModule1 <> nil then
  begin
    if pModule1.Initialized then
    begin
      @rDllEntry := Pointer(NativeUInt(pModule1.CodeBase) +
        pModule1.Headers.OptionalHeader.AddressOfEntryPoint);
      rDllEntry(NativeUInt(pModule1.CodeBase), DLL_PROCESS_DETACH, nil);
      pModule1.Initialized := false;

      // Free previously opened libraries
      for i := 0 to pModule1.NumModules - 1 do
      begin
        iTemp := (sizeof(NativeUInt) * (i));
        Inc(NativeUInt(pModule1.Modules), iTemp);
        if NativeUInt(pModule2.Modules^) <> INVALID_HANDLE_VALUE then
          FreeLibrary(NativeUInt(pModule2.Modules^));
        Dec(NativeUInt(pModule1.Modules), iTemp);
      end;

      FreeMemory(pModule1.Modules);
      if pModule1.CodeBase <> nil then
        VirtualFree(pModule1.CodeBase, 0, MEM_RELEASE);
      HeapFree(GetProcessHeap(), 0, pModule2);
      Pointer(pModule2) := nil;
    end;
  end;
end;
{$ENDREGION}
end.


Для x86 прекрасно работает, для x64 загрузка библиотеки в память также отрабатывает, но при попытке присоединиться к процессу в _MemoryLoadLibary выдает ошибку:
First chance exception at $0000000003B28D30. Exception class $C0000005 with message 'c0000005 ACCESS_VIOLATION'.


Может кто-нибудь пересекался с такой проблемой и знает как нужно модифицировать код для x64 проектов? ЗС

Модератор: Как мне оформить свое сообщение?
...
Рейтинг: 0 / 0
Загрузка dll-ресурса из памяти для x64
    #39422808
__Avenger__
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
kopiev,

Ну как минимум:

1.
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
function _GetImageSnapByOrdinal(AOrdinal: NativeUInt): boolean; stdcall; inline;
begin
  {$IFDEF WIN64}
  Result := (AOrdinal and IMAGE_ORDINAL_FLAG64 <> 0);
  {$ELSE}
  Result := (AOrdinal and IMAGE_ORDINAL_FLAG32 <> 0);
  {$ENDIF}
end;



2. Заменить в _MemoryLoadLibary все PAGE_READWRITE на PAGE_EXECUTE_READWRITE.

3. Убрать packed на _IMAGE_IMPORT_DESCRIPTOR и _IMAGE_BASE_RELOCATION.
...
Рейтинг: 0 / 0
Загрузка dll-ресурса из памяти для x64
    #39423311
__Avenger__
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
__Avenger__kopiev,
Ну как минимум:
2. Заменить в _MemoryLoadLibary все PAGE_READWRITE на PAGE_EXECUTE_READWRITE.


2-е достаточно сделать здесь:

Код: pascal
1.
2.
3.
4.
    // Commit memory block and copy data from DLL
    pDest := VirtualAlloc(Pointer(NativeUInt(pCodebase) +
      pSection.VirtualAddress), pSection.SizeOfRawData, MEM_COMMIT,
      PAGE_EXECUTE_READWRITE);
...
Рейтинг: 0 / 0
Загрузка dll-ресурса из памяти для x64
    #39423493
kopiev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Спсб, попробовал, у меня выдает ту же ошибку. Те же библиотеки (выгруженные в файл) работают через LoadLibrary(), GetProcAddress() and FreeLibrary(). Так что, похоже нужны еще какие-то корректировки.
...
Рейтинг: 0 / 0
Загрузка dll-ресурса из памяти для x64
    #39423526
Авн
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
kopiev,

У меня с данными корректировками на х64 все работает.
...
Рейтинг: 0 / 0
Период между сообщениями больше года.
Загрузка dll-ресурса из памяти для x64
    #39908848
Alex_xelA
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Здравствуйте, проблема повторяется под win32, либу собрали в новой версии visual studio, появилась ошибка AV при вызове функции:
Код: pascal
1.
bSuccessfull := rDllEntry(NativeUInt(pCode), DLL_PROCESS_ATTACH, nil);



Подскажите, пж, как победить эту багу?
...
Рейтинг: 0 / 0
6 сообщений из 6, страница 1 из 1
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Загрузка dll-ресурса из памяти для x64
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]