|
Новичок
Регистрация: 18.06.2022
Сообщений: 4
С нами:
2057168
Репутация:
1
|
|
Сообщение от kin4stat
Да, так оно и есть. Но есть одно главное отличие: operator new - стандартная фича плюсов, и она будет работать везде, где поддержан C++. VirtualAlloc же есть только на винде.
Второе отличие - VirtuaAlloc аллоцирует страницу памяти, а не отдает кусок из заранее выделенной памяти. Также operator new юзает под капотом HeapAlloc на винде, а не VirtualAlloc.
Почему для хуков юзают VirtualAlloc: operator new выделяет невыровненный кусок памяти, а также выделяет ее с правами ReadWrite, когда у VirtualAlloc можно выбрать самому сразу, с какой защитой будет выдана страница памяти. Выровненный кусок памяти нужен для скорости. Процессор читает память в кеш кусками по 64 байта. Когда мы используем VirtuaAlloc, процессору нужно лишь подгрузить начало страницы, и он уже будет обладать всеми нужными инструкциями. В случае operator new, ему придется подгрузить невыровненный кусок памяти, который в худшем случае будет содержать всего один байт инструкций, а все остальное будет мусором, что побудит его подгрузить еще 64 байта памяти в кеш линию
Разницу в перфе оно будет иметь. Т.к. когда мы создаем хук через аналогичную функцию, мы сохраняем только нужные регистры, и имеем право изменять некоторые регистры, т.к. они являются volatile. Т.е. мы сохраняем на стек 2-3 регистра, и перезатираем 2-3 регистра, не сохраняя их, т.к. до этого вызывающая сторона уже позаботилась об их сохранении, либо не использовала их вообще. Когда мы делаем pusha и popa, мы сохраняем все регистры. Само копирование регистров не сильно ощутимо. Ощутимо количество памяти, которое мы при этом дергаем(стек).
При должной обертке, можно реализовать и такое. Например kthook научился так делать недавно - https://www.blast.hk/threads/101004/post-1063328
Эту память все еще аллоцирует система при подгрузке приложения в память с HDD. Она точно также через условный VirtualAlloc создает страницы памяти, загружает туда код, размечает секции и прочее.
Также, если мы будем создавать хуки на такой основе - мы будем раздувать размер файла, вместо того чтобы выделять нужное количество памяти когда нам нужно в рантайме.
Спасибо за развёрнутый ответ. У меня есть ещё пара вопросов:
1) Касательно этого момента:
Сообщение от kin4stat
Эту память все еще аллоцирует система при подгрузке приложения в память с HDD. Она точно также через условный VirtualAlloc создает страницы памяти, загружает туда код, размечает секции и прочее.
То есть, по сути, можно сказать, что скорость работы при обращении к буферу, который был выделен через VirtualAlloc будет даже быстрее за счёт того, что там отсутствуют опкоды для pusha и popa. Следовательно и памяти (я не считаю выделенный блок в 4 кб целиком, а именно ту часть, что занята под буфер) будет занято меньше за счёт отсутствия тех двух опкодов. Надеюсь, правильно понял.
2) Вы писали о том, что постоянное такое использование приведёт к раздутию файла. Собсна, к этому у меня идёт следующий вопрос:
Сообщение от D3ad_Parad15e
Ещё, как я читал, VirtualAlloc выделяет большой блок памяти (4 кб), и постоянный вызов по сути каждый раз выделяет такой блок памяти. То есть, для того, чтобы не растрачивать память попусту, стоит выделять её один раз, а дальше записывать в память, и делать смещение указателя на размер хука, а после записывать новый хук уже по данному смещению и так далее, верно?
К примеру, для записи затёртых опкодов понадобилось 6 байт, + 5 байт - call на наш код, + ещё 5 байт - прыжок на продолжение оригинала. Выходит 16 байт. Они прибавляются к указателю на выделенный ранее VirtualAlloc и при следующем хуке запись пройдёт по этому указателю и к нему прибавится вновь какой-то оффсет. И так далее.
|