Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > Замена кода С++ на ходу


Автор: dark_religion 17.7.2007, 20:01
Подскажите пожалуйста как можно заменить код программы во время выполнения и выполнить его снова без перекомпиляции на С++

Или какие еще другие варианты возможны кроме С++

Автор: Daevaorn 17.7.2007, 20:23
Цитата(dark_religion @  17.7.2007,  21:01 Найти цитируемый пост)
Или какие еще другие варианты возможны кроме С++ 

С++ компилируемый язык, поэтому на выходе получается машинный код. Вот его с некоторыми трудностями, но можно редактировать в ран-тайм

Автор: bsa 17.7.2007, 20:25
Имхо, проще для этого использовать наследование классов и виртуальные функции.
А если надо писать самомодифицирующийся код (вирус пишишь?), то пиши на ассемблере.

Автор: chipset 17.7.2007, 20:26
Скрипты или (до некоторого уровня) полиморфизм спасет тебя smile

Автор: dark_religion 17.7.2007, 20:37
Ребята а можно поконкретнее про каждый метод. Каким образом . кто-то может предложить реализацию для 

например "Hello world "
шоб менялось С "привет Россия" 

если "Hello world" выводится вот так 

printf("Hello world"); без переменной. без всяких if & else шоб эта строчка в коде менялась на 
printf("Privet Russia");

Автор: Daevaorn 17.7.2007, 20:41
Цитата(dark_religion @  17.7.2007,  21:37 Найти цитируемый пост)
если "Hello world" выводится вот так 

этого "так" в exe нет. менять нужно данные, а не код.

Автор: dark_religion 17.7.2007, 20:43
А мне нужно именно код. Но я не поспорить кто-то может показать конкретный метод?

Автор: dark_religion 17.7.2007, 21:10
Мне посоветовали менять линки в минарнике .. как это можно понять? что такое бинарник?

Автор: nickless 17.7.2007, 21:23
http://forum.vingrad.ru/index.php?showtopic=155591&view=findpost&p=1164944 был небольшой примерчик самомодифицирующегося кода smile 

Цитата(dark_religion @  17.7.2007,  20:10 Найти цитируемый пост)
что такое бинарник?

dark_religion, а ты уверен что оно тебе надо? smile 

Автор: fish9370 17.7.2007, 21:42
Код

//оптимизация отключена полностью

//---------------------------------------------------------------------------
#include <stdio.h>
#include <conio.h>
#pragma hdrstop

//---------------------------------------------------------------------------

#pragma argsused
void Demo(int (*_printf) (const char *,...) )
{
  _printf("Hello, Word!\n");
  return;
}

int main(int argc, char* argv[])
{
  char buff[1000];
  int (*_printf) (const char *,...);
  int (*_main) (int, char **);
  void (*_Demo) (int (*) (const char *,...));
  _printf=printf;

  int func_len = (unsigned int) _main - (unsigned int) _Demo;
  for (int a=0;a<func_len;a++)
    buff[a]= ((char *) Demo)[a];
  _Demo = (void (*) (int (*) (const char *,...)))&buff[0];

  _Demo(_printf);
  getch();
  return 0;
}


пояснение к примеру.. здесь код фунции помещается в область стека, в которой позволяется производить запись/чтение/исполнение кода.. после чего функции передается управление..

Автор: bsa 17.7.2007, 22:00
fish9370, мало того, что глупость сморозил, так еще и _main не проинициализировал перед использованием.
А потом, кто тебе сказал, что функция из области стека будет исполняться?

Автор: fish9370 17.7.2007, 22:07
а _main лишь нужен, чтобы вычислить конец функции..   smile 

читай матчасть!!

Автор: bsa 17.7.2007, 22:31
Во-первых, твой код компилируется так (после убирания кривых заголовков, прагм и getch):
Код
$ g++ -Wall aaa.cpp
aaa.cpp: In function ‘int main(int, char**)’:
aaa.cpp:25: ошибка: cast from ‘int (*)(int, char**)’ to ‘unsigned int’ loses precision
aaa.cpp:25: ошибка: cast from ‘void (*)(int (*)(const char*, ...))’ to ‘unsigned int’ loses precision
Как ты мог заметить, совсем не компилируется.
Во-вторых, после земены unsigned int на unsigned long (не забываем, что кроме 32-х битной windows существуют другие платформы с другой разрядностью) программа собирается без ошибок. Но при этом при запуске повисает.
В-третьих, после добавления между строк 25 и 26 операции printf("%i\n", func_len); появляется вывод:
Код
$ ./a.out 
4195952
Ошибка сегментирования
$ ./a.out 
905601952

