Встроенный 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: запись данных в память по заданному адре
От: exp_1  
Дата: 03.11.05 19:21
Оценка:
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: запись данных в память по заданному адре
От: svd71 http://visualdesigner.fatal.ru/
Дата: 03.11.05 19:34
Оценка:
Здравствуйте, Аноним, Вы писали:

А>function JustTest(p:pchar):integer;

А>begin
А> asm


А>function JustTest2(s:shortstring):integer;

А>begin
А> asm

А>Но хочется именно pchar.


не поверишь:


procedure TForm1.Button1Click(Sender: TObject);
var S : string;
begin
   S := Caption;
   JustTest(PChar(S));
   Caption := S;
end;



проходит на "ура".
Re: Встроенный asm: запись данных в память по заданному адре
От: _Michael_V_  
Дата: 03.11.05 20:01
Оценка:
Спасибо за ответы. Похоже, оно действительно работает. Но не всегда.
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  
Дата: 06.11.05 07:20
Оценка:
А>Это действительно так. Константы хранятся с сегменте кода, который защищён от записи.

ну если очень хочется, посмотри VirtualProtectEx
Re[4]: Встроенный asm: запись данных в память по заданному а
От: _Michael_V_  
Дата: 06.11.05 12:34
Оценка:
Здравствуйте, 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: запись данных в память по заданному а
От: Dimonka Верблюд  
Дата: 06.11.05 18:24
Оценка:
Здравствуйте, _Michael_V_, Вы писали:

