Программа должна вывести OK.
Solution
Первый взгляд
Посмотрю строки в файле:
root@3eac03729f34:/rev# strings const.elf
Flag{This_is_definetly_a_flag}
...
Подозрительно, но ладно. Попробую:
root@3eac03729f34:/rev# ./const.elf
Flag{This_is_definetly_a_flag}
Ничего. Перейду к статике.
Анализ main
int32_t main(int32_t argc, char** argv, char** envp)
{
char buf[0x10c];
int32_t var_c = fgets(&buf, 255, __TMC_END__);
buf[strlen(&buf) - 1] = 0;
if (!strcmp("Flag{This_is_definetly_a_flag}", &buf))
puts("OK!");
return 0;
}
Всё выглядит нормально. strcmp — библиотечная функция, strace не поможет. Но вот ltrace…
root@3eac03729f34:/rev# ltrace ./const.elf
fgets(1234
"1234\n", 255, 0x7d597022e8e0) = 0x7ffc92f978e0
strlen("1234\n") = 5
strcmp("Flag{ehls_is_dTfineyti_a_flag}", "1234") = 21
+++ exited (status 0) +++
А вот и подвох — строка при сравнении уже изменена! Попробую:
root@3eac03729f34:/rev# ./const.elf
Flag{ehls_is_dTfineyti_a_flag}
OK!
Флаг есть. Разберёмся почему.
.init_array и конструкторы GCC
Секция .init выполняется раньше любого другого кода — до передачи управления main. Все функции, которые должны выполниться до main, находятся в списке .init_array.
Вот наша функция:
int64_t swaps()
{
flag[5][0] = flag[0xe][0];
flag[0xe][0] = flag[5][0];
flag[0x14][0] = flag[0x15][0];
flag[0x15][0] = flag[7][0];
flag[7][0] = flag[0x14][0];
char result = flag[0x13][0];
flag[0x13][0] = flag[0x14][0];
flag[0x14][0] = result;
return result;
}
Она переставляет символы в строке флага до того, как main начинает работу.
В GCC для этого используется атрибут constructor:
#include <stdio.h>
void init_func() __attribute__((constructor));
void init_func() {
puts("init function call");
}
int main() {
puts("main function call");
return 0;
}
root@4428be4b59d9:/rev# ./main
init function call
main function call
Секции в бинаре:
root@4428be4b59d9:/rev# readelf --sections main | grep init
[12] .init PROGBITS 0000000000001000 00001000
[21] .init_array INIT_ARRAY 0000000000003db0 00002db0
Именно там и лежит указатель на swaps.