Понимание несмежной адресации стека в разборке gcc x86 - PullRequest
0 голосов
/ 25 июня 2019

Я использую этот исходный код C для компиляции с gcc (Ubuntu 7.4.0-1ubuntu1 ~ 18.04.1) 7.4.0.

/////////////////////////////////////////////////////////////////////////////////////////////
// Name: megabeets_0x1.c
// Description: Simple crackme intended to teach radare2 framework capabilities.
// Compilation: $ gcc megabeets_0x1.c -o megabeets_0x1 -fno-stack-protector -m32 -z execstac
//
// Author: Itay Cohen (@megabeets)
// Website: https://www.megabeets.net
/////////////////////////////////////////////////////////////////////////////////////////////


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

void rot13 (char *s) {
    if (s == NULL)
        return;
    int i;
    for (i = 0; s[i]; i++) {
        if (s[i] >= 'a' && s[i] <= 'm') { s[i] += 13; continue; }
        if (s[i] >= 'A' && s[i] <= 'M') { s[i] += 13; continue; }
        if (s[i] >= 'n' && s[i] <= 'z') { s[i] -= 13; continue; }
        if (s[i] >= 'N' && s[i] <= 'Z') { s[i] -= 13; continue; }
    }
}

int beet(char *name)
{
    char buf[128];
    strcpy(buf, name);
    char string[] = "Megabeets";
    rot13(string);

    return !strcmp(buf, string);
}

int main(int argc, char *argv[])
{
    printf("\n  .:: Megabeets ::.\n");
    printf("Think you can make it?\n");
    if (argc >= 2 && beet(argv[1]))
    {
        printf("Success!\n\n");
    }
    else
        printf("Nop, Wrong argument.\n\n");

    return 0;
}

Используется команда gcc

gcc megabeets_0x1.c -o test32 -fno-stack-protector -z execstack -m32 -no-pie -fno-pic

Разборка функции beet, сгенерированной с помощью objdump, выглядит следующим образом:

080485a8 <beet>:
 80485a8:   55                      push   ebp
 80485a9:   89 e5                   mov    ebp,esp
 80485ab:   81 ec 98 00 00 00       sub    esp,0x98
 80485b1:   83 ec 08                sub    esp,0x8
 80485b4:   ff 75 08                push   DWORD PTR [ebp+0x8]
 80485b7:   8d 85 78 ff ff ff       lea    eax,[ebp-0x88]
 80485bd:   50                      push   eax
 80485be:   e8 6d fd ff ff          call   8048330 <strcpy@plt>
 80485c3:   83 c4 10                add    esp,0x10
 80485c6:   c7 85 6e ff ff ff 4d    mov    DWORD PTR [ebp-0x92],0x6167654d
 80485cd:   65 67 61 
 80485d0:   c7 85 72 ff ff ff 62    mov    DWORD PTR [ebp-0x8e],0x74656562
 80485d7:   65 65 74 
 80485da:   66 c7 85 76 ff ff ff    mov    WORD PTR [ebp-0x8a],0x73
 80485e1:   73 00 
 80485e3:   83 ec 0c                sub    esp,0xc
 80485e6:   8d 85 6e ff ff ff       lea    eax,[ebp-0x92]
 80485ec:   50                      push   eax
 80485ed:   e8 94 fe ff ff          call   8048486 <rot13>
 80485f2:   83 c4 10                add    esp,0x10
 80485f5:   83 ec 08                sub    esp,0x8
 80485f8:   8d 85 6e ff ff ff       lea    eax,[ebp-0x92]
 80485fe:   50                      push   eax
 80485ff:   8d 85 78 ff ff ff       lea    eax,[ebp-0x88]
 8048605:   50                      push   eax
 8048606:   e8 15 fd ff ff          call   8048320 <strcmp@plt>
 804860b:   83 c4 10                add    esp,0x10
 804860e:   85 c0                   test   eax,eax
 8048610:   0f 94 c0                sete   al
 8048613:   0f b6 c0                movzx  eax,al
 8048616:   c9                      leave  
 8048617:   c3                      ret   

У меня мало сомнений относительно этой разборки,

  1. После нажатия ebp и перемещения *От 1015 * до ebp, указатель стека уменьшается вначале на 0x98, затем на 0x8, в сумме до 0xA0, в результате чего кадр стека выравнивается до 16 байтов.Почему компилятор не сделал прямого вычитания 0xA0 из esp вместо 2 последующих вычитаний?
  2. Как видно из кода C, переменная buf в функции beet составляет 128 байтов.Но в этой разборке buf указан ebp-0x88, что означает 136 байт для буфера.Почему выделено 136 байтов вместо 128 байтов?
  3. Перед вызовом таких функций, как strcpy или rot13, случайное число байтов , сначала вычтенное из esp перед вызовом и после завершения выполнения этих функций еще одно случайное число байтов добавлено в esp (что, я думаю, чтобы очистить аргументы, отправленные этим функциям).Пример - перед вызовом rot13, 0xc вычитается из esp, после завершения добавляется 0x10 вместо 0xc.Таким образом, эти случайные сдвиги esp и push-данных приводят к несмежным данным, что приводит к снижению использования стековой памяти.Есть ли какая-то особая причина этого поведения?

После поиска в google или stackoverflow я не смог найти ответа на эти сомнения.

Спасибо

ПРИМЕЧАНИЕ : код GCCРезультаты оптимизации почти такой же разборки.

1 Ответ

3 голосов
/ 25 июня 2019
  1. Вычитание 0x98 из стека оставляет его выровненным по 16 байтов.Дополнительные 8 байтов предназначены для подготовки к отправке параметров в strcpy, чтобы стек снова выравнивался по 16 байтов перед вызовом.

  2. Он выделяет 128 байтов для buf.Дополнительные байты между buf и ebp предназначены либо для выравнивания, либо для временных значений компилятора, либо для какой-либо другой цели компилятора.Возможно, здесь есть место для возвращаемого значения.В любом случае компилятору не нужно использовать пространство.Если вы включите оптимизацию, то, скорее всего, ее там не будет.

  3. Как и в # 1, указатель стека корректируется перед нажатием параметров для каждого вызова, так что стек составляет 16 байтвыровнен перед вызовом.

...