$ ./a.out 
-941235616
Ошибка сегментирования
$ ./a.out 
74263248

$ ./a.out 
1408701296

$ ./a.out 
1316613024

$ ./a.out 
828955280

$ ./a.out 
75426800

$ ./a.out 
-1305704752
Ошибка сегментирования
 (там где нет ошибки сегментации я прерывал Ctrl-C, так как было понятно, что все равно вылетит из-за переполнения стека мусором).

Цитата(fish9370)
читай матчасть!!
Кто бы говорил. Как ты думаешь, почему число каждый раз разное, в том числе отрицательное? А я тебе отвечу:
Цитата(bsa)
_main не проинициализировал перед использованием

Автор: Daevaorn 17.7.2007, 22:37
Цитата(fish9370 @  17.7.2007,  23:07 Найти цитируемый пост)
bsa, ты бы чем такие умные речи толкать.. почитал бы литературу.. и код бы откомпилил.. и посмотрел на результаты.. пустозвон.. 

тааак, выбираем выражения господа, не на базаре!

Автор: bsa 17.7.2007, 22:46
Более того, даже если бы эта прога заработала, то чуть более сложная все равно не пойдет, так как в ней обязательно будут внутренние абсолютные переходы, которые перестанут работать, если поместить код функции в другое место адресного пространства.
Я поражаюсь, меня - программиста-ассемблерщика с 10-ти летним стажем обвиняют в незнании матчасти!!! smile 

Автор: fish9370 17.7.2007, 22:49
Цитата(Daevaorn @ 17.7.2007,  22:37)
тааак, выбираем выражения господа, не на базаре!

заметь, не я первый начал..  smile 

bsa, код заточен под Windows (включая XP).. при компиляции нужно отключать свяческую оптимизацию.. код проверялся компилятором из BDS 2006 c опцией С++ Compiler (bcc32)->optimizations->Optimize: Disable all optimizations. (-Od)

Автор: bsa 17.7.2007, 22:55
НУ НЕ МОГ ОН РАБОТАТЬ ПРАВИЛЬНО! Так как ты переменную _main не проинициализировал. У тебя размер функции определялся неправильно. Соответственно, ты неизвестно сколько байт скопировал в буфер.

Автор: fish9370 17.7.2007, 23:00
Цитата(bsa @ 17.7.2007,  22:46)
Более того, даже если бы эта прога заработала, то чуть более сложная все равно не пойдет, так как в ней обязательно будут внутренние абсолютные переходы, которые перестанут работать, если поместить код функции в другое место адресного пространства.
Я поражаюсь, меня - программиста-ассемблерщика с 10-ти летним стажем обвиняют в незнании матчасти!!! smile 

идея заключается в том, чтобы на основании этого реализовывать защиту програм.. поскольку самомодифицирующийся код анализировать труднее.. и ломается сложне.. вот эти все заморочки с описанием указателей на функции и призваны создать перемещаемый код.. ведь тут же нет прямого вызова printf.. тебе ли это не знать с твоим 10 летним опытом.. кстати, за 10 лет можно многое подзабыть.. уж я то со своим 15 летним опытом знаю..  smile

Добавлено через 3 минуты и 44 секунды
прикрепляю проект..

Автор: dumb 17.7.2007, 23:09
Цитата(fish9370 @  17.7.2007,  22:49 Найти цитируемый пост)
код заточен под Windows (включая XP)

что такое DEP слышал?

Цитата(fish9370 @  17.7.2007,  23:00 Найти цитируемый пост)
идея заключается в том, чтобы на основании этого реализовывать защиту програм..

это... как бы помягче... вобщем, если приведенный выше код - демонстрация защитного механизма, то это была плохая, негодная идея.

Цитата(fish9370 @  17.7.2007,  23:00 Найти цитируемый пост)
поскольку самомодифицирующийся код анализировать труднее.. и ломается сложне..

