Встроенный asm: запись данных в память по заданному адресу
От:
Аноним
Дата:
03.11.05 16:39
Оценка:
Пытаюсь разобраться со встроенным ассемблером.
Пусть есть функция, которой в качестве параметра передается указатель (например pchar).
Как из встроенного асма записать что-то в память по заданному указателем адресу?
function JustTest(p:pchar):integer;
begin
asm
mov edi,p
//Адрес в edi
mov eax,[edi]
//Считываем 32 бита с адреса, записанного в edi.
//Работает. В отладчике видно появление нужных значений в регистре.
mov [edi],eax //Пытаемся записать обратно.
//Не работает. Вылетает из функции без сообщений при отладке.
//Если запустить сам exe, то он выполняет "недопустимую операцию".
end;
end;
Есть другой, рабочий вариант:
function JustTest2(s:shortstring):integer;
begin
asm
lea edi,s
//Получаем адрес s в edi
mov eax,[edi]
//Работает
mov [edi],eax
//Работает
end;
end;
Но хочется именно pchar.
Где я напутал?
Всем заранее спасибо.
Re: Встроенный asm: запись данных в память по заданному адре
1. При использовании ассемблера не стоит мешать его с паскалем. То есть вместо А>function JustTest(p:pchar):integer; А>begin А> asm
....... А> end; А>end;
надо писать просто А>function JustTest(p:pchar):integer; А> asm
....... А> end;
Иначе на некоторых версиях Delphi есть некоторые глюки.
2. В твоём случае надо так:
function JustTest(p:pchar):integer;
asm
mov ecx,[eax] //Считываем 32 бита данных по адресу p.
mov [eax],ecx //Записываем их обратно.
mov eax, 0 // == Result:=0
end;
Re: Встроенный asm: запись данных в память по заданному адре
Спасибо за ответы. Похоже, оно действительно работает. Но не всегда.
exp_1: Я проверил, твой пример также себя ведет.
А именно:
Не работает (на этом я и тестировал вначале):
.....
var p:pchar;
begin
p:='ABCDEFG';
JustTest(p);
...
end;
Работает:
.....
var p:pchar;
begin
p:=nil;
reallocmem(p,8);
JustTest(p);
...
end;
И дело здесь не в ассемблере. Можно просто попытаться сделать что-то вроде p[0]:='A' внутри JustTest. Получится то же самое. Присваивание не проходит, если p задана присваиванием константы.
Я думал, что память выделяется аналогично в обоих случаях. Это не так? Если сделать p:='ABCDEF', то p станет указателем на константу что ли, и запись в нее чем-то пресекается?
Re[2]: Встроенный asm: запись данных в память по заданному а
От:
Аноним
Дата:
05.11.05 19:38
Оценка:
Здравствуйте, _Michael_V_, Вы писали:
_M_> p:='ABCDEFG';
_M_>И дело здесь не в ассемблере. Можно просто попытаться сделать что-то вроде p[0]:='A' внутри JustTest. Получится то же самое. Присваивание не проходит, если p задана присваиванием константы.
_M_>Я думал, что память выделяется аналогично в обоих случаях. Это не так? Если сделать p:='ABCDEF', то p станет указателем на константу что ли, и запись в нее чем-то пресекается?
Это действительно так. Константы хранятся с сегменте кода, который защищён от записи.
Решением является использование вместо pchar просто string.
Тогда при присваивании происходит выделение памяти и копирование.
Надо только не забывать, что перед присваиванием переменная должна быть инициализирована.
Re[3]: Встроенный asm: запись данных в память по заданному а
Здравствуйте, iskatel, Вы писали:
А>>Это действительно так. Константы хранятся с сегменте кода, который защищён от записи.
I>ну если очень хочется, посмотри VirtualProtectEx
А вот за это действительно спасибо! И вообще, пора мне все-таки почитать этот самый Memory Management SDK.
Я тут продолжил свои эксперименты... Сделал функцию, которая получает указатель на другую функцию, ищет по этому адресу комманду возврата (RET, оно же С3) и выдает длину ее тела. Короче, вот:
function getproccodelen(proc:pointer):integer;
label l;
asm
xor edx,edx
l:
mov bl,byte ptr [eax]
inc eax
inc edx
cmp bl,$C3
jne l
mov @Result,edx
end;
...В связи с чем, у меня есть возможность сохранять тела функций и процедур в машинном коде в файл и загружать их оттуда. Не получается только передать управление на загруженный код. Похоже, как раз из-за этого protect`а.
Re[5]: Встроенный asm: запись данных в память по заданному а
Здравствуйте, _Michael_V_, Вы писали:
__M_>...В связи с чем, у меня есть возможность сохранять тела функций и процедур в машинном коде в файл и загружать их оттуда. Не получается только передать управление на загруженный код. Похоже, как раз из-за этого protect`а.
Конечно можно изобретать очередные велосипеды, только есть ли смысл делать самопальные защиты?
Хотел ещё заметить, что не все функции заканчиваются простым RET и не все функции заканчиваются одним RET. Так что буть более осторожен с определением длины функции. Ну и ещё не забывай об относительных переходах/вызовах/ссылках — тоже можно огрести проблем и неожиданных результатов. Так что VirtualProtect в этой теме не самое сложное
Re: Встроенный asm: запись данных в память по заданному адре
Посмотри реализацию пакера UPX, он OpenSource. Многое станет понятно, а если добавить туда функции криптования и частичной распаковки "на лету"- будет очень неплохо.
... <<DuDuLa — Трек 7>>
Не восхрапи на работе, ибо храпом своим разбудишь начальника своего.
Re[6]: Встроенный asm: запись данных в память по заданному а
D>Конечно можно изобретать очередные велосипеды, только есть ли смысл делать самопальные защиты?
Не, ну почему обязательно защиты . Сейчас это больше просто в образовательных целях.
D>Хотел ещё заметить, что не все функции заканчиваются простым RET и не все функции заканчиваются одним RET.
А можно поподробнее здесь? Я просто посмотрел несколько разных дельфовских — вроде все на RET и кончались. Т.е. дельфи как-то иначе их оформлять может? Несколько RET — это функция внутри функции что ли?
D>Так что буть более осторожен с определением длины функции. Ну и ещё не забывай об относительных переходах/вызовах/ссылках — тоже можно огрести проблем и неожиданных результатов.
Это есть такое... И за этим придется следить. Как вариант — адреса всего, что только может использоваться в функции передать в некой структуре, адрес которой дать в параметре. Правда тут от дельфи уже мало чего останется. Короче, сейчас разберусь с одним проектом и курсовиком еще, и к следующим выходным продолжу эксперименты.
Re[2]: Встроенный asm: запись данных в память по заданному а
Здравствуйте, _spin_, Вы писали:
__>Здравствуйте, <Аноним>, Вы писали:
__>Посмотри реализацию пакера UPX, он OpenSource. Многое станет понятно, а если добавить туда функции криптования и частичной распаковки "на лету"- будет очень неплохо.
Спасибо. Обязательно займусь.
Re[3]: Встроенный asm: запись данных в память по заданному а
Здравствуйте, _Michael_V_, Вы писали:
__>>Посмотри реализацию пакера UPX, он OpenSource. Многое станет понятно, а если добавить туда функции криптования и частичной распаковки "на лету"- будет очень неплохо. _M_>Спасибо. Обязательно займусь.
Если доведёшь до ума — свисти, оценим на стойкость .
З.Ы. А ещё можно добавить "заметание следов", т.е. подмену сигнатур своего пакера на случайно выбранную из коллекции сигнатуру чужого пакера, благо их сейчас — море.
Удачи!
... <<#2 — 06 Mo'horizons Hit the road Jack (Maria mix)>>
Не восхрапи на работе, ибо храпом своим разбудишь начальника своего.
Re[4]: Встроенный asm: запись данных в память по заданному а
Здравствуйте, _spin_, Вы писали:
__>Если доведёшь до ума — свисти, оценим на стойкость .
Ok __>З.Ы. А ещё можно добавить "заметание следов", т.е. подмену сигнатур своего пакера на случайно выбранную из коллекции сигнатуру чужого пакера, благо их сейчас — море.
__>Удачи!
Re[7]: Встроенный asm: запись данных в память по заданному а
Здравствуйте, _Michael_V_, Вы писали:
D>>Конечно можно изобретать очередные велосипеды, только есть ли смысл делать самопальные защиты? _M_>Не, ну почему обязательно защиты . Сейчас это больше просто в образовательных целях.
Чёрт его конечно знает, но на мой взгляд странное направление для образования..
D>>Хотел ещё заметить, что не все функции заканчиваются простым RET и не все функции заканчиваются одним RET. _M_>А можно поподробнее здесь? Я просто посмотрел несколько разных дельфовских — вроде все на RET и кончались. Т.е. дельфи как-то иначе их оформлять может? Несколько RET — это функция внутри функции что ли?
Ещё существет RET N, правда в дельфи я такого возврата не видел — в основном на паскале. А вообще если в функции используется Try/Finally, то практически всегда вставляется два RET (пускай меня поправят специалисты), причём такие функции IDA плохо понимает.
D>>Так что буть более осторожен с определением длины функции. Ну и ещё не забывай об относительных переходах/вызовах/ссылках — тоже можно огрести проблем и неожиданных результатов. _M_>Это есть такое... И за этим придется следить. Как вариант — адреса всего, что только может использоваться в функции передать в некой структуре, адрес которой дать в параметре. Правда тут от дельфи уже мало чего останется. Короче, сейчас разберусь с одним проектом и курсовиком еще, и к следующим выходным продолжу эксперименты.
Бог в помощь, но на мой взгляд направление для образования/самообразования слегка странное..
Re[8]: Встроенный asm: запись данных в память по заданному а
Здравствуйте, Dimonka, Вы писали:
D>Здравствуйте, _Michael_V_, Вы писали:
D>Чёрт его конечно знает, но на мой взгляд странное направление для образования.
Да интересно просто.
D>Ещё существет RET N, правда в дельфи я такого возврата не видел — в основном на паскале. А вообще если в функции используется Try/Finally, то практически всегда вставляется два RET (пускай меня поправят специалисты), причём такие функции IDA плохо понимает.
Ret N видел один раз, и это вроде был даже не конец процедуры, а что-то еще страшное.
Про try — точно. Сейчас проверил. Там что-то вроде этого:
try
Сохранение в стек адреса, по которому находится "jmp @HandleFinally"
...
Код внутри try. Если сделать здесь ret, то попадем на вышеупомянутый jmp.
...
Сохранение в стек адреса первой комманды по окончании finally...end.
finally
Код внутри finally. Если внутри сделать ret, то попадем на код после finally...end.
...
ret — попадаем на после end, который ниже. Как раз этот второй ret.
...
jmp @HandleFinally. Не понял, куда это.
end
продолжение процедуры
...
И ret действительно два. Поискал получше. Границу, процедур кажется можно определять по "pop ebp; ret" (это уже перебор, наверняка попадутся исключения) Ну или на крайний случай, просто самому помечать чем-нибудь конец нужных процедур еще в исходнике. Или не ипсользовать try.
Вообще я еще не могу понять, как он определяет само наличие исключения. Сейчас вот посмотрел, что происходит при sl.Clear, где sl — объявленный, но не созданный TStringlist. Поскольку объекта нет, то происходит переход в непонятное место, по которому лежит некий бред, котороый не дизассемблируется. При первой попытке выполнить что-то оттуда, управление передается на некую процедуру обработки исключения, которая столь длинна, что пока я ее понять не могу. По окончании процедуры управление попадает непосредственно на "Код внутри finally" (см. выше).
А как определяется, что бред — это бред?
Re[9]: Встроенный asm: запись данных в память по заданному а