Модераторы: Snowy, bartram, MetalFan, bems, Poseidon, Riply

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Перехват вызова API под x64 
:(
    Опции темы
over
Дата 11.7.2013, 18:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 31
Регистрация: 8.7.2008

Репутация: нет
Всего: нет



Пытаюсь перехватить вызов MessageBoxW под х64, инструкцию меняю следующим кодом:

Код

  hm := GetModuleHandle('user32.dll');
  pa := GetProcAddress(hm, 'MessageBoxW');
  if not VirtualProtect(pa, SizeOf(Pointer) + 1, PAGE_EXECUTE_READWRITE, OldProtect) then Exit;
  byte(pa^) := $E9;
  DWORD(Pointer(DWORD(pa) + 1)^) :=  DWORD(@NewMessageBoxW) - DWORD(pa) - (SizeOf(Pointer) + 1);


В x32 отрабатывает как нужно (и в своем приложении и через dll)
В x64 работает, но на половину, т.е. в своем приложении все ок, а если перенести этот код в dll и подгрузить ее - ошибка на вызове MessageBoxW

В чем может быть причина? 

Это сообщение отредактировал(а) Poseidon - 12.7.2013, 09:18
PM MAIL   Вверх
over
Дата 11.7.2013, 18:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 31
Регистрация: 8.7.2008

Репутация: нет
Всего: нет



Вроде понял в чем причина,

DWORD(@NewMessageBoxW) - DWORD(pa) - (SizeOf(Pointer) + 1) - при использотивании в dll, длина прыжка > 2гб.

Теперь другая проблема как обойти эту проблему, ведь всегда есть универсальный способ..


PM MAIL   Вверх
Illusion Dolphin
Дата 11.7.2013, 19:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник Клуба
Сообщений: 1198
Регистрация: 3.5.2003

Репутация: 4
Всего: 63



Ошибка как минимум тут:
Код

DWORD(pa) 

и тут
Код

DWORD(@NewMessageBoxW)

Для этого теперь используйте NativeInt/NativeUInt. По моему опыту такого править надо много где smile В инете все  примеры кривые.


--------------------
В мире всего две бесконечности: вселенная и человеческая глупость... На счёт вселенной я не уверен.
Шифрование и организация фотографий - Photo Database 4.5
PM MAIL WWW ICQ   Вверх
over
Дата 11.7.2013, 19:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 31
Регистрация: 8.7.2008

Репутация: нет
Всего: нет



пробовал и с NativeInt, но не помогло (
PM MAIL   Вверх
Illusion Dolphin
Дата 11.7.2013, 19:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник Клуба
Сообщений: 1198
Регистрация: 3.5.2003

Репутация: 4
Всего: 63



Цитата

пробовал и с NativeInt, но не помогло ( 

Значит ошибка в 17й строчке


--------------------
В мире всего две бесконечности: вселенная и человеческая глупость... На счёт вселенной я не уверен.
Шифрование и организация фотографий - Photo Database 4.5
PM MAIL WWW ICQ   Вверх
over
Дата 11.7.2013, 21:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 31
Регистрация: 8.7.2008

Репутация: нет
Всего: нет



тут видимо проблема в длине прыжка, которая в некоторых случаях больше 2gb
PM MAIL   Вверх
Illusion Dolphin
Дата 11.7.2013, 22:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник Клуба
Сообщений: 1198
Регистрация: 3.5.2003

Репутация: 4
Всего: 63



Цитата

тут видимо проблема в длине прыжка, которая в некоторых случаях больше 2gb 

Проблема в том, что длинна указателя - 8 байт вместо 4 под x86 и всё. Проверяйте вычисления, убирая Cardinal, Integer, DWORD и другую глупость. 


--------------------
В мире всего две бесконечности: вселенная и человеческая глупость... На счёт вселенной я не уверен.
Шифрование и организация фотографий - Photo Database 4.5
PM MAIL WWW ICQ   Вверх
Illusion Dolphin
Дата 12.7.2013, 10:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник Клуба
Сообщений: 1198
Регистрация: 3.5.2003

Репутация: 4
Всего: 63



Кстати, я в своём коде (работает под 32/64) не заметил установки опкодов $E9 (JMP), возможно, что стоит кроме того пересмотреть алгоритм сплайсинга.

Добавлено через 6 минут и 46 секунд
И не забывайте восстанавливать старые права через VirtualProtect и FlushInstructionCache рекомендуется также. 


--------------------
В мире всего две бесконечности: вселенная и человеческая глупость... На счёт вселенной я не уверен.
Шифрование и организация фотографий - Photo Database 4.5
PM MAIL WWW ICQ   Вверх
over
Дата 12.7.2013, 11:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 31
Регистрация: 8.7.2008

Репутация: нет
Всего: нет



Уже всю голову сломал, как только не пробовал.. наверное что то упускаю.. Если не сложно, приведите рабочий участок кода перехвата.
PM MAIL   Вверх
Illusion Dolphin
Дата 12.7.2013, 12:31 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник Клуба
Сообщений: 1198
Регистрация: 3.5.2003

Репутация: 4
Всего: 63



Вот такой, с вас пиво  smile :
Код

function GetActualAddr(Proc: Pointer): Pointer;
type
  PAbsoluteIndirectJmp = ^TAbsoluteIndirectJmp;
  TAbsoluteIndirectJmp = packed record
    OpCode: Word;   //$FF25(Jmp, FF /4)
    Addr: Cardinal;
  end;
var J: PAbsoluteIndirectJmp;
    P: PPointer;
begin
  J := PAbsoluteIndirectJmp(Proc);
  if (J.OpCode = $25FF) then
  begin
    {$ifdef Win32}
    P := PPointer(J.Addr);
    {$endif}
    {$ifdef Win64}
    P := PPointer(TNativeUInt(Proc) + J.Addr + 6{Instruction Size});
    {$endif}
    if IsBadReadPtr(P, SizeOf(NativeUInt)) then
      Exit(nil);
    Result := P^;
  end else
    Result := Proc;
end;

function HookCode(PEModule: HModule; Recursive: Boolean; TargetAddress, NewAddress: Pointer; var OldAddress: Pointer): Integer;
var
  HookedModules: string;

  function HookModule(ImageDosHeader: PImageDosHeader; TargetAddress, NewAddress: Pointer; var OldAddress: Pointer): Integer;
  var
    Address: Pointer;
    ImportCode: ^Pointer;
    BytesWritten: NativeUInt;
    ImageNTHeaders: PImageNTHeaders;
    ImageImportEntry: ^TImageImportEntry;
    Module: string;
    OldProtect: Cardinal;
    ModuleHandle: HModule;
  begin
    Result := 0;

    if OldAddress = nil then
      OldAddress := GetActualAddr(TargetAddress);

    //check the header and see if there is one, if there isn't then exit hook routine
    If ImageDosHeader.e_magic <> IMAGE_DOS_SIGNATURE then Exit;
    //Loads the API headers into ImageNTHeaders
    ImageNTHeaders := Pointer(NativeInt(ImageDosHeader) + ImageDosHeader._lfanew);

    //checks if there are API header? (I think)
    If ImageNTHeaders^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = 0 then Exit;
    //Gets just the API header addresses? (I think)
    ImageImportEntry := Pointer(NativeUInt(ImageDosHeader) + ImageNTHeaders^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);

    //Loops through each API header looking for the name you specified ready to patch!
    while ImageImportEntry^.Name <> 0 do
    begin
      //If its found then go into
      Module := string(AnsiString(PAnsiChar(NativeUInt(ImageDosHeader) + ImageImportEntry^.Name)));

      if Recursive then
        if Pos(LowerCase(Module), HookedModules) = 0 then
        begin
          //Writes the redirection of API
          HookedModules := HookedModules + LowerCase(Module);
          ModuleHandle := GetModuleHandle(PWideChar(Module));
          if (ModuleHandle > 0) and (ImageDosHeader <> Pointer(ModuleHandle)) then
            HookModule(Pointer(ModuleHandle), TargetAddress, NewAddress, OldAddress);
        end;

      //Sets the Address of the Table?
      ImportCode := Pointer(NativeUInt(ImageDosHeader) + ImageImportEntry.LookupTable);

      //TODO: remove magic constant
      while (ImportCode^ <> nil) and (NativeUInt(ImportCode^) > 4) do
      begin
        Address := ImportCode^;

        if Address <> OldAddress then
          Address := GetActualAddr(Address);

        //checks address and writes our one!
        if Address = OldAddress then
        begin
          if VirtualProtect(ImportCode, SizeOf(Pointer), PAGE_EXECUTE_READWRITE, OldProtect) then
          begin
            if WriteProcessMemory(GetCurrentProcess, ImportCode, @NewAddress, SizeOf(Pointer), BytesWritten) then
            begin
              //x64_test CloseHandle(FileCreate('d:\dbg\' + IntToStr(NativeUInt(ImportCode))));
              VirtualProtect(ImportCode, SizeOf(Pointer), OldProtect, @OldProtect);
              FlushInstructionCache(GetCurrentProcess, ImportCode, SizeOf(Pointer));
              Inc(Result);
            end;
          end;
        end;

        //increment the importcode until it finds the correct address
        Inc(ImportCode);
      end;

      //keep stepping thru each API Header
      Inc(ImageImportEntry);
    end;
  end;

begin
  Result := 0;
  if PEModule > 0 then
    Result := HookModule(Pointer(PEModule), TargetAddress, NewAddress, OldAddress);
end;



--------------------
В мире всего две бесконечности: вселенная и человеческая глупость... На счёт вселенной я не уверен.
Шифрование и организация фотографий - Photo Database 4.5
PM MAIL WWW ICQ   Вверх
over
Дата 13.7.2013, 17:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 31
Регистрация: 8.7.2008

Репутация: нет
Всего: нет



Спасибо огромное, все заработало, правда пришлось немного допилить:

Код

  {$ifdef Win32}
  ImageNTHeaders : PImageNtHeaders;
  {$endif}
  {$ifdef Win64}
  ImageNTHeaders : PImageNtHeaders64;
  {$endif}


Это сообщение отредактировал(а) Poseidon - 15.7.2013, 09:26
PM MAIL   Вверх
Illusion Dolphin
Дата 13.7.2013, 20:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник Клуба
Сообщений: 1198
Регистрация: 3.5.2003

Репутация: 4
Всего: 63



Цитата

  {$ifdef Win32}
  ImageNTHeaders : PImageNtHeaders;
  {$endif}
  {$ifdef Win64}
  ImageNTHeaders : PImageNtHeaders64;
  {$endif} 

Лишнее. Смотрите Winapi.Windows.pas


--------------------
В мире всего две бесконечности: вселенная и человеческая глупость... На счёт вселенной я не уверен.
Шифрование и организация фотографий - Photo Database 4.5
PM MAIL WWW ICQ   Вверх
Чучмек
Дата 22.7.2013, 19:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


НЭТ БИЛЭТ
**


Профиль
Группа: Участник
Сообщений: 841
Регистрация: 11.5.2008
Где: СССР

Репутация: 7
Всего: 41



Перехват функции реализуется через запись  инструкции jmp по адресу функции.
Для x64 один из джампов выглядит так:
Код

48FF2501000000   jmp qword ptr [rel $00000001]

В простейшем случае (без сохранения работоспособности перехватываемой функции)
Код

type
 PJampRec64=^TJampRec64;
 TJampRec64=packed record
   jb0,jb1,jb2:byte;
   jra:Cardinal;
   rb:byte;
   fa:pointer;
 end;


function MyMessageBoxW(hWnd: HWND; lpText, lpCaption: PWideChar; uType: UINT):integer;
begin
ShowMessage('call MessageBoxW');
end;



procedure TForm1.FormCreate(Sender: TObject);
var
 JampRec64:PJampRec64;
 op:cardinal;
begin
JampRec64:=GetProcAddress(GetModuleHandle('user32.dll'),'MessageBoxW');
VirtualProtect(JampRec64,SizeOf(TJampRec64),PAGE_EXECUTE_READWRITE,op);
JampRec64^.jb0:=$48;
JampRec64^.jb1:=$FF;
JampRec64^.jb2:=$25;
JampRec64^.jra:=1;
JampRec64^.fa:=@MyMessageBoxW;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
MessageBox(0,'','',0);
end;


Добавлено @ 19:55
p.s Поправка на Illusion Dolphin 
Цитата(Чучмек @  22.7.2013,  19:47 Найти цитируемый пост)
Перехват функции реализуется через запись  инструкции jmp по адресу функции.

Или через правку таблицы импорта.


Это сообщение отредактировал(а) Чучмек - 22.7.2013, 20:02


--------------------
умную мысль держи при себе, а дурной - поделись с другими 
PM MAIL   Вверх
bems
Дата 23.7.2013, 13:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 3400
Регистрация: 5.1.2006

Репутация: 21
Всего: 88



я писал в начало перехватываемой функции jmp -8, в расчете на то что перед функцией есть минимум 6 инструкций nop
эти 6 свободных байт заменял на call qword ptr [offset], где offset указывает на место в dos-stub куда я записал абсолютный адрес функции-диспетчера хуков.
эта функция по адресу возврата на стеке (результат call qword ptr [offset]) определяет адрес хука, подменяет адрес на стеке и делает ret в хук


Это сообщение отредактировал(а) bems - 23.7.2013, 13:40


--------------------
Обижено школьников: 8
PM MAIL   Вверх
over
Дата 24.7.2013, 12:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 31
Регистрация: 8.7.2008

Репутация: нет
Всего: нет



Так и не нашел универсального способа под x64, перепробовал и через jmp и редактирование таблицы импорта..
в x64 7-ке почти все отрабатывает нормально, а под x64 XP, либо вообще не работает либо кое как (как пример, перехват MessageBoxW отрабатывает, а StartDocW из gdi32 никак не хочет).

Вот и не могу понять в чем разница..
PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Delphi: WinAPI и системное программирование"
Snowybartram
MetalFanbems
PoseidonRrader
Riply

Запрещено:

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Литературу по Delphi обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь
  • 90% ответов на свои вопросы можно найти в DRKB (Delphi Russian Knowledge Base) - крупнейшем в рунете сборнике материалов по Дельфи
  • 99% ответов по WinAPI можно найти в MSDN Library, оставшиеся 1% здесь

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Snowy, bartram, MetalFan, bems, Poseidon, Rrader, Riply.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Delphi: WinAPI и системное программирование | Следующая тема »


 




[ Время генерации скрипта: 0.0945 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.