Комментарии 92
В C, очевидно, это тоже будет работать. Ничего специфичного для C++ (не считая cout, конечно) в вашем примере нет.
Отличная задача для какого-нибудь бесчеловечного собеседования.
а почему reinterpret не работает? я всегда считал что c-cast==static_cast+reinterpret_cast
Я пока не дорос до трактования смысла каждого числа. Их получил путем просмотра памяти занимаемой функцией int sum(int a, int b){return a+b;}. В примере говорю компилятору, чтобы этот массив(тех самых чисел в памяти) рассматривал как функцию.
Для проникновения в глубины вселенной и ответа на вопрос 42 вам потребуются:
1) www.idapro.ru/ или ему подобные
2) Калькулятор, который высчитывает HEX
3) wasm.ru или книжку Стива Хатчетсона, ну или любой манускрипт с толковым описанием асьма
4) Смекалка.
В действительности, вы правы, это — машинный код. Его можно перевести в АСМь
1) www.idapro.ru/ или ему подобные
2) Калькулятор, который высчитывает HEX
3) wasm.ru или книжку Стива Хатчетсона, ну или любой манускрипт с толковым описанием асьма
4) Смекалка.
В действительности, вы правы, это — машинный код. Его можно перевести в АСМь
Ох, ну и раззадорили Вы меня…
FF55
FF89
FFE5
FF8B
0045
000C
0003
0045
0008
005D
FFC3
FF90
FF55
FF89
FFE5
FF8B
0045
000C
0003
0045
0008
005D
FFC3
FF90
После гугления выходит следующее:
0055 — *
FF89 —
FFE5 — BIT (2 байта)
FF8B — 0045 — *
000C — CLC
0003 — *
0045 — *
0008 — INX (1 байт)
005D — TST (1 байт)
FFC3 — *
FF90 —
Опытный читатель задаст вопрос: «Ну и что всё это значит?». Вопрос будет очень к месту. Значит это, что мои, пятилетней давности кульбиты на ассемблере давно уже забыты. Я не помню, как правильно читать байткоды из памяти, сколько бит использовать на каждый, и вообще и так далее.
Да… Программирование надо учить ежедневно.
Ладно, есть варианты, как правильно дизасембленуть? 8-)
0055 — *
FF89 —
FFE5 — BIT (2 байта)
FF8B — 0045 — *
000C — CLC
0003 — *
0045 — *
0008 — INX (1 байт)
005D — TST (1 байт)
FFC3 — *
FF90 —
Опытный читатель задаст вопрос: «Ну и что всё это значит?». Вопрос будет очень к месту. Значит это, что мои, пятилетней давности кульбиты на ассемблере давно уже забыты. Я не помню, как правильно читать байткоды из памяти, сколько бит использовать на каждый, и вообще и так далее.
Да… Программирование надо учить ежедневно.
Ладно, есть варианты, как правильно дизасембленуть? 8-)
0055 — PUSH rBP
FF89 — MOV Ev,Gv
FFE5 — IN eAX,Ib
FF8B — MOV Gv,Ev
0045 — INC eBP
000C — OR AL,Ib
0003 — ADD Gv,Ev
0045 — INC eBP
0008 — OR Eb,Gb
005D — POP rBP
FFC3 — CMP AL,Ib
FF90 — NOP
После возьни и прочей финги я нашёл таки интерпритатор кодов для процессора 386 а не для моторолы 6800, стало проще, хотя всё ещё не похоже на программу.
Вывод. Надо больше спать, и не париться с асьмой.
FF89 — MOV Ev,Gv
FFE5 — IN eAX,Ib
FF8B — MOV Gv,Ev
0045 — INC eBP
000C — OR AL,Ib
0003 — ADD Gv,Ev
0045 — INC eBP
0008 — OR Eb,Gb
005D — POP rBP
FFC3 — CMP AL,Ib
FF90 — NOP
После возьни и прочей финги я нашёл таки интерпритатор кодов для процессора 386 а не для моторолы 6800, стало проще, хотя всё ещё не похоже на программу.
Вывод. Надо больше спать, и не париться с асьмой.
есть мнение, что за такое в продакшн коде надо отрывать руки по самые яйца
Зря человека минусуете, очень правильную мысль hellraiser09 говорит. Полностью согласен!
По самые яйца включительно.
В продакшене за многое нужно отрывать и руки и яйца, но давайте не будем забывать что это просто кусок кода, который демонстрирует просто определенную возможность. И это интересно, это любопытно, это позволяет залезть за кулисы… Если вы считаете что это бесполезно, значет этот топик не для вас. Я не говорю что при этом вы плохой программист, просто вам достаточно того уровня на котором пишут в продакшене. Для таких как автор топика и я, этого не достаточно, хочется понять все, а не «напишите вот это, а получите это». И знать как использовать это совсем не значит использовать на практике!
Возможность, простите, чего? Программировать в машинных кодах и вызывать это из C/C++?
Зачем тогда вообще нужны компиляторы, линковщики и пр.? Пишите сразу EXE файл в блокноте.
Зачем тогда вообще нужны компиляторы, линковщики и пр.? Пишите сразу EXE файл в блокноте.
Я же сказал, знать, не значит использовать. Это в образовательных целях. Вам это не интересно? Значит это не ваше :)
Все зависит от того, насколько глубоко человек хочет вникнуть в систему. Для кого то достаточно понять фреймворк, для кого-то нужно залезть поглубже в API, еще кому то нужно расковырять все до уровня работы с памятью, регистрами, стеком, умения понимать дизасемблированный код, узнавать свои переменные/функции/классы в окне Memory View. Каждый в итоге займет свою нишу в IT сфере. Кто-то будет рубить капусту в C# выпуская бизнес приложения по пять штук в месяц. И этому человеку абсолютно пофиг что где то в С++ можно сделать грязный хак… А кто-то будет просто торчать от того что он нашел новый грязный хак, не потому что он будет теперь писать ехе файлы в блокноте, а потому что система стала ему на один шаг ближе. Он чему то научился, и что-то что ему было не знакомо еще пару минут назад, теперь стало его достоянием. Тот первый никогда не поймет радости второго. Автор топика написал что это бесполезный код. Он не будет использовать его не только в продакшене, а и вообще где нибудь… Он просто открыл для себя нечто новое, и ему это так понравилось, что он решил поделиться этим с остальными… И сдесь есть люди которым это было адресовано, а для остальных это всего лишь бесполезно прочитаный топик
Все зависит от того, насколько глубоко человек хочет вникнуть в систему. Для кого то достаточно понять фреймворк, для кого-то нужно залезть поглубже в API, еще кому то нужно расковырять все до уровня работы с памятью, регистрами, стеком, умения понимать дизасемблированный код, узнавать свои переменные/функции/классы в окне Memory View. Каждый в итоге займет свою нишу в IT сфере. Кто-то будет рубить капусту в C# выпуская бизнес приложения по пять штук в месяц. И этому человеку абсолютно пофиг что где то в С++ можно сделать грязный хак… А кто-то будет просто торчать от того что он нашел новый грязный хак, не потому что он будет теперь писать ехе файлы в блокноте, а потому что система стала ему на один шаг ближе. Он чему то научился, и что-то что ему было не знакомо еще пару минут назад, теперь стало его достоянием. Тот первый никогда не поймет радости второго. Автор топика написал что это бесполезный код. Он не будет использовать его не только в продакшене, а и вообще где нибудь… Он просто открыл для себя нечто новое, и ему это так понравилось, что он решил поделиться этим с остальными… И сдесь есть люди которым это было адресовано, а для остальных это всего лишь бесполезно прочитаный топик
Спасибо за поддержку, я бы не смог сказать лучше :)
Я считаю, что это не только интересно, но и что такие штучки помогают понять сложное.
Я считаю, что это не только интересно, но и что такие штучки помогают понять сложное.
Если человек хочет глубже понять систему, то нужно начинать не сверху — от C++ к ассемблеру и машинному коду, а наоборот — изучить ассемблер, понять, зачем и кому он нужен, после чего перейти на C, оценить преимущества, которые даёт структурированный язык с переменными и организованной кучей, после чего перейти к ООП, интерпретируемым и скриптовым языкам, фреймворкам, постепенно повторяя в своём развитии, в некотором роде, всё развитие компьютерной эры.
А подобные «открытия» «сверху вниз», возможно, интересны, но не несут ничего полезного в качестве знаний, так как не имеют под собой базиса.
А подобные «открытия» «сверху вниз», возможно, интересны, но не несут ничего полезного в качестве знаний, так как не имеют под собой базиса.
Ходить вы начинали учится с 100 киломметровых марафонов? :)
Для начала как раз и сойдут скриптовые языки и фреймворки, что бы человек не вдаваясь в подробности просто проникся самой сутью программирования, алгоритмов, логики и т.д. Для начала нужно просто вникнуть что такое переменная, прочувствовать ее сущность, потом разобратся во всех тонкостях указателей и ссылок на нее, понять разницу между l и r-значениями… И лишь потом изучать по какому смещению и в каком сегменте ее искать (для начала изучив что такое смещение и сегмент)
Зачем начинающему программисту, который еще толком не может объявить эту самую переменную, знать такие тонкости? :)
Для начала как раз и сойдут скриптовые языки и фреймворки, что бы человек не вдаваясь в подробности просто проникся самой сутью программирования, алгоритмов, логики и т.д. Для начала нужно просто вникнуть что такое переменная, прочувствовать ее сущность, потом разобратся во всех тонкостях указателей и ссылок на нее, понять разницу между l и r-значениями… И лишь потом изучать по какому смещению и в каком сегменте ее искать (для начала изучив что такое смещение и сегмент)
Зачем начинающему программисту, который еще толком не может объявить эту самую переменную, знать такие тонкости? :)
З.Ы. А кто-то интересовался как компилятор физически реализует ссылку на переменную? :) Нет? рекомендую посмотреть. Мне было довольно интересно узнать как это делает MSVC++ :)
Перед тем, как учиться водить машину, человек учится ходить. А если человек сразу сел за руль, для него будет открытием, что, оказывается, можно открыть дверь и пойти пешком.
Очень бы интересно было посмотреть на человека, который бы стал использовать такое в продакшне.
Как и следовало ожидать:
Так что хак немного устарел.
Unhandled exception at 0x0012ff54 in FunctionWithoutDefinition.exe: 0xC0000005: Access violation.
0x0012ff54
— адрес массива с
Так что хак немного устарел.
Автор видимо эзотерик, вообще есть же среди программеров старая развлекуха «написать дважды два в тысячу строчек», тут другой вариант: сделать простую вещь самым неочевидным из возможных способов. Думаю как задачка она хороша, а вот как реальный боевой код за такое по рукам дают
short main[] = { 277, 04735, -4129, 25, 0, 477, 1019, 0xbef, 0, 12800, -113, 21119, 0x52d7, -1006, -7151, 0, 0x4bc, 020004, 14880, 10541, 2056, 04010, 4548, 3044, -6716, 0x9, 4407, 6, 5568, 1, -30460, 0, 0x9, 5570, 512, -30419, 0x7e82, 0760, 6, 0, 4, 02400, 15, 0, 4, 1280, 4, 0, 4, 0, 0, 0, 0x8, 0, 4, 0, ',', 0, 12, 0, 4, 0, '#', 0, 020, 0, 4, 0, 30, 0, 026, 0, 0x6176, 120, 25712, 'p', 072163, 'r', 29303, 29801, 'e' };
отсюда
Ха-ха, выходит на Сях вполне можно реализовать метапрограммитрование — подавать на вход правильные коды и исполнять произвольные функции
Хехе. На самом деле, то что вы сейчас сказали, звучит странно.
Представьте себе человека, который увидел впервые в жизни вафельницу и говорит: «Ух ты, она греется! Выходит на ней можно сделать блины, или вафли!»
Не в обиду.
Просто раньше это делали очень часто. Для написания эмуляторов, в основном.
У Майкрософта на смену с++ пришёл С#, в котором, слава богу, позапрещали 90% хаков и подковырок. Как-то жить стало проще, консервативнее, чтоли 8-)
Представьте себе человека, который увидел впервые в жизни вафельницу и говорит: «Ух ты, она греется! Выходит на ней можно сделать блины, или вафли!»
Не в обиду.
Просто раньше это делали очень часто. Для написания эмуляторов, в основном.
У Майкрософта на смену с++ пришёл С#, в котором, слава богу, позапрещали 90% хаков и подковырок. Как-то жить стало проще, консервативнее, чтоли 8-)
Не кроссплатформенно… Это далеко не тоже самое, что eval, хотя да можно конечно в рантайме дёргать компилятор, а потом егоные объектные файлы в память грузить и кастовать в нужные вещи и юзать, но только это того не стоит.
Да про любой компилируемый язык
А че это вы фразы из контекста вырываете? а? Куда дели окончание
>но только это того не стоит.
Я лишь утверждаю, что даже на C++ можно сделать аналог evalа, но из за сложностей языка он будет весьма страшным и неудобным
>но только это того не стоит.
Я лишь утверждаю, что даже на C++ можно сделать аналог evalа, но из за сложностей языка он будет весьма страшным и неудобным
1. Для опенсорс программ это не проблема
2. Видимо вы не врубились в суть происходящего: дергается внешний процесс, который запускает сборку, по его завершению загружаем в память объектный файл, как массив байт, он будет выглядеть примерно в духе того, что тут было представлено, а дальше просто делаем тоже самое, что было сделано в статье.
2. Видимо вы не врубились в суть происходящего: дергается внешний процесс, который запускает сборку, по его завершению загружаем в память объектный файл, как массив байт, он будет выглядеть примерно в духе того, что тут было представлено, а дальше просто делаем тоже самое, что было сделано в статье.
Ну, это старый трюк…
Когда-то, в начале 80-х, мы писали для 8080 в кодах. Потом на ассемблере. Потом PL-M и C.
Тал вот иногда было проще прямо кодами, как у Вас. Только удобнее в шеснадцатиричном формате писать — потом читать легче…
Когда-то, в начале 80-х, мы писали для 8080 в кодах. Потом на ассемблере. Потом PL-M и C.
Тал вот иногда было проще прямо кодами, как у Вас. Только удобнее в шеснадцатиричном формате писать — потом читать легче…
За такое — я бы просто уволил.
Вы глупый человек :)
Аналогично — машинные коды надо писать байтами через 0x запись, поскольку ни один вменяемый человек не привык дизассемблировать в уме из десятичной записи. Ну и вообще для подобных вещей ассемблерные вставки придуманы. Ну и без очень серьезных оснований их использовать разумеется не стоит.
Это не совсем бесполезный трюк. С помощью него можно делать в определенных случаях «санки». Например, когда НЕЧТО хочет от нас callback функцию без user-аргументов, а мы хотим чтобы эта callback функция была связана с экземпляром класса в памяти. Делаем указанным выше способом функцию-«санки», которая внутри сгенерированного кода содержит указатель на класс и при вызове вызывает уже его метод.
P.S. Это я к вопросу о ТЕОРЕТИЧЕСКОЙ применимости. В коммерческих продуктах лучше так не делать :).
P.S. Это я к вопросу о ТЕОРЕТИЧЕСКОЙ применимости. В коммерческих продуктах лучше так не делать :).
В Delphi так реализованы оконные процедуры.
Что-то мне кажется такой подход из серии «А не запутаться ли нам вместе со всеми».
Действительно, лучше не применять, а на собеседованиях бурно негодовать.
Действительно, лучше не применять, а на собеседованиях бурно негодовать.
Забавный вариант встроить ассемблер в программу. Надо напугать одногруппников в универе)))
Да, ещё помно, когда был Borland C первых версий, там прямо в хелпе писали хак, которым можно поменять константу… Только зачем, я так и не понял, ни тогда, ни 10 лет спустя.
Хорошо, какая мораль? С — это не игрушка и в ней можно играть с памятью на прямую? Ну так это уже не новость :)
скорее о том как работают уязвимости типа «ошибка переполнения с возможностью выполнения произвольного кода»
Не вижу никакой связи. Здесь просто человек присвоил адрес указателю на функции грязным хаком, все.
Мда, я таким в паскале занимался еще — по адресу влезал в функцию, искал ее пределы( а потом сохранял данные для повторного использования)
Тогда на меня снизошло откровение, которое не отпускает до сих пор — а нахнера тогда скриптовые языки придумали?
пс:(и кстати да — DEP рулит )
Тогда на меня снизошло откровение, которое не отпускает до сих пор — а нахнера тогда скриптовые языки придумали?
пс:(и кстати да — DEP рулит )
Ну кстати красивее было бы в виде строки (и короче). Единственный минус — автонультерминатор (хотя в данном случае это не принципиально, т.к. он за ретом)
char c[] = "\xFF\x55\xFF\x89\xFF\xE5\xFF\x8B\x00\x45\x00\x0C\x00\x03\x00\x45\x00\x08\x00\x5D\xFF\xC3\xFF\x90";
char c[] = "\xFF\x55\xFF\x89\xFF\xE5\xFF\x8B\x00\x45\x00\x0C\x00\x03\x00\x45\x00\x08\x00\x5D\xFF\xC3\xFF\x90";
Вероятно(,) опытных людей…
Хи клевый хак. Хотя в современной ОС с процом поддерживающим бит исполнения страницы не прокатит.
Между прочим, при соблюдении нужных процедур вынесения в HAL и тп. этот прием может использоваться для частичной самокомпиляции в целях «ушоб побыстрее, ежели компилятор не сильно оптимизирующий», и лет 10 назад даже в продакшн коде так делали иногда.
А в сегодняшних реалиях — присоединяюсь к ораторам с точкой зрения «руки оторвать за такое», более быстрая машина стоит дешевле времени программистов на веселую отладку таких перлов :)
А в сегодняшних реалиях — присоединяюсь к ораторам с точкой зрения «руки оторвать за такое», более быстрая машина стоит дешевле времени программистов на веселую отладку таких перлов :)
Мало того что опасный бред, так он ещё и (вполне предсказуемо) не работает:
(honeyman@honeyman-lap:pts/4, 13:55:17)
139:/tmp:$ cat > 1.cpp
#include using namespace std;
typedef int (*pf)(int, int);
char c[] = {85,-119,-27,-117,69,12,3,69,8,93,-61,-112};
pf sum = (pf)c;
int main(void) {cout << sum(2,3);}
(honeyman@honeyman-lap:pts/4, 13:55:34)
/tmp:$ g++ 1.cpp -o 1.exe; ./1.exe
zsh: segmentation fault ./1.exe
Это, конечно, занятно, но не более. Так вообще лучше нигде и никогда не писать, если только не стоит задача максимально запутать чтение кода. Код к тому же совершенно непортируем.
Хз…
…
pf sum = (pf)c;
…
-> «error C2440: 'type cast': cannot convert from 'char [12]' to 'pf'»
…
pf sum = (pf)c;
…
-> «error C2440: 'type cast': cannot convert from 'char [12]' to 'pf'»
Тсс, только не говорите про шелдкоды! А то топик сползёт к обсуждению написания эксплоитов.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
Функция без явного определения