Comments 72
Я когда-то тоже писал аналогичный велосипед.
Но вместо сравнивания первых 5 байт с фиксированной константой (в методе Analyze) я взял <a href=«www.google.ru/search?q=length+disassembler>дизассемблер длин LDE32.
тогда каждую перехватываемую процедуру не надо описывать в _Analyze
Но вместо сравнивания первых 5 байт с фиксированной константой (в методе Analyze) я взял <a href=«www.google.ru/search?q=length+disassembler>дизассемблер длин LDE32.
тогда каждую перехватываемую процедуру не надо описывать в _Analyze
+4
p.s.: для того чтобы случайно не «задеть» косвенную адресацию, достаточно опкоды проверять с небольшим списком. т.к. в прологе большинства WinAPI функций содержатся только push и mov.
0
В большинстве API-функций в начала вообще находится стандартый 5-байтовый пролог, однако в недрах WinNT.h, например, все уже не столь радужно.
0
ntdll.dll, конечно же, а не winnt.h
0
мне этого хватало для перехвата довольно большого количества даже Nt* и Zw* функций. конечно, для нормального продукта этого тоже мало (надо перехватывать всё), но на просторах интернета есть также и бесплатные и _очень_ продвинутые аналоги detours.
P.P.S.: в девичестве detours был бесплатен и даже не требовал detours.dll. у меня где-то даже его сорцы остались.
P.P.S.: в девичестве detours был бесплатен и даже не требовал detours.dll. у меня где-то даже его сорцы остались.
0
В данном случае, _Analyze — это просто метод-заглушка под будущую реализацию подобного механизма.
Я именно поэтому описал в возможностях модернизации применение какого-либо дизассемблера. Именно туда его и планируется вставить.
Я именно поэтому описал в возможностях модернизации применение какого-либо дизассемблера. Именно туда его и планируется вставить.
0
Есть еще hde32, который можно использовать в этих целях. Вообще, таких решений пусть и не очень много, но они есть. Причем, по возможностям они почти не отличаются друг от друга.
0
Это всё чудесно, но какой смысл что-то перехватывать в рамках одного (своего) модуля? ;) Если же вы влезаете (inject) в другой (чужой) модуль, то появляется новая проблема, например ASLR.
+1
Смысл есть. Например, в том случае, если вы — add-in для ворда. Либо — shell extension. Либо во всех остальных случаях, когда вашу DLL совершенно легально загружают в процесс.
Кроме того, методики внедрения DLL в чужой процесс описаны на том же RSDN.
Кроме того, методики внедрения DLL в чужой процесс описаны на том же RSDN.
0
смотря как влезем. если боле-менее «легально» то всю эту рандомизацию нам сдаст с потрохами загрузчик.
ASLR имеет смысл когда мы залезаем через buffer overflow и прочие «вирусные» варианты.
ASLR имеет смысл когда мы залезаем через buffer overflow и прочие «вирусные» варианты.
0
Да-да, но если мы влезаем «легально», то зачем нам что-то перехватывать? ;) Ведь тогда есть «легальные» способы для доступа к данным.
0
В том то и проблема, что они есть не всегда, и позволяют делать не все.
0
иногда требуется.
либо, как ниже написали — слегка изменить поведение программы.
либо, как мне однажды понадобилось, вытаскивать данные из другой программы, но не ковырянием в памяти, а по мере их поступления.
либо, как ниже написали — слегка изменить поведение программы.
либо, как мне однажды понадобилось, вытаскивать данные из другой программы, но не ковырянием в памяти, а по мере их поступления.
0
Нет «легальных» способов для доступа к данным если код не ваш. Например внедрение в браузер, например если вы пишете программу которая управляет другими программами те же GUI test/automation. Мои друзья когда появилась такая задача всё таки купили detours, потому что она того стоит и самим такое универсальное решение разработать будет стоить дороже.
+1
«Сэкономить 10.000$» — достаточно пафосно :)
В таком случае, используя в работе www.codeproject.com/KB/winsdk/LibMinHook.aspx, я экономлю еще и время на написание велосипеда :)
В таком случае, используя в работе www.codeproject.com/KB/winsdk/LibMinHook.aspx, я экономлю еще и время на написание велосипеда :)
0
И в который раз скажу — не надо так делать :-) Если вы, конечно, не вирье пишите :-)
-1
Все зависит от поставленной задачи. Иногда приходится применять и такие методы.
Например, через перехват CreateFile мы реализуем прозрачную загрузку файлов с сервера.
Например, через перехват CreateFile мы реализуем прозрачную загрузку файлов с сервера.
0
Не, понятно, что в некоторых случаях иначе никак и для использования нужны очень веские основания.
0
Я тоже с использованием этого механизма позволяю организовать работу в пакете NX(бывший Unigraphics) в рамках нашей plm-системы.
Перехват функций работы с файлами+внутренних функций NX, для того, чтобы вместо имен файлов видны были обозначение+ревизия и пользователь не работал напрямую с файловой системой.
Перехват функций работы с файлами+внутренних функций NX, для того, чтобы вместо имен файлов видны были обозначение+ревизия и пользователь не работал напрямую с файловой системой.
+1
Не логичнее ли сделать отдельную ФС и не лезть в программу?
-3
Слабо с ходу прикинуть трудозатраты на разработку?
+2
Я же сказал, что вся работа ведется в рамках нашей системы.
В данном случае, пользователь нажимает где-то в nx на кнопку требующую открытия файла с диска — перехватывается GetOpenFilename — и он видит диалоги выбора, написанные мной(думаю очевидно, что это даёт бОльшие возможности по поиску, сортировкам, выборке по критериям).
Я уж не говорю, что это только одна из граней, а вообще перехватывается обращение nx к реестру, чтобы настроить вид колонок в навигаторе сборки, перехватывается чтение атрибутов из модели, чтобы показать уже упомянутые обозначение и ревизию(хотя в файле они не записаны и по умолчанию функция бы ничего не прочитала).
Много чего удобного благодаря этому уже сделано :) Мыслите шире.
В данном случае, пользователь нажимает где-то в nx на кнопку требующую открытия файла с диска — перехватывается GetOpenFilename — и он видит диалоги выбора, написанные мной(думаю очевидно, что это даёт бОльшие возможности по поиску, сортировкам, выборке по критериям).
Я уж не говорю, что это только одна из граней, а вообще перехватывается обращение nx к реестру, чтобы настроить вид колонок в навигаторе сборки, перехватывается чтение атрибутов из модели, чтобы показать уже упомянутые обозначение и ревизию(хотя в файле они не записаны и по умолчанию функция бы ничего не прочитала).
Много чего удобного благодаря этому уже сделано :) Мыслите шире.
+1
и если вирьё пишете, то тоже делать так не надо.
для вирья надо (как минимум):
1. всё-таки нормальный LDE, т.к. перехватить надо реально много функций
2. перехват не в первых 5 байтах, а дальше (т.к. большинство антивирусов проверяют прологи на джамп за пределы модуля). вы же не хотите спалиться? ;)
для вирья надо (как минимум):
1. всё-таки нормальный LDE, т.к. перехватить надо реально много функций
2. перехват не в первых 5 байтах, а дальше (т.к. большинство антивирусов проверяют прологи на джамп за пределы модуля). вы же не хотите спалиться? ;)
0
Библиотека от майкрософта:
research.microsoft.com/en-us/projects/detours/
research.microsoft.com/en-us/projects/detours/
+2
Извините, если задам сейчас глупый вопрос. Но я правильно понимаю, что программы, написанные таким образом, совершенно точно не будут работать под Wine и в ReactOS? Там ведь те же функции API реализуются совершенно иначе?
Я не специалист в этой области, но все равно жутко интересно :)
Я не специалист в этой области, но все равно жутко интересно :)
0
Аналогичный метод в свое время очень детально описал MsRem на wasm.ru, плюс рассмотрел варианты о том, как обмануть файерволлы, дабы они не выкидывали варнинги.
0
Интересно, что же такое создаёт автор, что требует перехвата CreateFile и CloseHandle? ;)
0
Что-то мне подсказывает, что Detours не зря стоит 10к $.
P.S.: боян, и метод называется splicing
P.S.: боян, и метод называется splicing
+3
Супербизон. Горжусь и плюсую.
0
Общеизвестных методов перехвата API-функций существует ровно два, все остальные – их вариации.
Скажем так: первые приходящие на ум.
Половина вопросов автора решится методом VEH (описан подробно здесь
Вообще говоря, перехват API в user-mode дело крайне неблагодарное и некрасивое.
0
Я статью еще не читал, только вкратце пробежал по заголовкам, но, честно говоря, не совсем понимаю, какое структурная обработка исключений имеет отношение к перехвату функций.
0
На самом деле, если вкратце пробежаться по заголовкам, то речь идет о векторной обработке исключений.
Статья описывает данную технологию, и в качестве примера по ее использованию приводится в пример с перехватом функции LoadLibraryExW (к которой сводятся все UM версии LoadLibraryX). Суть в следующем: в начало функции мы вставляем одну единственную инструкцию 'INT 03', при вызове функции получаем исключение STATUS_BREAKPOINT… Ну а дальше суть понятна.
Статья описывает данную технологию, и в качестве примера по ее использованию приводится в пример с перехватом функции LoadLibraryExW (к которой сводятся все UM версии LoadLibraryX). Суть в следующем: в начало функции мы вставляем одну единственную инструкцию 'INT 03', при вызове функции получаем исключение STATUS_BREAKPOINT… Ну а дальше суть понятна.
0
Плюс тебе за анекдот про такси!
0
Спасибо за статью
0
Спасибо за статью.
Поидее, если делать инъекцию не в свое адресное пространство, а в чужое, то, если между вызовами
Решением может быть использование одной из команд mov из SSE, которые умеют атомарно 8 или 16 байт переносить.
Поидее, если делать инъекцию не в свое адресное пространство, а в чужое, то, если между вызовами
lpFunc->opcode = 0xe9;произойдет переключение задачи, и атакуемая задача попробует вызвать недоизмененную функцию, то произойдет джамп непонятно куда, что очень печально.
lpFunc->relativeAddress = _CalculateDispacement(lpFunc, &_My_CreateFileW);
Решением может быть использование одной из команд mov из SSE, которые умеют атомарно 8 или 16 байт переносить.
0
На самом деле, в реальном приложении вероятность этого довольно мала, так как подключение обработчиков происходит в момент LoadLibrary. Если хочется перестраховаться — можно использовать атомарные инструкции MMX или SSE.
0
Почему вы используете
void* lpFunc = GetProcAddress(hKernel32, «CreateFileW»);
вместо
void* lpFunc = &CreateFileW;
?
void* lpFunc = GetProcAddress(hKernel32, «CreateFileW»);
вместо
void* lpFunc = &CreateFileW;
?
+1
Кстати, про проблему, с которой можно столкнуться на x64, написано тут
+1
тут -> cr4sh-0x48k.livejournal.com/38812.html
прошу прощения за косяк с тегом.
прошу прощения за косяк с тегом.
0
UFO just landed and posted this here
На самом деле, он совсем не страшный — это всего-навсего один такт процессора. Любая высокоуровневая инструкция сожрет таких тактов 10-15, особенно вызов функции.
Судя по тому, что я в свое время гуглил — она вставлена специально для возможности организовать там перехват.
Судя по тому, что я в свое время гуглил — она вставлена специально для возможности организовать там перехват.
+1
может не в тему (много букв, не прочитал все), а может кому-то пригодится — так я перехватываю waveOutWrite (к примеру):
[pascal]
type
TFarJmp = packed record
PuhsOp: byte;
PushArg: pointer;
RetOp: byte;
end;
var
FCurrentProcess: cardinal;
WaveOutFnAddr: pointer;
WaveOutOldProc, WaveOutNewProc: TFarJmp;
// init
FCurrentProcess := GetCurrentProcess;
WaveOutFnAddr := GetProcAddress(h, 'waveOutWrite');
WaveOutNewProc.PuhsOp := $68;
WaveOutNewProc.PushArg := @WaveOutWriteMod;
WaveOutNewProc.RetOp := $C3;
ReadProcessMemory(FCurrentProcess, WaveOutFnAddr, @WaveOutOldProc, sizeof (TFarJmp), w);
WriteProcessMemory(FCurrentProcess, WaveOutFnAddr, @WaveOutNewProc, sizeof (TFarJmp), w);
// fine
WriteProcessMemory(FCurrentProcess, WaveOutFnAddr, @WaveOutOldProc, SizeOf (TFarJmp), w);
function WaveOutWriteMod (hWaveOut: HWAVEOUT; lpWaveOutHdr: PWaveHdr; uSize: UINT): MMRESULT; stdcall;
begin
// чегото тут поделал скажем с данными
WriteProcessMemory (FCurrentProcess, WaveOutFnAddr, @WaveOutOldProc, SizeOf(TFarJmp), w);
Result := waveOutWrite(hWaveOut, lpWaveOutHdr, uSize);
WriteProcessMemory (FCurrentProcess, WaveOutFnAddr, @WaveOutNewProc, SizeOf(TFarJmp), w);
end;
[/pascal]
как-то так…
[pascal]
type
TFarJmp = packed record
PuhsOp: byte;
PushArg: pointer;
RetOp: byte;
end;
var
FCurrentProcess: cardinal;
WaveOutFnAddr: pointer;
WaveOutOldProc, WaveOutNewProc: TFarJmp;
// init
FCurrentProcess := GetCurrentProcess;
WaveOutFnAddr := GetProcAddress(h, 'waveOutWrite');
WaveOutNewProc.PuhsOp := $68;
WaveOutNewProc.PushArg := @WaveOutWriteMod;
WaveOutNewProc.RetOp := $C3;
ReadProcessMemory(FCurrentProcess, WaveOutFnAddr, @WaveOutOldProc, sizeof (TFarJmp), w);
WriteProcessMemory(FCurrentProcess, WaveOutFnAddr, @WaveOutNewProc, sizeof (TFarJmp), w);
// fine
WriteProcessMemory(FCurrentProcess, WaveOutFnAddr, @WaveOutOldProc, SizeOf (TFarJmp), w);
function WaveOutWriteMod (hWaveOut: HWAVEOUT; lpWaveOutHdr: PWaveHdr; uSize: UINT): MMRESULT; stdcall;
begin
// чегото тут поделал скажем с данными
WriteProcessMemory (FCurrentProcess, WaveOutFnAddr, @WaveOutOldProc, SizeOf(TFarJmp), w);
Result := waveOutWrite(hWaveOut, lpWaveOutHdr, uSize);
WriteProcessMemory (FCurrentProcess, WaveOutFnAddr, @WaveOutNewProc, SizeOf(TFarJmp), w);
end;
[/pascal]
как-то так…
0
Ну, это, еще одна методика
push retaddr
ret
Только она по размеру вроде как больше 5 байт (5 байт только на push уйдет, + байт на ret), нэ?
push retaddr
ret
Только она по размеру вроде как больше 5 байт (5 байт только на push уйдет, + байт на ret), нэ?
0
а я хз, 5 байт или сколько там… когда-то когда надо было нашел способ, проверил, что работает — и пользую, а как работает — уже «черный ящик», пусть себе работает
0
А что мешает сохранять, например, первые байт 8 или скока нада, и потом при восстановлении возвращать все на место?
0
На wasm.ru есть отличный цикл статей на тему перехвата API с примерами и библиотекой.
wasm.ru/series.php?sid=8
Правда, примеры на Delphi. Библиотеки для С++ можно найти на codeproject, например:
www.codeproject.com/KB/DLL/EasyHook64.aspx
или (писали выше) www.codeproject.com/KB/winsdk/LibMinHook.aspx
wasm.ru/series.php?sid=8
Правда, примеры на Delphi. Библиотеки для С++ можно найти на codeproject, например:
www.codeproject.com/KB/DLL/EasyHook64.aspx
или (писали выше) www.codeproject.com/KB/winsdk/LibMinHook.aspx
+1
А как быть с DEP? B потом когда антивирусы видят VirtualProtect они начинают нервничать.
0
DEP обходится как раз VirtualProtect-ом.
А нервничать начинают антивирусы только в том случае, если мы пишем в память чужого процесса.
А нервничать начинают антивирусы только в том случае, если мы пишем в память чужого процесса.
0
Ужас. Я не понимаю зачем это надо в разделе С++? Какое отношение пост имеет к С++? Тоже самое можно сделать на любом другом языке, это рас. Во вторых это ужасно устарело и не знают об этом разве что дотеры и веб дизайнеры. Вот уж не думал что пост ещё и комментировать будут.
Я разочарован хабром :(
Я разочарован хабром :(
0
Sign up to leave a comment.
Перехват вызовов API-функций