Я столкнулся с проблемой переполнения целых чисел, которую мне удалось решить, но только методом проб и ошибок.
Поскольку это проблема целочисленного переполнения, я написал код для распечатки буфера.
Начало буфера - это адрес, где хранится массив [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]» будет интерпретирован так же.
Почему значение слота изменяется в зависимости от его использования?