Ответ 1
Здесь C-эквивалент фазы2:
int t[6];
read_six_numbers (t);
if ((t[0] != 0) || (t[1] != 1)) {
explode_bomb();
}
for (int i = 2; i < 6; i++) {
if (t[i] != t[i - 2] + t[i - 1]) {
explode_bomb();
}
}
Итак, пароль равен 0, 1, 1, 2, 3, 5.
Как я это сделал? Постепенно заменяя сборку на C.
Вы заметите, что указатель стека (rsp) никогда не изменяется. Стек можно увидеть как массив t из 32-битных чисел. Это каждый раз, когда вы перемещаетесь на 4 байта, вы переходите к следующему элементу. то есть 0 (% rsp), 4 (% rsp),... эквивалентны t [0], t [1],...
Я покажу вам возможную постепенную трансформацию бит, с которым у вас возникают проблемы:
lea 0x8(%rsp),%rbx
lea 0x18(%rsp),%rbp
<phase_2+42>: mov -0x8(%rbx),%eax
add -0x4(%rbx),%eax
cmp %eax,(%rbx)
je <phase_2+57>
callq explode_bomb
<phase_2+57>: add $0x4,%rbx
cmp %rbp,%rbx
jne phase_2+42
------------------------------------------------------
rbx = rsp + 8;
rbp = rsp + 24;
<phase_2+42>: eax = [rbx - 8];
eax += [rbx - 4];
if (eax == [rbx]) goto <phase_2+57>;
explode_bomb();
<phase_2+57>: rbx += 4;
if (rbx != rbp) goto phase_2+42;
------------------------------------------------------
rbx = rsp + 8;
rbp = rsp + 24;
do {
eax = [rbx - 8] + [rbx - 4];
if (eax != [rbx]) {
explode_bomb();
}
rbx += 4;
} while (rbx != rbp);
------------------------------------------------------
rbx = 8;
do {
eax = [rsp + rbx - 8] + [rsp + rbx - 4];
if (eax != [rsp + rbx]) {
explode_bomb();
}
rbx += 4;
} while (rbx < 24);
------------------------------------------------------
i = 2;
do {
eax = t[i - 2] + t[i - 1];
if (eax != t[i]) {
explode_bomb();
}
i += 1;
} while (i < 6);
------------------------------------------------------
for (int i = 2; i < 6; i++) {
if (t[i] != t[i - 2] + t[i - 1]) {
explode_bomb();
}
}
Если вы потратите время на понимание этих преобразований, вы сможете трансформировать и понять любую часть сборки.