да, только никакой связи между твоим примером и "самомодифицирующимся кодом" нет.

Автор: bsa 17.7.2007, 23:13
У меня и сейчас основной доход именно от продукции на asm. smile

Про защиту это понятно... Но в данном случае у тебя простая ошибка. Более того, их две - значение func_len всегда случайное число...
Под Линуксом не работает в принципе, даже если это исправить. Вываливается сегфолт. Думаю, потому что у меня в ядре включено опция защиты от выполнения кода в левых местах.

Автор: fish9370 17.7.2007, 23:18
Цитата(bsa @ 17.7.2007,  22:55)
НУ НЕ МОГ ОН РАБОТАТЬ ПРАВИЛЬНО! Так как ты переменную _main не проинициализировал. У тебя размер функции определялся неправильно. Соответственно, ты неизвестно сколько байт скопировал в буфер.

по началу ты и в то, что код можно в стеке исполнять не верил..

еще по теме..
Цитата

Разрешение на выполнение кода в стеке объясняется тем, что исполняемый стек необходим многим программам, в том числе и самой операционной системе для выполнения некоторых системных функций. Благодаря этому упрощается генерация кода компиляторами и компилирующими интерпретаторами

Цитата

Замечательно, что для программ, выполняющихся в стеке, справедлив принцип Фон Неймана - в один момент времени текст программы может рассматриваться как данные, а в другой - как исполняемый код. Именно это необходимо для нормальной работы всех распаковщиков и расшифровщиков исполняемого кода.

Цитата

При разработке кода, выполняющегося в стеке, следует учитывать, что в операционных системах Windows 9x, Windows NT и Windows 2000 местоположение стека различно, и, чтобы сохранить работоспособность при переходе от одной системы к другой, код должен быть безразличен к адресу, по которому он будет загружен. Такой код называют перемещаемым, и в его создании нет ничего сложного, достаточно следовать нескольким простым соглашениям - вот и все.

Цитата

что произойдет, если следующую функцию "void Demo() { printf("Demo\n");}" скопировать в стек и передать ей управление? Поскольку, инструкция call, вызывающая функцию pritnf, "переехала" на новое место, разница адресов вызываемой функции и следующей за call инструкции станет совсем иной, и управление получит отнюдь не printf, а не имеющий к ней никакого отношения код! Вероятнее всего, им окажется "мусор", порождающий исключение с последующим аварийным закрытием приложения. 

Цитата

Программируя на ассемблере, такое ограничение можно легко обойти, используя регистровую адресацию. Перемещаемый вызов функции printf упрощенно может выглядеть, например, так:"lea eax, printf\ncall eax" В регистр eax (или любой другой регистр общего назначения на выбор) заносится абсолютный линейный, а не относительный адрес и, независимо от положения инструкции call, управление будет передано функции printf, а не чему-то еще.
Для решения данной задачи исключительно средствами языка высокого уровня, - необходимо передать стековой функции указатели на вызываемые ее функции как аргументы. Это несколько неудобно, но более короткого пути, по-видимому, не существует.

Автор: fish9370 17.7.2007, 23:34
Цитата(dumb @  17.7.2007,  23:09 Найти цитируемый пост)
что такое DEP слышал?


нет.. но с удовольствием послушаю.. )

Цитата(dumb @  17.7.2007,  23:09 Найти цитируемый пост)
это... как бы помягче... вобщем, если приведенный выше код - демонстрация защитного механизма, то это была плохая, негодная идея.


как бы это помягче сказать.. это похоже на защитный код!?! это лишь пример доказывающий, что код может быть исполнен в области стека..

Цитата(dumb @  17.7.2007,  23:09 Найти цитируемый пост)
да, только никакой связи между твоим примером и "самомодифицирующимся кодом" нет.


нет? то что можно править код в области стека ты не веришь? 

P.S. читай выше.. 

Автор: W4FhLF 18.7.2007, 03:31
Цитата(fish9370 @  17.7.2007,  23:00 Найти цитируемый пост)
 и ломается сложне.. вот эти все заморочки с описанием указателей на функции и призваны создать перемещаемый код..


Повешают бряк на исполнение в стеке и будут отлаживать точно такой же код, а все эти заморочки побокуsmile 