__M_>...В связи с чем, у меня есть возможность сохранять тела функций и процедур в машинном коде в файл и загружать их оттуда. Не получается только передать управление на загруженный код. Похоже, как раз из-за этого protect`а.


Конечно можно изобретать очередные велосипеды, только есть ли смысл делать самопальные защиты?
Хотел ещё заметить, что не все функции заканчиваются простым RET и не все функции заканчиваются одним RET. Так что буть более осторожен с определением длины функции. Ну и ещё не забывай об относительных переходах/вызовах/ссылках — тоже можно огрести проблем и неожиданных результатов. Так что VirtualProtect в этой теме не самое сложное
Re: Встроенный asm: запись данных в память по заданному адре
От: _spin_ Россия  
Дата: 06.11.05 18:30
Оценка:
Здравствуйте, <Аноним>, Вы писали:

Посмотри реализацию пакера UPX, он OpenSource. Многое станет понятно, а если добавить туда функции криптования и частичной распаковки "на лету"- будет очень неплохо.
... <<DuDuLa — Трек 7>>
Не восхрапи на работе, ибо храпом своим разбудишь начальника своего.
Re[6]: Встроенный asm: запись данных в память по заданному а
От: _Michael_V_  
Дата: 06.11.05 20:29
Оценка:
Здравствуйте, Dimonka, Вы писали:


D>Конечно можно изобретать очередные велосипеды, только есть ли смысл делать самопальные защиты?

Не, ну почему обязательно защиты . Сейчас это больше просто в образовательных целях.

D>Хотел ещё заметить, что не все функции заканчиваются простым RET и не все функции заканчиваются одним RET.

А можно поподробнее здесь? Я просто посмотрел несколько разных дельфовских — вроде все на RET и кончались. Т.е. дельфи как-то иначе их оформлять может? Несколько RET — это функция внутри функции что ли?

D>Так что буть более осторожен с определением длины функции. Ну и ещё не забывай об относительных переходах/вызовах/ссылках — тоже можно огрести проблем и неожиданных результатов.

Это есть такое... И за этим придется следить. Как вариант — адреса всего, что только может использоваться в функции передать в некой структуре, адрес которой дать в параметре. Правда тут от дельфи уже мало чего останется. Короче, сейчас разберусь с одним проектом и курсовиком еще, и к следующим выходным продолжу эксперименты.
Re[2]: Встроенный asm: запись данных в память по заданному а
От: _Michael_V_  
Дата: 06.11.05 20:31
Оценка:
Здравствуйте, _spin_, Вы писали:

__>Здравствуйте, <Аноним>, Вы писали:


__>Посмотри реализацию пакера UPX, он OpenSource. Многое станет понятно, а если добавить туда функции криптования и частичной распаковки "на лету"- будет очень неплохо.

Спасибо. Обязательно займусь.
Re[3]: Встроенный asm: запись данных в память по заданному а
От: _spin_ Россия  
Дата: 06.11.05 20:41
Оценка:
Здравствуйте, _Michael_V_, Вы писали:

__>>Посмотри реализацию пакера UPX, он OpenSource. Многое станет понятно, а если добавить туда функции криптования и частичной распаковки "на лету"- будет очень неплохо.

_M_>Спасибо. Обязательно займусь.

Если доведёшь до ума — свисти, оценим на стойкость .

З.Ы. А ещё можно добавить "заметание следов", т.е. подмену сигнатур своего пакера на случайно выбранную из коллекции сигнатуру чужого пакера, благо их сейчас — море.

Удачи!
... <<#2 — 06 Mo'horizons Hit the road Jack (Maria mix)>>
Не восхрапи на работе, ибо храпом своим разбудишь начальника своего.
Re[4]: Встроенный asm: запись данных в память по заданному а
От: _Michael_V_  
Дата: 06.11.05 21:11
Оценка:
Здравствуйте, _spin_, Вы писали:

__>Если доведёшь до ума — свисти, оценим на стойкость .


Ok
__>З.Ы. А ещё можно добавить "заметание следов", т.е. подмену сигнатур своего пакера на случайно выбранную из коллекции сигнатуру чужого пакера, благо их сейчас — море.

__>Удачи!
Re[7]: Встроенный asm: запись данных в память по заданному а
От: Dimonka Верблюд  
Дата: 06.11.05 21:25
Оценка:
Здравствуйте, _Michael_V_, Вы писали:

D>>Конечно можно изобретать очередные велосипеды, только есть ли смысл делать самопальные защиты?

_M_>Не, ну почему обязательно защиты . Сейчас это больше просто в образовательных целях.

Чёрт его конечно знает, но на мой взгляд странное направление для образования..

D>>Хотел ещё заметить, что не все функции заканчиваются простым RET и не все функции заканчиваются одним RET.

_M_>А можно поподробнее здесь? Я просто посмотрел несколько разных дельфовских — вроде все на RET и кончались. Т.е. дельфи как-то иначе их оформлять может? Несколько RET — это функция внутри функции что ли?

Ещё существет RET N, правда в дельфи я такого возврата не видел — в основном на паскале. А вообще если в функции используется Try/Finally, то практически всегда вставляется два RET (пускай меня поправят специалисты), причём такие функции IDA плохо понимает.

D>>Так что буть более осторожен с определением длины функции. Ну и ещё не забывай об относительных переходах/вызовах/ссылках — тоже можно огрести проблем и неожиданных результатов.

_M_>Это есть такое... И за этим придется следить. Как вариант — адреса всего, что только может использоваться в функции передать в некой структуре, адрес которой дать в параметре. Правда тут от дельфи уже мало чего останется. Короче, сейчас разберусь с одним проектом и курсовиком еще, и к следующим выходным продолжу эксперименты.

Бог в помощь, но на мой взгляд направление для образования/самообразования слегка странное..
Re[8]: Встроенный asm: запись данных в память по заданному а
От: _Michael_V_  
Дата: 07.11.05 00:43
Оценка:
Здравствуйте, 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: запись данных в память по заданному а
От: Softwarer http://softwarer.ru
Дата: 09.11.05 09:07
Оценка:
Здравствуйте, _Michael_V_, Вы писали:

D>А вообще если в функции используется Try/Finally, то практически всегда вставляется два RET


Блок try — это практически неявная подпрограмма. Со всеми вытекающими.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.