Thema: Delphi Inject DLL from Memory

Einzelnen Beitrag anzeigen

brechi

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

Re: Inject DLL from Memory

  Alt 15. Sep 2008, 12:44
Vorläufige Version (in der Mittagspause gemacht, funktioniert aber noch nicht richtig, denke wegen den 3 Parametern bei DllMain)
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;

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;
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, 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) then begin
                  hThread := CreateRemoteThread(hProcessHandle, nil, 0, @DllMain, nil, 0, dwThreadID);
                  if hThread <> 0 then begin
                    Result := True;
                    CloseHandle(hThread);
                  end;
                end else begin
                  VirtualFreeEx(hProcessHandle, pMemProcess, dwMemSize, MEM_DECOMMIT);
                end;
              end;
            end;
            VirtualFree(pMemLocal, dwMemSize, MEM_DECOMMIT);
          end;
        end;
        VirtualFree(pFileMem, fsLibrary.Size, MEM_DECOMMIT);
      end;
    end;
    CloseHandle(hProcessHandle);
  end;
end;

procedure TForm12.FormCreate(Sender: TObject);
var
  fm: TFileStream;
begin
  fm := TFileStream.Create(ExtractFilePath(Paramstr(0))+'test.dll', fmOpenRead);
  LoadLibraryEx(fm, GetCurrentProcessID);
  fm.Free;
end;
jep liegt an dem RemoteThread, dies funcktioniert:
muss man noch bisl Code injezieren um DllMain richtig aufzurufen
vill schaffst das selber, ansonsten meld ich mich vill heute abend

Delphi-Quellcode:
                  //hThread := CreateRemoteThread(hProcessHandle, nil, 0, @DllMain, nil, 0, dwThreadID);
                  DllMain(0, DLL_PROCESS_ATTACH, 0);
  Mit Zitat antworten Zitat