Автор: dark_religion 18.7.2007, 13:22
Спасибо fish9370, Я хоть и ниче не понял и немогу подискусировать, что будет, а чего не будет, но он единственный из всех показал реальное решение остальные просто поговорили. Может это и не оптимально, но лучшего никто не предложил. 

Автор: Daevaorn 18.7.2007, 14:04
Цитата(dark_religion @  18.7.2007,  14:22 Найти цитируемый пост)
из всех показал реальное решение

ага. которое не правильное.

Автор: bsa 18.7.2007, 14:06
Цитата(dark_religion @ 18.7.2007,  13:22)
Спасибо fish9370, Я хоть и ниче не понял и немогу подискусировать, что будет, а чего не будет, но он единственный из всех показал реальное решение остальные просто поговорили. Может это и не оптимально, но лучшего никто не предложил.

Ты не понял. Повторяю еще раз коротко и ясно то, что было сказано ранее:
1. Данный код содержит ошибки.
2. Данный код если и работает, то только у автора. А после включения DEP может и перестать работать.
3. Даже после устранения всех ошибок код у меня не заработал.

Автор: anthony 18.7.2007, 14:47
bsa, Программа полностью работоспособна с небольшой модификацией (инициализацией _main и _Demo) (Microsoft Visual Studio 2005 Professional Edition C++) даже с включенной оптимизацией (контроль ошибок выключен, сборка в Release).

Код

#include <stdio.h>
#include <conio.h>

#pragma pack ( 1 )

void Demo(int (*_printf) (const char *,...) )
{
  _printf("Hello, Word!\n");
  return;
}

int main(int argc, char* argv[])
{
  char buff[1000];
  int (*_printf) (const char *,...);
  int (*_main) (int, char **) = main;
  void (*_Demo) (int (*) (const char *,...)) = Demo;
  _printf=printf;
  int func_len = (unsigned int) _main - (unsigned int) _Demo;
  for ( int a=0; a<func_len; a++ ) {
        buff[a]= ((char *) Demo)[a];
  }
  _Demo = (void (*) (int (*) (const char *,...)))&buff[0];
  _Demo(_printf);
  getch();
  return 0;
}



W4FhLF, DEP по умолчанию отключен, с включенным протестирую после (нужно перегружаться). Но и в принципе Ваш довод не так силен.

Так что господа Вы не правы. 

bsa относитесь к другим и их программам с большим уважением и пониманием, а не предвзято.

Автор: W4FhLF 18.7.2007, 15:12
Цитата(anthony @  18.7.2007,  14:47 Найти цитируемый пост)
W4FhLF, DEP по умолчанию отключен, с включенным протестирую после (нужно перегружаться). Но и в принципе Ваш довод не так силен.


Я что-то про DEP говорил?

Автор: anthony 18.7.2007, 15:15
Да с включенным DEP тоже работает.


Та же программа немного модифицированная для языка С (проверено на MSVC 2005 PE, Release, Warnings Level 1)

Код

#include <stdio.h>

void Demo(int (*_printf) (const char *,...) )
{
  _printf( "Hello, Word!\n" );
  return;
}

int main ( void ) {

    char buff [ 1000 ];
    int (*_printf) (const char *,...) = printf;
    int (*_main) ( void ) = main;
    void (*_Demo) (int (*) (const char *,...)) = Demo;
    int a = 0;
    int func_len = ( unsigned int ) _main - ( unsigned int ) _Demo;

    for ( a=0; a < func_len; a++ ) {
        buff [ a ] = ( ( char * ) Demo ) [ a ];
    }
    _Demo = ( void (*) ( int (*) ( const char *,... ) ) ) &buff [ 0 ];
    _Demo(_printf);
    getchar ( );
    return 0;
}

Автор: bsa 18.7.2007, 16:48
Хорошо, плюс еще один компилятор, который это делать позволяет. Но только после исправления ошибок, про которые я кучу раз говорил...
Повторяю, на Linux x86_64 с компилятором g++ 4.1.2 программа не заработала, даже после исправления ошибок.

Автор: JackYF 18.7.2007, 16:58
anthony, по твоей программе.

XP SP2, MinGW - g++ 3.4.5 без оптимизаций - работает.
Те же, там же, с оптимизациями - сегфолт.

