Когда речь идет о взломе и модификации чужого приложения, то на ум приходит использование декомпилятора, дизассемблера и отладчика. Но есть софтина, которая работает по другому. Знакомьтесь — Frida, тулкит, который позволяет внедриться в какой-нибудь процесс и переписать его части на языке JavaScript.
Публикация данной статьи на портале www.spy-soft.net несет исключительно образовательный характер. Ни редакция сайта, ни автор статьи не несут ответственности за ненадлежащее использование полученной из статьи информации!
Внедрение кода в чужое приложение
Представьте, что вам в руки попал семпл какого-нибудь вредоноса. Вы запускаете его в эмуляторе и пытаетесь проанализировать поведение. Но оказывается, что в эмуляторе он работает совсем не так, как на реальном устройстве, и никакой подозрительной активности не проявляет: вредонос умеет определять, что находится в эмулируемой среде.
Вы об этом догадываетесь и поэтому решаете запустить вредонос под дебаггером (предварительно распаковав малварь и добавив строчку android_debuggable=»true» в AndroidManifest.xml), чтобы определить, как именно вредонос производит проверку на эмулятор. И снова проблема: она умеет определять, что работает под отладчиком, и просто не запускается при запуске. Следующий шаг: статический анализ кода с помощью декомпилятора и дизассемблера, правка с целью вырезать куски, проверяющие наличие отладчика и эмулируемой среды, снова правка кода по причине ошибки и все в таком духе.
С++ для начинающих: советы по улучшению кода
А теперь представьте, что у вас есть инструмент, позволяющий прямо во время работы приложения отключить все эти проверки, просто переписав проверочные функции на JavaScript. Никаких дизассемблерных листингов smali, никаких правок низкоуровневого кода, никаких пересборок приложения; вы просто подключаетесь к работающему приложению, находите нужную функцию и переписываете ее тело. Не плохо звучит, не так ли?
Внедрение кода в чужое приложение с помощью Frida
Frida — это так называемый Dinamic Instrumentation Toolkit, то есть набор инструментов, позволяющих на лету внедрять собственный код в другие приложения. Ближайшие аналоги Frida — это знаменитый Cydia Substrate для iOS и Xposed Framework для Android, те самые фреймворки, благодаря которым появились твики. Frida отличается от них тем, что нацелена на быструю правку кода в режиме реального времени. Отсюда и язык JavaScript вместо Objective-C или Java, и отсутствие необходимости упаковывать «твики» в настоящие приложения. Вы просто подключаетесь к процессу и меняете его поведение, используя интерактивную JS-консоль (ну или отдаете команду на загрузку ранее написанного скрипта).
Frida умеет работать с приложениями, написанными для всех популярных ОС, включая Windows, Linux, macOS, iOS и даже QNX. Мы же будем использовать ее для модификации приложений под Android.
Итак, что нам потребуется:
- Машина под управлением Linux. Можно и Windows, но, когда занимаешься пентестом приложений для Android, лучше использовать Linux.
- Установленный adb. В Ubuntu/Debian/Mint устанавливается командой sudo apt-get install adb.
- Рутованный смартфон или эмулятор на базе Android 4.2 и выше. Frida умеет работать и на нерутованном, но для этого вам придется модифицировать APK подопытного приложения. Это просто неудобно.
Для начала мы установим Frida:
Уроки С++. Изучай и оптимизируй! Советы С++. Оптимизация цикла!
Источник: spy-soft.net
Самомодифицирующийся код
В статье подробно рассказано о самомодифицирующимся коде (СМК), и о том, как его использовать в своих программах. Примеры написаны на C++ с использованием встроенного ассемблера. Ещё я расскажу о том, как выполнять код на стеке, что является существенным козырем при написании и выполнении СМК.
1. Вступление
Ну что ж, поехали. Статья обещает быть длинной, так как мне хочется написать её такой, чтобы у вас не возникло никаких вопросов. На тему СМК уже существует миллион статей, но здесь представлено моё видение проблемы – после сотен часов написания СМК… Я попытаюсь впихнуть все свои труды сюда. Всё, хватайте томатный сок (или что вы там предпочитаете пить), делайте музыку громче и готовьтесь узнать, как избавить своё приложение от начинающих кракеров! Попутно, я расскажу вам о памяти Windows и некоторых других вещах, о которых вы даже и не подозреваете.
2. Краткая история самомодифицирующегося кода
Совсем ещё недавно программисты имели роскошь использовать самомодифицирующийся код где душе угодно. 10-20 лет назад все более или менее серьёзные попытки защиты программ использовали СМК (самомодифицирующийся код). Даже некоторые компиляторы использовали СМК, оперируя кодом в памяти.
Затем в середине 90-х кое-что произошло. Это кое-что называлось Windows 95/NT. Внезапно нам, программистам, дали понять, что всё, что мы делали раньше – это фуфло, и мы должны осваивать новую платформу. Все ранее придуманные уловки можно было забыть, поскольку теперь нам уже было нельзя без спросу играть с памятью, железом и операционной системой.
У большинства людей закрались мысли, что написание СМК далее не будет возможным без использования VxD, для которого, что характерно для Windows, отсутствовала более или менее грамотная документация. Спустя некоторое время было обнаружено, что мы всё-таки МОЖЕМ использовать СМК в своих программах. Один из способов – это использование функции WriteProcessMemory, экспортируемой библиотекой Kernel32, другой – размещение кода на стеке с последующей его модификацией.
Остаток статьи в основном посвящён Microsoft Visual C++ и 32-х разрядной подсистеме.
3. Память Windows как она есть
Создать СМК в Windows не так просто, как хотелось бы. Здесь придётся столкнуться с некоторыми подводными камнями, заботливо разложенными создателями Windows. Почему? Да потому что это Microsoft.
Как вы знаете, Windows отводит 4 гигабайта виртуальной памяти для каждого процесса. Для адресации этой памяти, в Windows задействованы два селектора. Один загружается в сегментный регистр CS, а другой бросили в регистры DS, SS и ES. Все они используют один и тот же базовый адрес (равный 0) и ограничены пространством в 4 гигабайта.
В программе может быть только ОДИН сегмент, содержащий и код и данные, также как и ОДИН стек процесса. Вы можете использовать БЛИЖНИЙ вызов процедуры или переход на управляющий код расположенный на стеке. В последнем случае вы не должны использовать SS для обращения к стеку. Хотя значение регистра CS не совпадает с DS, SS и ES, команды MOV dest, CS:[src], MOV dest, DS:[src] и MOV dest, SS:[src] обращаются к одному и тому же участку памяти.
У областей памяти (страниц) содержащих данные, код и стек, могут присутствовать некоторые атрибуты. Например, у страниц кода, разрешены чтение и исполнение, у страниц данных – чтение и запись, у стека – чтение, запись и исполнение одновременно.
Также у этих страниц может быть ряд атрибутов безопасности. Я расскажу о них чуть позже, когда они нам понадобятся.
4. WriteProcessMemory – новый лучший друг
Проще всего изменить несколько байтов в процессе (на мой взгляд) можно воспользовавшись функцией WriteProcessMemory (если не установлены флаги защиты).
Первое, что нужно сделать для этого – получить доступ к загруженному в память процессу, при помощи функции OpenProcess с атрибутами доступа PROCESS_VM_OPERATION и PROCESS_VM_WRITE. Ниже приведён пример простейшего СМК, о котором мы и поговорим. На C++ для реализации данного механизма, нам потребуются некоторые встроенные возможности языка. Само собой, всё это можно проделать и на других языках, но только об этом поговорим как-нибудь в другой раз. Кроме того, на других языках всё это выглядит гораздо сложнее.
Листинг 1. WriteProcessMemory на службе СМК
int WriteMe(void *addr, int wb) < HANDLE h=OpenProcess(PROCESS_VM_OPERATION| PROCESS_VM_WRITE, true, GetCurrentProcessId()); return WriteProcessMemory(h, addr, >int main(int argc, char* argv[]) < _asm < push 0x74 ; JMP >> JZ push offset Here call WriteMe add esp, 8 Here: JMP short Here > printf(«Holy Sh^); return 0; >
Как видите, программа заменяет бесконечный цикл простым переходом JZ.
Это позволяет программе перейти к следующей инструкции, и мы видим сообщение, которое подтверждает факт замены. Здорово, да? Бьюсь об заклад, теперь вы думаете… хмм, интересно, а я мог бы сделать что-то подобное? Скорее всего, да!
Вместе с тем, у такого способа (использования WriteProcessMemory) есть ряд уязвимостей. Прежде всего, опытный кракер БУДЕТ анализировать таблицу импорта и обнаружит подозрительную функцию. Он, скорее всего, поставит несколько бряков на этот вызов, проанализирует рядом стоящий код и найдёт то, что ему нужно.
Потому что использование WriteProcessMemory характерно только для компиляторов, которые собирают код в памяти, или для распаковщиков исполняемых файлов. Вместе с тем, таким трюком вы свободно можете поставить в тупик начинающего кракера. Я часто в своих программах использую такой приём.
Ещё один сакс WriteProcessMemory – невозможность создания в памяти новых страниц. Трюк с этой функцией работает только на существующих страницах. Поэтому, хотя и существуют несколько способов довести применение этой функции до ума, мы обратим своё внимание к выполнению кода на стеке.
5. Размещение кода на стеке, и его исполнение!
Размещать код на стеке не только допустимо, но иногда даже и необходимо. В частности, это облегчает жизнь компиляторам, позволяя им генерировать код на лету. Но не поставят ли такие вольности со стеком под угрозу безопасность системы? Само собой, – они могут навлечь неприятности на вашу задницу.
Кроме того, это не самая лучшая технология для ваших программ, поскольку установка патча, запрещающего исполнение кода на стеке, парализует работу большинства ваших творений. С другой стороны, хотя такой патч есть, — в частности для Linux, для Solaris, — и хотя он весьма полезен, я думаю, что его устанавливают только два человека (сами авторы, хи-хи).
Вы ещё помните об упомянутых выше уязвимостях WriteProcessMemory? Трюк с размещением исполняемого кода на стеке дарит нам две приятные возможности для их устранения. Во-первых, инструкции модифицирующие код, располагаются в неизвестном участке памяти, и поэтому кракеру практически невозможно отследить их.
Для анализа защищённого кода, ему придётся пилить дерево нашей программы под самый комель, поэтому скорее всего его работа не увенчается большим успехом! Другой аргумент в пользу исполнения кода на стеке – программа в любой момент может выделить себе столько памяти, сколько нужно, и в любой момент может освободить её. По умолчанию операционная система выделяет для стека 1 Мб памяти. Если же выполняемая задача требует большей памяти, программа может запросить дополнительную квоту.
Вместе с тем, есть несколько нюансов, которые необходимо знать, прежде чем размещать свой код на стеке… Поэтому мы о них сейчас и поговорим.
6. Почему перемещаемый код может быть вреден для вашего здоровья
Вам должно быть известно, что Windows 9x, Windows NT и Windows 2к располагают стек в разных местах. Поэтому для того чтобы ваша программа была кроссплатформенной, важно использовать относительную адресацию. Реализовать это требование не так уж и сложно, для этого всего лишь нужно следовать нескольким простым правилам – будь они прокляты, эти правила!
К нашей великой радости, в мире 80×86 все «шорт-джампы» и «нир-калы» – относительные. Это значит, что не надо использовать линейные адреса, но надо использовать разницу между целевым адресом и адресом следующей программной инструкции. Такая относительная адресация существенно упростит нашу жизнь, но даже она имеет свои ограничения.
Например, что произойдёт, если функцию void OSIXDemo() скопировать в стек и затем вызвать её? Такой вызов скорее всего приведёт к ошибке, поскольку адрес printf изменился.
На ассемблере, посредством регистра адресации, мы можем легко устранить эту проблему. Перемещаемый вызов функции printf можно реализовать очень просто, например, LEA EAX, printfNCALL EAX. Теперь АБСОЛЮТНЫЙ линейный адрес, – не относительный, – размещён в регистре EAX. Поэтому не имеет никакого значения, откуда вызывается функция printf – она будет работать корректно.
Для воспроизводства подобных трюков, необходимо, чтобы ваш компилятор поддерживал ассемблерные вставки. Я знаю, если вы не интересуетесь низкоуровневым программированием, для вас это полный сакс, но точно то же самое МОЖНО проделать ограничившись арсеналом, предоставляемым языками высокого уровня. Вот простой пример:
Листинг 2. Как скопировать функцию в стек и запустить её там
void Demo(int (*_printf) (const char *. )) < _printf(«Hello, OSIX!n»); return; >int main(int argc, char* argv[])
Так что не позволяйте никому вешать себе лапшу на уши, что языки высокого уровня не позволяют выполнять код на стеке.
7. Начинаем оптимизацию прямо сейчас!
Если вы планируете писать СМК или пользоваться кодом выполняемом на стеке, то вам нужно серьёзно подойти к выбору компилятора, и изучить особенности его работы. Скорее всего ваш код ОБВАЛИТСЯ ОШИБКОЙ при первом же обращении к нему из программы, в особенности если ваш компилятор установлен в режим «оптимизации».
Почему так происходит? Потому что в таких чисто высокоуровневых языках программирования как Си или Паскаль, архи-чертовски сложно скопировать код функции в стек или куда-либо ещё. У программиста есть возможность получить указатель на функцию, но вместе с тем, нет никаких правил, стандартизирующих его использование. В среде программистов это называется «магическое число», о котором известно только компилятору.
К счастью, практически все компиляторы при генерации кода пользуются схожей логикой. Это своеобразные негласные правила компилирования кода. Поэтому программист также может пользоваться ими.
Давайте ещё раз взглянем на Листинг 2. Мы справедливо предполагаем, что указатель на нашу функцию Demo() совпадает с её началом, и что тело функции расположено сразу же за началом этой функции. Большинство компиляторов придерживаются такого «здравого смысла компилирования», но не рассчитывайте, что все из них следуют этому.
Хорошо хоть, большие парни (VC++, Borland и т.д.) всё-таки придерживаются этого правила. Поэтому если вы не используете какой-то неизвестный или новый компилятор, не беспокойтесь об отсутствии «здравого смысла компилирования». Одно замечание относительно VC++: если вы работаете в режиме отладки, компилятор вставляет некий «адаптер» и размещает функцию в другом месте. Чёртов Microsoft.
Но не беспокойтесь, просто убедитесь, что в настройках установлен флаг «Link Incrementally», который вынудит ваш компилятор генерировать хороший код. Если же у вашего компилятора нет такой опции, вы можете либо не использовать СМК, или же использовать другой компилятор!
Другая проблема заключается в определении длины функции. Для этого есть простой и надёжный трюк. В C++ инструкция sizeof возвращает размер указателя на функцию, а не размер самой функции. Вместе с тем, как правило компиляторы выделяют память под объекты, в соответствии с порядком их появления в исходном коде.
Итак… размер функции – это разность между указателем на функцию и указателем на функцию, следующей за ней. Очень просто! Запомните этот трюк, он вам пригодится, даже несмотря на то, что оптимизирующие компиляторы НЕ БУДУТ следовать этим правилам, а следовательно и метод, который я только что описал, не будет работать. Видите, почему оптимизирующие компиляторы так вредны для вашего здоровья, если вы пишите СМК.
Ещё одна вещь, которую делают оптимизирующие компиляторы, это удаление переменных, которые, как они ДУМАЮТ, не используются. Возвращаясь к нашему примеру из листинга 2, мы увидим, что в буфер buff записывается какое-то значение, но ничего оттуда НЕ ЧИТАЕТСЯ.
Большинство компиляторов не способно распознать факт передачи управления в буфер, поэтому они удаляют инструкции, копирующие код в буфер. Ублюдки! Вот почему управление передаётся на неинициализированный буфер, и затем… бум. Крах. Если такая проблема имеет место быть, снимите флажок с «Global optimization», и всё у вас будет в порядке.
Если же ваша программа всё ещё не работает, не сдавайтесь. Вероятная причина в том, что компилятор в конце каждой функции вставляет вызовы подпрограмм, контролирующие стек. Так поступает Microsoft VC++. Она добавляет в отлаживаемых проектах вызовы функции __chkesp. Не утруждайте себя поиском описания этой функции, в документации его нет!
Этот вызов является относительным, и нет никакого способа исключить его. Однако, в финальном проекте VC++ проверяет состояние стека при выходе из функции, поэтому ваша программа будет работать как часы.
8. СМК в Ваших собственных программах
Итак, наконец пришло время для того, чего вы все давно ждали. Если вы проделали весь этот большой путь, описанный в статье, я приветствую вас. (бурные аплодисменты)
Хорошо, теперь вы можете спросить себя (или спросить меня) «Каковы преимущества выполнения кода (функции) на стеке?» И ответ таков (пожалуйста включите барабанную дробь…) Код функции, размещённой на стеке, может быть изменён на лету, например дешифратором. В ответ на это толпа говорит: Ахххххххххххх.
Зашифрованный код – это такая большая заноза в заднице кракера, занимающегося дизассемблированием. Конечно, пользуясь отладчиком, он слегка облегчает свою жизнь, но всё равно шифрованный код делает его/её жизнь невероятно трудной.
Например, простейший алгоритм шифрования, последовательно применяющий к каждой строке кода операцию исключающего ИЛИ (XOR) и который при повторном использовании восстанавливает исходный код!
Вот пример, который считывает содержимое нашей функции Demo(), зашифровывает её и записывает результат в файл.
Листинг 3. Как зашифровать функцию Demo
void _bild()
Результат шифрования помещается в строковою переменную. Теперь функцию Demo() можно удалить из исходного кода. В последствии, когда она нам потребуется, её можно будет дешифровать, скопировать в локальный буфер и вызвать для выполнения. Пинок под зад, да?
Вот пример реализации данного алгоритма:
Листинг 4. Зашифрованная программа
int main(int argc, char* argv[])
Обратите внимание, что функция printf() отображает приветствие. При беглом взгляде вы не заметите ничего необычного, но вы посмотрите, где находится строка «Hello, OSIX!». Ей не место в сегменте кода (хотя Borland по каким-то своим причинам размещает там строки), проверив сегмент данных, вы убедитесь, что она там, где и должна быть.
Теперь, даже если перед глазами кракера будет исходный код, для него наша программа по-прежнему останется одной из адских головоломок. Я использую этот метод для сокрытия «секретной» информации (серийные номера и ключи для моих программ, и т.д.).
Если вы собираетесь использовать данный метод для проверки серийного номера, верификацию нужно организовать таким образом, чтобы даже при дешифровке, сохранилась головоломка для кракера. Я покажу как это сделать в следующем листинге.
Запомните, при реализации СМК, вам нужно знать ТОЧНОЕ расположение байтов, которые вы собираетесь изменять. Поэтому вместо языков высокого уровня, следует использовать ассемблер. Давай, оставайся со мной, мы почти закончили!
При использовании ассемблера в реализации вышеописанного метода, существует одна проблема. Для изменения какого-либо байта посредством инструкции MOV, необходимо в качестве параметра передать АБСОЛЮТНЫЙ линейный адрес (который, как вы наверно догадались, до компиляции НЕИЗВЕСТЕН). НО… мы можем получить эту информацию в ходе выполнения программы.
CALL $+5/POP REG/MOV [reg+relative_address], xx – код, пользующийся огромной популярностью среди меня. Он работает следующим образом. В результате выполнения инструкции CALL на стеке остаётся адрес (или абсолютный адрес этой инструкции). Этот адрес используется в качестве базового для адресации кода стековой функции.
А вот пример верификации серийного номера, который я обещал вам…
Листинг 5. Генерация серийного номера и выполнение на стеке
MyFunc: push esi ; Сохраняем регистр ESI на стеке mov esi, [esp+8] ; ESI = Сохранение других регистров на стеке push ecx push edx xor eax, eax ; Обнуление рабочих регистров xor edx, edx RepeatString: ; Цикл побайтной обработки строки Lodsb ; Чтение очередного байта в AL test al, al ; Достигнут конец строки? jz short Exit ; Значение счётчика, который обрабатывает 1 байт стоки должно быть ; выбрано таким образом, чтобы все биты были перемешаны, но чётность ; (нечётность) обеспечивается за счёт преобразований, выполняемых операцией XOR mov ecx, 21h RepeatChar: xor edx, eax ; Многократные замены XOR и ADC ror eax, 3 rol edx, 5 call $+5 ; EBX = EIP pop ebx ; / xor byte ptr [ebx0Dh], 26h; ; Эта инструкция обеспечивает цикл ; Инструкция XOR заменяется ADC. loop RepeatChar jmp short RepeatString Exit: xchg eax, edx ; Результат работы (сер.ном) в EAX pop edx ; Восстановление регистров pop ecx pop ebx pop esi retn ; Возврат из функции
Этот код выглядит довольно-таки странным, поскольку повторные его вызовы, при передаче тех же самых аргументов, на выходе дают либо что-то одинаковое, либо совершенно различные результаты! Это зависит от длины имени пользователя. Если она нечётная, XOR при выходе из функции заменяется ADC. Иначе же, ничего подобного не происходит!
Ну вот и всё пока. Я надеюсь, что данная статья была хоть чем-то полезна вам. Её печать заняла у меня целых два часа! Обратная связь всегда приветствуется.
Английский первоисточник: Giovanni Tropeano. Self modifying code // CodeBreakers Journal. Vol. 1, No. 2, 2006.
- совершенный код
- системное программирование
- c++
- ассемблер
- win32
- ненормальное программирование
- хакерство
- реверс-инженеринг
- Ненормальное программирование
- C++
- Системное программирование
Источник: habr.com
программа, дописывающая свой код (не вирус)
Я читал вскользь о самомодифицирующемся коде:
1) вирус изменяет свой код на другой, дающий тот же результат
2) программа определяет какие-то условия, и ставит дальше в коде INC или DEC, и это даёт прирост скорости (использовалось в ассемблере под ДОС)
Это не то, о чём я хочу спросить.
В темах о создании мега-ИИ иногда пишут «сделать на скриптах, и чтобы писал новые скрипты и внедрял их в себя».
Я хочу спросить, как (хотя бы приблизительно) сделать программу, которая обрабатывает входные данные, на основе обработки создаёт код, внедряет его в себя и благодаря этому работает более эффективно. (например, выходные данные — какое-то значение, и чем лучше программа обрабатывает входные данные (чем больше кода она в себя записала, чем более точно учитываются входные данные), тем больше это значение, которое и надо максимизировать)
Программа попутно с обработкой данных должна создавать код, неоднообразный и осмысленный, эффективный, и не просто несколько строчек, а много, столько, сколько потребуется для эффективной обработки входных данных.
Предполагается что программа способна эффективно обрабатывать определённый набор входных данных. Сначала Подаются данные из такого набора, а затем к подаче добавляются данные, не входящие в этот набор, и эти новые даные программа обрабатывает неэффективно. Программа должна создать новый скрипт и использовать его при обработке, в результате чего будет эффективно обратаывать новый набор данных.
Я так вижу самообучение программы.
Пожалуйста, расскажите есть ли где-то что-то подобное?
Расскажите, какие есть идеи по реализации описанной программы?
Р.S.
1) Я использую слово «скрипт» в смысле «интерпретируемый код» (т.е. в программе есть интерпретатор, а новые участки кода генерируются в виде текста, который потом скармливается интерпретатору)
2) нейросети не предлагать пожалуйста.
#1
23:09, 15 янв 2008
на .net так же как среда разработки компилирует код может сама прога код компилить и запускать)
#2
23:45, 15 янв 2008
Centuri0n
меня интересует не техническая часть как запускать вновь созданный код, а имено то, КАК создавать новый код.
#3
23:52, 15 янв 2008
>меня интересует не техническая часть как запускать вновь созданный код
Береш и запускаеш
И даже так работает (я так делал когда создавал WndProc персонально для каждого класса(языкового) окна 🙂
Правда я догадываюсь о существовании подводных камней. О каких именно я пока помолчу (ибо только догадки)
#4
2:17, 16 янв 2008
soflot
Ну или свой скриптовый язык выдумать в зависимости от потребностей. Или взять один из исходных. а че непонятного то??
#5
2:41, 16 янв 2008
soflot
Я так понял, ты хочешь на лету откомпилировать некий скрипт в машинный код, и иметь возможность передать в этот код управление из основной программы?
Тебе надо выделить память под этот откомпиленный код функцией VirtualAlloc с флажком защиты PAGE_EXECUTE_READWRITE, чтобы винда позволила передать в него управление.
#6
2:58, 16 янв 2008
на питоне можно генерировать код в строках и потом его запускать
- crazyRand0m
- Постоялец
#7
5:58, 16 янв 2008
*vmr, Centuri0n, BUzer, CyberZX
Если я не ошибаюсь, то soflot спрашивал не как реализовать загрузку/выполнение сгенерированного кода, а какими алгоритмами можно его сгенерировать
(если ошибаюсь — то сорри %))
Мне бы тоже было бы интересно как можно генерировать код следуя какой-либо логике.
#8
8:05, 16 янв 2008
#9
9:48, 16 янв 2008
crazyRand0m
ты прав.
*vmr, Centuri0n, BUzer, CyberZX
Вы все очень невнимательно читаете.
ЗАБЕЙТЕ НА ЗАПУСК КОДА, я сам разберусь как запускать.
как мне СОЗДАТЬ НОВЫЙ код? (программно)
fr
спасибо за ключевые слова, поищу. Но подозреваю что это не то, что мне надо.
Народ, жду ваших вариантов.
#10
9:59, 16 янв 2008
soflot
Какой код? Для чего?
То, что ты написал в посте №0 понятно, вопрос в том под, что код?
У тебя есть своя виртуальная машина, с эмулятором проца, памяти и переферии? Тогда вопроса в получении нового кода не должно быть, ведь систему команд ты сам и придумал)
Есть под платформу х86 то посмотри машинный код команд процесора, и как они переводяться из асма в код процессора (для примера).
Где собираешься запускать?
В ХРюшке?
Тогда еще тебе нужно посмотреть как формируеться PE (Portable executable) файл с расширеним EXE.
И соответвенно генерируя новый код, знать старый, и модифицируя новый записывать его в виде экзешника и потом пускать.
Если где-то упустил или промахнулся — поправьте)
#11
12:02, 16 янв 2008
РЕФАЛ, Турчин
метакомпиляция
Источник: gamedev.ru