Я видел этот код сегодня в каком-то профиле fb, и не смог понять, что и как это работает:
(*(void(*)()) shellcode)()
Может кто-нибудь, пожалуйста, объясните мне, что означает приведенный выше код?
Полный фрагмент кода ниже: —
#include <stdio.h>
#include <string.h>
char *shellcode = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69""\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80";
int main(void)
{
fprintf(stdout,"Length: %d\n",strlen(shellcode));
(*(void(*)()) shellcode)();
return 0;
}
Это приведение к указателю на функцию (без возвращаемого результата и без аргументов). Я предпочитаю использовать typedef
определить сигнатуру таких функций:
typedef void plainsig_t(void);
тогда просто код
(*(plainsig_t*)shellcode) ();
Для указателей на функции вам не нужно разыменовывать их, поэтому короче просто кодировать:
((plainsig_t*) shellcode) ();
который в основном вызывает функцию, машинный код которой находится внутри shellcode
зона памяти.
Кстати, это не является строго переносимым C. В принципе, нет никакой гарантии, что вы можете привести указатель данных к указателю на функцию. (На некоторых странных процессорах, например, встроенных микроконтроллерах, DSP, компьютерах эпохи 1970-х годов, код и данные располагаются в разных адресных пространствах или имеют разные размеры указателей и т. Д ….). Но большинство распространенных процессоров и ABI (x86-64 / Linux, ARM / Android, ….) имеют одинаковое адресное пространство для кода и данных и принимают указатели функций приведения к указателям на данные и наоборот.
Это единственное место, где C и C ++ отличаются.
В C это означает указатель на функцию, возвращающую void и принимающую неопределенное количество аргументов неопределенного типа.
В C ++ это означает указатель на функцию, которая возвращает void и не принимает аргументов.
Выражение в целом принимает адрес shellcode
, преобразует его в указатель на тип функции, затем вызывает функцию, т. е. выполняет коды операции в этой строке.
void(*)()
означает «указатель на пустую функцию, которая не принимает аргументов». Линия
(*(void(*)()) shellcode)();
кастинг shellcode
на указатель на такую функцию, разыменование указателя (на самом деле не обязательно), а затем вызов функции.
Это указатель на функцию. Спецификаторы типов соответствуют объявлениям; так что функция void f()
имеет тип void()
; и указатель на функцию void (*pf)()
имеет тип void(*)()
,
Обратите внимание, что, как и в случае с объявлениями функций, в C и C ++ оно имеет несколько разные значения. В C пустые скобки означают, что у него есть неопределенное количество параметров, а в C ++ это означает, что у него нет параметров. Однако это не влияет на смысл кода.
Этот код интерпретирует массив как функцию и пытается вызвать его. Предположительно, массив содержит машинный код для печати сообщения, форматирования жесткого диска или чего-то еще. На большинстве современных платформ это вызовет сбой защиты, так как статические данные (надеюсь) по умолчанию не выполняются.