Linux Fedora 5, i686, g++ 4.1.1 без оптимизаций - сегфолт.
Те же, там же, с оптимизациями - сегфолт.

Вопросы?

Автор: Damarus 18.7.2007, 17:04
Цитата(JackYF @  18.7.2007,  17:58 Найти цитируемый пост)
XP SP2, MinGW - g++ 3.4.5 без оптимизаций - работает.
Те же, там же, с оптимизациями - сегфолт.

При тех же условиях у меня не работает.

Автор: bsa 18.7.2007, 17:32
Проверил еще на x86 (gentoo, x86, gcc 4.1.2).
Результат забавный:
Код
$ g++ -O0 -Wall -o aaa aaa.cpp
$ ./aaa
Hello World!
$ g++ -O0 -Wall -fPIC -o aaa aaa.cpp
$ ./aaa
Segmentation fault

Автор: fish9370 18.7.2007, 18:27
anthony, спасибо за поддержку..

Цитата(Daevaorn @  18.7.2007,  14:04 Найти цитируемый пост)
ага. которое не правильное.


в чем неправильность, друг?


Цитата(W4FhLF @  18.7.2007,  03:31 Найти цитируемый пост)
Повешают бряк на исполнение в стеке и будут отлаживать точно такой же код, а все эти заморочки побоку


ты идею не понял.. я вынесу часть кода за приделы проги.. зашифрую ключем.. при вводе правильного ключа сформируется правельный код.. без ключа, куда бряк будешь накладывать? это как пример..

Добавлено @ 18:30
и вообще, когда я о линуксе хоть раз заякнулся? в линуксе кругом один опенсорс, там вопрос о защите вообще не стоит.. 
bsa
, так вообще код в отстой записал, типа код не по теме.. хм.. хотя сам ничего, кроме своей нелепой критики, предложить не может..

Автор: JackYF 18.7.2007, 18:37
Цитата(fish9370 @  18.7.2007,  18:27 Найти цитируемый пост)
в чем неправильность, друг?

ты три предыдущих сообщения прочитал? почему твой правильный код не работает на перечисленных нами выше платформах?

Автор: nickless 18.7.2007, 20:12
Попробовал код у себя, с выключеным NX-битом работает, со включеным нет, теперь будем знать что NX действительно пашет smile

Автор: Damarus 18.7.2007, 20:24
Цитата(fish9370 @  18.7.2007,  19:27 Найти цитируемый пост)
ты идею не понял.. я вынесу часть кода за приделы проги.. зашифрую ключем.. при вводе правильного ключа сформируется правельный код.. без ключа, куда бряк будешь накладывать? это как пример..

Тогда может проще сделать обычную dll'ку, а потом зашифровать её smile В программе будешь сначала расшифровывать, а потом динамически загружать smile А не изобретать велосипед с исполнением кода из стека.

P.S. Только толку от такой защиты не много будет.

Автор: fish9370 18.7.2007, 21:14
Цитата(JackYF @  18.7.2007,  18:37 Найти цитируемый пост)
ты три предыдущих сообщения прочитал? почему твой правильный код не работает на перечисленных нами выше платформах?


а ты мои сообщения читал? что я говорил про линукс..
Цитата(Damarus @  18.7.2007,  20:24 Найти цитируемый пост)
Тогда может проще сделать обычную dll'ку, а потом зашифровать её  В программе будешь сначала расшифровывать, а потом динамически загружать  А не изобретать велосипед с исполнением кода из стека.

P.S. Только толку от такой защиты не много будет. 


как известно, самым слабым звеном, в любой защите, является человек.. против раскаленного утюга еще никто не устоял.. Dll'ку шифровать это велосипед, тут я согласен.. шифровать код это тема не новая.. просто у некоторых все еще много стериотипов..

Автор: JackYF 18.7.2007, 21:31
Цитата(fish9370 @  18.7.2007,  21:14 Найти цитируемый пост)
а ты мои сообщения читал? что я говорил про линукс..

а что из твоего кода принципиально заточено под XP, можно спросить?

Автор: fish9370 18.7.2007, 21:33
Цитата(JackYF @  18.7.2007,  21:31 Найти цитируемый пост)
а что из твоего кода принципиально заточено под XP, можно спросить? 


