Понимание декомпилированного кода сборки

Я пытаюсь понять этот код из сборки,

int32_t phase_5(char * str) {
    int32_t v1 = 0;
    if (strlen(str) != 4) {
        // 0x8049153
        alert_henchmen(5);
        v1 = 0;
        // branch -> 0x80491a6
    }
    while (true) {
        int32_t * v2 = (int32_t *)(4 * v1 + (int32_t)&g2); // 0x8049192_0
        char * v3 = (char *)(v1 + (int32_t)str);
        int32_t v4 = 0;
        int32_t v5 = 0; // 0x01516
        // branch -> 0x8049175
        int32_t v6; // bp+014
        while (true) {
            char v7 = *(char *)(v4 + (int32_t)"4l6aiqhor20x"); // 0x8049188
            v6 = v5;
            if ((int32_t)*v3 == (int32_t)v7) {
                // 0x804918f
                v6 = *v2 == v4 ? 1 : v5;
                // branch -> 0x80491a2
            }
            int32_t v8 = v4 + 1; // 0x80491a2
            if (v8 >= 12) {
                // break -> 0x80491ac
                break;
            }
            v4 = v8;
            v5 = v6;
            // continue -> 0x8049175
        }
        // 0x80491ac
        if (v6 % 256 != 1) {
            // 0x80491b7
            alert_henchmen(5);
            // branch -> 0x80491c3
        }
        int32_t v9 = v1 + 1; // 0x80491c3
        if (v9 >= 4) {
            // break -> 0x80491cd
            break;
        }
        v1 = v9;
        // continue -> 0x80491a6
    }
    // 0x80491cd
    return confirm_phase(5, str);
}

и я просто не уверен, что делает эта строка:

int32_t * v2 = (int32_t *)(4 * v1 + (int32_t)&g2) 

а также эта строка:

char v7 = *(char *)(v4 + (int32_t)"4l6aiqhor20x")

а что значит int32_t?

2 ответа

int32_t это один из типов, определенных в <stdint.h>; это 32-битный целочисленный тип со знаком с представлением дополнения 2 и без битов заполнения.

Декомпилятор, кажется, выбирает кратчайший путь, фактически не понимая, как писать идиоматический C-код. Сам код может даже не быть допустимым C, поскольку я считаю, что он может не соответствовать строгим требованиям псевдонимов C.

Вот, например:

int32_t * v2 = (int32_t *)(4 * v1 + (int32_t)&g2); // 0x8049192_0

Значение адреса g2 превращается в int32_t; тогда значение 4 * v1 добавляется к нему; и полученное целое число приводится к указателю на int32_t, Это надуманный способ написания

int32_t *v2 = ((int32_t *)&g2) + v1;

Или же; если g2 уже объявлен как массив int32_t, достаточно написать

int32_t *v2 = g2 + v1;

В общем, код бросает адрес g2 в указатель на int32_t, а затем назначает указатель на v1 th (на основе 0) int32_t в массиве последовательных int32_t s, первым из которых является тот в этом указателе, в v2,

Снова,

char v7 = *(char *)(v4 + (int32_t)"4l6aiqhor20x")

Это простой - но непереносимый код (он не работает в 64-битных процессорах!) Для кода

char v7 = "4l6aiqhor20x"[v4];

т.е. значение v4 й символ из строки "4l6aiqhor20x" назначен на v7,

Я не совсем уверен, что ваш вопрос, но я постараюсь помочь в ответе, объяснив, что когда программист пишет что-то, есть цель для каждой строки, о которой он или она знает - например, если они хотят написать сообщение, они могут вызвать переменную "myMessage". Эта информация не включена в окончательный результат. Таким образом, декомпилятор не будет называть его "myMessage" и просто назначит адрес памяти (обозначенный символом & &) или случайное имя переменной (обозначенное буквой v выше). После некоторого подробного изучения вы можете выяснить, что конкретно делает эта часть кода, но без подсказок, таких как "myMessage", вам, возможно, придется обработать и отобразить всю программу перед тем, как действительно ее понять.

Так для строки кода: int32_t * v2 = (int32_t *)(4 * v1 + (int32_t)&g2)

Вы можете только сказать, что он берет 4, умножает его на v1 и добавляет к адресу переменной g2. Результатом является 32-битный адрес, который хранится в v2. Поскольку здесь нет упоминаний о том, что такое g2, то вы можете начать видеть обоснование в моем ответе. Поскольку это 32 бита (4 байта), это может объяснить умножение на 4, и, возможно, v1 является счетчиком.

Другие вопросы по тегам