SetUnhandledExceptionFilter не совсем то что тебе надо KiUserExceptionDispatcher - то. Смотри почему. Вариант с SetUnhandledExceptionFilter: 1. Система по очереди вызывает SEH хендлеры 2. Если ни один не обработал exception, вызывает твой хендлер переданный в SetUnhandledExceptionFilter Теперь предположим что программисты программы таки сделали проверку на разные типы exception'ов в своем SEH обработчике и при exception покажут окошко - мол, извините, мы упали. Твой handler так и не получит управления. KiUserExceptionDispatcher как раз и есть та самая функция, которая вызывает SEH handler'ы и если ни один не обработал exception - вызывает Unhandled exception handler. Т.е. она первая из всех, кто получает инфу о exception. Что до THREAD_DETACH - ага, если поток завершился (TerminateThread или просто вышли). Закрытие процесса закрывает все нитки. Edit: Кстати, хранение данных в потоке я бы делал с TlsGetValue()/TlsSetValue(). В смысле в куче выделял бы памяти и с помощью TlsSetValue() сохранял бы указатель на нее. Потом, когда надо - с TlsGetValue() читал бы и работал. Никаких блокировок, ляпота. Как вариант, в принципе. Можно и руками разрулить.
Как я понял для KiUserExceptionDispatcher нет функции типа SetUserExceptionDispatcher, надо хукать... Сейчас буду разбираться. С TLS мне не всё нравится, я вообще бумал свой список делать. Просто получается такая картина: 1.если со списком PROCESS_ATTACH: добавляю в список структуру с регистрами THREAD_ATTACH: добавляю в список структуру с регистрами THREAD_ATTACH: добавляю в список структуру с регистрами THREAD_ATTACH: добавляю в список структуру с регистрами THREAD_DETACH: удаляю из списка структуру с регистрами PROCESS_DETACH: удаляю весь список 2. если с TLS PROCESS_ATTACH: добавляю в TLS адрес структуры с регистрами THREAD_ATTACH: добавляю в TLS адрес структуры с регистрами THREAD_ATTACH: добавляю в TLS адрес структуры с регистрами THREAD_ATTACH: добавляю в TLS адрес структуры с регистрами THREAD_DETACH: удаляю из TLS адрес структуры с регистрами PROCESS_DETACH: удаляю из TLS адрес структуры с регистрами Я не могу удалить весь список - не знаю адресов, а THREAD_DETACH вызвалось не для всех потоков. Выходят утечки памяти. Хотя при закрытии процесса оно конечно всё равно, но не красиво...
Блин, есть где-нибудь нормальный пример как хукнуть функцию из ntdll? Куча вопросов. Сплайсинг не подходит - мне надо будет вызывать оригинальзую функцию если исключение не моё. А пока я восстановлю оригинальное начало функции до того момента как я восстановлю хук если произойдёт переключение потоков то исключение я не поймаю...
Ээ. Сплайсить можно (и нужно обязательно) так, чтоб сохранялись старые байты и вызов старой функции - это выполнение сохраненных инструкций + джамп на оригинальный_адрес+размер_сохраненных_инструкций. Сплайс получается безопасным и ничего перезаписывать не надо будет никогда. Или я не понимаю что-то?)
И как ты предлагаеш мне сохранить с начала функции целое количество инструкций? Дизассемблер длин туда ещё засунуть? Если я сохраню 5 байт с начала функции, туда всуну свой джамп, потом мне надо вызывать оригинальную функцию. Я НЕ могу выполнить SavedBytes+jmp (HookedFunc+sizeof(SavedBytes)) потому что в буфер я мог скопировать только кусок последней команды. И даже если я скопировал целиком - а если там относительный jmp или call? При выполнении на новом месте управление будет передано в далёкий туман... Делать надо как-то так: Код (Text): Save5Bytes(); PatchJmpToMyFunc(); А в моей функции что-то в духе: Код (Text): MyFunc() { // Do something useful... RestoreSavedBytes(); call OriginalFunction(); PatchJmpToMyFunc(); } И тут важно чтобы между RestoreSavedBytes() и PatchJmpToMyFunc() не произошло переключение потоков, а то в этот момент хук не установлен. Да его и прочитал, не очень понятно. Переводить все потоки в Suspend что-то не охота. Может кроме сплайса есть другой метод перехвата без создания потоков и т.д.?
Нет, я хочу писать эмулятор SSE с дизассемблером исключительно SSE, а не обобщённым. Там всё очень упрощается - например недопустим префикс 66h и т.д.
cppasm Сплайс - Ищем дизассемблером длин в нужной функции достаточно длинную инструкцию/команду, чтобы целиком внутри поместить код перенаправления потока - lock cmpxchg8b/cmpxchg16b (при этом заменив в (r)ecxr)ebx только те байты от исходных, которые сплайсим, которые необходимо, т.е. напр. 6 из 8, то остальные 2 оставляем исходными т.к. могут относиться к другой инструкции, исполняющейся в др. потоке. Иначе -> BSOD) Усё.
Гм, ничего сложного в сплайсе нет. 1. Берешь дизассемблер длин, их сейчас куча. Пример - ADE32, LDE, etc. 2. Кормишь дизассемблеру начало функции в ntdll. Оно говорит тебе размер комманды. 3. Увеличиваешь указатель на размер предидущей комманды и повторяешь пункты 2-3 до тех пор пока не наберется 5 или 6 байт (6 если ты хочешь push/ret) 4. Копируешь начало функции с получившейся длиной в свой локальный буффер. 5. В локальный буффер дописываешь JMP или тот же PUSH/RET на продолжние оригинальной функции 6. На место оригинальной функции пишешь JMP на твой обработчик. Вот и все. Когда надо дергнуть оригинал - вызываешь свой буффер как обычную функцию.
Не считая того что надо дизассемблер длин применять, меня смущает такой вариант. Что если в начале функции (тот код который будем копировать) будет относительный переход. При выполнении этого кода по другим адресам (в моём буфере) результат будет печальный.
Ага, и проверку на jmp/call. В ADE32 оно флажок ADE_REL (или как там его) вернет. Но в конкретно нужной тебе функции точно не будет прыжка. Кстати, если не хочется возиться с дизассемблером длин - просто выкуси в свой буффер начало нужной функции. Потом когда будешь патчить - сравнивай. Совпало - пиши смело JMP. Непереносимо, но для старта и так сойдет.
Мм.. Я новичок, наверно не понимаю чего - но нельзя ли дизассемблировать программу и в ней заменить все SSE инструкции вызовами функций, которые будут добавлены в эту программу, а потом ее ассемблировать заново? В этом случае теряется геморрой с подгоном длин команд, как это было бы при патчинге готового бинарника.
Novi4ek ты типа предлогаеш в ней таскать дизасм и ассемблер. Пожалуйста только в KERNELMODE не делай таких подсказок. В BEGINERS твори что хочеш
Ассемблер и дизассемблер такие тяжелые программы? По сути в их таскании, как мне представляется, и заключается решение задачи, добавить нужные функции и заменить инструкции - это совсем нетрудно. И KERNELMODE в таком случае не понадобится. Только я не уловил - увеличение размера программы на несколько килобайт это единственный аргумент против такого подхода?.. Кроме того это простейший способ решения задачи (если конечно нет каких-то сопряженных с этим проблем, которые мне не очевидны) на коленке, т.к. не совсем ясно для массового ли потребителя без SSE или исключительно для себя автор хотел запустить этот продукт. Если второй вариант то по-моему нет ничего проще моего решения. Или я ошибаюсь?..
Novi4ek Автор хочет сделать эмулятор для всех страждующих... Писать дизасм и асм для этого смысла нет. Вы когда-нибудь в дизасме нарывались на битый код? И что дизасм должен делать? Мож ещё эмулятор прикрутить? Пусть автор пишет как писал
На текущий момент использую UnhandledExceptionFilter, для данной конкретной программы подходит. Если понадобится, можно заменить и на VEH, и на KiUserExceptionDispatcher. Там по сути две строки заменить. Novi4ek - не говоря о Adobe Bridge, просто попробуй ничего не изменяя взять мега сложную программу notepad.exe, её дизассемблировать и потом пересобрать. И ты поймёш что это гиблое дело по сути. Ни один дизассемблер (в том числе и IDA) не выдаст тебе листинг который сразу можно пересобрать. Тут возник вопрос по опкодам, а точнее по lock префиксу. Есть к примеру команда lock movss xmm0,[mem_addr] Вопрос - на процессорах без SSE UD# будет на lock, или на movss?? Или на разных процессорах может быть по-разному?