идея!!

Автор: JackYF 18.7.2007, 21:41
Цитата(fish9370 @  18.7.2007,  21:33 Найти цитируемый пост)
идея!! 

почему тогда не работает

Цитата(JackYF @  18.7.2007,  16:58 Найти цитируемый пост)
XP SP2, MinGW - g++ 3.4.5 без оптимизаций - работает.
Те же, там же, с оптимизациями - сегфолт.

это (вторая строчка)?

Автор: fish9370 18.7.2007, 21:51
Цитата(JackYF @  18.7.2007,  21:41 Найти цитируемый пост)
почему тогда не работает


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

Автор: dumb 19.7.2007, 04:54
так как это был мой довод, то и отвечу я.
Цитата(anthony @  18.7.2007,  14:47 Найти цитируемый пост)
DEP по умолчанию отключен
он не отключен, а включен только для сервисов итп. в XP. в серверных вариантах - по умолчанию включен для всех программ.

Цитата(anthony @  18.7.2007,  15:15 Найти цитируемый пост)
Да с включенным DEP тоже работает.
гон. smile слово жесткое, но подходящее.

Цитата(JackYF @  18.7.2007,  16:58 Найти цитируемый пост)
Те же, там же, с оптимизациями - сегфолт.
если кому интересно, посмотрите на кашу, получающуюся в результате оптимизации. smile

Цитата(fish9370 @  18.7.2007,  18:27 Найти цитируемый пост)
в чем неправильность, друг?
ответь на простой вопрос: какое отношение имеет представленный тобой код к вопросу в первом посте темы? - то, что автор этого вопроса сказал тебе спасибо, можно не упоминать - он сам, к сожалению, не понимает о чем спросил и что ты ему "выдал".

Цитата(fish9370 @  18.7.2007,  18:27 Найти цитируемый пост)
ты идею не понял.. я вынесу часть кода за приделы проги.. зашифрую ключем.. при вводе правильного ключа сформируется правельный код.. без ключа, куда бряк будешь накладывать? это как пример..
на чем ты 15 лет программировал, друг?!

вобщем после всех этих "идей, заточенных под XP" становится как-то скучно и грустно. user posted image
fish9370, можно тебя просто попросить не употреблять выражений типа "пустозвон","нелепый","прямые руки"? - становится смешно. а с таким набором ощущений и до "белых столбов" недалеко...

ps.
Цитата(fish9370 @  18.7.2007,  21:51 Найти цитируемый пост)
кстати, у меня еще есть способ модификации кода во время исполнения.. не такой интересный, но есть.. 
smile

Автор: W4FhLF 19.7.2007, 07:22
Цитата(fish9370 @  18.7.2007,  18:27 Найти цитируемый пост)
ты идею не понял.. я вынесу часть кода за приделы проги.. зашифрую ключем.. при вводе правильного ключа сформируется правельный код.. без ключа, куда бряк будешь накладывать? это как пример..


Ты просто собираешься шифровать часть кода ключом, который куда-то там вынесен-перенесён? А где защита? Ну да, допустим без ключа не узнают, какой у тебя там код, а с одним валидным ключом(это в худшем случае, в лучшем просто кейген напишут, всё от твоей грамотности зависит) смогут отвязать твою программу от любых проверок. Можешь выложить свою задумку в виде готового exe, мне бы просто интересно было посмотреть, т.к. возможно, что я тебя неправильно понимаю. 
С таким же успехом можно программу заархивировать в rar с 20 символьным паролем и назвать это защитой. 

Автор: Santilka85 19.7.2007, 07:53
Цитата(W4FhLF @  19.7.2007,  07:22 Найти цитируемый пост)
можно программу заархивировать в rar с 20 символьным паролем и назвать это защитой. 



 smile  smile  smile 

Автор: anthony 19.7.2007, 09:25
Обновленный код (устранены ошибки и предупреждения, сокращен объем, изменен стиль).

Протестировано на Win XP PE/HE SP 2 с включенным и выключенным DEP (процессоры без поддержки DEP).

Проверена большая часть настроек компиляции для MSVC 2005 PE SP 1, для других компиляторов нужно аккуратно проверять настройки.

Код

