Возвращение строки, инициализированной из скаляра летучих, ведет себя очень странно? - PullRequest
3 голосов
/ 02 февраля 2020

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

#include <stdio.h>
static const volatile char a = 'a', b = 'b', c = 'c', d = 'd', e = 'e', f = 'f';
inline const char *_GetString(void) {
    return (const char[]){a, b, c, d, e, f, 0};
}
const char *GetString(void) {
    const char *x = _GetString();
    puts(x);
    return x;
}

int main(int argc, char *argv[]) {
    puts(GetString());
    return 0;
}

Предыдущее не печатает abcdef дважды. Однако это так:

#include <stdio.h>
const char *_GetString(void) {
    return "abcdef";
}
const char *GetString(void) {
    const char *x = _GetString();
    puts(x);
    return x;
}

int main(int argc, char *argv[]) {
    puts(GetString());
    return 0;
}

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

Ответы [ 3 ]

4 голосов
/ 02 февраля 2020

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

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

1 голос
/ 02 февраля 2020

Эта функция:

inline const char *_GetString(void)
{
    return (const char[]){a, b, c, d, e, f, 0};
}

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

Что касается попытки запутывания, если ваша цель - сохранить действительный пароль внутри исполняемого файла, я настоятельно рекомендую вам избегать этого. Если ваша программа может получить доступ к паролю в текстовом виде, хакер сможет это сделать; единственное, что вы должны хранить в этом случае, это криптография c га sh пароля (после его засолки).

0 голосов
/ 02 февраля 2020

Это работает, но не соответствует inline. Он возвращает строку и не содержит строковых литералов.

#include <stdio.h>
#include <string.h>

static const volatile char a = 'a', b = 'b', c = 'c', d = 'd', e = 'e', f = 'f';
const char *GetString(void) {
    static char array[7];
    strcpy(array, (const char[]){a, b, c, d, e, f, 0});
    return array;
}
int main() {
    puts(GetString());
    return 0;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...