Показать сообщение отдельно

  #5  
Старый 18.06.2022, 14:57
kin4stat
Флудер
Регистрация: 06.11.2017
Сообщений: 2,759
С нами: 4483143

Репутация: 183


По умолчанию

Цитата:
Сообщение от D3ad_Parad15e  

Вопрос первый: есть ли какие-то различия между new[] и VirtualAlloc в данном случае? Искал информацию в интернете по этому поводу - и понял так, что VirtualAlloc выделяет именно фиксированное число памяти, в то время как new при первом разе выделяет какое-то большое количество памяти, а потом, при каждом новом вызове - хватает из выделенном буфера память, оттого и работает он при каждом вызове быстрее, чем VirtualAlloc. Поправьте, если ошибаюсь. Мне просто интересно, почему используют именно его, а не operator new.
Да, так оно и есть. Но есть одно главное отличие: operator new - стандартная фича плюсов, и она будет работать везде, где поддержан C++. VirtualAlloc же есть только на винде.

Второе отличие - VirtuaAlloc аллоцирует страницу памяти, а не отдает кусок из заранее выделенной памяти. Также operator new юзает под капотом HeapAlloc на винде, а не VirtualAlloc.

Почему для хуков юзают VirtualAlloc: operator new выделяет невыровненный кусок памяти, а также выделяет ее с правами ReadWrite, когда у VirtualAlloc можно выбрать самому сразу, с какой защитой будет выдана страница памяти. Выровненный кусок памяти нужен для скорости. Процессор читает память в кеш кусками по 64 байта. Когда мы используем VirtuaAlloc, процессору нужно лишь подгрузить начало страницы, и он уже будет обладать всеми нужными инструкциями. В случае operator new, ему придется подгрузить невыровненный кусок памяти, который в худшем случае будет содержать всего один байт инструкций, а все остальное будет мусором, что побудит его подгрузить еще 64 байта памяти в кеш линию

Цитата:
Сообщение от D3ad_Parad15e  

опрос второй: фактически, можно ведь создать что-то вроде своего обработчика через naked? То есть, по сути, записать в naked функцию pusha, сделать jmp (или call, но здесь уже понадобится реализация передачи параметров) на функцию со своим кодом, а после вернуться на это же место, выполнить popa, выполнить код тех опкодов, которые были затёрты хуком и продолжить работу функции. Так вот, вопрос такой: будет ли это иметь разницу в производительности?
Разницу в перфе оно будет иметь. Т.к. когда мы создаем хук через аналогичную функцию, мы сохраняем только нужные регистры, и имеем право изменять некоторые регистры, т.к. они являются volatile. Т.е. мы сохраняем на стек 2-3 регистра, и перезатираем 2-3 регистра, не сохраняя их, т.к. до этого вызывающая сторона уже позаботилась об их сохранении, либо не использовала их вообще. Когда мы делаем pusha и popa, мы сохраняем все регистры. Само копирование регистров не сильно ощутимо. Ощутимо количество памяти, которое мы при этом дергаем(стек).

Цитата:
Сообщение от D3ad_Parad15e  

И, как я понимаю, из-за этого уже не получится делать хуки при помощи операторов и лямбд (именно тех лямбд, в которых описан код, который должен выполняться при переходе).
При должной обертке, можно реализовать и такое. Например kthook научился так делать недавно - https://www.blast.hk/threads/101004/post-1063328

Цитата:
Сообщение от D3ad_Parad15e  

В случае, если вариант два является более производительным за счёт того, что там не выделяется динамически память, возможно ли сделать это как-то статически, дабы не создавать naked функцию? К примеру, байтовый массив, в котором будут записаны необходимые опкоды. По факту - как с VirtualAlloc, но память будет выделена не динамически, а, грубо говоря, глобально, так, словно была создана какая-то static переменная? То есть, вызывается функция для хука, и там создаётся эта самая переменная, которая будет жить до конца работы программы
Эту память все еще аллоцирует система при подгрузке приложения в память с HDD. Она точно также через условный VirtualAlloc создает страницы памяти, загружает туда код, размечает секции и прочее.

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