Конференция "WinAPI" » Выгрузка WinApi перехватчика [D7, WinXP]
 
  • KygECHuK © (26.08.08 10:33) [0]
    занимаюсь автоматизированным тестированием, оформил плагин для перехвата отрисовки текста. он подменяет адресса к функциям в таблице импорта, в моём случае это textOut в GDI32.dll. Всё работает хорошо, вот только что при выгрузке перхватчика с некоторойй вероятностью появлятся ошибка доступа к памяти...

    Возможно кто нибудь занимался подомной проблематикой и может что нибудь посоветовать...
  • Сергей М. © (26.08.08 11:21) [1]

    > подменяет адресса к функциям в таблице импорта


    Для полноценного перехвата в произвольном приложении этого недостаточно - необходим еще и перехват соотв.записей в EAT.


    > с некоторойй вероятностью появлятся ошибка доступа к памяти


    Слишком мало инф-ции для анализа.
  • KygECHuK © (26.08.08 12:02) [2]

    > Для полноценного перехвата в произвольном приложении этого
    > недостаточно - необходим еще и перехват соотв.записей в
    > EAT.

    Здесь, пожалуйста, поподробней...


    > Слишком мало инф-ции для анализа.


    я в таком же положении - ошибка не имеет какойто опрелённой стабильности.
    Иследуя проблему, пришел к выводу что ошибка МОЖЕТ появляться из-за того, что в момент выгрузки данна функция используется в основном потоке,
    и соответсвенно при работе со стеком происходит оно..
  • Сергей М. © (26.08.08 12:23) [3]

    > поподробней


    Вызывающий модуль вправе и может получить адрес т.входа в требуемую подпрограмму вызываемого модуля и прямо в ран-тайм, т.е. с пом. a-wbb GetProcAddress, которая как раз и обращается к EAT вызываемого модуля.

    Отсюда вывод - либо модифицировать EAT, либо перехватывать в IAT вход в GetProcAddress с целью подмены оригинальных адресных значений из EAT требуемыми адресами точек входа.
  • KygECHuK © (26.08.08 12:39) [4]

    > либо перехватывать в IAT вход в GetProcAddress с целью подмены
    > оригинальных адресных значений из EAT требуемыми адресами
    > точек входа.

    Вы имеете ввиду следующее ?
    function MyLoadLibraryA(
     pszModuleName: pChar
     ): HMODULE; stdcall;
    begin
     sm_pInstance.funcEvent.ResetEvent;
      // debug
     sm_pInstance.funcEvent.CurFuncName := 'MyLoadLibraryA';
     //

     try
      Result := LoadLibraryA(pszModuleName);
       TModuleScope(sm_pModuleScope).LogMessage(pChar('Подгружена библиотека :' + pszModuleName));
      TApiHookMgr.HackModuleOnLoad(Result, 0);
     finally
       sm_pInstance.funcEvent.setEvent;
     end
    end;

    class procedure TApiHookMgr.HackModuleOnLoad(hmod: HMODULE; dwFlags: Cardinal);
    var
     lockMgr : TLockMgr;
     i       : Integer;
     Hook    : THookedFunction;
    begin
    // Если был загружен новый модуль то тоже вставим перехватчик
    if ((hmod <> 0) and ((dwFlags and LOAD_LIBRARY_AS_DATAFILE) = 0)) then
    begin
     lockMgr := TLockMgr.Create(sm_CritSec, TRUE);
       try
       for i := 0 to sm_pHookedFunctions.Count - 1 do
         begin
           Hook := sm_pHookedFunctions[i];
        Hook.ReplaceInOneModule(
         Hook.CalleeModName,
         Hook.pfnOrig,
         Hook.pfnHook,
         hmod
         );
       end; // for
       finally
         lockMgr.Free;
       end;
    end // if
    end;

    function MyGetProcAddress(hModule: HMODULE; lpProcName: LPCSTR): FARPROC; stdcall;
    var
     lockMgr  : TLockMgr;
     pfn      : pointer;
     FuncHook : THookedFunction;
    begin
      sm_pInstance.funcEvent.ResetEvent;
      // debug
     sm_pInstance.funcEvent.CurFuncName := 'MyGetProcAddress';
     //

     try

       lockMgr := TLockMgr.Create(sm_CritSec, TRUE);
       try
         // получение оргинального адресса функции
         pfn := Pointer(TApiHookMgr.GetProcAddressWindows(hModule, lpProcName));
         //  попытка найти если функция была сломана
         FuncHook :=
           sm_pHookedFunctions.GetHookedFunction(
             hModule,
             lpProcName
             );

         if (nil <> FuncHook) then
           // возаращаем адрес перехваченной функции
           pfn := FuncHook.pfnHook;
         Result := pfn;
       finally
         lockMgr.Free;
       end;
     finally
       sm_pInstance.funcEvent.setEvent;
     end;

     TModuleScope(sm_pModuleScope).LogMessage(pChar('В библиотеке :' + GetModuleName(hModule) +
                                                    ' запрошена функция :'+ lpProcName));

    end;


  • Сергей М. © (26.08.08 12:45) [5]
    Да.
  • KygECHuK © (26.08.08 12:50) [6]
    локонично :)

    А моё предполежение насчёт стека может иметь какой нибуть вес?
    з. ы. Сам просто только в догадках.
  • Сергей М. © (26.08.08 12:51) [7]

    > предполежение насчёт стека может иметь какой нибуть вес?


    Скорее нет чем да.
  • Сергей М. © (26.08.08 12:54) [8]
    Вне сомнения лишь одно - пока выполняется код, принадлежащий адр.пространству, занимаемому модулем, выгружать этот модуль недопустимо.
  • KygECHuK © (26.08.08 14:09) [9]

    > Вне сомнения лишь одно - пока выполняется код, принадлежащий
    > адр.пространству, занимаемому модулем, выгружать этот модуль
    > недопустимо.

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

    я насильственно ни один модуль не выгражую.

    Но так или иначе, возможно следует попробывать вариант с синхронизацией доступа к целевым функцииям?
  • Сергей М. © (26.08.08 15:47) [10]

    > под выгрузкой ловушки я подразумевал замену подстваленных
    > адресов на оригинальные


    Выгрузкой это назвать никак нельзя.


    > насильственно ни один модуль не выгражую


    А как он, модуль, у тебя вообще попадает в АП "жертвы" ?


    > синхронизацией доступа к целевым функцииям?


    если ты не выгружаешь модуль из АП процесса-"жертвы" вплоть до его завершения, то синхронизация вряд ли имеет смысл.
  • KygECHuK © (26.08.08 16:35) [11]

    > А как он, модуль, у тебя вообще попадает в АП "жертвы" ?


    Да, действительно.. сдесь я напутал (тока из месячного отпуска вышел :) )...
    Надо будет на этим подумать


    > если ты не выгружаешь модуль из АП процесса-"жертвы" вплоть
    > до его завершения, то синхронизация вряд ли имеет смысл.
    >

    приложение в основном и работает с активным выводом текстовой информации и если перехватчик вовремя не выгрузить, это приведёт  к  потере производительности. И хочется сделать плагин правильно..

    в купе с вашим предыдущим замечанием и моим стремлением удачно выгрузить модуль получается, что поток выгружающий библиотеку действительно придеться синхронизировать с основным потоком, чтобы оградить и АП.

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

    Вот только как сделать синхронизацию с чужим потоком? Пока ума не приложу...
  • Rouse_ © (26.08.08 16:43) [12]

    > Вот только как сделать синхронизацию с чужим потоком? Пока
    > ума не приложу...

    Дык как... как обычно вестимо:
    Остановить все потоки процесса за исключением своего, из которого снимаешь перехватчик. Снять перехватчик и запустить потоки далее.
  • Сергей М. © (26.08.08 16:51) [13]
    Ты о каких потоках ?

    Приложение чужое, заранее знать из какого потока будет осуществляться загрузка/выгрузка твоего модуля ты не можешь, как не можешь и заранее знать из каких потоков будут вызываться ф-ции, которые ты перехватил.

    Что и с чем ты собрался "синхронизировать", я пока не понимаю ..
  • KygECHuK © (26.08.08 16:51) [14]
    С потоками мало имел дела, а по сему вопрос есть гарантия что при остановке стороних потоков они не будут использовать требуемого АП?
    Т.е остановяться в этом АП , а при попыке их восстановить получим, то же исключение?
  • KygECHuK © (26.08.08 16:59) [15]

    > Приложение чужое, заранее знать из какого потока будет осуществляться
    > загрузка/выгрузка твоего модуля ты не можешь, как не можешь
    > и заранее знать из каких потоков будут вызываться ф-ции,
    >  которые ты перехватил.


    Плагин для тестировния интерфесных форм, по первому приблежению должно хватить потока, которы обработывает сообщения требуемой формы, хотя о достаточности такого подхода утверждать не берусь.


    > Что и с чем ты собрался "синхронизировать", я пока не понимаю
    > ..


    поток, котрый выгружает библиотеку и все остальные потоки.
  • Сергей М. © (26.08.08 16:59) [16]

    > при остановке стороних потоков они не будут использовать
    > требуемого АП?


    Разумеется не будут.
  • Сергей М. © (26.08.08 17:05) [17]
    Приложение-то дельфийское ?
  • KygECHuK © (26.08.08 17:09) [18]

    > Разумеется не будут.

    Что то я не понимаю...
    А как тогда система реагирует на suspend
    и что будет если такой поток востановить. он что будет переинициализован?

    ЗЫ
     дико извиняюсь за свою некомпетентность в этой области
  • KygECHuK © (26.08.08 17:10) [19]

    > Приложение-то дельфийское ?


    Да
  • Сергей М. © (26.08.08 17:21) [20]

    > как тогда система реагирует на suspend


    Система просто перестает выделять потоку кванты процессорного времени.
    Соответственно ни одна машинструкция им не выполняется.


    > что будет если такой поток востановить. он что будет переинициализован?


    Нет, не будет.
    Упрощенно говоря, система продолжит квантование потока. Поток возобновит выполнение машинструкций начиная с инструкции, следующей за той которая была исполнена поледней на момент предшествующей его приостановки системой.

    Если приложение дельфийское и для реализации GUI-интерфейса оно использует исключительно VCL-формы/контролы, можно практически со 100%-й уверенностью утверждать, что вызовы ф-ции TextOut осуществляются в основном потоке.
    Крайне маловероятно, что какому-то идиоту взбредет в голову месить в одном проекте VCL-формы/контролы и создание/работа с окнами/контролами непосредственно через WinAPI)

    Впрочем, этот довольно легко выяснить.
  • Сергей М. © (26.08.08 17:24) [21]
    Любопытно, а как ты определяешь, в каком потоке загружается/выгружается твой плагин-модуль ?

    Подозреваю, что логика твоя в этой части неверна ..
  • Rouse_ © (26.08.08 17:31) [22]

    > а как ты определяешь, в каком потоке загружается/выгружается
    > твой плагин-модуль ?

    Дык эта... тормозим все что не GetCurrentThreadId в нашем процессе и всего делов :)
  • KygECHuK © (26.08.08 17:32) [23]

    > Любопытно, а как ты определяешь, в каком потоке загружается/выгружается
    > твой плагин-модуль ?Подозреваю, что логика твоя в этой части
    > неверна ..


    Я пока ничего не брался определять, только советуюсь как поступить дальше
    с подомным исключением.
    Но предполагаю стоит вызвать GetCurrentThreadId внутри потока а по Id уже ориентироваться далее.
  • Сергей М. © (26.08.08 20:24) [24]

    > предполагаю стоит вызвать GetCurrentThreadId внутри потока
    > а по Id уже ориентироваться далее


    Ну вот получил ты Id тек.треда.
    Рассказывай про твои дальнейшие действия ..
  • KygECHuK © (26.08.08 22:41) [25]

    > Ну вот получил ты Id тек.треда.Рассказывай про твои дальнейшие
    > действия ..


    * Предчуствие неладного
    Беру текущий процесс и перечисляю все его потоки и сравниваю их Id c id текущего потока при помощи Toolhelp32...
  • Сергей М. © (26.08.08 22:58) [26]

    > Предчуствие неладного


    Уже радует ..

    Рассказывай как ты получил ID ОСНОВНОГО треда текущего процесса
  • KygECHuK © (26.08.08 23:47) [27]

    > Рассказывай как ты получил ID ОСНОВНОГО треда текущего процесса


    * Чё то мне совсем сыкотно
    а зачем мне определять ID ОСНОВНОГО треда текущего процесса? Или в этом есть принципиальный момент?
  • Сергей М. © (27.08.08 08:17) [28]

    > зачем мне определять ID ОСНОВНОГО треда текущего процесса?


    Почем мне знать зачем оно тебе надо ?)

    Цитирую тебя:


    > функция используется в основном потоке


    > синхронизировать с основным потоком


    Раз ты этим озаботился, значит ты все же как-то определяешь, что такой-то поток является именно основным, а не дополнительным ?

    Вот я и спрашиваю как ты это делаешь)
  • KygECHuK © (27.08.08 09:39) [29]

    > Почем мне знать зачем оно тебе надо ?)


    Действительно....
    Надёжней будет приостонавливать все потоки кроме, того что восстанавливает адреса.

    Ну а если мне потребуется взять основной поток, то я просто использую GetWindowThreadProcessId от требуемого окна, ибо Delphi и VCL

    Вас интересует что я имею под понятием "основной поток"? Ну наверно тот поток в котором изначально инициализирован обработчик сообщений.
  • Сергей М. © (27.08.08 09:46) [30]
    А что, собственно, ты тестируешь-то ? Цель какая ?
  • KygECHuK © (27.08.08 10:03) [31]

    > А что, собственно, ты тестируешь-то ?

    АИС


    >  Цель какая ?

    найти всемозможный ошибки расчётов, вывода инвормации и передачи данных... то есть регресивное тестирование каждой новой версии продукта.
    Данный  плагин необходим для сбора текстовой информации из элементов управления не просходящих от TWinControl
  • Сергей М. © (27.08.08 10:14) [32]
    А что, подсистема поддержки плагинов у этой самой "АИС" не позволяет передавать в плагины требуемую тебе инф-цию ?
  • KygECHuK © (27.08.08 10:26) [33]

    > А что, подсистема поддержки плагинов у этой самой "АИС"
    > не позволяет передавать в плагины требуемую тебе инф-цию
    > ?


    У АИС нет такой подсисетмы - плагин для Системы теирования.
    И большая часть жалоб и замечаний именно на отображении данных в интерфейсе, а у нашей "чудо - системы" эти значения могут отличаться от расчитанных или принятых... так что следующим этапом и будет сравнение таких между различнымы способами их вывода. Собственно говоря вот и понадобился таковой плагин.
  • Сергей М. © (27.08.08 10:36) [34]

    > У АИС нет такой подсисетмы


    Но плагины-то эта система поддерживает, раз она грузит твой плагин ?

    Вот я и спрашиваю, нет ли в SDK документированных способов передать в плагин интересующую тебя инф-цию ..
  • KygECHuK © (27.08.08 10:47) [35]

    > Но плагины-то эта система поддерживает, раз она грузит твой
    > плагин ?


    Плагины поддержеивает ОТДЕЛЬНАЯ сторонняя система тетсирования.

    Естетественно есть способ получать данные не из интерфейса, но, как я утверждал раньше они могут отличаться от данных полученных непосредственно из интерфейса... не спрашиваёте меня как это получается у разаработчиков.
  • Сергей М. © (27.08.08 10:58) [36]

    > ОТДЕЛЬНАЯ сторонняя система тетсирования


    А как связан процесс этой системы тестирования с процессом АИС ?

    Плагин-то твой, как я понимаю, грузится в АП процесса системы тестирования, а не в АП процесса АИС ..


    > не спрашиваёте меня как это получается у разаработчиков


    Не буду, я и так догадываюсь)
  • KygECHuK © (27.08.08 11:21) [37]

    > А как связан процесс этой системы тестирования с процессом
    > АИС ?


    Опосредованно - симулирует сообщения от лица пользователя. т. е. для системы тестирования АИС черный ящик... с одной стороны очень сложно симулировать пользователя, а с другой можно находить концептуальные ошибки и создовать наиболее ёмкие тесты.
  • Сергей М. © (27.08.08 11:35) [38]

    > для системы тестирования АИС черный ящик


    Так а зачем же нужно перехватывать TextOut в процессе системы тестирования ? Не понимаю ..


    > жалоб и замечаний именно на отображении данных в интерфейсе


    Я так понял, что интерфейсе приложения АИС, а не интерфейсе приложения-тестера, которое грузит твой плагин ..
  • KygECHuK © (27.08.08 11:47) [39]

    > Так а зачем же нужно перехватывать TextOut в процессе системы
    > тестирования ? Не понимаю ..


    Приходится его немного "сломать" не сисетму же распознования писать?
    Ведь данные предоставляемые АИС во время тестирования влияют на его ход.


    > Я так понял, что интерфейсе приложения АИС, а не интерфейсе
    > приложения-тестера, которое грузит твой плагин ..

    да именно, так, приложение - тестор чисто внутренний проект

    Интерфейсное приложение - красиво звучит для этой АИС оно все вместе и в одном исполняемом файле.... весит до 60 mb.
  • Сергей М. © (27.08.08 12:14) [40]

    > тестор чисто внутренний проект


    Дельфийское ? Без исходников ?
  • KygECHuK © (27.08.08 12:38) [41]

    > Дельфийское ? Без исходников ?

    да без них самих Зовут TestComplete "внутренний" в смысле не для клиентов
  • Сергей М. © (27.08.08 12:58) [42]
    Т.е. задача твоего плагина - перехватить данные, выводимые ТестКомплитом в некие контролы с пом. ф-ции TextOut, поскольку получить эти данные у ТестКомплита каким-либо иным легальным способом якобы не представляется возможным ?
  • KygECHuK © (27.08.08 13:49) [43]

    > Т.е. задача твоего плагина - перехватить данные, выводимые
    > ТестКомплитом в некие контролы с пом. ф-ции TextOut, поскольку
    > получить эти данные у ТестКомплита каким-либо иным легальным
    > способом якобы не представляется возможным ?

    Ключевое слово сдесь "якобы" ?

    Постойте... сечас соберусь.. знаю что не умею объяснять...

    TestComplete основан на движке Java. Он прогоняет срипты в которых и содержиться сама логика теста. Он снабжен оч. большим арсеналом инструментария. Не хватет только функциональности моего плагина.

    АИС это  продукт разрабатываемый нашей компании уже 10 лет (хотя он мало с того времени изменился :) ). Она обладает стандартным набором:
    Ввод данных предметной области, передача их между организациями, и формировании отчетности.  Моя задача написать срипты которые отслеживали идентичность этих данных в любой из этих операций.

    Поэтому следует учесть всевозможные способы вывода информации для сравнения её с ранее введённой. одним из таких спообов вывода и является интерфейс.
    Так, в любой момент времени мне могут понадобиться данны из интерфейса вводились они ранее имелись ли они в
  • KygECHuK © (27.08.08 13:51) [44]
    Базе данных
  • KygECHuK © (27.08.08 13:54) [45]
    Вот я перехватываю вывод АИС в опредлённой области
  • Сергей М. © (27.08.08 14:03) [46]

    > я перехватываю вывод АИС в опредлённой области


    Все чудесатее и чудесатее становится)

    Каким образом твой плагин, будучи загруженный в АП ТестКомплита, умудряется перехватывать вызовы ф-ций в АП совсем другого процесса, т.е. процесса АИС ?
  • KygECHuK © (27.08.08 14:18) [47]

    > Все чудесатее и чудесатее становится)


    Конечно я ж хто?


    > Каким образом твой плагин, будучи загруженный в АП ТестКомплита,
    >  умудряется перехватывать вызовы ф-ций в АП совсем другого
    > процесса, т.е. процесса АИС ?

    Ну да, всё так....
    Совсем другого процесса.. А как исчо WinApi хук делают?
  • Сергей М. © (27.08.08 14:36) [48]

    > как исчо WinApi хук делают?


    Наконец-то на 47-м (!!) посте прозвучало ключевое слово во всей этой бодяге)

    Т.е. слово "плагин" можно смело бросить фтопку, оно тут вообще ни с какого боку, как и ТестКомплит с АИС'ом, ибо речь, оказывается, идет просто о глобальном хуке как одном из методов внедрения своего кода в АП процесса-"жертвы".

    Итак, ты сотворяешь в Делфи некую dll, которая, кроме всего прочего, реализует функциональность хук-модуля для его внедрения в АП процесса некоего дельфийского приложения, исходники которого недоступны, с целью перехвата вызовов в контексте потоков этого процесса неких API-функций, например, TextOut.

    Картина правильно нарисована ?)
  • KygECHuK © (27.08.08 15:08) [49]

    > Картина правильно нарисована ?)

    ну собственно говоря.. да.. вот только он не глобальный.

    а я думал это с самого начала понятно?
  • KygECHuK © (27.08.08 15:09) [50]
    Мне даже Rouse_ по теме отписывался...
  • Сергей М. © (27.08.08 15:36) [51]

    > вот только он не глобальный


    А по барабану какой.

    Но раз не глобальный, то значит ты указывал конкретный целевой тред для ассоциации с хуком. В этом потоке твой хук-модуль и будет загружен в АП "жертвы", в этом же потоке будет вызываться указанная тобой при установке хук-функция.


    > думал это с самого начала понятно


    С чего бы вдруг ?

    Тебя ж про какие-то плагины понесло, которые, оказывается, к делу отношения не имеют)
    Да и метод установки хука для решения задачи "насильственного" внедрения вовсе не единственный.
  • KygECHuK © (27.08.08 15:57) [52]

    > Тебя ж про какие-то плагины понесло, которые, оказывается,
    >  к делу отношения не имеют)Да и метод установки хука для
    > решения задачи "насильственного" внедрения вовсе не единственный.
    >


    я плохо выражаю свои мысли, ибо сам в них путаюсь )


    > Но раз не глобальный, то значит ты указывал конкретный целевой
    > тред для ассоциации с хуком. В этом потоке твой хук-модуль
    > и будет загружен в АП "жертвы", в этом же потоке будет вызываться
    > указанная тобой при установке хук-функция.


    Вот это я все зделал, но.. ошибка...
  • Сергей М. © (27.08.08 16:04) [53]

    > но.. ошибка..


    Т.е. ты вызываешь UnhookWindowsHookEx и в этот же момент получаешь AV ?
    А по какому адресу ?
  • KygECHuK © (27.08.08 16:18) [54]

    > Т.е. ты вызываешь UnhookWindowsHookEx и в этот же момент
    > получаешь AV ?


    Нет это перехват сообщений. у мну реализован перехват на уровне подмены адресов функций IAT
  • Сергей М. © (27.08.08 16:26) [55]

    > Нет это перехват сообщений


    Причем здесь он ?

    Я прекрасно понимаю, что он тебе нафих не нужен.


    > подмены адресов функций IAT


    И это прекрасно понимаю, повторяться про это нет повода.

    "Выгрузка перехватчика" в какой момент и при каких условиях у тебя осуществляется ?

    Давай уже иллюстрируй фрагментами реального кода, имеющего непосредственное отношение к делу, если не можешь изъясняться терминологически правильно)
  • KygECHuK © (27.08.08 16:45) [56]

    > "Выгрузка перехватчика" в какой момент и при каких условиях
    > у тебя осуществляется ?


    Когда партия прикажет, т. е. влюбой момент времени когда понадобиться
    Без каких либо условий...

    Вызывается поток CreateRemoteThread котоый заставляет выгрузится библиотеку. на что она реагирует обратной заменой всех адрессов и выгружается.


    > Давай уже иллюстрируй фрагментами реального кода, имеющего
    > непосредственное отношение к делу, если не можешь изъясняться
    > терминологически правильно)


    Ну да? нет у меня специального образования....
    Сейчас фрагмент предоставить не могу - уже дома, поэтому завтра.
    Да и кокнретный участок кода выявить не могу в дебаге все проходит идеально.
  • Сергей М. © (27.08.08 16:52) [57]

    > Вызывается поток CreateRemoteThread котоый заставляет выгрузится
    > библиотеку


    Не понял ..

    Почему через сфинктер это тобой делается ?

    Если ты влупил куда-то свой хук-модуль средствами SetWindowsHookEx, то почему не "вылупить" его штатно, т.е. средствами UnhookWindowsHookEx ?
  • KygECHuK © (27.08.08 16:58) [58]

    > Если ты влупил куда-то свой хук-модуль средствами SetWindowsHookEx,
    >  то почему не "вылупить" его штатно, т.е. средствами UnhookWindowsHookEx
    > ?

    Потому что это свечка :))
    я её так и всатвлял...
  • Сергей М. © (27.08.08 17:00) [59]

    > я её так и всатвлял


    А причем здесь тогда хук ?
  • Сергей М. © (27.08.08 17:04) [60]
    Хук обычно "вставляют" так как прописал доктор БГ)

    А доктор прописал вставлять через SetWindowsHookEx, а вынять, соотв-но, через UnhookWindowsHookEx.

    Ты чего мудришь-то ? В реанимацию метишь ?)
  • KygECHuK © (27.08.08 17:16) [61]

    > А причем здесь тогда хук ?


    hook - ловушка - те же яйца тока в профиль


    > Ты чего мудришь-то ? В реанимацию метишь ?)


    И не думал мутить - казалось так все делают.... :)
  • KygECHuK © (27.08.08 17:19) [62]
    Раз так, тогда завтра предоставлю код
    и попробую "Засуспензить" родные потки при выгрузке
  • Сергей М. © (27.08.08 17:29) [63]

    > казалось так все делают


    Перекрестись на всякслучай, если православный)

    За каким лешим, спрашивается, извращаться со стартом удаленного потока, если заведомо известно, что "жертва" является GUI-приложением и внедрение своего кода в его АП достигается документированным и рекомендованным способом, т.е. установкой ловушки при помощи SetWindowsHookEx ?

    Прокомментируй свою логику, если она вообще имеется, мне она пока не ясна ..
  • KygECHuK © (27.08.08 17:40) [64]

    > Прокомментируй свою логику, если она вообще имеется, мне
    > она пока не ясна ..

    ай ай ай... А ктооо.... А кто это сделал? Ммммммммм...

    Меня что предадут анафине? Ну допустим не в курсе я был что  документированным и рекомендованным способом можно перехватывать определённые импортированиы функции. SetWindowsHook использовал только для перехвата сообщений окна и то это было давно и недавно, не думаю что моё решение столь опасно... и к тому же вроде работает.. ну почти.. :)
  • KygECHuK © (27.08.08 17:41) [65]
    *давно и не правда..
  • KygECHuK © (27.08.08 17:54) [66]
    Ну допустим я использую  SetWindowsHookEx,  тогда какими будут праметры для перехвата TextOut'а?
  • Сергей М. © (27.08.08 19:28) [67]

    > допустим я использую  SetWindowsHookEx,  тогда какими будут
    > праметры для перехвата TextOut'а?
    >


    Какие еще нафих "параметры перехвата" ?
    В огороде бузина, а в Киеве дядька)


    > не в курсе я был что  документированным и рекомендованным
    > способом можно перехватывать определённые импортированиы
    > функции


    Ты вообще слышишь что я говорю ?

    Я пока говорю о методах внедрения кода в чужое АП, а не о каком-то там "перехвате".

    До "перехвата" в нашем с тобой разговоре еще как до Китая ползком на карачках)
  • Сергей М. © (27.08.08 19:32) [68]

    > вроде работает.. ну почти.


    А чем же ты тогда в этом топике озабочен ?)

    Ну подумаешь - в основном работает, но маленько не работает - стоило ли волноваться ?) Нехай себе маленько глючит, глвное чтобы в целом немаленько неглючило)
  • KygECHuK © (27.08.08 19:47) [69]

    > Я пока говорю о методах внедрения кода в чужое АП, а не
    > о каком-то там "перехвате".

    Нет, постой паравоз, мне все равно интересно с каками параметрами должна вызваться SetWindowsHookEx, что бы переданная CallBack процедура срабатывала на вызов TextOut ? Вопрос вроде простой..
  • Сергей М. © (27.08.08 19:55) [70]

    > с каками параметрами должна вызваться SetWindowsHookEx,
    > что бы переданная CallBack процедура срабатывала на вызов
    > TextOut ?


    Ни с какими.
    В огороде бузина, а в Киеве дядька.

    Мы пока еще говорим только о внедрении кода, а не о каких-то там колбэках и перехватах.

    Ты его, свой код то бишь, нахрена внедряешь средствами CreateRemoteThread ?
    Почему ты для этой цели не пользуешь SetWindowsHookex ?
    Пока ты не прокомментируешь логику принятия своего решения, дальнейшее обсуждение темы и проблемы лишено резона.
  • KygECHuK © (27.08.08 20:16) [71]

    > Почему ты для этой цели не пользуешь SetWindowsHookex ?

    Как этот способ может мне помочь?
    Вот листаю докуметнтацию:
    "Функция SetWindowsHookEx устанавливает определяемую программой подключаемую процедуру в цепочку hook-точек."
    Что общего может иметь цепочка hook-точек и вызов TextOut из какой то библиотеки хоть user32.dll функция DrawText
  • KygECHuK © (27.08.08 20:17) [72]
    *функцией DrawText
  • Сергей М. © (27.08.08 20:46) [73]

    > Что общего может иметь цепочка hook-точек и вызов TextOut
    > из какой то библиотеки


    Ничего общего.
    Тебе оно и не надо.
    Тебе надо получить управление при загрузке/выгрузке своего модуля в/из АП жертвы.
    При получении управления при загрузке ты включаешь свой перехват, при получении управления при выгрузке ты выключаешь свой перехват.
    Эту самую загрузку/выгрузку твоего модуля система выполнит самостоятельно,  с соблюдением канонов межпоточной синхронизации.
  • KygECHuK © (27.08.08 21:41) [74]
    А как справоцировать получение управления в таком случае? Как Заставить загружаться модуль? Я не в смысле что это не возможно... просто реально не знаю.
  • Сергей М. © (28.08.08 08:18) [75]

    > Как Заставить загружаться модуль?


    Хук-модуль загрузит сама система при первом же возникновении того события,  которое ты укажешь в параметрах вызова SetWindowsHookex.


    > как справоцировать получение управления


    Обеспечить условия, при которых это событие гарантированно возникнет.
    Например, "подписаться" на WH_GETMESSAGE и послать целевому окну WM_USER.
    Как только целевая оконная ф-ция выберет любое сообщение из очереди, система немедленно загрузит твой хук-модуль, при этом отработает процедура инициализации, где ты волен выполнять модификацию IAT.
  • KygECHuK © (28.08.08 09:38) [76]
    Ну а выгрузка, получается, вызовом  UnhookWindowsHookEx ?

    То есть, получатся, код библиотеки в при инциализации и финализации менять не надо?

    И тело CallBack процедуры можно оставить пустым?
  • Сергей М. © (28.08.08 10:18) [77]

    > выгрузка, получается, вызовом  UnhookWindowsHookEx ?


    Нет, она тоже не сразу произойдет, только при первом событии подписки.


    > код библиотеки в при инциализации и финализации менять не
    > надо?


    Смотря что за код у тебя там.


    > тело CallBack процедуры можно оставить пустым?


    Пустым нельзя. Цепочку хуков оборвешь тем самым.
    см. CallNextHookEx
  • KygECHuK © (28.08.08 10:37) [78]

    > Нет, она тоже не сразу произойдет, только при первом событии
    > подписки.


    Т.е.

    ставим WindowsHookEx
    посылаем событие подписки  
    //библиотека загружена

    снимаем UnhookWindowsHookEx
    посылаем событие подписки  
    // библиотека выгружена

    я правильно понял?
  • Сергей М. © (28.08.08 10:58) [79]

    > я правильно понял?


    Ну вроде того)
    Только вот события не "посылают", они происходят или возникают.
  • KygECHuK © (28.08.08 11:22) [80]

    > Ну вроде того)Только вот события не "посылают", они происходят
    > или возникают.


    Ну вызываем событие...
    Так или иначе СПАСИБО за терпение.
    Надо опробывать ваш совет
  • Leonid Troyanovsky © (28.08.08 13:05) [81]

    > KygECHuK ©   (28.08.08 11:22) [80]

    http://www.podgoretsky.com/ftp/Docs/Delphi/FAQ/ru.delphi.html#N109

    --
    Regards, LVT.
  • KygECHuK © (28.08.08 13:44) [82]

    > Leonid Troyanovsky ©   (28.08.08 13:05) [81]

    Спасибо за пример
  • Сергей М. © (28.08.08 14:16) [83]

    > KygECHuK ©   (28.08.08 13:44) [82]


    Не наступи на грабли)

    В примере - глобальный хук, и хук-модуль будет внедряться во все процессы, обращающиеся к очередям сообщений своих окон
  • Leonid Troyanovsky © (28.08.08 14:29) [84]

    > Сергей М. ©   (28.08.08 14:16) [83]

    > В примере - глобальный хук, и хук-модуль будет внедряться
    > во все процессы,

    Почему во все?
    Хук цепляется на определенный поток.

    --
    Regards, LVT.
  • Сергей М. © (28.08.08 14:48) [85]

    > Leonid Troyanovsky ©   (28.08.08 14:29) [84]


    > Хук цепляется на определенный поток


    Да. если при вызове указан id этого потока.
    А в примере он = 0

    dwThreadId

    Specifies the identifier of the thread with which the hook procedure is to be associated. If this parameter is zero, the hook procedure is associated with all existing threads.
  • KygECHuK © (28.08.08 14:53) [86]

    > Да. если при вызове указан id этого потока.А в примере он
    > = 0


    "SetWindowsHookEx(WH_GETMESSAGE,  Answer,  Hinstance,  tid)"
    Нет Здесь 0
  • Leonid Troyanovsky © (28.08.08 15:05) [87]

    > Сергей М. ©   (28.08.08 14:48) [85]

    > А в примере он = 0

    GetWindowThreadProcessID(ahwnd,  nil)

    --
    Regards, LVT.
  • Сергей М. © (28.08.08 15:09) [88]

    > Нет Здесь 0


    Здесь он вообще хз чему равен - декларация и иниц-ия этой переменной напрочь отсутствует.

    Тем не менее имей ввиду - для внедрения хук-модуля в конкретный целевой процесс указание потока этого процесса обязательно.
  • Сергей М. © (28.08.08 15:11) [89]

    > Leonid Troyanovsky ©   (28.08.08 15:05) [87]
    >
    >


    Ага, вижу tid параметром.
    А глаз искал переменную)
  • KygECHuK © (01.09.08 14:20) [90]
    Эт снова я...
    Чё то странное - библиотека почти сразу выгружется ?
    Т.е вызывается DLLEntryPoint с параметром DLL_PROCESS_DETACH. Оно так должно работать?
  • Сергей М. © (01.09.08 14:32) [91]
    Ты пример из [81] имеешь ввиду ?
    Тогда да, так и должно.
  • KygECHuK © (01.09.08 14:43) [92]

    > Ты пример из [81] имеешь ввиду ?

    нет, там всё понятно...
    я уже внес изменения в свой код, и вот тут такое...

    вот код:

    function TRemThreadInjector.DoInjectModuleIntoGUI(process: TExeModuleInstance): boolean;
    var
     szLibFile        : TShortCharArr;
     Found            : boolean;
     ModuleInstance   : TModuleInstance;
     i                : Integer;
     Tid              : Cardinal;
    begin
     Result := FALSE;

    if (nil = Process) then
       exit;

    GetModuleFileNameA(
     ModuleFromAddress(@sm_CritSecInjector),
     szLibFile,
     MAX_PATH
     );

    Found := FALSE;
    for i := 0 to Process.GetModuleCount() - 1 do
    begin
     ModuleInstance := Process.GetModuleByIndex(i);
     if (0 = AnsiStrIComp(ModuleInstance.FullName, szLibFile)) then
     begin
      Found := TRUE;
      break;
     end; // if
    end; // for
    if (Found) then
     exit;
     // Получаем идентификатор потока целевого окна
     Tid := GetWindowThreadProcessId(TModuleScope(m_ModeleScope).TargWindow);

     // Устанавливаем ловушку
     TModuleScope(m_ModeleScope).HookHandle := SetWindowsHookEx(WH_GETMESSAGE, @CallBack,  HInstance, TID);

     // Псылаем характерное сообщение
     if  TModuleScope(m_ModeleScope).HookHandle  <>  0  then
       PostThreadMessage(tid,  0,  0,  0);
    end;

  • Сергей М. © (01.09.08 14:49) [93]
    Показывай тело колбэка ..
  • KygECHuK © (01.09.08 14:51) [94]
    Вот



    function CallBack(nCode: Integer; wprm: WParam;
     lprm: LParam): LResult;
    begin
     result := CallNextHookEx(Modulescope.sm_pInstance.HookHandle, nCode, wprm, lprm);
    end;




    и всё
  • Сергей М. © (01.09.08 15:01) [95]
    А ты что, инжектируешь в АП "жертвы" свой трэд и уже в контексте этого трэда пытаешься установить хук ?
  • KygECHuK © (01.09.08 15:13) [96]

    > А ты что, инжектируешь в АП "жертвы" свой трэд и уже в контексте
    > этого трэда пытаешься установить хук ?


    Не я не изаращенец.... имхо... :)

    Вот ставлю хук... ну в DLLEntryPoint на DLL_PROCESS_ATTACH инициализирую прехват.

    предвосхищая ворпрос, сразу скажу, что HookHandle лежит в расшареном файле.
  • Сергей М. © (01.09.08 15:20) [97]

    > HookHandle лежит в расшареном файле


    Это неактуально.
    Под NT можно передавать 0 в кач-ве перевого параметра CallNextHookEx
  • KygECHuK © (01.09.08 15:31) [98]

    > Под NT можно передавать 0 в кач-ве перевого параметра CallNextHookEx


    Вот жеж.. В рот мне ноги ! :(

    Сейчас перепроверял - хук стоит.
    Вот только он библиетеку не сразу подгружает а только когда пока пойдут характерные сообщения, как только они прекращаются библиотека выгружается.
    Но потом опять загружается и выгружает и т.д. пока не извлеч хук.
    Получается что всё работает, но вот тока постоянная автоматическая загрузка\выгрузка вызывает у мну сомнение и подозрение... Доктор, это параноя? А?
  • Сергей М. © (01.09.08 15:43) [99]

    > он библиетеку не сразу подгружает а только когда пока пойдут
    > характерные сообщения


    Вот именно для этого ты и вызываешь PostThreadMessage(tid,  0,  0,  0) сразу после вызова ф-ции, устанавливающей хук.


    > как только они прекращаются библиотека выгружается.
    > Но потом опять загружается и выгружает и т.д. пока не извлеч
    > хук


    При нормальных условиях хук-модуль будет выгружен из АП "жертвы" не ранее явного или неявного вызова UnhookWindowsHoohEx.

    Насколько я понимаю, явно ты UnhookWindowsHoohEx не вызываешь, по кр. мере раньше чем тебе станет нененужным этот модуль в АП "жертвы".
    А неявный вызов выполняется самой системой при завершении процесса "жертвы".

    Т.о., если эти условия заведомо не выполняются, но хук-модуль с какого-то перепугу исчезает из АП "жертвы", то это уже паранойя)
  • KygECHuK © (01.09.08 15:58) [100]

    > Вот именно для этого ты и вызываешь PostThreadMessage(tid,
    >   0,  0,  0) сразу после вызова ф-ции, устанавливающей хук.


    Я имел ввиду и все остальные сообщения вместе взятые...


    > Т.о., если эти условия заведомо не выполняются, но хук-модуль
    > с какого-то перепугу исчезает из АП "жертвы", то это уже
    > паранойя)


    Видимо так... Ладно, отдам сотрудникам на тестирование... если пойдёт без ошибок, то просто забью....
  • Сергей М. © (01.09.08 16:07) [101]

    > вызывается DLLEntryPoint с параметром DLL_PROCESS_DETACH


    А как ты этот факт определил ?
  • KygECHuK © (01.09.08 16:29) [102]

    > А как ты этот факт определил ?

    мну там логирующая процедура
  • Сергей М. © (01.09.08 16:37) [103]

    > мну там логирующая процедура
    >


    А про возможности встроенного отладчика ты, конечно, ничего не слышал ?
  • KygECHuK © (01.09.08 16:51) [104]

    > А про возможности встроенного отладчика ты, конечно, ничего
    > не слышал ?


    Ну, давай, апостол, затронь мою душу... :)
  • Сергей М. © (01.09.08 17:12) [105]
    Отладчиком по душе - это ж не серпом по фаберже) ..
  • KygECHuK © (01.09.08 17:18) [106]

    > Отладчиком по душе - это ж не серпом по фаберже) ..


    главное Ctrl+F2 не нажимать х_х..

    вот я и использую логи, ибо при создании серверной части надо было отслеживать поведение внедряемой чати в рантайме.

    Ну и получается красиво.. парами... Загрузился-выгрзился, зугрузился- выгрузился....
  • Сергей М. © (01.09.08 17:24) [107]

    > использую логи, ибо при создании серверной части надо было
    > отслеживать поведение внедряемой чати в рантайме


    И чем же отладчик не угодил ?
  • KygECHuK © (01.09.08 17:33) [108]

    > И чем же отладчик не угодил ?


    Ничего плохого про него сказать немогу.
    Ну пишеться лог:

     библеотека в такой то процесс внедренна
     ...
     содержимое перехваченного
     ...
     разные там библиотеки подгруружены в рантайме
     ...
     библеотека в из такого-то процесс извлечена


    и что сдесь такого крамольного?
    Тем более что по ним можно отследить работу и на других машинах..
  • Сергей М. © (01.09.08 18:54) [109]

    > что сдесь такого крамольного?


    А где лог колбэка ?

    Он ведь д.б. вызван аккурат между загрузкой и выгрузкой хук-модуля ..


    > по ним можно отследить работу и на других машинах


    Ты на своей-то разберись, прежде тыкать свой код, в логике работы которого ты пока еще ничерта не разобрался, на чужую машину)
  • KygECHuK © (01.09.08 19:17) [110]

    > Ты на своей-то разберись, прежде тыкать свой код, в логике
    > работы которого ты пока еще ничерта не разобрался, на чужую
    > машину)


    Это как это я не разобрался в логике СВОЕГО кода? все логично - страдает концепция, то бишь проект.


    > А где лог колбэка ?


    зачем? Что в нем может быть интересного?
    там же вообще ничего интересного не происходит..

    ЗЫ
     тестеры ошибок не нашли, за что ещё раз спасибо!
  • Сергей М. © (01.09.08 19:22) [111]

    > как это я не разобрался в логике СВОЕГО кода? все логично


    да уж куда кж логичней - в протоколе фигурирует выгрузка модуля, а модуль при  этом  как был так и остался в АП)
  • KygECHuK © (01.09.08 19:33) [112]

    > да уж куда кж логичней - в протоколе фигурирует выгрузка
    > модуля, а модуль при  этом  как был так и остался в АП)


    в прошлой "версии" с CreateRemoteThread так оно и было... все выгражалось.. один раз... последний.. )

    Но м сйчас он тоже ТОЧНО не останется в АП жертвы после вызова UnHook'а.
  • Сергей М. © (02.09.08 08:53) [113]

    > сйчас он тоже ТОЧНО не останется в АП жертвы после вызова
    > UnHook'а.


    да я не об этом)

    Вот твои слова:

    > библиотека почти сразу выгружется


    Как я понял, UnHook ты не вызываешь, но модуль с какого-то перепугу выгружается при заведомо работающем процессе "жертвы", и при всем этом ты видишь, что модуль присутствует в его АП.

    Вот ведь кудеса-то !) И ты не разобравшись в них отдаешь свое творение в эксплуатацию, пусть и тестовую ..
  • KygECHuK © (02.09.08 09:30) [114]

    > Как я понял, UnHook ты не вызываешь, но модуль с какого-
    > то перепугу выгружается при заведомо работающем процессе
    > "жертвы", и при всем этом ты видишь, что модуль присутствует
    > в его АП.


    нет, все интереснее, даже, можно сказать, лучше чем я предпологал:
    библеотека сама внедряется в процесс когда идут сообщения, а как только они прекращаюся она сам выгружается.... А потом снова как только пойдут сообщения она опять загружается и т. д. Поэтому наличие её потстоянного нахождения в АП жертвы я установить не могу. Только по результатам успешной работы перехватчика...
  • Сергей М. © (02.09.08 09:57) [115]

    > как только они прекращаюся она сам выгружается.... А потом
    > снова как только пойдут сообщения она опять загружается


    Быть того не может)


    > по результатам успешной работы перехватчика


    Если он успешно у тебя работает, то это означает только одно - твой модуль присутствует в целевом АП и никуда он не "выгружался".

    Где и какую ты там "выгрузку" узрел - ума не приложу ..

    Продолжай разгребать чудеса)
  • evvcom © (02.09.08 10:06) [116]
    где-нибудь дополнительную тестовую запись в лог-файл воткнул с тем же текстом. Текст поменяй в нужном месте и посмотри результат.
  • KygECHuK © (02.09.08 10:15) [117]

    > Быть того не может)


    Может мне глаза врут?

    Вот метод обработки


    procedure DLLEntryPoint(Reason: DWORD);
     begin
       case Reason of
         DLL_PROCESS_ATTACH:
         begin
           InitSharedFile;
           sg_hwndServer := @sm_lpSharedRec^.m_phwndServer;
           sg_bHookInstalled := @sm_lpSharedRec^.m_pbHookInstalled;
           sg_hwndTarget := @sm_lpSharedRec^.m_phwndTarget;
           sg_bSendMsg := @sm_lpSharedRec^.m_SendResults;
           sg_hHookHandle := @sm_lpSharedRec^.m_HookHandle;
             // Отключаем События потока
          // Чтоб потоки не звали ни на что больше не риагировал
        DisableThreadLibraryCalls(HINSTANCE);

        g_pModuleScope := TModuleScope.GetInstance(
          sg_hwndServer,
         sg_bHookInstalled,
             sg_hwndTarget,
             sg_bSendMsg,
             sg_hHookHandle
         );
        g_pModuleScope.ManageModuleEnlistment();
         end;
         DLL_THREAD_ATTACH:
         begin

         end;
         DLL_THREAD_DETACH:
         begin

         end;
         DLL_PROCESS_DETACH:
         begin
         //  DLL Выходит из адресного пространства процесса .
           g_pModuleScope.HookAll := true;
        g_pModuleScope.ManageModuleDetachment();
           ReleaseShredFile;
         end;
      end;



    Вот на DLL_PROCESS_ATTACH и DLL_PROCESS_DETACH пишутся соответсвующие сообщения в лог. Строго парами. вот и получается у меня такое впечатление.
  • Сергей М. © (02.09.08 10:31) [118]

    > // Чтоб потоки не звали ни на что больше не риагировал
    >     DisableThreadLibraryCalls(HINSTANCE);


    а зачем тогда кейсы DLL_THREAD_ATTACH и DLL_THREAD_DETACH в твоем коде фигурируют, раз ты заведомо не хочешь получать эти извещения ?


    > g_pModuleScope.HookAll := true;


    Что у тебя происходит при этом присвоении ?
  • KygECHuK © (02.09.08 11:03) [119]

    > а зачем тогда кейсы DLL_THREAD_ATTACH и DLL_THREAD_DETACH
    > в твоем коде фигурируют, раз ты заведомо не хочешь получать
    > эти извещения ?


    Как это..... Reserved... так обычно пишут :)

    > Что у тебя происходит при этом присвоении ?

    ничего поле присвается а прямую и используется тоько в серверной чати библиотеки при её выгрузке
  • Сергей М. © (02.09.08 11:14) [120]

    > Как это..... Reserved... так обычно пишут


    Обычно пишут писатели .. Ильф и Петров)..

    Тебя ж не интересуют события создания/завершения потоков в целевом процессе, зачем же ты оставил эти кейсы ?

    Это, конечно, непринципиально, наводит на мысль что ты не понимаешь что делаешь)

    Ну хорошо, а где протоколирование и анализ потоков, вызывающих аттач/детач ?
  • KygECHuK © (02.09.08 11:27) [121]

    > Это, конечно, непринципиально, наводит на мысль что ты не
    > понимаешь что делаешь)


    Шерлок как вы это делаете? :)
    Очень даже  не принципиально... Я еще очень много лишнего дописал в поисике ошибки. В ближайшее время все это будет убранно.


    > Ну хорошо, а где протоколирование и анализ потоков, вызывающих
    > аттач/детач ?


    Никакого анализа потоков нет.


    procedure TModuleScope.ManageModuleDetachment;
    begin
    //
    // Проверка сообщения что оно из перехваченого приложения
    //
    if (not m_bIsThisServerProcess) then
    begin
      // Извлекаем перехватчики
     FinalizeHookManagement();
     // Сервер исчо работает?
     if (0 <> m_phwndServer^) then
        // Посылаем сообщение серверу об отключении
      PostMessage(
       m_phwndServer^,
       UWM_HOOKTOOL_DLL_UNLOADED,
       0,
       GetCurrentProcessId()
       );
    end else
    begin
     m_pInjector.EjectModuleFromAllProcesses(m_pWhenZero.GetZeroHandle);
     LogMessage( '-------  Сервер становлен и все ловушки выгружены ------');
    end;
    end;




    Вот по получении сообщения в серверной части и пишется сообщение в лог
  • evvcom © (02.09.08 11:46) [122]
    Что-то всё с ног на голову. Кто такой сервер? Жертва? Почему жертва стала сервером?
  • KygECHuK © (02.09.08 11:52) [123]

    > Что-то всё с ног на голову. Кто такой сервер? Жертва? Почему
    > жертва стала сервером


    В библиотеке реализована и серверная часть перехватчика. она себя и внедряет в АП жертвы.
  • evvcom © (02.09.08 12:06) [124]

    > В библиотеке реализована и серверная часть перехватчика

    Я догадался

    > она себя и внедряет в АП жертвы

    так все-таки сервер рулит внедрением. Я обычно в LogMessage еще включаю и дату/время события. Зачем отрицание "(not m_bIsThisServerProcess)", почему бы его не убрать и then/else не поменять местами для уменьшения путаницы? Так получается, что не только хук снимается, но и на сервере dll завершается/выгружается? Это так тестировщик работает?
  • KygECHuK © (02.09.08 12:16) [125]

    >  Так получается, что не только хук снимается, но и на сервере
    > dll завершается/выгружается?


    Если библитека серверным процессом выгружается, то соответсвенно, выгружаюися и все прехватчики. и никак не наоборот.


    > Это так тестировщик работает?


    Тестировщик это в смысле я? :)
  • Сергей М. © (02.09.08 12:17) [126]
    Черт те что и сбоку бантик)... Серверы какие-то, соообщения какие-тио кому-то, эжекты какие-то из всех процессов ..

    Выкинь нафих всю эту требуху хотя бы на время и органичься только протоколированием:

    procedure DLLEntryPoint(Reason: DWORD);
    begin
      case Reason of
        DLL_PROCESS_ATTACH: LogMessage('Process attach, tid = ' + IntToStr(GetCurrentThreadId));
        DLL_PROCESS_DETACH: LogMessage('Process detach, tid = ' + IntToStr(GetCurrentThreadId));
      end;
    end;


    При получении управления при инициализации хук-модуля СРАЗУ ЖЕ установи
    IsMultiThread := True;



    Теперь стартуй целевой процесс и устанвливай хук. Что видишь в протоколе ?

    Теперь снимай хук. Что видишь в протоколе ?

    Теперь вновь ставль хук. Завершай целевой процесс. Что видишь в протоколе ?
  • Сергей М. © (02.09.08 12:22) [127]

    > Если библитека серверным процессом выгружается


    Не знаю я никаких твоих "серверных процессов" !)

    Хук-модуль у тебя должен выгружаться либо по завершению "жертвы" либо после вызова UnHook-ф-ции, и по барабану кто и откуда ее вызывает - хоть из "серверного процесса", хоть с серобуромалинового, хоть с Луны)
  • KygECHuK © (02.09.08 12:32) [128]

    > Хук-модуль у тебя должен выгружаться либо по завершению
    > "жертвы" либо после вызова UnHook-ф-ции, и по барабану кто
    > и откуда ее вызывает - хоть из "серверного процесса", хоть
    > с серобуромалинового, хоть с Луны)


    мне тоже поборабану, ну человек спросил...
  • evvcom © (02.09.08 12:36) [129]

    > Тестировщик это в смысле я? :)

    Нет, это та прога, про которую ты говорил в начале... а, нет, та прога - жертва :)
  • KygECHuK © (02.09.08 12:45) [130]

    > Нет, это та прога, про которую ты говорил в начале... а,
    >  нет, та прога - жертва :)

    ААА... брат по разуму!! Я его не понимаю, точно так же, как меня не понимают другие!!!! :))

    Жертва - АИС, не жертва - TestComplete. он же серверный процесс.
  • Сергей М. © (02.09.08 13:18) [131]

    > Если библитека серверным процессом выгружается, то соответсвенно,
    >  выгружаюися и все прехватчики


    Ты осознаешь, что в процессах АИС и ТестКомплит фигурируют два совершенно разных экз-ра твоего модуля ?
  • KygECHuK © (02.09.08 13:38) [132]

    > Ты осознаешь, что в процессах АИС и ТестКомплит фигурируют
    > два совершенно разных экз-ра твоего модуля ?


    Да, это так...
  • Сергей М. © (02.09.08 13:49) [133]
    Ну так что насчет [126] ?
  • KygECHuK © (02.09.08 13:54) [134]

    > Ну так что насчет [126] ?

    Ща гоняю, какойто фарш выходит.... сейчас разберусь и напишу
  • Сергей М. © (02.09.08 14:27) [135]

    > какойто фарш выходит


    Известно какой - из мух и котлет) ..
  • KygECHuK © (02.09.08 15:42) [136]
    Насчёт фарша, у меня ошибочно опредяется состояние ловушки, надо определять не по наличию модуля в процессе, а сделать специальный флаг.

    Сейчас написал тестовый проект чтоб иcпользовать его как сервер.
    Сделал два режима
    первый:
    1 Жмакаем кнопку хук внедряется
    2 что то делаем в жертве
    3 Жмакаем другую кнопку хук извлекается

    то есть всё как вы написали

    второй:

    Но существует необходимость оперативно пересылать данные после прехвата в форму сервера для чего я реши использовать WM_COPYDATA,

    для этого я создал отдельный поток который внедряет хук и перерисовывает окно.
    Вот в этом случае и происходит самостоятельная выгрызка библиотеки перехватчика, т. к. я её , выгрызку, нигде не вызываю.

    А точно неявная выгрузка ловушки происходит только по завершению процесса?

    На этот раз проверяд не по логу, а в Process Sxplorer'е
  • Сергей М. © (02.09.08 16:05) [137]

    > 1 Жмакаем кнопку хук внедряется
    > 3 Жмакаем другую кнопку хук извлекается
    >
    > то есть всё как вы написали


    Так ведь иначе и быть не может)

    А все остальное, что ты нагородил вокруг этого огорода, к собственно огороду отношения не имеет - разгребай уж сам)


    > А точно неявная выгрузка ловушки происходит только по завершению
    > процесса?


    Ну если ты нигде не вызываешь ни UnHook ни FreeLibrary, то кто еще может сделать это кроме системы по завершению целевого процесса ? Сторонний код, внедренный кем-то в то же АП и "пасущий" твой модуль чтобы навредить тебе, естественно, я не рассматриваю ..
  • KygECHuK © (02.09.08 16:30) [138]

    >  Сторонний код, внедренный кем-то в то же АП и "пасущий"
    > твой модуль чтобы навредить тебе, естественно, я не рассматриваю
    > ..


    проверял на Notepad'е - нет там ничего партизанского


    > разгребай уж сам)


    Постараюсь
  • evvcom © (02.09.08 16:30) [139]
    Я-то чего влез? Сам пишу подобное. У меня раньше была задача аналогичная, я ее решил локально. Теперь еще 2 похожие задачи нарисовались. Вот только процесс в одной из них уже не GUI. Вот и решил написать нечто универсальное. Сервис, чтобы работать могло и под учеткой простого смертного, универсальная dll-внедрялка через RemoteThread и собственно для каждой задачи своя dll, реализующая перехваченные функции. По ходу возникают разные проблемы, но они пока решаются, хотя и до завершения еще далеко :)
  • KygECHuK © (02.09.08 16:42) [140]

    > завершения еще далеко :)


    Желаю удачи, будут проблемы - поделюсь наболевшим..
  • evvcom © (02.09.08 17:07) [141]
    Да я и сам могу поделиться :)
    DLL уже внедряется и выгружается без ошибок.
    Сейчас пишу систему общения, протокол обмена информацией.
    В той задаче с локальным решением устанавливались ловушки, а вот со съемом была проблема. IDA Pro тогда показал, что после загрузки плагинов, то приложение читало адрес перехваченной функции, сохраняло его в регистре и дальше уже в рабочем цикле выполняло call <Register>. Внутри этого цикла в итоге вызывалась и FreeLibrary для плагина. Так и пришлось тогда перехватывать еще и FreeLibrary и в случае выгрузки моей dll команду пропускать мимо ушей :)
  • Сергей М. © (02.09.08 17:08) [142]

    > проверял на Notepad'е - нет там ничего партизанского
    >


    Да я и не утверждаю, что тут партизаны шорох наводят)
    Как раз наоборот - их появление тут крайне маловероятно, да и ты тоже вроде бы не оккупант, чтобы свои стратегические неудачи на партизанские вылазки сваливать)
  • KygECHuK © (02.09.08 17:10) [143]
    нашел причину, все дело в вспомогательном потоке, по его завершении выгружается перехватчик, всего делов. Дело не критчное. Ошибок не нашли. Акуна матата...
  • KygECHuK © (02.09.08 17:16) [144]

    > DLL уже внедряется и выгружается без ошибок.


    У меня тоже до "полевого" применения ошибок не было, а вот потом...
  • evvcom © (02.09.08 17:27) [145]
    Кстати, с доп.потоками в dll. Может пригодится. На днях выяснил, что если создавать или завершать доп.поток внутри DLL_PROCESS_ATTACH/DETACH, то получим граблями, так как тогда должны одновременно выполняться коды DLL_THREAD_ATTACH/DETACH, а это запрещено системой. Причем DisableThreadLibraryCalls не спасает, т.к. связано это все же с выделением памяти под структуры потока.
  • evvcom © (02.09.08 17:28) [146]

    > У меня тоже до "полевого" применения ошибок не было, а вот
    > потом...

    Ну так я сразу на реальной жертве экспериментирую :-)
  • KygECHuK © (02.09.08 17:33) [147]

    > Ну так я сразу на реальной жертве экспериментирую :-)


    Ну так выгрузку при CreatRemoteThread ты как организовал?
  • evvcom © (02.09.08 17:57) [148]
    загрузка CreatRemoteThread Loadlibrary
    выгрузка CreatRemoteThread FreeLibrary
    все как у Рихтера. Или ты что-то иное имеешь ввиду?
  • Leonid Troyanovsky © (02.09.08 18:04) [149]

    > KygECHuK ©   (02.09.08 15:42) [136]

    > А точно неявная выгрузка ловушки происходит только по завершению
    > процесса?

    Хук - собственность потока, его создавшего,
    освобождается вместе с ним.
    И не сразу, а при свершении очередного отлавливаемого события.

    --
    Regards, LVT.
  • KygECHuK © (02.09.08 19:09) [150]

    > Хук - собственность потока, его создавшего, освобождается
    > вместе с ним.И не сразу, а при свершении очередного отлавливаемого
    > события.


    Вот это я уже сам выяснил эвристически то-есть тыком :). Спасибо за подтверждение моей догадки.


    > все как у Рихтера. Или ты что-то иное имеешь ввиду?

    Надо бы мне его почитать, это веть книга? )
  • Сергей М. © (02.09.08 19:29) [151]

    > Надо бы мне его почитать, это веть книга? )


    Нет, это зарубки на скальных образованиях Мезозоя.
  • KygECHuK © (02.09.08 19:33) [152]

    > Нет, это зарубки на скальных образованиях Мезозоя.


    Жестко, а что так?
  • Сергей М. © (02.09.08 20:11) [153]
    Да просто устал я от твоего Монте-Карло, извини уж)
  • KygECHuK © (02.09.08 20:21) [154]

    > Да просто устал я от твоего Монте-Карло, извини уж)


    Я вообще подумал что это про книгу котрая устарела )
  • KygECHuK © (02.09.08 21:00) [155]
    да и тема себя изчерпала
  • Сергей М. © (02.09.08 21:04) [156]
    Да и, похоже, ни о чем она была - как был у тебя вопрос про AV неразрешенным, так он таким и остался.
  • KygECHuK © (02.09.08 21:08) [157]

    > Да и, похоже, ни о чем она была - как был у тебя вопрос
    > про AV неразрешенным, так он таким и остался.


    нет, все получилось, я использовал ваш совет и AV больше нет.
    Ище раз спасибо.
  • evvcom © (03.09.08 08:17) [158]

    > это веть книга? )

    Джефри Рихтер. Windows для профессионалов.
    Если не путаю, у Анатолия Подгорецкого на сайте есть.
  • KygECHuK © (03.09.08 10:34) [159]

    > Джефри Рихтер. Windows для профессионалов.Если не путаю,
    >  у Анатолия Подгорецкого на сайте есть.

    Спасибо посмотрю

    > выгрузка CreatRemoteThread FreeLibrary


    Ты её делаешь сразу без условий или с какими то либо задержками или синхронизацией?
  • evvcom © (03.09.08 13:54) [160]
    честно говоря, такую деталь не помню. Писал давно, да и по сути делал перевод с сишного примера Рихтера на паскаль, а под рукой сейчас исходника нет. Вечером посмотрю, если не забуду :)
  • KygECHuK © (03.09.08 15:11) [161]

    >  сишного примера Рихтера на паскаль


    я то же с чьегото сишного примера делал
  • Anatoly Podgoretsky © (03.09.08 20:14) [162]
    > KygECHuK  (03.09.2008 10:34:39)  [159]

    Есть и на русском и на английском. Четвертое издание.
  • evvcom © (04.09.08 23:27) [163]
    // На вход передаем dwProcessId - идентификатор процесса,
    // в который требуется внедрить dll с именем lpModName
    function InjectLibByRemoteThread(dwProcessId: DWORD; lpModName: PChar): Boolean;
    var
     l_hProcess: THandle;
     l_hThread: THandle;
     l_ThreadFunc: TFNThreadStartRoutine;
     l_ThreadId: DWORD;
     l_iLength: Cardinal;
     l_pBuffer: PChar;
     l_NumberOfBytesWritten: DWORD;
    begin
     Result := False;
     l_hProcess := OpenProcess(PROCESS_CREATE_THREAD or PROCESS_VM_OPERATION or
       PROCESS_VM_WRITE, False, dwProcessId);
     if l_hProcess = 0 then Exit;
     try
       l_ThreadFunc := GetProcAddress(GetModuleHandle(kernel32), 'LoadLibraryA');
       if not Assigned(l_ThreadFunc) then Exit;
       l_iLength := Length(lpModName);
       l_pBuffer := VirtualAllocEx(l_hProcess, nil, l_iLength + 1,
         MEM_COMMIT, PAGE_READWRITE);
       if not Assigned(l_pBuffer) then Exit;
       try
         if not WriteProcessMemory(l_hProcess, l_pBuffer, lpModName, l_iLength,
           l_NumberOfBytesWritten)
         then Exit;
         l_hThread := CreateRemoteThread(l_hProcess, nil, 0, l_ThreadFunc,
           l_pBuffer, 0, l_ThreadId);
         Result := l_hThread <> 0;
         if Result then begin
           WaitForSingleObject(l_hThread, INFINITE);
           CloseHandle(l_hThread);
         end;
       finally
         VirtualFreeEx(l_hProcess, l_pBuffer, 0, MEM_RELEASE);
       end;
     finally
       CloseHandle(l_hProcess);
     end;
    end;

    // На вход передаем dwProcessId - идентификатор процесса,
    // из которого требуется выгрузить dll с именем lpModName
    function WithdrawLibByRemoteThread(dwProcessId: DWORD; lpModName: PChar): Boolean;
    var
     l_hProcess: THandle;
     l_hThread: THandle;
     l_ThreadFunc: TFNThreadStartRoutine;
     l_ToolHelp: TToolHelp;
     l_me: TModuleEntry32;
     l_ThreadId: DWORD;
    begin
     Result := False;
     l_hProcess := OpenProcess(PROCESS_CREATE_THREAD or PROCESS_VM_OPERATION or
       PROCESS_VM_WRITE, False, dwProcessId);
     if l_hProcess = 0 then Exit;
     try
       l_ThreadFunc := GetProcAddress(GetModuleHandle(kernel32), 'FreeLibrary');
       if not Assigned(l_ThreadFunc) then Exit;
       // Найдем внедренную библиотеку в целевом процессе
       l_ToolHelp := TToolHelp.Create(TH32CS_SNAPMODULE, dwProcessId);
       try
         l_me.dwSize := SizeOf(TModuleEntry32);
         if not l_ToolHelp.ModuleByNameFind(lpModName, l_me) then Exit;
         l_hThread := CreateRemoteThread(l_hProcess, nil, 0, l_ThreadFunc,
           Pointer(l_me.hModule), 0, l_ThreadId);
         Result := l_hThread <> 0;
         if Result then begin
           WaitForSingleObject(l_hThread, INFINITE);
           CloseHandle(l_hThread);
         end;
       finally
         l_ToolHelp.Free;
       end;
     finally
       CloseHandle(l_hProcess);
     end;
    end;

  • evvcom © (05.09.08 08:27) [164]

    > Ты её делаешь сразу без условий или с какими то либо задержками
    > или синхронизацией?

    Из кода видно, что выполняется ожидание завершения потока до закрытия хэндла. Или ты под задержкой/синхронизацией имел ввиду что-то другое?
  • KygECHuK © (05.09.08 09:53) [165]

    > Из кода видно, что выполняется ожидание завершения потока
    > до закрытия хэндла. Или ты под задержкой/синхронизацией
    > имел ввиду что-то другое?


    Я имел ввиду действия, которые производит библиотека при отключении жертвы от неё.
  • evvcom © (05.09.08 10:34) [166]
    Действия, которые производит библиотека при отключении, выполняются в DLL_PROCESS_DETACH (в АП жертвы). Пока они не выполнятся, поток не завершит свою работу. А сервис (у меня сервис), т.е. процесс, который занимается внедрением/изъятием dll в/из АП жертвы, ждет завершения удаленного потока
    WaitForSingleObject(l_hThread, INFINITE);

    Этим и достигается синхронизация.
  • KygECHuK © (05.09.08 10:41) [167]

    > Этим и достигается синхронизация.

    Все это хоршо, я это понял из предыдущего поста. мения интеризуют не конкретно используемые объекты синхронизации Windows, а "синхронизация" потока, исправляющего адреса с другими потоками процесса жертвы
  • evvcom © (05.09.08 12:07) [168]
    аааа.... Ты вот о чем. Идея такова. После того, как случился внедреж :), dll в жертве (далее просто жертва) начинает общаться с сервисом, вариантов реализации этого общения - масса, каждый выбирает, что ему по вкусу, поэтому не буду на этом останавливаться. Жертва запрашивает у сервиса, что приготовлено для данного процесса, какую dll надо загрузить, после чего выполняет LoadLibrary уже штатно. Далее останавливаются все потоки процесса кроме текущего (или это лучше сделать самым первым делом после внедрения), из загруженной dll вытягивается инфа, что должно быть перехвачено, вычисляются адреса и данные, которые должны быть по ним записаны, и все это сообщается сервису, который успешно производит подмены адресов. Сообщение жертве "все готово", та запускает потоки и завершает свой стартовый код DLL_PROCESS_ATTACH. Ну вот типа такого.
  • Сергей М. © (05.09.08 12:24) [169]

    > evvcom ©   (05.09.08 12:07) [168]


    А грабли как были , так и остались, не смотря на все эти хитромудрые телодвижения)

    Ведь выгрузку модуля-перехватчика нельзя делать пор, пока хотя бы в одном из потоков процесса-жертвы исполняется код, принадлежащий АП модуля-перехватчика..

    Первое что напрашивается для устранения засады - в ходе деинициализации перехватчика вернуть на место оригинальные IAT/EAT-элементы и в цикле (опасно, но куда деваться ?) проверять, не ссылается ли контекст каждого из существующих потоков жертвы на код в АП перехватчика или не фигурирует ли в стеках потоков адреса возвратов, указывающие на АП перехватчика.

    Это отдельный геморрой, но он, видимо, того стОит ..
  • evvcom © (05.09.08 13:13) [170]
    Согласен :)
    Я не все здесь описал, что задумал. Даже если в настоящий момент код не выполняется, и мы определим это из контекстов, стеков и прочих ухищрений, нет никакой гарантии, что не схватим AV после Resume потоков. Я столкнулся с этим в первой же своей подобной задаче, о чем упомянул в [141]. Гораздо проще, имхо, и надежнее сделать нечто типа MakeObjectInstance, которая конструировала бы в куче что-то типа вызова перехваченной функции или оригинала по условию в зависимости от взведенного флага и соответственно перед выполнением кода "ловушки" inc счетчика, после dec. Естественно все это надежно защитить, например, крит. секцией. Детали я еще не реализовывал, потому по ходу будут грабли, обязательно будут.
  • Сергей М. © (05.09.08 13:40) [171]

    > нет никакой гарантии, что не схватим AV после Resume потоков


    Гарантия есть, потому что тек.контексты и стеки потоков отныне ни прямо ни косвенно не ссылаются ни на один из адресов в АП модуля-перехватчика, что как раз и покажет проверка. И более никогда не будут обращаться к этому АП, потому что оригинальная IAT восстановлена перед началом проверки.
  • evvcom © (05.09.08 14:10) [172]
    Сергей, ты в [141] читал ситуацию?

    > И более никогда не будут обращаться к этому АП, потому что
    > оригинальная IAT восстановлена перед началом проверки.

    Разве обращаться к функции можно только каждый раз проверяя IAT? Еще раз поясню ситуацию. Процесс загрузил мою dll, dll изменила IAT, процесс считал адрес (это уже адрес в моей dll) и сохранил его в ebx, далее

    цикл:
    push ebx

    условие 1:
    call ebx // перехваченная функция

    ... прочие условия

    условие N:
    call FreeLibrary

    pop ebx
    cmp ...
    jmp nz, цикл



    Вот такая вот реальная ситуация была и происходило это в однопоточном приложении.
  • Сергей М. © (05.09.08 14:33) [173]

    > evvcom ©   (05.09.08 14:10) [172]


    А, ты вон о чем ..

    Ч.г., я не вник в [141], а ты там завел речь о частном случае (довольно редкий он и заведомо не случай автора, потому я и не рассматривал его) ..

    Ну что тут сказать ?
    Для случаев, подобных твоему, метод перехвата путем модификации IAT/EAT не годится, здесь на сцену выходит метод сплайсинга.
  • KygECHuK © (05.09.08 15:20) [174]

    > здесь на сцену выходит метод сплайсинга.


    Что за зверь, где о нём можно раздобыть инфу?
  • Сергей М. © (05.09.08 15:29) [175]

    > KygECHuK ©   (05.09.08 15:20) [174]


    "Шурик, это же не наш метод !" (С)

    Тебе-т он зачем ? Явно же не твой же случай ..

    Или "Надо, Федя, надо"  ?)

    http://www.wasm.ru/article.php?article=apihook_1
  • KygECHuK © (05.09.08 15:44) [176]

    > Тебе-т он зачем ? Явно же не твой же случай ..


    Автор:

    Для того, чтобы его понять нужна всего-лишь капля мозгов (не больше).


    по минимальным требованиям, вроде подхожу... :)
    Учиться никогда не поздно, хотя часто бесполезно ....
 
Конференция "WinAPI" » Выгрузка WinApi перехватчика [D7, WinXP]
Есть новые Нет новых   [134435   +33][b:0.001][p:0.008]