Dll inject в 64-битный процесс

 
0
 
Delphi, Kylix and Pascal
ava
xteam777 | 03.10.2016, 12:57
Мне необходимо заинжектить свою Dll (64 бита) в 64-битный процесс. Следующий код прекрасно отрабатывает если Dll и процесс 32-битные.
Но если перекомпилировать все в 64 бита, то при отсоединении Dll, в процессе, к тоторому присоединяем вываливается Access Violation $C0000005. Подскажите в чем может быть дело.

Код инжектора:

function SetDebugPriv: Boolean;
var
  Token: THandle;
  tkp: TTokenPrivileges;
  ReturnLength: DWORD;
begin
  Result := false;
  // Получаем токен текущего процесса
  if OpenProcessToken(GetCurrentProcess, TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY, Token) then
  try
    // Получаем Luid привилегии
    if LookupPrivilegeValue(nil, PChar('SeDebugPrivilege'), tkp.Privileges[0].Luid) then
    begin
      // Заполняем необходимые параметры
      tkp.PrivilegeCount := 1;
      tkp.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED;
      // Включаем привилегию
      Result := AdjustTokenPrivileges(Token, false, tkp, 0, nil, ReturnLength);
    end;
  finally
    CloseHandle(Token);
  end;
end;

function TForm22.InjectLib(ProcessID: Integer): Boolean;
var
  Process: HWND;
  ThreadRtn: FARPROC;
  DllPath: AnsiString;
  RemoteDll: Pointer;
  BytesWriten: SIZE_T;
  Thread: DWORD;
  ThreadId: DWORD;
begin
  // Устанавливаем отладочные привилегии для нашего процесса
  Result := SetDebugPriv;
  if not Result then Exit;

  // Открываем процесс
  Process := OpenProcess(PROCESS_CREATE_THREAD or PROCESS_VM_OPERATION or
    PROCESS_VM_WRITE, True, ProcessID);
  if Process = 0 then Exit;
  try
    // Выделяем в нем память под строку
    DllPath := AnsiString({ExtractFilePath(ParamStr(0)) +} DLLName) + #0;
    RemoteDll := VirtualAllocEx(Process, nil, Length(DllPath),
      MEM_COMMIT or MEM_TOP_DOWN, PAGE_READWRITE);
    if RemoteDll = nil then Exit;
    try
      // Пишем путь к длл в его адресное пространство
      if not WriteProcessMemory(Process, RemoteDll, @DllPath[1],
        Length(DllPath), BytesWriten) then Exit;
      if BytesWriten <> DWORD(Length(DllPath)) then Exit;
      // Получаем адрес функции из Kernel32.dll
      ThreadRtn := GetProcAddress(GetModuleHandle('Kernel32.dll'), 'LoadLibraryA');
      if ThreadRtn = nil then Exit;
      // Запускаем удаленный поток
      Thread := CreateRemoteThread(Process, nil, 0, ThreadRtn, RemoteDll, 0, ThreadId);
      if Thread = 0 then Exit;
      try
        // Ждем пока удаленный поток отработает...
        Result := WaitForSingleObject(Thread, INFINITE) = WAIT_OBJECT_0;
      finally
        CloseHandle(Thread);
      end;
    finally
      VirtualFreeEx(Process, RemoteDll, 0, MEM_RELEASE);
    end;
  finally
    CloseHandle(Process);
  end;
end;

//  Данная функция запускает в удаленном процессе поток
//  который стартует с инструкции JMP [EBX]
//  В EBX будет лежать адрес функции SelfUnload,
//  который будет выгружать библиотеку.
//  Адрес функции рассчитывается отдельно и равен
//  адресу загрузки библиотеки + смещение на саму функцию
// =============================================================================
function TForm22.EjectLib(ProcessID: Integer): Boolean;
var
  hLibHandle: THandle;
  hModuleSnap: THandle;
  ModuleEntry: TModuleEntry32;
  OpCodeData: Word;
  Process: HWND;
  BytesWriten: SIZE_T;
  Thread: DWORD;
  ThreadId: DWORD;
  ExitCode: DWORD;
  PLibHandle: PDWORD;
  OpCode: PWORD;
  CurrUnloadAddrOffset: DWORD;
  UnloadAddrOffset: DWORD;
