Thema: Delphi Inject DLL from Memory

Einzelnen Beitrag anzeigen

brechi

Registriert seit: 30. Jan 2004
823 Beiträge
 
#14

Re: Inject DLL from Memory

  Alt 19. Sep 2008, 16:25
Delphi-Quellcode:
function LoadLibraryEx(const fsLibrary: TStream; dwProcessID: DWord): Boolean; stdcall;
type
  TRelocBlock = packed record
    dwAddress: DWord;
    dwSize: DWord;
  end;
  PRelocBlock = ^TRelocBlock;

  TImportBlock = packed record
    dwCharacteristics: DWord;
    dwTimeDateStamp: DWord;
    dwForwarderChain: DWord;
    dwName: DWord;
    pFirstThunk: Pointer;
  end;
  PImportBlock = ^TImportBlock;

  TImportNameBlock = packed record
    wHint: Word;
    pName: PChar;
  end;
  PImportNameBlock = ^TImportNameBlock;

  procedure ChangeReloc(POrigBase, PBaseTemp, PReloc, PBaseTarget: Pointer; dwRelocSize: DWord); stdcall;
  var
    pCurrentRelocBlock: PRelocBlock;
    RelocCount: DWord;
    PCurrentStart: PWord;
    i: Integer;
    pRelocAddress: PInteger;
    iDif: Integer;
  begin
    pCurrentRelocBlock := PReloc;
    iDif := Integer(PBaseTarget) - Integer(POrigBase);
    PCurrentStart := Pointer(Integer(PReloc) + 8);
    while (not isBadReadPtr(pCurrentRelocBlock, SizeOf(TRelocBlock))) and
      (not isBadReadPtr(pCurrentStart, SizeOf(Pointer))) and
      (DWord(pCurrentRelocBlock) < DWord(pReloc) + dwRelocSize) do begin
      RelocCount := (pCurrentRelocBlock^.dwSize - 8) div SizeOf(Word);
      for i := 0 to RelocCount - 1 do begin
        if (not isBadReadPtr(pCurrentStart, SizeOf(Pointer))) and
          (PCurrentStart^ xor $3000 < $1000) then begin
          pRelocAddress := Pointer(pCurrentRelocBlock^.dwAddress + PCurrentStart^ mod $3000 + DWord(PBaseTemp));
          if (not isBadWritePtr(pRelocAddress, SizeOf(Integer))) then
            pRelocAddress^ := pRelocAddress^ + iDif;
        end;
        PCurrentStart := Pointer(DWord(PCurrentStart) + SizeOf(Word));
      end;
      pCurrentRelocBlock := Pointer(PCurrentStart);
      pCurrentStart := Pointer(DWord(PCurrentStart) + 8);
    end;
  end;

  procedure CreateImportTable(pLibraryHandle, pImportTable: pointer); stdcall;
  var
    pIBlock: PImportBlock;
    pThunksRead: PDWord;
    pThunksWrite: PDWord;
    pDllName: PChar;
    dwLibraryHandle: DWord;
    dwOldProtect: DWord;
  begin
    pIBlock := pImportTable;
    while (not isBadReadPtr(pIBlock, SizeOf(TImportBlock))) and
      (pIBlock^.pFirstThunk <> nil) and (pIBlock^.dwName <> 0) do begin
      pDllName := Pointer(DWord(pLibraryHandle) + DWord(pIBlock^.dwName));
      if (not isBadReadPtr(pDllName, 4)) then begin
        dwLibraryHandle := LoadLibrary(pDllName);
        pThunksRead := Pointer(DWord(pIBlock^.pFirstThunk) + DWord(pLibraryHandle));
        pThunksWrite := pThunksRead;
        if (DWord(pIBlock^.dwTimeDateStamp) = $FFFFFFFF) then
          pThunksRead := Pointer(DWord(pIBlock^.dwCharacteristics) + DWord(pLibraryHandle));
        while (not isBadReadPtr(pThunksRead, SizeOf(DWord))) and
          (not isBadReadPtr(pThunksWrite, SizeOf(Word))) and
          (pThunksRead^ <> 0) do begin
          if VirtualProtect(pThunksWrite, SizeOf(DWord), PAGE_EXECUTE_READWRITE, dwOldProtect) then begin
            if (DWord(pThunksRead^) and $80000000 <> 0) then
              pThunksWrite^ := DWord(GetProcAddress(dwLibraryHandle, PChar(pThunksRead^ and $FFFF)))
            else
              pThunksWrite^ := DWord(GetProcAddress(dwLibraryHandle, PChar(DWord(pLibraryHandle) + pThunksRead^ + SizeOf(Word))));
            VirtualProtect(pThunksWrite, SizeOf(DWord), dwOldProtect, dwOldProtect);
          end;
          Inc(pThunksRead);
          Inc(pThunksWrite);
        end;
      end;
      pIBlock := Pointer(DWord(pIBlock) + SizeOf(TImportBlock));
    end;
  end;

  procedure StartDll(dwDllHandle: DWord); stdcall;
  asm
    MOV EBX, DWORD PTR [dwDllHandle]
    CALL @@J
    @@J:
    POP EAX
    AND EAX, $FFFFF000
    MOV EAX, DWORD PTR [EAX]
    PUSH 0
    PUSH DLL_PROCESS_ATTACH
    PUSH EBX
    CALL EAX
  end;
  procedure EndDll; asm end;


