Крис Касперски - Неявный самоконтроль как средство создания не ломаемых защит
Название: | Неявный самоконтроль как средство создания не ломаемых защит | |
Автор: | Крис Касперски | |
Жанр: | Статьи и рефераты, Самиздат, сетевая литература, Литература ХXI века (эпоха Глобализации экономики), Крэкинг и реверсинжиниринг | |
Изадано в серии: | неизвестно | |
Издательство: | неизвестно | |
Год издания: | - | |
ISBN: | неизвестно | |
Отзывы: | Комментировать | |
Рейтинг: | ||
Поделись книгой с друзьями! Помощь сайту: донат на оплату сервера |
Краткое содержание книги "Неявный самоконтроль как средство создания не ломаемых защит"
Аннотация к этой книге отсутствует.
Читаем онлайн "Неявный самоконтроль как средство создания не ломаемых защит". [Страница - 4]
целиком,
будет следить за обращениями к одной, ну максимум двумтрем, измененным им
ячейкам и… с удивлением обнаружит, что защита их вообще не контролирует.
После того, как контрольные точки выбраны, вы должны определить их сме
щение в откомпилированном файле. К сожалению, языки высокого уровня не по
зволяют определять адреса отдельных машинных инструкций и, если только вы не
пишите защиту на ассемблерных вставках, то у вас остается одинединственный
путь – воспользоваться каким ни будь дизассемблером (например, IDA).
Крис Касперски
6
Неявный самоконтроль как средство создания не ломаемых защит
Допустим, критическая часть защиты выглядит так и нам необходимо про
контролировать целостность условного оператора if, выделенного жирным синим
шрифтом:
int my_func()
{
if (check_user())
{
fprintf(stderr, "passwd ok\n");
}
else
{
fprintf(stderr, "wrong passwd\n");
exit(1);
}
return 0;
}
Загрузив откомпилированный файл в дизассемблер, мы получим следую
щий код (чтобы быстро узнать которая из всех процедур и есть my_func, опирайтесь
на тот факт, что большинство компиляторов располагает функции в памяти в по
рядке их объявления, т. е. my_func будет вторая по счету функция):
.text:00401060
.text:00401060
.text:00401065
.text:00401067
.text:00401069
.text:0040106E
.text:00401073
.text:00401078
.text:0040107B
.text:0040107D
.text:0040107E
.text:0040107E
.text:0040107E
.text:0040107E
.text:00401083
.text:00401088
.text:0040108D
.text:0040108F
.text:0040108F
sub_401060
proc near
; CODE XREF: sub_4010A0+AFvp
call
sub_401000
test
eax, eax
jz
short loc_40107E
push
offset aPasswdOk
; "passwd ok\n"
push
offset unk_407110
call
_fprintf
add
esp, 8
xor
eax, eax
retn
;
loc_40107E:
sub_401060
push
push
call
push
call
endp
; CODE XREF: sub_401060+7^j
offset aWrongPasswd ; "wrong passwd\n"
offset unk_407110
_fprintf
0FFFFFFFFh
; int
_exit
Как нетрудно сообразить, условный переход, расположенный по адресу
0x401067 и есть тот самый "if", который нам нужен. Однако, это не весь if, а только
малая чего часть. Хакер может и не трогать условного перехода, а заменить инструк
цию test eax, eax на любую другую инструкцию, сбрасывающую флаг нуля. Так же
он может модифицировать защитную функцию sub_401000, которая и осуществля
ет проверку пароля. Словом, тут много разных вариантов и на этом несчастном
условном переходе свет клином не сошелся, а потому для надежного распознавания
взлома нам потребуются дополнительные проверки. Впрочем, это уже детали. Глав
ное, что мы определили смещение контролируемого байта. Кстати, а почему имен
но байта?! Ведь мы можем контролировать хоть целое двойное слово, расположен
ное по данному смещению! Особого смысла в этом нет, просто так проще.
Крис Касперски
7
Неявный самоконтроль как средство создания не ломаемых защит
Чтобы не работать с непосредственными смещениями (это неудобно и вооб
ще некрасиво), давайте загоним их в специально на то предназначенную структуру
следующего вида:
union anti_hack
{
// буфер, содержащий оригинальный код программы
char buf[MAX_CODE_SIZE];
// локальные переменные программы
struct local_var
{
int
local_var_1;
int
local_var_2;
};
// неявно контролируемые переменные программы
struct code_control
{
char
gag_1[OFFSET_1];
int
x_val_1;
char
gag_2[OFFSET_2 OFFSET_1 sizeof(int)];
int
x_val_2;
};
};
Массив buf – это тот самый буфер, в который загружается оригинальный
код программы для его последующей расшифровки (распаковки). Поверх массива
накладываются две структуры: local_val, содержащая в себе локальные перемен
ные, которые в процессе своей инициализации затирают соответствующие им
ячейки buf'a и тем самым создают впечатление, что прежнее содержимое буфера
стало теперь ненужным и более уже не используется. Количество локальных пере
менных может быть любым, главное – следить за тем, чтобы они не перекрывали
контрольные точки программы, изменять содержимое которых нельзя. В приве
денном выше примере, по соображениям наглядности, контрольные точки выне
сены в отдельную структуру code_control, два массива которой gag_1 и gag_2 ис
пользуются лишь для того, чтобы переменные x_val_1 и x_val_2 были размещены
компилятором по необходимым нам адресам. Как нетрудно долгаться: константа
OFFSET_1 задает смещение первой контрольной точки, а OFFSET_2 – второй.
Достоинство такой схемы заключается в том, что при добавлении или удалении
локальных переменных в структуру local_var, структура code_contorl остается не
изменной. Напротив, если объединить локальные переменные и контрольные
точки --">
будет следить за обращениями к одной, ну максимум двумтрем, измененным им
ячейкам и… с удивлением обнаружит, что защита их вообще не контролирует.
После того, как контрольные точки выбраны, вы должны определить их сме
щение в откомпилированном файле. К сожалению, языки высокого уровня не по
зволяют определять адреса отдельных машинных инструкций и, если только вы не
пишите защиту на ассемблерных вставках, то у вас остается одинединственный
путь – воспользоваться каким ни будь дизассемблером (например, IDA).
Крис Касперски
6
Неявный самоконтроль как средство создания не ломаемых защит
Допустим, критическая часть защиты выглядит так и нам необходимо про
контролировать целостность условного оператора if, выделенного жирным синим
шрифтом:
int my_func()
{
if (check_user())
{
fprintf(stderr, "passwd ok\n");
}
else
{
fprintf(stderr, "wrong passwd\n");
exit(1);
}
return 0;
}
Загрузив откомпилированный файл в дизассемблер, мы получим следую
щий код (чтобы быстро узнать которая из всех процедур и есть my_func, опирайтесь
на тот факт, что большинство компиляторов располагает функции в памяти в по
рядке их объявления, т. е. my_func будет вторая по счету функция):
.text:00401060
.text:00401060
.text:00401065
.text:00401067
.text:00401069
.text:0040106E
.text:00401073
.text:00401078
.text:0040107B
.text:0040107D
.text:0040107E
.text:0040107E
.text:0040107E
.text:0040107E
.text:00401083
.text:00401088
.text:0040108D
.text:0040108F
.text:0040108F
sub_401060
proc near
; CODE XREF: sub_4010A0+AFvp
call
sub_401000
test
eax, eax
jz
short loc_40107E
push
offset aPasswdOk
; "passwd ok\n"
push
offset unk_407110
call
_fprintf
add
esp, 8
xor
eax, eax
retn
;
loc_40107E:
sub_401060
push
push
call
push
call
endp
; CODE XREF: sub_401060+7^j
offset aWrongPasswd ; "wrong passwd\n"
offset unk_407110
_fprintf
0FFFFFFFFh
; int
_exit
Как нетрудно сообразить, условный переход, расположенный по адресу
0x401067 и есть тот самый "if", который нам нужен. Однако, это не весь if, а только
малая чего часть. Хакер может и не трогать условного перехода, а заменить инструк
цию test eax, eax на любую другую инструкцию, сбрасывающую флаг нуля. Так же
он может модифицировать защитную функцию sub_401000, которая и осуществля
ет проверку пароля. Словом, тут много разных вариантов и на этом несчастном
условном переходе свет клином не сошелся, а потому для надежного распознавания
взлома нам потребуются дополнительные проверки. Впрочем, это уже детали. Глав
ное, что мы определили смещение контролируемого байта. Кстати, а почему имен
но байта?! Ведь мы можем контролировать хоть целое двойное слово, расположен
ное по данному смещению! Особого смысла в этом нет, просто так проще.
Крис Касперски
7
Неявный самоконтроль как средство создания не ломаемых защит
Чтобы не работать с непосредственными смещениями (это неудобно и вооб
ще некрасиво), давайте загоним их в специально на то предназначенную структуру
следующего вида:
union anti_hack
{
// буфер, содержащий оригинальный код программы
char buf[MAX_CODE_SIZE];
// локальные переменные программы
struct local_var
{
int
local_var_1;
int
local_var_2;
};
// неявно контролируемые переменные программы
struct code_control
{
char
gag_1[OFFSET_1];
int
x_val_1;
char
gag_2[OFFSET_2 OFFSET_1 sizeof(int)];
int
x_val_2;
};
};
Массив buf – это тот самый буфер, в который загружается оригинальный
код программы для его последующей расшифровки (распаковки). Поверх массива
накладываются две структуры: local_val, содержащая в себе локальные перемен
ные, которые в процессе своей инициализации затирают соответствующие им
ячейки buf'a и тем самым создают впечатление, что прежнее содержимое буфера
стало теперь ненужным и более уже не используется. Количество локальных пере
менных может быть любым, главное – следить за тем, чтобы они не перекрывали
контрольные точки программы, изменять содержимое которых нельзя. В приве
денном выше примере, по соображениям наглядности, контрольные точки выне
сены в отдельную структуру code_control, два массива которой gag_1 и gag_2 ис
пользуются лишь для того, чтобы переменные x_val_1 и x_val_2 были размещены
компилятором по необходимым нам адресам. Как нетрудно долгаться: константа
OFFSET_1 задает смещение первой контрольной точки, а OFFSET_2 – второй.
Достоинство такой схемы заключается в том, что при добавлении или удалении
локальных переменных в структуру local_var, структура code_contorl остается не
изменной. Напротив, если объединить локальные переменные и контрольные
точки --">
Книги схожие с «Неявный самоконтроль как средство создания не ломаемых защит» по жанру, серии, автору или названию:
Другие книги автора «Крис Касперски»:
Крис Касперски - Техника хакерских атак. Фундаментальные основы хакерства Жанр: Руководства и инструкции Год издания: 2005 |
Крис Касперски - Техника и философия хакерских атак — записки мыщ'а Жанр: Руководства и инструкции Год издания: 2004 Серия: Кодокопатель |