begin
  // Устанавливаем отладочные привилегии для нашего процесса
  Result := SetDebugPriv;
  if not Result then Exit;

  // рассчитываем оффсет адреса выгрузки библиотеки относительно адреса ее загрузки
  hLibHandle := LoadLibrary(PChar(DLLName));
  try
    UnloadAddrOffset :=
      DWORD(GetProcAddress(hLibHandle, 'SelfUnload')) - hLibHandle;
    if UnloadAddrOffset = -hLibHandle then Exit;
  finally
    FreeLibrary(hLibHandle);
  end;

  // Находим адрес библиотеки в чужом адресном пространстве
  hModuleSnap := CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, ProcessID);
  if hModuleSnap <> INVALID_HANDLE_VALUE then
  try
    FillChar(ModuleEntry, SizeOf(TModuleEntry32), #0);
    ModuleEntry.dwSize := SizeOf(TModuleEntry32);
    if not Module32First(hModuleSnap, ModuleEntry) then Exit;
    repeat
      if AnsiUpperCase(ModuleEntry.szModule) =
        AnsiUpperCase(ExtractFileName(DLLName)) then
      begin
        // Получаем адрес функции выгрузки
        CurrUnloadAddrOffset := ModuleEntry.hModule + UnloadAddrOffset;
        Break;
      end;
    until not Module32Next(hModuleSnap, ModuleEntry);
  finally
    CloseHandle(hModuleSnap);
  end;

  if CurrUnloadAddrOffset = 0 then
  begin
    lbStatus.Items.Add('Library has not injected.');
    Exit;
  end;

  // Открываем процесс
  Process := OpenProcess(PROCESS_CREATE_THREAD or PROCESS_VM_OPERATION or
    PROCESS_VM_WRITE, True, ProcessID);
  if Process = 0 then Exit;
  try
    // Пишем опкод jmp [ebx]
    OpCode := VirtualAllocEx(Process, nil, 2,
      MEM_COMMIT or MEM_TOP_DOWN, PAGE_READWRITE);
    if OpCode = nil then Exit;
    try
      OpCodeData := $23FF;
      if not WriteProcessMemory(Process, OpCode, @OpCodeData,
        2, BytesWriten) then Exit;

      // Пишем адрес функции выгрузки (он будет лежать в EBX при старте потока)
      PLibHandle := VirtualAllocEx(Process, nil, 4,
        MEM_COMMIT or MEM_TOP_DOWN, PAGE_READWRITE);
      if PLibHandle = nil then Exit;
      try
        if not WriteProcessMemory(Process, PLibHandle, @CurrUnloadAddrOffset,
          4, BytesWriten) then Exit;

        // запускаем поток
        Thread := CreateRemoteThread(Process, nil, 0, OpCode,
          PLibHandle, 0, ThreadId);
        if Thread = 0 then Exit;
        try
          // Ждем пока удаленный поток отработает...
          if (WaitForSingleObject(Thread, INFINITE) = WAIT_OBJECT_0) then
            if GetExitCodeThread(Thread, ExitCode) then
              Result := ExitCode = 0;
        finally
          CloseHandle(Thread);
        end;
      finally
        VirtualFreeEx(Process, PLibHandle, 0, MEM_RELEASE);
      end;
    finally
      VirtualFreeEx(Process, OpCode, 0, MEM_RELEASE);
    end;
  finally
    CloseHandle(Process);
  end;
end;



Код Dll:

procedure DLLEntryPoint(dwReason: DWORD);
begin
  case dwReason of
    DLL_PROCESS_ATTACH:
    begin
      MessageBoxA(0, 'Injected', 'Injected', MB_OK);
      // coCreateInstance hook
      //HookAPI( 'ole32.dll', 'CoCreateInstance', @CoCreateInstance_cb, @CoCreateInstance_np);
//      CoCreateInstance_np := InterceptCreate('ole32.dll', 'CoCreateInstance', @CoCreateInstance_cb);

      // инициализируем структуру для перехватчика
      //InitHotPatchSpliceRec;
      // пишем прыжок в область NOP-ов
      //SpliceNearJmp(PAnsiChar(HotPathSpliceRec.FuncAddr) - 5, HotPathSpliceRec.SpliceRec);
      // перехватываем MessageBoxW
      //SpliceLockJmp(HotPathSpliceRec.FuncAddr, LOCK_JMP_OPKODE);
    end;
    DLL_PROCESS_DETACH:
    begin
      MessageBoxA(0, 'Rejected', 'Rejected', MB_OK);
      // при выгрузке библиотеки снимаем перехват
      //SpliceLockJmp(HotPathSpliceRec.FuncAddr, HotPathSpliceRec.LockJmp);

//      InterceptRemove(@CoCreateInstance_np);
    end;
  end;
end;

procedure SelfUnload(lpParametr: Pointer); stdcall;
begin
  FreeLibraryAndExitThread(HInstance, 0);
end;

exports
  SelfUnload;

begin
  DLLProc := @DLLEntryPoint;
  DLLEntryPoint(DLL_PROCESS_ATTACH);
end.
Ответы (5)
ava
xteam777 | 04.10.2016, 09:34 #
UP
ava
xteam777 | 05.10.2016, 13:19 #
Спасибо. Но у меня проблема не в определении разрядности Windows. Проблема в том, что выложенный код отлично работает в связке 32bit Injector + 32bit Dll + 32bit Targer processs, а при перекомпиляции всех участников в 64bit Injector + 64bit Dll + 64bit Targer processs, при выгрузке Dll в Target process AV $C0000005. Все тесты выполняются в Win 10 x64.
ava
_zorn_ | 06.10.2016, 15:43 #
А у вас прав то хоть хватает в системе на такие варварские операции ? Под админом пробовали запускать ?
Хотя скорей всего и это не поможет. Вам наверное невдомек что помимо разрядности ОЧЕНЬ СИЛЬНО влияет и версия операционной системы.
Вы УВЕРЕНЫ, что ваш код будет работать на х32 win10 ?
ava
kami | 14.10.2016, 18:55 #

OpCodeData := $23FF;

Думаю, что 32-битные машинные коды как минимум не должны отработать на 64 битах. ASM-то отличается. И разрядности регистров тоже.
Зарегистрируйтесь или войдите, чтобы написать.
Фирма дня
Вы также можете добавить свою фирму в каталог IT-фирм, и публиковать статьи, новости, вакансии и другую информацию от имени фирмы.
Подробнее
Участники
advanced
Отправить