var
  DllMain: function(dwHandle, dwReason, dwReserved: DWord): DWord; stdcall;
  IDH: PImageDosHeader;
  INH: PImageNtHeaders;
  SEC: PImageSectionHeader;
  dwSecCount: DWord;
  dwmemsize: DWord;
  i: Integer;
  pFileMem: Pointer;
  pMemLocal: Pointer;
  pMemProcess: Pointer;
  hProcessHandle: THandle;
  dwWritten: DWord;
  hThread: THandle;
  dwThreadID: DWord;
  ThreadStart: function(_Param: Pointer): Integer; stdcall;
begin
  Result := False;
  // ProcessHandle holen um Speicher für DLL zu allozieren und RemoteThread zu starten
  hProcessHandle := OpenProcess(PROCESS_ALL_ACCESS, false, dwProcessID);
  if hProcessHandle <> 0 then begin
    // für den Stream speicher holen um leichter auf die Daten zuzugreifen
    pFileMem := VirtualAlloc(nil, fsLibrary.Size, MEM_COMMIT or MEM_RESERVE, PAGE_EXECUTE_READWRITE);
    if (pFileMem <> nil) then begin
      fsLibrary.Position := 0;
      fsLibrary.Read(pFileMem^, fsLibrary.Size);
      IDH := pFileMem;
      // ImageDosHeader gültig?
      if (not isBadReadPtr(IDH, SizeOf(TImageDosHeader))) and
        (IDH^.e_magic = IMAGE_DOS_SIGNATURE) then begin
        // ImageNtHeader gültig?
        INH := pointer(cardinal(pFileMem) + cardinal(IDH^._lfanew));
        if (not isBadReadPtr(INH, SizeOf(TImageNtHeaders))) and
          (INH^.Signature = IMAGE_NT_SIGNATURE) then begin
          SEC := Pointer(Integer(INH) + SizeOf(TImageNtHeaders));

          // Virtuelle größe der Dll/Exe ermitteln
          dwMemSize := INH^.OptionalHeader.SizeOfImage;
          if (dwMemSize <> 0) then begin
            // Lokalen speicher für die DLL holen (wir bereiten die in userem Prozess vor)
            pMemLocal := VirtualAlloc(nil, dwMemSize, MEM_COMMIT or MEM_RESERVE, PAGE_EXECUTE_READWRITE);
            if (pMemLocal <> nil) then begin
              // Speicher aus dem Fremdprozess holen (indem wir die dll nachher kopieren und ausführen)
              pMemProcess := VirtualAllocEx(hProcessHandle, nil, dwMemSize+$1000, MEM_COMMIT or MEM_RESERVE, PAGE_EXECUTE_READWRITE);
              if pMemProcess <> nil then begin

                // jede Sektion and die richtige Adresse kopieren
                dwSecCount := INH^.FileHeader.NumberOfSections;
                CopyMemory(pMemLocal, IDH, DWord(SEC) - DWord(IDH) + dwSecCount * SizeOf(TImageSectionHeader));
                for i := 0 to dwSecCount - 1 do begin
                  CopyMemory(Pointer(DWord(pMemLocal) + SEC^.VirtualAddress),
                    Pointer(DWord(pFileMem) + DWord(SEC^.PointerToRawData)),
                    SEC^.SizeOfRawData);
                  SEC := Pointer(Integer(SEC) + SizeOf(TImageSectionHeader));
                end;

                // Adressen der Dll für den Zielprozess anpassen
                if (INH^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress <> 0) then begin
                  ChangeReloc(Pointer(INH^.OptionalHeader.ImageBase),
                    pMemLocal,
                    Pointer(DWord(pMemLocal) + INH^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress),
                    Pointer(pMemProcess),
                    INH^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size);
                end;

                // die Importtabelle anpassen, die Adressen holen wir lokal aus unserem Prozess
                // sollte die Dll nicht im Zielprozess geladen sein -> crash
                // theoretisch kann man diese auch aus dem Zielprozess ermitteln
                // und fehlende Dlls dort ebenfalls nachladen
                // aber jetzt nicht hier behandelt, da dll die in einen Fremdprozess injeziert werden
                // IMMER nur ntdll/kernel32/(user32 falls Prozess mit Fenster) Funktionen benutzen sollen
                CreateImportTable(pMemLocal, Pointer(DWord(pMemLocal) + INH^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress));

                // bei DLL-Main einen Thread starten
                @DllMain := Pointer(INH^.OptionalHeader.AddressOfEntryPoint + DWord(pMemProcess));
                if WriteProcessMemory(hProcessHandle, pMemProcess, pMemLocal, dwMemSize, dwWritten) and (dwWritten = dwMemSize) and
                   WriteProcessMemory(hProcessHandle, Pointer(DWord(pMemProcess)+dwMemSize), @@DllMain, 4, dwWritten) and (dwWritten = 4) and
                   WriteProcessMemory(hProcessHandle, Pointer(DWord(pMemProcess)+dwMemSize+4), @StartDll, Integer(@EndDll)-Integer(@StartDll), dwWritten) then begin
                  @ThreadStart := Pointer(DWord(pMemProcess)+dwMemSize+4);
                  //ThreadStart(nil);
                  hThread := CreateRemoteThread(hProcessHandle, nil, 0, @ThreadStart, nil, 0, dwThreadID);
                  if hThread <> 0 then begin
                    Result := True;
                    CloseHandle(hThread);
                  end;
                end else begin
                  VirtualFreeEx(hProcessHandle, pMemProcess, dwMemSize+$1000, MEM_DECOMMIT);
                end;
              end;
            end;
            VirtualFree(pMemLocal, dwMemSize, MEM_DECOMMIT);
          end;
        end;
        VirtualFree(pFileMem, fsLibrary.Size, MEM_DECOMMIT);
      end;
    end;
    CloseHandle(hProcessHandle);
  end;
end;
Davon ab verstehe ich aber nicht warum du nicht InjectMe verwendest. Diese ist genua dafür gedacht dll&exe in einem Programm zu haben und die Exe dann zu injecten wobei dort dann andere Funktionen (die z.b. von der Dll) ausgeführt werden können. Gerade jetzt mach ich mir wieder Gedanken ob ich den Code oben umsonst programmiert habe. Jedenfalls hätte ich dir direkt zu InjectMe geraten wenn du mir dein Anliegen erklärt hättest.
  Mit Zitat antworten Zitat