C файл без №? - PullRequest
       2

C файл без №?

7 голосов
/ 25 июля 2011

Предположим, вам дается один C source file, который содержит макс.300 строк кода.

Предположим также, что файл, при реализации нескольких функций, НЕ содержит в себе символ '#' (то есть, НЕТ #include уставок,и нет других операторов, которые имеют «#» в файле).

Мой вопрос заключается в том, гарантирует ли вышеуказанный , что файл не не выполняет никаких операций ввода-вывода?гарантирует ли это, что файл не не сможет (скажем) стереть содержимое жесткого диска или выполнить другие подозрительные действия?

(я должен получить 100-200 синглов)C файлов, которые (как уже упоминалось) не включают в себя символ #. Меня попросили написать простую программу, которая будет программно проверять, есть ли один C source file без #потенциально участвует в операциях ввода-вывода, доступа к сети и т. д.)

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

Я знаю , что никакая проверка не даст 100% точности - но мне интересно по крайней мере сделать некоторые базовые проверки, которые поднимут красный флаг, если некоторые выражения /ключевые слова найдены.Есть идеи, что искать?

Ответы [ 9 ]

12 голосов
/ 25 июля 2011

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

5 голосов
/ 25 июля 2011

Можно просто скопировать и вставить определения стандартных типов файлов и функций (например, FILE, fopen (), fprintf (), flocse ()) и т. Д. В файл C.Таким образом, включение не требуется, и когда файл скомпилирован и связан с соответствующими библиотеками, он сможет выполнять ввод / вывод.

5 голосов
/ 25 июля 2011

Если бы оригинальный кодер включал встроенную сборку, он мог бы делать практически все, что им нравилось, без импорта каких-либо библиотек.

3 голосов
/ 26 июля 2011

# - не единственный токен, который может запустить директиву препроцессора.??= и %: являются эквивалентными определениями в стандарте.(Но они не распознаются всеми компиляторами.)

2 голосов
/ 26 июля 2011

Отсутствие директив препроцессора не гарантирует ничего , кроме отсутствия директив препроцессора.

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

Когда-то давно я видел код (возможно, для IOCCC), который использовал массив беззнаковых символов для хранения необработанных кодов операций, а затем использовал тип punning, чтобы рассматривать его как функцию, что-то вроде

unsigned char instr[] = {0x00, 0x12, 0x33, ...};

void (*foo)(void) = (void (*)(void)) instr;
foo();

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

EDIT

Я нашел код, о котором думал, - это была запись IOCCC от 1984 года. Однако она работает не так, как я описал. Эй, я старею, и вещи не прилипают к моему мозгу, как это было раньше.

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'
};

Вот объяснение :

The Grand Prize: 

    Sjoerd Mullender & Robbert van Renesse

Without question, this C program is the most obfuscated C program that
has ever been received!  Like all great contest entries, they result
in a change of rules for the following year.  To prevent a flood of
similar programs, we requested that programs be non machine specific.

This program was selected for the 1987 t-shirt collection.

NOTE: If your machine is not a Vax-11 or pdp-11, this program will
      not execute correctly.  In later years, machine dependent
      code was discouraged.

The C startup routine (via crt0.o) transfers control to a location
named main.  In this case, main just happens to be in the data area.
The array of shorts, which has been further obfuscated by use of
different data types, just happens to form a meaningful set of PDP-11
and Vax instructions.  The first word is a PDP-11 branch instruction
that branches to the rest of the PDP code.  On the Vax main is called with
the calls instruction which uses the first word of the subroutine as a
mask of registers to be saved.  So on the Vax the first word can be anything.
The real Vax code starts with the second word.  This small program
makes direct calls to the write() Unix system call to produce a
message on the screen.  Can you guess what is printed?  We knew you
couldn't!  :-)

Copyright (c) 1984, Landon Curt Noll.
All Rights Reserved.  Permission for personal, educational or non-profit use is
granted provided this this copyright and notice are included in its entirety
and remains unaltered.  All other uses must receive prior permission in writing
from both Landon Curt Noll and Larry Bassel.

Опять же, я не знаю, сработает ли этот трюк на любой современной настольной ОС, но было бы интересно узнать.

2 голосов
/ 25 июля 2011

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

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

1 голос
/ 26 июля 2011

Вы также можете попробовать скомпилировать файлы C в статический двоичный файл, разобрать его и проверить инструкции для системного вызова (sysenter, int).IO не может быть выполнен из пространства пользователя, и процесс должен будет перейти к ядру для выполнения любого вида IO.

Однако это все еще не защищает от выполнения команд в нетекстовых частях вашего двоичного файла.В худшем случае у вас могут быть инструкции, изготовленные во время выполнения и выполненные.Для этого, я думаю, лучше всего сделать покрытие кода, отслеживая процесс для системных вызовов.В Linux есть strace, который может помочь с этим.

1 голос
/ 26 июля 2011

Следующая программа является допустимой программой C, которая выдает выходные данные на stdout. Он не содержит # символов:

int puts(const char *s);

int main(void)
{
    puts("hi");
    return 0;
}

Он даже не выдает предупреждение от компилятора (/Wall /W3 на MSVC и -Wall -Wextra на MinGW), тем более ошибка.

1 голос
/ 25 июля 2011

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

Вы, вероятно, должны бегать с низкими привилегиями в песочнице и посмотреть, какие системные вызовы они делают с чем-то вроде strace.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...