/*    Purpose: Stacked function calling.
    About: This example shows how could be organized function call from program stack.
        Example shows method of self-modification program in C.
    Algorithm:
        1. Creating 'stacked' char (byte) array - buffer for function body placement.
        2. Resolving target function address and function body size in bytes.
        3. Copying target function body into stack.
        4. Resolving 'stacked' function address and indirect call.

    Language: Ansi C.

    Environment: MSVC 2005 PE - ENU Service Pack 1.
    Options (for MSVC 2005 PE - ENU Service Pack 1 only):
        compiler -> Basic Runtime Checks -> Stack Frames (/RTCs) enabled - program works improper,
        all other options - not influencing factors.
    Program compiled with 'warning level 4' and 'treat warnings as errors' properties. */
#include "stdio.h"

/* Pointer to stackedFunction type definition. */
typedef void ( * StackedFunctionPointer ) ( int ( * printf ) ( const char *, ... ) );
/* Pointer type definition. */
typedef size_t Pointer;

/* Simple function definition. */
void stackedFunction ( int ( * _printf ) ( const char *, ... ) ) {
    _printf ( "Stacked function executed\n" );
}

int main ( void ) {

    /* Stacked char array. */
    char stackArea [ 1000 ];
    /* Pointer to stackedFunction interpreted as char array. */
    char *directPointer = ( char * ) ( ( Pointer ) stackedFunction );
    /* Pointer to stacked char array interpreted as pointer to stackedFunction. 
        Stacked char array will be filled with stackedFunction body data, 
        so this pointer points to the stackedFunction copy.*/
    StackedFunctionPointer indirectPointer = ( StackedFunctionPointer ) ( ( Pointer ) stackArea );

    /* Size of stackedFunction in bytes determination.*/
    size_t marker = ( Pointer ) main - ( Pointer ) stackedFunction;

    /* Copying stackedFunction body into stacked char array.*/
    while ( marker-- ) {
        stackArea [ marker ] = directPointer [ marker ];
    }

    /* Calling stackedFunction copy from stack.*/
    indirectPointer ( printf );

    return 0;
}

Автор: bsa 19.7.2007, 10:33
anthony, какой у тебя процессор? Он поддеживает DEP?

Автор: JackYF 19.7.2007, 11:28
Вот теперь лучше.
g++ [-O2] -Wall, 4.1.3, Debian lenny - полет нормальный.

DEP, естественно, не стоит.
С ним не должно работать, так как программа пытается выполнить инструкции, находящиеся в стеке.

Автор: Daevaorn 19.7.2007, 14:07
fish9370, продолжай в том же духе и получишь предупреждение.

Автор: fish9370 19.7.2007, 19:56

Добавлено @ 20:04
обсуждаем дальше..

Цитата

Использование WriteProcessMemory

Если требуется изменить некоторое количество байт своего (или чужого) процесса, самый простой способ сделать это - вызвать функцию WriteProcessMemory. Она позволяет модифицировать существующие страницы памяти, чей флаг супервизора не взведен, т.е., все страницы, доступные из кольца 3, в котором выполняются прикладные приложения. Совершенно бесполезно с помощью WriteProcessMemory пытаться изменить критические структуры данных операционной системы (например, page directory или page table) - они доступны лишь из нулевого кольца. Поэтому, эта функция не представляет никакой угрозы для безопасности системы и успешно вызывается независимо от уровня привилегий пользователя (автору этих строк доводилось слышать утверждение, дескать, WriteProcessMemory требует прав отладки приложений, но это не так). 

Процесс, в память которого происходит запись, должен быть предварительно открыт функцией OpenProcess с атрибутами доступа "PROCESS_VM_OPERATION" и "PROCESS_VM_WRITE". Часто программисты, ленивые от природы, идут более коротким путем, устанавливая все атрибуты - "PROCESS_ALL_ACCESS". И это вполне законно, хотя справедливо считается дурным стилем программирования.



Код

int WriteMe(void *addr, int wb)
  {
    HANDLE h=OpenProcess(PROCESS_VM_OPERATION
          |PROCESS_VM_WRITE,
          true,GetCurrentProcessId());
    return WriteProcessMemory(h, addr,&wb,1,NULL);
  }

  int main(int argc, char* argv[])
  {
    _asm {
      push 0x74    ; JMP --> > JZ
      push offset Here
      call WriteMe
      add esp,8
  Here:    JMP short here
    }

    printf("#JMP SHORT $-2  was changed to JZ $-2\n");
    return 0;
  }


