Разные значения Int для одного и того же значения? - PullRequest
0 голосов
/ 07 мая 2019

Я столкнулся с проблемой переполнения целых чисел, которую мне удалось решить, но только методом проб и ошибок.

Поскольку это проблема целочисленного переполнения, я написал код для распечатки буфера. Начало буфера - это адрес, где хранится массив [0]. Затем я начал передавать значения MAX_INT и MIN_INT в программу. Я заметил, что когда я передавал значение MIN_INT в argv [1], он перезаписывал начало буфера. поэтому я передал значение MIN_INT + 1 и заметил, что он перезаписал второй адрес буфера. оттуда это было легко решить.

Дело в том, что я не понимаю, почему это работает. В функции place_int_array, когда я передаю, скажем, значение MIN_INT + 6 в argv [1], оператор if "if (slot> 3)" возвращает false, поэтому он переходит к оператору "else", поскольку MIN_INT + 6 отрицательное значение, поэтому оно меньше или равно 3, поэтому значение слота интерпретируется как значение «MIN_INT + 6». Но в выражении «else» массив [slot] поднялся в буфере до адреса «array [0] +6», что означает, что значение слота как индекса «array» интерпретировалось как «6».

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int secretCode = 10;

void dump_stack(void **stack, size_t n, void **arg0) {
    printf("Stack dump (stack at %p, len %d): \n", stack, n);
    //if the buffer if not aligned on a dword boundary - force alignment of print

    void** alignedStack = (void**)(((unsigned int)stack >> 2) << 2);
    while (n-- > 0) {
        printf("0x%08x: 0x%08x", (unsigned int)&alignedStack[n], (unsigned int)alignedStack[n]);
        if (n == 0) {
            printf(" (beginning of buffer)");
        }
        if (&alignedStack[n] == arg0 + 6+1) {
            printf(" (main first argument (argc))");
        }
        if (&alignedStack[n] == arg0 + 6) {
            printf(" (main return address (saved eip))");
        }
        if (&alignedStack[n] == arg0) {
            printf(" (second argument)");
        }
        if (&alignedStack[n] == arg0 - 1) {
            printf(" (first argument)");
        }
        if (&alignedStack[n] == arg0 - 2) {
            printf(" (place_int_array return address (saved eip))");
        }
        if (&alignedStack[n] == arg0 - 3) {
            printf(" (saved ebp)");
        }

        printf("\n");
    }
}

void print_secret_code() {
    //TODO - call this from somewhere...
    printf("You get better at this stuff, ah?! Go get your treasure, the code is %d\n", secretCode);
}

void  fill_array(int array[], size_t len) {
    unsigned int i;
    for (i = 0; i < len; i++) {
        array[i] = i * 10;
    }
}

void place_int_array(int slot, int value) {
    int array[3];

    printf("place_int_array ret address: %p\n‬", __builtin_return_address(0));
    printf("&array: %p\n", &array);
    printf("slot: %d\n", slot);
    printf("&array[slot]: %p\n", &array[slot]);


    fill_array(array, sizeof(array) / sizeof(array[0]));

    printf("slot: %d\n", slot);
    if (slot > 3) //we stop bad guys here
        printf("safe number is greater than 3, out of bounds.\n");
    else {
        array[slot] = value;
        dump_stack((void **) array, 30, (void **) &value);
        printf("filled safe %d with %d.\n", slot, value);
    }
    return;
}

int main(int argc, char **argv) {
    printf("print_secret_code function = %p\n", print_secret_code);

    if (argc != 3) {
        printf("Welcome to Alladin's magic cave!\n");
        printf("Enter the secret number into the right safe and get the treasure cave entrance code!\n");
        printf("syntax: %s [SAFE NUMBER] [SECRET NUMBER]\n", argv[0]);

        //TEMP TEMP - for debugging only
        printf("print_secret_code function = %p\n", print_secret_code);
    }
    else
    {

        place_int_array(atoi(argv[1]), atoi(argv[2]));
    }

    exit(0);
}

Вот вывод:

[lab8_IntegerOverflow]$ ./aladdinSafe -2147483648 1
print_secret_code function = 0x804864b
place_int_array ret address: 0x804880d
&array: 0xffbd8464
slot: -2147483648
&array[slot]: 0xffbd8464
slot: -2147483648
Stack dump (stack at 0xffbd8464, len 30): 
0xffbd84d8: 0xbca9b1bd
0xffbd84d4: 0x72f595ac
0xffbd84d0: 0x00000000
0xffbd84cc: 0x00000000
0xffbd84c8: 0x00000000
0xffbd84c4: 0xf773c000
0xffbd84c0: 0x0804825c
0xffbd84bc: 0x0804a01c
0xffbd84b8: 0xffbd84d4
0xffbd84b4: 0xffbd8534
0xffbd84b0: 0x00000003
0xffbd84ac: 0xf7765cca
0xffbd84a8: 0xffbd8544
0xffbd84a4: 0xffbd8534
0xffbd84a0: 0x00000003 (main first argument (argc))
0xffbd849c: 0xf75aaaf3 (main return address (saved eip))
0xffbd8498: 0x00000000
0xffbd8494: 0xf773c000
0xffbd8490: 0x08048820
0xffbd848c: 0xf773c000
0xffbd8488: 0x0804882b
0xffbd8484: 0x00000001 (second argument)
0xffbd8480: 0x80000000 (first argument)
0xffbd847c: 0x0804880d (place_int_array return address (saved eip))
0xffbd8478: 0xffbd8498 (saved ebp)
0xffbd8474: 0xf7778938
0xffbd8470: 0xffbda5cb
0xffbd846c: 0x00000014 //address of array[2], filled at "fill_array" function with 2*10 = 20 = 0x14
0xffbd8468: 0x0000000a //address of array[1], filled at "fill_array" function with 1*10 = 10 = 0xa
0xffbd8464: 0x00000001 (beginning of buffer) //address of array[0], overwritten with argv[2] = 1.
filled safe -2147483648 with 1.

Я ожидаю, что если слот «slot> 3» будет интерпретирован как MIN_INT + 6, то слот «array [slot]» будет интерпретирован так же.

Почему значение слота изменяется в зависимости от его использования?

1 Ответ

0 голосов
/ 07 мая 2019

@ Иан Эбботт понял. Целочисленное значение «slot» уменьшается в массиве «slot [slot]», потому что компилятор умножает «slot» на 4. поэтому, когда INT_MIN умножается на 4 - он падает до 0. и когда slot = INT_MIN + 6, при попытке вычислить адрес массива [slot], это первый многоканальный слот на 4, что равно (INT_MIN + 6) * 4, что понижает до 0 + 6 * 4, что точно 6 адресов выше адреса «array [0]». но при этом утверждении «if (slot> 3)» - slot просто отрицательное число, то есть INT_MIN + 6, поэтому «slot> 3» возвращает false.

...