PS. надеюсь, это никому не придет в голову, компилить под линукс.. )

Автор: JackYF 20.7.2007, 11:46
Цитата(fish9370 @  19.7.2007,  19:56 Найти цитируемый пост)
хорош флудить!!

Daevaorn, вообще-то, модератор этого раздела. Так что не надо здесь разжигать страсти.

Цитата(fish9370 @  19.7.2007,  19:56 Найти цитируемый пост)
обсуждаем дальше..

а, собственно, что мы сейчас обсуждаем?

Теперь. Приведенные участки кода - это хорошо. Однако раздел называется: "С++: Общие вопросы".
И тема называется "Замена кода С++ на ходу". А не "Замена кода С++ на ходу в операционной системе Windows".

Так что последнее полным решением не является. Есть раздел "С++: Системное программирование и WinAPI". Вот там последний код окажется полезен, наверное.

Автор: Earnest 20.7.2007, 20:45
Ребята, давайте жить дружно  smile  smile  smile 
Конечно, заставить код выполняться в стеке или другой не-исполняемой памяти можно, хотя и не на всех системах. Причем прошу заметить, со временем этих систем (где нельзя), видимо, будет становиться все больше.
Я когда-то этим баловалась и тоже с целью защиты, но тогда это работало почти всегда, т.к. защитный флажок хоть и имелся, но явно был задумкой на будущее...

Ладно, допустим, загрузили, расшифровали, передали управление... Однако это может быть совсем не любой код, а ведь чтобы удовлетворить задумку автора, такой код должен быть a) достаточно объемный (не три оператора), б) критичный для правильной работы приложения...

Ладно, напряглись, преодолели все трудности...
Однако не забываем, что программ с одной версией не бывает; если программа не развивается, причем быстро, кому она нафиг нужна ... А такой способ защиты будет мешать жить прежде всего самому разработчику... Особенно приятно будет изменять и отлаживать код, который вынесен из программы (помним, что он не должен быть совсем уж тривиальным).
И наконец, как уже было сказано, это спасает до получения взломщиком первого же валидного ключа (а у мало-мальски ценной программы они всегда утекают - как только появляются первые пользователи)...
Т.е. само по себе это абсолютно не достаточно. Нужно применять и другие приемы...

Короче, не стоит овчинка выделки. Сложность защиты (в смысле усилий, потраченных как на ее разработку, так и на развитие) должна соответствовать ценности программы.


Автор: chipset 20.7.2007, 21:37

 ! 
chipset
Смягчаем тон и становимся более вежливыми во избежаний последствий.
Спасибо :)
Chipset.

Автор: DDyDog 21.7.2007, 10:43
1. Первый раз запустил программу(скопировал выше), вывело Hello, World!

2. Закоментировал часть кода 

Код

#include <stdio.h>
#include <conio.h>

#pragma pack ( 1 )

void Demo(int (*_printf) (const char *,...) )
{
  _printf("Hello, Word!\n");
  return;
}

int main(int argc, char* argv[])
{
  char buff[1000];
  int (*_printf) (const char *,...);
  int (*_main) (int, char **) = main;
  void (*_Demo) (int (*) (const char *,...)) = Demo;
  _printf=printf;
  /*int func_len = (unsigned int) _main - (unsigned int) _Demo;
  for ( int a=0; a<func_len; a++ ) {
        buff[a]= ((char *) Demo)[a];
  }
  _Demo = (void (*) (int (*) (const char *,...)))&buff[0];*/
  _Demo(_printf);
  getch();
  return 0;
}

Снова вывело Hello, World!
В первом случае выполнялась функция из стека (buf), во втором из сегмента кода

А вопрос такой, где произошла модификация кода? И даже если модифицировать буфер и
выполнить его, чем это будет отличатся от вызова еще одной функции адресс которой присвоен _Demo (вот если бы произвести модификацию  сегмента кода или исполняемого файла)? А стек мы и так постоянно модифицируем  smile 

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

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)